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

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# Quickstart: Transfer EURC on EVM chains

> Transfer EURC between wallets on EVM chains using a Node.js script

This guide walks you through transferring EURC on EVM testnets using Viem and
Node.js. You'll build a simple script that checks your balance and sends test
transfers.

## Prerequisites

Before you begin, ensure that you've:

* Installed [Node.js v22.6+](https://nodejs.org/)
* Prepared a testnet wallet on the selected chain funded with:
  * Testnet EURC for the transfer
  * Testnet native tokens for gas fees

<Note>
  You can get testnet EURC from [Circle's faucet](https://faucet.circle.com/).
</Note>

## Step 1. Set up the project

This step shows you how to prepare your project and environment.

### 1.1. Create the project and install dependencies

Create a new directory and install the required dependencies:

```bash Shell theme={null}
# Set up your directory and initialize a Node.js project
mkdir transfer-eurc-evm
cd transfer-eurc-evm
npm init -y

# Set up module type and start command
npm pkg set type=module
npm pkg set scripts.start="node --env-file=.env index.ts"

# Install runtime dependencies
npm install viem

# Install dev dependencies
npm install --save-dev typescript @types/node
```

### 1.2. Configure TypeScript (optional)

<Tip>
  This step is optional. It helps prevent missing types in your IDE or editor.
</Tip>

Create a `tsconfig.json` file:

```shell theme={null}
npx tsc --init
```

Then, update the `tsconfig.json` file:

```shell theme={null}
cat <<'EOF' > tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "types": ["node"]
  }
}
EOF
```

### 1.3. Set environment variables

Create a `.env` file in the project directory and add your wallet private key,
replacing `{YOUR_PRIVATE_KEY}` with the private key from your EVM wallet and
`{YOUR_RECIPIENT_ADDRESS}` with the address of the recipient.

```text theme={null}
PRIVATE_KEY={YOUR_PRIVATE_KEY}
RECIPIENT_ADDRESS={YOUR_RECIPIENT_ADDRESS}
```

* `PRIVATE_KEY` is the private key for the EVM wallet sending the transfer.
* `RECIPIENT_ADDRESS` is the EVM wallet address that will receive the EURC.

<Tip>
  Open `.env` in your editor rather than writing values with shell commands, and
  add `.env` to your `.gitignore`. This prevents credentials from leaking into
  your shell history or version control.
</Tip>

The `npm run start` command loads variables from `.env` using Node.js native
env-file support.

<Warning>
  This example uses one or more private keys for local testing. In production,
  use a secure key management solution and never expose or share private keys.
</Warning>

## Step 2. Create the transfer script

In this step, you'll build a script in TypeScript that transfers EURC on the
selected EVM testnet. The script derives supported chains from Viem, prompts you
to choose one at runtime, and then runs the same transfer flow for that chain.

### 2.1. Create the script file

```shell theme={null}
touch index.ts
```

### 2.2. Add the script

In `index.ts`, add the following script. It derives supported chains from the
EURC token definition and chain definitions in Viem, so the transfer flow stays
shared across EVM testnets. The script uses the client-attached ERC-20 token
actions and the EURC token definition from `viem/tokens`.

```typescript TypeScript expandable theme={null}
import { createClient, http, publicActions, walletActions } from "viem";
import * as chains from "viem/chains";
import { filterChains, isAddress, isHex } from "viem/utils";
import { privateKeyToAccount } from "viem/accounts";
import { eurc } from "viem/tokens";

import * as process from "node:process";
import * as readline from "node:readline/promises";

// 1. Ensure environment variables are set up
if (!isHex(process.env.PRIVATE_KEY) || process.env.PRIVATE_KEY.length !== 66)
  throw new Error("Set PRIVATE_KEY to a 0x-prefixed 32-byte hex string");
if (!process.env.RECIPIENT_ADDRESS || !isAddress(process.env.RECIPIENT_ADDRESS))
  throw new Error("Set RECIPIENT_ADDRESS to valid EVM address");

// 2. Setup Viem Client with `eurc` token and public/wallet actions
const client = createClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: await selectChain(),
  tokens: [eurc],
  transport: http(),
})
  .extend(publicActions)
  .extend(walletActions);

try {
  // 3. Read sender token balance before transfer
  const balance = await client.token.getBalance({ token: "eurc" });
  const amount = { formatted: "1" };
  const recipient = process.env.RECIPIENT_ADDRESS;

  console.log("Chain:", client.chain.name);
  console.log("Sender:", client.account.address);
  console.log("Recipient:", recipient);
  console.log("Balance:", balance.formatted, eurc.symbol);

  // 4. Ensure sender has enough balance
  if (Number(amount.formatted) > Number(balance.formatted))
    throw new Error("Insufficient balance");

  // 5. Estimate gas and apply a safety floor
  const estimatedGas = await client.token.transfer.estimateGas({
    amount,
    to: recipient,
    token: "eurc",
  });
  const buffered = estimatedGas + (estimatedGas * 50n) / 100n;
  const floor = 85_000n;

  // 6. Submit EURC transfer
  const hash = await client.token.transfer({
    amount,
    gas: buffered > floor ? buffered : floor,
    to: recipient,
    token: "eurc",
  });

  // 7. Print transaction details
  console.log("Transaction submitted.");
  console.log("Tx hash:", hash);
  if (client.chain.blockExplorers?.default)
    console.log(
      "Explorer:",
      `${client.chain.blockExplorers.default.url}/tx/${hash}`,
    );

  // 8. Wait for transaction confirmation
  const receipt = await client.waitForTransactionReceipt({ hash });
  if (receipt.status !== "success") throw new Error("Transaction reverted");

  console.log("Transfer confirmed!");
} catch (error) {
  // 9. Handle transfer errors
  console.error(
    "Transfer failed:",
    error instanceof Error ? error.message : error,
  );
  process.exit(1);
}

async function selectChain() {
  // Find supported testnet chains for `eurc`
  const supportedChains = filterChains({
    chains,
    sort: "name",
    testnet: true,
    token: eurc,
  });
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  try {
    // Prompt user to choose a chain
    const answer = await rl.question(
      `Select a chain for your ${eurc.symbol} transfer:\n${supportedChains
        .map((chain, index) => `${index + 1}. ${chain.name}`)
        .join("\n")}\n\nEnter a number: `,
    );
    // Validate selected chain
    const selected = supportedChains[Number.parseInt(answer, 10) - 1];
    if (!selected) throw new Error("Select a valid chain");
    return selected;
  } finally {
    rl.close();
  }
}
```

## Step 3. Run the script

Run the script using the following command:

```shell Shell theme={null}
npm start
```

You'll see output similar to the following:

```text theme={null}
Select a chain for your EURC transfer:
1. Arc Testnet
2. Avalanche Fuji
...

Enter a number: 1
Chain: Arc Testnet
Sender: 0x1A2b...7890
Recipient: 0x9F8f...1234
Balance: 250.0 EURC
Transaction submitted.
Tx hash: 0xabc123...def456
Explorer: https://explorer.testnet.arc.io/tx/0xabc123...def456
Transfer confirmed!
```

To verify the transfer, copy the transaction hash URL from the `Explorer:` line
and open it in your browser. This will take you to the testnet's block explorer,
where you can view full transaction details.

<Tip>
  **Tip:** If your script doesn't output a full explorer URL, you can manually
  paste the transaction hash into the testnet's block explorer.
</Tip>

## Summary

In this quickstart, you learned how to check balances and transfer EURC on EVM
testnets using one multichain Viem script in Node.js. Here are the key points to
remember:

* **Testnet only**. Testnet EURC has no real value.
* **Gas fees**. You need a small amount of the testnet's native token for gas.
* **Security**. Keep your private key in `.env`. Never commit secrets.
* **Single script**. The same script works across all supported EVM testnets.
* **Token actions**. The script uses ERC-20 token actions and the EURC token
  definition from [`viem/tokens`](https://viem.sh/tokens) instead of a
  hand-written ABI.
