> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sending USDC

> Send USDC from a Dynamic embedded wallet on EVM chains using the JavaScript SDK.

USDC is an ERC-20 token, so a transfer is a `transfer(to, value)` call on the USDC contract. The JS SDK exposes a viem `WalletClient` for any wallet account via [`createWalletClientForWalletAccount`](https://docs.dynamic.xyz/docs/javascript/reference/evm/getting-viem-wallet-client) — you read the account from `getWalletAccounts` (or `useGetWalletAccounts` in React), encode the call with viem's `erc20Abi`, and you're done.

## Setup

Follow the [JavaScript Quickstart](https://docs.dynamic.xyz/docs/javascript/reference/quickstart.md) for a vanilla setup, or the [React Quickstart (JS SDK)](https://docs.dynamic.xyz/docs/javascript/reference/react-quickstart.md) for a Vite + React app with `<DynamicProvider>` and the EVM extension. The rest of this guide picks up from there.

Install viem alongside the SDK packages:

```bash theme={"system"}
npm i viem
```

## Step 1: Get the USDC contract address

USDC is deployed at a different address on every chain. Look up the right one on Circle's references:

* [USDC on main networks](https://developers.circle.com/stablecoins/usdc-on-main-networks)
* [USDC on test networks](https://developers.circle.com/stablecoins/usdc-on-test-networks)

USDC has **6 decimals** on every EVM chain — always convert with `parseUnits(amount, 6)`.

## Step 2: Build the send function

Read the user's EVM wallet account with `getWalletAccounts` (or `useGetWalletAccounts` in React), narrow it with `isEvmWalletAccount`, then call `writeContract` against the USDC contract using viem's built-in `erc20Abi`.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { getWalletAccounts, getActiveNetworkData } from "@dynamic-labs-sdk/client";
> import { isEvmWalletAccount } from "@dynamic-labs-sdk/evm";
> import {
>   createWalletClientForWalletAccount,
>   createPublicClientFromNetworkData,
> } from "@dynamic-labs-sdk/evm/viem";
> import { parseUnits, erc20Abi } from "viem";
>
> // Base mainnet USDC — swap for the address on your target chain.
> const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
>
> async function sendUsdc(recipient, amount) {
>   const accounts = getWalletAccounts();
>   const walletAccount = accounts.find(isEvmWalletAccount);
>   if (!walletAccount) throw new Error("No EVM wallet account found");
>
>   const walletClient = await createWalletClientForWalletAccount({ walletAccount });
>   const hash = await walletClient.writeContract({
>     address: USDC_ADDRESS,
>     abi: erc20Abi,
>     functionName: "transfer",
>     args: [recipient, parseUnits(amount, 6)],
>   });
>
>   const { networkData } = await getActiveNetworkData({ walletAccount });
>   const publicClient = createPublicClientFromNetworkData({ networkData });
>   await publicClient.waitForTransactionReceipt({ hash });
>
>   return hash;
> }
> ```

> [tab] React
>
> Use `useGetWalletAccounts` to reactively get the wallet, then call `createWalletClientForWalletAccount` inside the click handler:
>
> ```tsx src/components/SendUsdcButton.tsx theme={"system"}
> import { useState } from "react";
> import { useGetWalletAccounts } from "@dynamic-labs-sdk/react-hooks";
> import { isEvmWalletAccount } from "@dynamic-labs-sdk/evm";
> import {
>   createWalletClientForWalletAccount,
>   createPublicClientFromNetworkData,
> } from "@dynamic-labs-sdk/evm/viem";
> import { getActiveNetworkData } from "@dynamic-labs-sdk/client";
> import { parseUnits, erc20Abi } from "viem";
>
> // Base mainnet USDC — swap for the address on your target chain.
> const USDC_ADDRESS: `0x${string}` = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
>
> export function SendUsdcButton({
>   recipient,
>   amount,
> }: {
>   recipient: `0x${string}`;
>   amount: string;
> }) {
>   const { data: accounts = [] } = useGetWalletAccounts();
>   const walletAccount = accounts.find(isEvmWalletAccount);
>   const [txHash, setTxHash] = useState<`0x${string}` | null>(null);
>   const [pending, setPending] = useState(false);
>
>   const handleSend = async () => {
>     if (!walletAccount) return;
>     setPending(true);
>     try {
>       const walletClient = await createWalletClientForWalletAccount({ walletAccount });
>       const hash = await walletClient.writeContract({
>         address: USDC_ADDRESS,
>         abi: erc20Abi,
>         functionName: "transfer",
>         args: [recipient, parseUnits(amount, 6)],
>       });
>       setTxHash(hash);
>
>       const { networkData } = await getActiveNetworkData({ walletAccount });
>       const publicClient = createPublicClientFromNetworkData({ networkData });
>       await publicClient.waitForTransactionReceipt({ hash });
>     } finally {
>       setPending(false);
>     }
>   };
>
>   return (
>     <>
>       <button onClick={handleSend} disabled={!walletAccount || pending}>
>         {pending ? "Sending…" : `Send ${amount} USDC`}
>       </button>
>       {txHash && <p>Tx: {txHash}</p>}
>     </>
>   );
> }
> ```

> [!NOTE]
>
> `createWalletClientForWalletAccount` signs on whatever network the wallet is currently on. To target a specific chain, switch the wallet first with [`switchActiveNetwork`](https://docs.dynamic.xyz/docs/javascript/reference/wallets/switch-active-network) — `useSwitchActiveNetwork` in React.

> [!TIP]
>
> The sender needs native token (ETH, and so on) to pay gas for the transfer. To pay it for them instead, use [EVM gas sponsorship](https://docs.dynamic.xyz/docs/javascript/reference/evm/evm-gas-sponsorship.md): `sendSponsoredTransaction` takes the same `transfer` call as encoded calldata.

## Handling errors

Wrap the send call (`sendUsdc` in the JavaScript tab, `handleSend` in the React tab) in a try/catch and match on the message to tell the common failures apart:

```ts theme={"system"}
try {
  await sendUsdc(recipient, amount);
} catch (err: any) {
  if (err.message?.includes("insufficient funds")) {
    // Not enough native token for gas, or not enough USDC.
  } else if (err.message?.includes("User rejected")) {
    // User dismissed the signing prompt.
  } else {
    console.error(err);
  }
}
```

To catch a failing transfer before the user signs, preview it with [`simulateEvmTransaction`](https://docs.dynamic.xyz/docs/javascript/reference/evm/simulate-evm-transaction), which returns the expected asset changes plus a security verdict.

## Related

* [`createWalletClientForWalletAccount`](https://docs.dynamic.xyz/docs/javascript/reference/evm/getting-viem-wallet-client) — viem wallet client for any EVM wallet account
* [`createPublicClientFromNetworkData`](https://docs.dynamic.xyz/docs/javascript/reference/evm/getting-viem-public-client) — viem public client for reads and receipts
* [`isEvmWalletAccount`](https://docs.dynamic.xyz/docs/javascript/reference/evm/checking-evm-wallet-account-type) — type guard for EVM accounts
* [Sign and send a transaction](https://docs.dynamic.xyz/docs/javascript/reference/evm/sign-transaction.md) — lower-level transaction reference
* [`getTokenBalances`](https://docs.dynamic.xyz/docs/javascript/reference/wallets/get-token-balances) — check the sender's USDC balance before transferring
* [EVM gas sponsorship](https://docs.dynamic.xyz/docs/javascript/reference/evm/evm-gas-sponsorship.md) — pay the user's gas for them
* [`simulateEvmTransaction`](https://docs.dynamic.xyz/docs/javascript/reference/evm/simulate-evm-transaction) — preview a transfer before sending
* [Receiving USDC](https://docs.dynamic.xyz/docs/recipes/stablecoins/receive-usdc.md)
* [Sending USDC by email or phone](https://docs.dynamic.xyz/docs/recipes/stablecoins/transfer-usdc-by-identifier.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.