Skip to content

Batch Transactions

Multiple calls in one wallet request

Use Wagmi's useSendCalls hook to send multiple calls in one wallet request. ZeroDev Wallet handles the underlying wallet_sendCalls request and executes the calls through the user's smart account.

Batching is useful for flows such as approve-and-swap, mint-and-stake, or any app action that should feel like one confirmation instead of several wallet prompts.

By default, batches are atomic: if one call reverts, the whole batch reverts.

useSendCalls

This example sends a 0 ETH self-transfer and an ERC-20 transfer in one batch. Replace the contract, calldata, and values with the calls your app needs.

import { waitForCallsStatus } from '@wagmi/core'
import { useState } from 'react'
import { type Address, type Hex, encodeFunctionData, erc20Abi } from 'viem'
import { useAccount, useConfig, useSendCalls } from 'wagmi'
 
export function BatchCalls({
  tokenAddress,
}: {
  tokenAddress: `0x${string}`
}) {
  const { address, isConnected } = useAccount()
  const config = useConfig()
  const { sendCallsAsync, isPending, error } = useSendCalls()
  const [status, setStatus] = useState<string | null>(null)
  const [transactionHash, setTransactionHash] = useState<
    `0x${string}` | null
  >(null)
 
  const sendBatch = async () => {
    if (!isConnected || !address) return
    setStatus(null)
    setTransactionHash(null)
 
    const calls: {
      to: Address
      value?: bigint
      data?: Hex
    }[] = [
      {
        to: address,
        value: BigInt(0),
      },
      {
        to: tokenAddress,
        data: encodeFunctionData({
          abi: erc20Abi,
          functionName: 'transfer',
          args: [address, BigInt(1_000_000)],
        }),
      },
    ]
 
    const { id } = await sendCallsAsync({ calls })
 
    const result = await waitForCallsStatus(config, { id })
    setStatus(result.status ?? null)
    setTransactionHash(result.receipts?.[0]?.transactionHash ?? null)
  }
 
  return (
    <div>
      <button type="button" onClick={sendBatch} disabled={isPending}>
        {isPending ? 'Sending batch...' : 'Send batch'}
      </button>
 
      {status ? <p>Status: {status}</p> : null}
      {transactionHash ? <p>Hash: {transactionHash}</p> : null}
      {error ? <p>Batch failed: {error.message}</p> : null}
    </div>
  )
}

Notes

  • useSendCalls sends an EIP-5792 wallet_sendCalls request through the connected wallet.
  • Batches can be sponsored when your project has a matching gas policy for the chain.
  • In 7702 mode, the exposed wallet address stays the user's address while the batch still uses smart wallet execution.
  • In 4337 mode, the batch executes through the user's Kernel smart account.
  • Use waitForCallsStatus with the returned id to wait for the batch result.
  • Use BigInt(...) instead of BigInt literals such as 0n if your TypeScript target is lower than ES2020.

Next steps