Send batch transactions

Using Smart Wallets, you can batch multiple actions (such as token transfers, approvals, or swaps) into a single transaction. Users will no longer need multiple confirmations or pop-ups to handle sequential actions. This helps you speed up how users interact with your app and improve the user experience.

How it works

Smart wallets support running a batch of actions, called “calls”, in a single transaction. These actions are atomic, which means if any of them fail (revert), the entire batched transaction will revert. This protects users from accidentally having part of a batch apply, but not all.

To use this feature, you just need to specify multiple calls to make. The parameter type accepts an array of calls, and each element should contain the action you want the wallet to take.

Prerequisites

Implementation

Required SDK version: ^v4.59.1

Use the useSendCalls hook to send a batched transaction. You can also use the usePrepareCalls hook to only prepare the transaction for signing.

sendCalls.tsx
1import { useSendCalls, useSmartAccountClient } from "@account-kit/react";
2import { type Address, encodeFunctionData, erc20Abi, parseUnits } from "viem";
3import { swapAbi } from "./swapAbi";
4
5export default function SendCalls() {
6 const { client } = useSmartAccountClient({});
7 const { sendCallsAsync } = useSendCalls({
8 client,
9 });
10
11 const DEMO_USDC_ADDRESS: Address =
12 "0xCFf7C6dA719408113DFcb5e36182c6d5aa491443";
13
14 const DEMO_SWAP_ADDRESS: Address =
15 "0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C";
16
17 const handleSend = async () => {
18 try {
19 const { ids } = await sendCallsAsync({
20 calls: [
21 // To batch, simply specify multiple calls in the calls array
22 {
23 // approve 5000 USDC to the swap contract
24 to: DEMO_USDC_ADDRESS,
25 data: encodeFunctionData({
26 abi: erc20Abi,
27 functionName: "approve",
28 args: [DEMO_SWAP_ADDRESS, parseUnits("5000", 6)],
29 }),
30 },
31 {
32 // swap 5000 USDC to 1 WETH
33 to: DEMO_SWAP_ADDRESS,
34 data: encodeFunctionData({
35 abi: swapAbi,
36 functionName: "swapUSDCtoWETH",
37 args: [parseUnits("5000", 6), parseUnits("1", 18)],
38 }),
39 },
40 ],
41 });
42
43 console.log("Transaction sent with ID:", ids[0]);
44 } catch (error) {
45 console.error(error);
46 }
47 };
48
49 return <button onClick={handleSend}>Click to Send</button>;
50}
export const 
const swapAbi: readonly [{ readonly type: "constructor"; readonly inputs: readonly []; readonly stateMutability: "nonpayable"; }, { readonly type: "function"; readonly name: "mint"; readonly inputs: readonly [{ readonly name: "amount1"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "amount2"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, { readonly type: "function"; readonly name: "swapUSDCtoWETH"; readonly inputs: readonly [{ readonly name: "amountIn"; readonly type: "uint256"; readonly internalType: "uint256"; }, { ...; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, { ...; }, { ...; }, { ...; }]
swapAbi
= [
{
type: "constructor"
type
: "constructor",
inputs: readonly []
inputs
: [],
stateMutability: "nonpayable"
stateMutability
: "nonpayable",
}, {
type: "function"
type
: "function",
name: "mint"
name
: "mint",
inputs: readonly [{ readonly name: "amount1"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "amount2"; readonly type: "uint256"; readonly internalType: "uint256"; }]
inputs
: [
{
name: "amount1"
name
: "amount1",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, {
name: "amount2"
name
: "amount2",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, ],
outputs: readonly []
outputs
: [],
stateMutability: "nonpayable"
stateMutability
: "nonpayable",
}, {
type: "function"
type
: "function",
name: "swapUSDCtoWETH"
name
: "swapUSDCtoWETH",
inputs: readonly [{ readonly name: "amountIn"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "amountOut"; readonly type: "uint256"; readonly internalType: "uint256"; }]
inputs
: [
{
name: "amountIn"
name
: "amountIn",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, {
name: "amountOut"
name
: "amountOut",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, ],
outputs: readonly []
outputs
: [],
stateMutability: "nonpayable"
stateMutability
: "nonpayable",
}, {
type: "function"
type
: "function",
name: "swapWETHtoUSDC"
name
: "swapWETHtoUSDC",
inputs: readonly [{ readonly name: "amountIn"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "amountOut"; readonly type: "uint256"; readonly internalType: "uint256"; }]
inputs
: [
{
name: "amountIn"
name
: "amountIn",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, {
name: "amountOut"
name
: "amountOut",
type: "uint256"
type
: "uint256",
internalType: "uint256"
internalType
: "uint256",
}, ],
outputs: readonly []
outputs
: [],
stateMutability: "nonpayable"
stateMutability
: "nonpayable",
}, {
type: "function"
type
: "function",
name: "usdc"
name
: "usdc",
inputs: readonly []
inputs
: [],
outputs: readonly [{ readonly name: ""; readonly type: "address"; readonly internalType: "contract ERC20Mintable"; }]
outputs
: [
{
name: ""
name
: "",
type: "address"
type
: "address",
internalType: "contract ERC20Mintable"
internalType
: "contract ERC20Mintable",
}, ],
stateMutability: "view"
stateMutability
: "view",
}, {
type: "function"
type
: "function",
name: "weth"
name
: "weth",
inputs: readonly []
inputs
: [],
outputs: readonly [{ readonly name: ""; readonly type: "address"; readonly internalType: "contract ERC20Mintable"; }]
outputs
: [
{
name: ""
name
: "",
type: "address"
type
: "address",
internalType: "contract ERC20Mintable"
internalType
: "contract ERC20Mintable",
}, ],
stateMutability: "view"
stateMutability
: "view",
}, ] as
type const = readonly [{ readonly type: "constructor"; readonly inputs: readonly []; readonly stateMutability: "nonpayable"; }, { readonly type: "function"; readonly name: "mint"; readonly inputs: readonly [{ readonly name: "amount1"; readonly type: "uint256"; readonly internalType: "uint256"; }, { readonly name: "amount2"; readonly type: "uint256"; readonly internalType: "uint256"; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, { readonly type: "function"; readonly name: "swapUSDCtoWETH"; readonly inputs: readonly [{ readonly name: "amountIn"; readonly type: "uint256"; readonly internalType: "uint256"; }, { ...; }]; readonly outputs: readonly []; readonly stateMutability: "nonpayable"; }, { ...; }, { ...; }, { ...; }]
const
;

Next steps

Build more: