Skip to content
Alchemy Logo

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.

  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.

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.
Was this page helpful?