In this recipe you'll construct an ERC-20 transfer call and submit it through a Smart Account Client. The same pattern works for any ERC-20 token; just swap the token address and number of decimals.
Prefer code? Jump straight to the React or Core tabs below.
- Smart wallets integrated in your app (see the React quickstart or Core quickstart).
- The quickstart uses Arbitrum Sepolia, so make sure your gas policy is configured for Arbitrum Sepolia if you're using the default settings.
- The USDC contract address for your target chain. For Arbitrum Sepolia this is
0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d.
- Visit Circle's documentation for USDC addresses on other chains.
import { encodeFunctionData, parseAbi } from "viem";
const usdcAddress = "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
const recipient = "0xRecipientAddress";
const amount = BigInt(10) * BigInt(1_000_000); // 10 USDC (6 decimals)
const transferCalldata = encodeFunctionData({
abi: parseAbi(["function transfer(address,uint256) returns (bool)"]),
functionName: "transfer",
args: [recipient, amount],
});import {
useSmartAccountClient,
useSendUserOperation,
} from "@account-kit/react";
export function SendUsdcButton() {
const { client } = useSmartAccountClient({});
const { sendUserOperation, sendUserOperationResult } = useSendUserOperation({
client,
waitForTxn: true,
onSuccess: () => {
console.log("USDC transfer successful!");
},
onError: (error) => {
console.error("USDC transfer failed:", error);
},
});
const handleClick = async () => {
if (!client) return;
sendUserOperation({
uo: {
target: usdcAddress,
data: transferCalldata,
value: BigInt(0), // no native value for ERC-20 transfers
},
});
};
return <button onClick={handleClick}>Send USDC</button>;
}If you're using the React hooks with waitForTxn: true, the transaction will automatically be waited for. You can access the transaction hash from sendUserOperationResult:
const { sendUserOperation, sendUserOperationResult } = useSendUserOperation({
client,
waitForTxn: true,
onSuccess: () => {
console.log("Transaction hash:", sendUserOperationResult?.hash);
},
});Alternatively, you can manually wait for the transaction:
import { useWaitForUserOperationTransaction } from "@account-kit/react";
const { waitForUserOp } = useWaitForUserOperationTransaction();
const receipt = await waitForUserOp(userOpHash);- Parameterize the token address/decimals to support any ERC-20.
- Batch multiple user operations in one request (e.g. aprrove, transfer, etc).
- Combine with sponsored gas for a completely gas-less UX.