This quickstart helps you write a server-side script that bridges USDC between
Solana and an EVM-compatible blockchain. The examples in this quickstart use
Solana Devnet and Arc Testnet, but you can use Solana and any
supported EVM chain as source or
destination.
Prerequisites
Before you begin, ensure that you’ve:
- Installed Node.js v22+ and
npm.
- Created a Solana Devnet wallet and an
Arc Testnet
wallet using a wallet provider such as MetaMask.
- Funded your wallets with testnet tokens:
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 Bridge Kit and its dependencies:
# Set up your directory and initialize the project
mkdir bridge-kit-quickstart-transfer-sol-to-arc
cd bridge-kit-quickstart-transfer-sol-to-arc
npm init -y
# Install Bridge Kit and tools (Solana + EVM adapters)
npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2 @circle-fin/adapter-solana-kit @solana/kit @solana/web3.js viem typescript tsx
First, initialize the project. This command creates a tsconfig.json file:
# Initialize a TypeScript project
npx tsc --init
Then, edit the tsconfig.json file:
# Replace the contents of the generated file
cat <<'EOF' > tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true
}
}
EOF
Create an .env file in the project directory and add your Solana wallet
private key and your Arc Testnet (EVM) wallet private key, replacing the
placeholders with your keys.
echo "SOLANA_PRIVATE_KEY={YOUR_SOLANA_PRIVATE_KEY}
EVM_PRIVATE_KEY={YOUR_ARC_TESTNET_PRIVATE_KEY}" > .env
This use of a private key is simplified for demonstration purposes. In
production, store and access your private key securely and never share it.
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 transfers 1 USDC from Solana Devnet to Arc
Testnet.
Using a different EVM chain or Solana as the destination? Change the chain
values in kit.bridge() and ensure your source wallet has USDC and both wallets
have native tokens.
// Import Bridge Kit and dependencies
import { BridgeKit } from "@circle-fin/bridge-kit";
import { createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2";
import { createSolanaKitAdapterFromPrivateKey } from "@circle-fin/adapter-solana-kit";
import { inspect } from "util";
const kit = new BridgeKit();
const bridgeUSDC = async (): Promise<void> => {
try {
const solanaAdapter = createSolanaKitAdapterFromPrivateKey({
privateKey: process.env.SOLANA_PRIVATE_KEY as string,
});
const evmAdapter = createViemAdapterFromPrivateKey({
privateKey: process.env.EVM_PRIVATE_KEY as string,
});
console.log("---------------Starting Bridging---------------");
const result = await kit.bridge({
from: { adapter: solanaAdapter, chain: "Solana_Devnet" },
to: { adapter: evmAdapter, 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();
2.2. Run the script
Save the index.ts file and run the script in your terminal:
npx tsx --env-file=.env index.ts
2.3. Verify the transfer
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 transferred.
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:
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",
},
},
];