createComposableBatch is the entry point of the SDK. It returns a ComposableBatchInstance — a builder that collects composable calls in order and serialises them for execution.
import { createComposableBatch } from '@biconomy/smart-batching';
const batch = createComposableBatch(publicClient, accountAddress);Parameters
| Parameter | Type | Description |
|---|---|---|
publicClient |
PublicClient |
Viem public client for the target chain |
accountAddress |
Address |
The smart account address that will execute the batch |
Returns ComposableBatchInstance
| Property | Type | Description |
|---|---|---|
publicClient |
PublicClient |
The public client passed at construction |
accountAddress |
Address |
The smart account address |
length |
number |
Number of pending calls currently in the batch |
Returns an ERC20TokenInstance for the given token address, bound to the batch's account.
erc20Token(tokenAddress: Address): ERC20TokenInstanceconst USDC = '0xUsdcAddress';
const usdc = batch.erc20Token(USDC);See token.md for all methods on ERC20TokenInstance.
Returns a NativeTokenInstance for native ETH, bound to the batch's account.
nativeToken(): NativeTokenInstanceconst eth = batch.nativeToken();See token.md for all methods on NativeTokenInstance.
Returns a fully typed ContractInstance for any contract with a given ABI.
contract<TAbi>(address: Address, abi: TAbi): ContractInstance<TAbi>const myContract = batch.contract('0xContractAddress', MY_ABI);See contract.md for all methods on ContractInstance.
Returns a StorageInstance scoped to the batch's account address.
storage(): StorageInstanceconst storage = batch.storage();See storage.md for all methods on StorageInstance.
Appends one or more calls to the batch. Order is preserved. Accepts a single call, a Promise of a call, or an array of either.
add(
calls: ComposableCall | Promise<ComposableCall> | (ComposableCall | Promise<ComposableCall>)[]
): voidconst USDC = '0xUsdcAddress';
const amount = parseUnits('10', 6);
const usdc = batch.erc20Token(USDC);
// Single call
batch.add(
usdc.write({ functionName: 'transfer', args: ['0xRecipientAddress', amount] }),
);
// Multiple calls — order is preserved
batch.add([
usdc.check({
functionName: 'balanceOf',
args: ['0xRecipientAddress'],
constraint: { gte: amount },
}),
usdc.write({ functionName: 'transfer', args: ['0xRecipientAddress', amount] }),
]);
console.log(batch.length); // 3Removes all pending calls from the batch.
clear(): voidbatch.clear();
console.log(batch.length); // 0Resolves all pending calls and returns a ComposableCall[]. Use this when your execution client accepts a calls array directly (e.g. MEE).
toCalls(): Promise<ComposableCall[]>const calls = await batch.toCalls();
const quote = await meeClient.getQuote({
instructions: [{ calls, chainId: baseSepolia.id, isComposable: true }],
feeToken: { address: '0xUsdcAddress', chainId: baseSepolia.id },
});
const { hash } = await meeClient.executeQuote({ quote });
await meeClient.waitForSupertransactionReceipt({ hash });Encodes the full batch as executeComposable calldata. Use this when you control the UserOp directly via a bundler (ZeroDev, Alchemy, Pimlico, or any ERC-4337 bundler).
toCalldata(): Promise<Hex>const calldata = await batch.toCalldata();
const userOpHash = await kernelClient.sendUserOperation({
callData: calldata,
});