Skip to main content
This quickstart helps you write a server-side script that bridges USDC between two EVM-compatible blockchains. The examples in this quickstart use Ethereum Sepolia and Arc Testnet, but you can use any supported EVM chains as the source or destination.

Prerequisites

Before you begin, ensure that you’ve:

Step 1. Set up the project

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

1.1. Set up your development environment

Create a new directory and install App Kit and its dependencies:
Shell
# Set up your directory and initialize a Node.js project
mkdir app-kit-quickstart-bridge-evm
cd app-kit-quickstart-bridge-evm
npm init -y

# Install App Kit and tools
npm install @circle-fin/app-kit @circle-fin/adapter-viem-v2 viem typescript tsx
Only need to bridge and want a lighter install than the full App Kit? Install the standalone bridge package instead: @circle-fin/bridge-kit

1.2. Configure TypeScript (optional)

This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:
Shell
npx tsc --init
Then, update the tsconfig.json file:
Shell
cat <<'EOF' > tsconfig.json
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "types": ["node"]
  }
}
EOF

1.3. Configure environment variables

Create an .env file in the project directory:
Shell
touch .env
Then, add your wallet private key. Replace YOUR_PRIVATE_KEY with the private key from your Ethereum Sepolia (or any EVM) wallet:
.env
PRIVATE_KEY=YOUR_PRIVATE_KEY
If you use MetaMask, follow their guide for how to find and export your private key.
Edit .env files in your IDE or editor so credentials are not leaked to your shell history.

Step 2. Bridge USDC

This step shows you how to set up your script, execute the bridge transfer, and check the result.

2.1. Create the script

Create an index.ts file in the project directory and add the following code. This code sets up your script and bridges 1.00 USDC from Ethereum Sepolia to Arc Testnet:
Using other EVM chains? Change the chain values in kit.bridge() and ensure your source wallet has USDC and both wallets have native tokens.
TypeScript
// Import App Kit and its dependencies
import { AppKit } from "@circle-fin/app-kit";
import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2";
import { inspect } from "util";

// Initialize the SDK
const kit = new AppKit();

const bridgeUSDC = async (): Promise<void> => {
  try {
    // Initialize the adapter which lets you bridge tokens from your wallet on any EVM-compatible chain
    const adapter = createViemAdapterFromPrivateKey({
      privateKey: process.env.PRIVATE_KEY as string,
    });

    console.log("---------------Starting Bridging---------------");

    // Use the same adapter for the source and destination blockchains
    const result = await kit.bridge({
      from: { adapter, chain: "Ethereum_Sepolia" },
      to: { adapter, chain: "Arc_Testnet" },
      amount: "1.00",
    });

    console.log("RESULT", inspect(result, false, null, true));
  } catch (err) {
    console.log("ERROR", inspect(err, false, null, true));
  }
};

void bridgeUSDC();
You can customize your bridges to collect a fee, use the CCTP Forwarding Service, or estimate gas and provider fees before bridging. Proceed only if the cost works for you.

2.2. Run the script

Save the index.ts file and run the script in your terminal:
Shell
npx tsx --env-file=.env index.ts

2.3. Verify the transaction

After the script finishes, find the returned steps array in the terminal output. Each transaction step includes an explorerUrl. Use that link to verify that the USDC amount matches the amount you bridged. The following code is an example of how an approve step might look in the terminal output. The values are used in this example only and are not a real transaction:
Shell
steps: [
  {
    name: "approve",
    state: "success",
    txHash: "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",
    data: {
      txHash:
        "0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",
      status: "success",
      cumulativeGasUsed: 17138643n,
      gasUsed: 38617n,
      blockNumber: 8778959n,
      blockHash:
        "0xbeadfacefeed1234567890abcdef1234567890abcdef1234567890abcdef12",
      transactionIndex: 173,
      effectiveGasPrice: 1037232n,
      explorerUrl:
        "https://testnet.arcscan.app/tx/0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",
    },
  },
];