Skip to content

Batch Transactions

With Smart Wallet, you can send multiple onchain calls in a single transaction. Doing so improves the UX of multi-step interactions by reducing them to a single click. A common example of where you might want to leverage batch transactions is an ERC-20 approve followed by a swap.

You can submit batch transactions by using EIP-5792 RPC methods.

Using Wagmi + Viem

1. (Optional) Check for atomic batching support

Smart Wallet will submit multiple calls as part of a single transaction. However, if your app supports other wallets, and you want to check that multiple calls will be submitted atomically (in a single transaction), check the wallet's capabilities.

import { useWalletClient } from 'wagmi'
import { walletActionsEip5792 } from 'viem/experimental'
 
const { data: walletClient } = useWalletClient()
 
if (walletClient) {
  const client = walletClient.extend(walletActionsEip5792())
  const capabilities = await client.getCapabilities()
{
8453: {
atomicBatch: {
supported: true,
},
}
}

The getCapabilities method will return, per chain, the capabilities that the connected wallet supports. If the connected wallet supports atomic batching, it will return an atomicBatch capability with a supported field equal to true for each chain it supports atomic batching on.

2. Send the calls

If you have your smart contract ABIs, the easiest way to send multiple calls is to use the Viem writeContracts action.

import { useWalletClient } from 'wagmi'
import { erc20Abi, parseUnits } from "viem";
import { walletActionsEip5792 } from 'viem/experimental'
 
const { data: walletClient } = useWalletClient()
 
if (walletClient) {
  const client = walletClient.extend(walletActionsEip5792())
  const id = await client.writeContracts({
    contracts: [
      {
        abi: erc20Abi,
        address: '0x...', // ERC-20
        functionName: 'approve',
        args: ['0x...', parseUnits('10', 18)],
      },
      {
        address: '0x...', // Your contract
        abi: [], // Your contract ABI
        functionName: '...',
        args: [],
      },
    ]
  })
}

The Viem writeContracts action will construct the necessary calldata for you, given you provide your smart contract ABIs. You can, however, use the lower level sendCalls method if you want to provide the calldata yourself.

import { useWalletClient } from 'wagmi'
import { erc20Abi, parseUnits, encodeFunctionData, parseEther } from "viem";
import { walletActionsEip5792 } from 'viem/experimental'
 
const { data: walletClient } = useWalletClient()
 
if (walletClient) {
  const client = walletClient.extend(walletActionsEip5792())
  const id = await client.sendCalls({
    calls: [
      {
        to: '0x...', // ERC-20
        data: encodeFunctionData({
          abi: erc20Abi,
          functionName: 'approve',
          args: ['0x...', parseUnits('10', 18)],
        }),
      },
      {
        to: '0x...', // Your contract
        data: '0x...',
        value: parseEther('0.001')
      },
    ],
  })
}

3. Check on the status of your calls

The above writeContracts and sendCalls examples both return a call bundle identifier. Ese the Viem getCallsStatus action with this identifier to check on the status of your calls.

This will return a PENDING or CONFIRMED status along with a subset of a transaction receipt.

import { useWalletClient } from 'wagmi'
import { walletActionsEip5792 } from 'viem/experimental'
 
const { data: walletClient } = useWalletClient()
 
if (walletClient) {
  const client = walletClient.extend(walletActionsEip5792())
  // ...
  // ...
  const status = await client.getCallsStatus({id: '...'}) // The id returned by writeContracts / sendCalls
{
status: 'CONFIRMED',
receipts: [
{
logs: [
{
address: '0x...',
topics: [
'0x...'
],
data: '0x...'
},
],
status: 'success',
blockHash: '0x...',
blockNumber: 122414523n,
gasUsed: 390000n,
transactionHash: '0x...'
}
]
}