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.
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.
- API key from your dashboard
- Smart Wallets installed and configured in your project.
@alchemy/wallet-apis (v5.x.x) is currently in beta but is the recommended replacement for @account-kit/wallet-client (v4.x.x). If you run into any issues, please reach out.You can batch transactions using either the smart wallet client sendCalls or prepareCalls actions.
import { type Address, erc20Abi, encodeFunctionData, parseUnits } from "viem";
import { client } from "./client";
import { swapAbi } from "./swapAbi";
const DEMO_USDC_ADDRESS: Address = "0xCFf7C6dA719408113DFcb5e36182c6d5aa491443";
const DEMO_SWAP_ADDRESS: Address = "0xB0AEC4c25E8332256A91bBaf169E3C32dfC3C33C";
// Send a batch of calls — approve + swap in a single transaction
const { id } = await client.sendCalls({
calls: [
// To batch, simply specify multiple calls in the calls array
{
// approve 5000 USDC to the swap contract
to: DEMO_USDC_ADDRESS,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "approve",
args: [DEMO_SWAP_ADDRESS, parseUnits("5000", 6)],
}),
},
{
// swap 5000 USDC to 1 WETH
to: DEMO_SWAP_ADDRESS,
data: encodeFunctionData({
abi: swapAbi,
functionName: "swapUSDCtoWETH",
args: [parseUnits("5000", 6), parseUnits("1", 18)],
}),
},
],
});
// Wait for the transaction to be confirmed
const result = await client.waitForCallsStatus({ id });
console.log(result);Using @account-kit/wallet-client (v4.x.x)?
The examples on this page use @alchemy/wallet-apis (v5.x.x). If you're using @account-kit/wallet-client (v4.x.x), the client setup looks like this:
import { LocalAccountSigner } from "@aa-sdk/core";
import { createSmartWalletClient } from "@account-kit/wallet-client";
import { alchemy, sepolia } from "@account-kit/infra";
const signer = LocalAccountSigner.privateKeyToAccountSigner("0xYOUR_PRIVATE_KEY" as const);
export const client = createSmartWalletClient({
transport: alchemy({ apiKey: "YOUR_API_KEY" }),
chain: sepolia,
signer,
account: signer.address, // can also be passed per action as `from` or `account`
// Optional: sponsor gas for your users (see "Sponsor gas" guide)
policyId: "YOUR_POLICY_ID",
});Key v4.x.x differences:
- Account address must be specified on the client or per action (
fromoraccount). In v5.x.x, the client automatically uses the signer's address as the account address via EIP-7702. - Chain imports come directly from
@account-kit/infrainstead ofviem/chains. - Numeric values use hex strings:
value: "0x0"instead ofvalue: BigInt(0). - In v4.x.x, the paymaster capability on
prepareCallsorsendCallsis calledpaymasterServiceinstead ofpaymaster, or you can set thepolicyIddirectly on the client. - Signers use
LocalAccountSigner/WalletClientSignerfrom@aa-sdk/core. In v5.x.x, a viemLocalAccountorWalletClientis used directly.
See the full migration guide for a complete cheat sheet.
Build more: