IntroductionRecipes

Send USDC (or other ERC-20s)

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.

Prerequisites

  1. 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.
  1. The USDC contract address for your target chain. For Arbitrum Sepolia this is 0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d.

1. Encode the transfer calldata

1import { encodeFunctionData, parseAbi } from "viem";
2
3const usdcAddress = "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d";
4const recipient = "0xRecipientAddress";
5const amount = BigInt(10) * BigInt(1_000_000); // 10 USDC (6 decimals)
6
7const transferCalldata = encodeFunctionData({
8 abi: parseAbi(["function transfer(address,uint256) returns (bool)"]),
9 functionName: "transfer",
10 args: [recipient, amount],
11});

2. Send the transaction

1import {
2 useSmartAccountClient,
3 useSendUserOperation,
4} from "@account-kit/react";
5
6export function SendUsdcButton() {
7 const { client } = useSmartAccountClient({});
8
9 const { sendUserOperation, sendUserOperationResult } = useSendUserOperation({
10 client,
11 waitForTxn: true,
12 onSuccess: () => {
13 console.log("USDC transfer successful!");
14 },
15 onError: (error) => {
16 console.error("USDC transfer failed:", error);
17 },
18 });
19
20 const handleClick = async () => {
21 if (!client) return;
22
23 sendUserOperation({
24 uo: {
25 target: usdcAddress,
26 data: transferCalldata,
27 value: BigInt(0), // no native value for ERC-20 transfers
28 },
29 });
30 };
31
32 return <button onClick={handleClick}>Send USDC</button>;
33}

3. Wait for the transaction to be mined

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:

1const { sendUserOperation, sendUserOperationResult } = useSendUserOperation({
2 client,
3 waitForTxn: true,
4 onSuccess: () => {
5 console.log("Transaction hash:", sendUserOperationResult?.hash);
6 },
7});

Alternatively, you can manually wait for the transaction:

1import { useWaitForUserOperationTransaction } from "@account-kit/react";
2
3const { waitForUserOp } = useWaitForUserOperationTransaction();
4const receipt = await waitForUserOp(userOpHash);

Next steps

  • 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.