meow-cto.xyz

How to Batch Multiple Transactions into One UserOperation

Batching multiple transactions into a single UserOperation means combining separate on-chain actions - like approving a token and then swapping it - into one atomic bundle that executes through a smart contract wallet via ERC-4337. This reduces gas costs, simplifies user experience, and ensures the entire sequence succeeds or fails together.

Why Batch Transactions in a UserOperation

A standard Ethereum transaction can only do one thing: call one contract function. If you need to approve a token and then trade it, you send two separate transactions. With a smart wallet and ERC-4337, you can pack both calls into a single UserOperation. The entry point contract executes them in order within one transaction, so you pay gas only once for the entire batch, and if the second step fails, the first is reverted.

Batching also helps with atomicity. If you need to deposit into a lending protocol and then borrow against that deposit, doing it in two separate transactions risks the price moving or the deposit succeeding while the borrow fails. A UserOperation batch locks the sequence together.

How batching works in ERC-4337

ERC-4337 defines a UserOperation as a struct that includes a callData field. Normally, this field contains a single ABI-encoded function call to your smart wallet. To batch, you instead encode a sequence of calls into that callData. The smart wallet contract must support this - most do by exposing a batchExecute or executeBatch function.

The typical flow:

  1. Prepare the individual calls. For each action, get the target contract address, the function selector, and the encoded parameters.
  2. Encode the batch. Pack the list of calls (target, value, data) into the format your wallet expects. For example, a Safe smart wallet uses execTransaction with an array of Operation structs; an Argent wallet uses multicall.
  3. Wrap the batch into a UserOperation. Set the callData field to the ABI-encoded executeBatch call with your array of actions.
  4. Sign and submit. Sign the UserOperation hash and send it to a bundler. The bundler includes it in a bundle sent to the entry point.

Step-by-Step example: approve and swap

Assume you want to swap USDC for ETH on Uniswap. The batch has two calls:

Step 1: Encode the approve call. Target: USDC contract address. Data: approve(spender, amount) ABI-encoded.

Step 2: Encode the swap call. Target: Uniswap router address. Data: swapExactTokensForETH(amountIn, amountOutMin, path, to, deadline) ABI-encoded.

Step 3: Combine into a batch array. Your smart wallet's executeBatch function expects something like: executeBatch([(usdcAddress, 0, approveData), (routerAddress, 0, swapData)])

Step 4: Set callData in the UserOperation. The callData field is the ABI-encoded executeBatch call with that array.

Step 5: Calculate the gas limit. Batching often uses less total gas than two separate UserOperations, but the bundled call may have a higher single-call gas limit. Estimate it carefully - most bundlers reject UserOperations with a callGasLimit too low to execute the batch.

Step 6: Sign and send. Use your smart wallet's signature method (ERC-1271 for contract wallets) to sign the UserOperation hash. Submit to a bundler.

What Happens On-Chain

The entry point contract validates the UserOperation, then calls your smart wallet's executeBatch function. The wallet iterates through your array, executing each call sequentially. If any call reverts, the entire executeBatch reverts, and the UserOperation fails. The entry point refunds any unused gas to the paymaster or user.

Common Pitfalls

Tools and Libraries

Most smart wallet SDKs - Safe's @safe-global/safe-core-sdk, Argent's SDK, Biconomy's SDK - expose batch execution methods. Ethers.js and viem both let you encode multiple calls into a single callData field. For testing, you can use the ERC-4337 bundler's eth_estimateUserOperationGas RPC method with your batched callData to see if the estimate succeeds.

When not to batch

Batching is not always optimal. If you need to confirm the result of the first transaction before proceeding (for example, checking a price feed), separate UserOperations give you that control. Also, batching increases the calldata size, which can raise the base fee if the network is congested. For simple sequences like "approve then transfer," batching is usually beneficial; for complex multi-step DeFi strategies, weigh the gas savings against the loss of intermediate state checks.

Not financial advice. meow-cto.xyz publishes market data and general information about Meow. Crypto assets are volatile and you can lose everything you put in. Nothing here is a recommendation to buy, sell or hold, and we make no price predictions.

Prices are sourced from third parties and may be delayed or wrong. Verify anything you intend to act on against a primary source.

Back to smart wallets