Tip: Collect a fee on transfers and estimate gas and provider fees before a transfer, only proceeding if the cost is acceptable.
This quickstart guide helps you write a script that transfers USDC from Ethereum to Solana.
Before you begin, ensure that you've:
Create a new directory, initialize a new Node.js project, and install dependencies:
# Setup your directory and initialize the project
mkdir bridge-kit-quickstart-transfer-eth-to-sol
cd bridge-kit-quickstart-transfer-eth-to-sol
npm init -y
# Install Bridge Kit and tools
npm install @circle-fin/bridge-kit @circle-fin/adapter-viem-v2 @circle-fin/adapter-solana @solana/web3.js @solana/spl-token viem typescript tsx dotenv
First, initialize the project, which 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 wallet private key,
replacing {YOUR_PRIVATE_KEY}
with the private key for your Ethereum Sepolia
wallet and {YOUR_SOLANA_PRIVATE_KEY}
with the Base58-encoded private key for
your Solana Devnet wallet. (You can find and
export your private key
in MetaMask.)
echo "PRIVATE_KEY={YOUR_PRIVATE_KEY}
SOLANA_PRIVATE_KEY={YOUR_SOLANA_PRIVATE_KEY}" > .env
For this quickstart, you need both USDC and native tokens in your Ethereum testnet wallet and native tokens in your Solana testnet wallet. If you need USDC testnet tokens, use the Circle Faucet to get 10 USDC on the Ethereum Sepolia and Solana Devnet testnets.
Use the following faucets to get testnet native tokens in your wallets:
The sections in this step demonstrate how to set up your script, execute the bridge transfer, and check the result.
Create an index.ts
file in the project directory and add the following code.
This code sets up your script and transfers 10 USDC from Ethereum to Solana:
// Import Bridge Kit and dependencies
import "dotenv/config";
import { BridgeKit } from "@circle-fin/bridge-kit";
import { createAdapterFromPrivateKey as createViemAdapterFromPrivateKey } from "@circle-fin/adapter-viem-v2";
import { createAdapterFromPrivateKey as createSolanaAdapterFromPrivateKey } from "@circle-fin/adapter-solana";
import { inspect } from "util";
// Initialize the SDK
const kit = new BridgeKit();
const bridgeUSDC = async (): Promise<void> => {
try {
// Initialize the Viem adapter which lets you transfer tokens from your wallet on any EVM-compatible chain
const viemAdapter = createViemAdapterFromPrivateKey({
privateKey: process.env.PRIVATE_KEY as string,
});
// Initialize the Solana adapter which lets you transfer tokens on Solana
const solanaAdapter = createSolanaAdapterFromPrivateKey({
privateKey: process.env.SOLANA_PRIVATE_KEY as string,
});
console.log("---------------Starting Bridging---------------");
// Transfer 10 USDC from Ethereum to Solana
const result = await kit.bridge({
from: { adapter: viemAdapter, chain: "Ethereum_Sepolia" },
to: { adapter: solanaAdapter, chain: "Solana_Devnet" },
amount: "10",
});
console.log("RESULT", inspect(result, false, null, true));
} catch (err) {
console.log("ERROR", inspect(err, false, null, true));
}
};
void bridgeUSDC();
To transfer from Solana to Ethereum, switch the source and destination adapter and chain in your bridge call:
// Transfer 10 USDC from Solana to Ethereum
const result = await kit.bridge({
// Specify Solana as the source chain
from: { adapter: solanaAdapter, chain: "Solana_Devnet" },
// Specify Ethereum as the destination chain
to: { adapter: viemAdapter, chain: "Ethereum_Sepolia" },
amount: "5",
});
Tip: Collect a fee on transfers and estimate gas and provider fees before a transfer, only proceeding if the cost is acceptable.
Save the index.ts
file and run the script in your terminal:
npx tsx index.ts
After your script completes, find the returned steps
array in the terminal
output. Each transaction step includes an explorerUrl
that you can visit 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://sepolia.etherscan.io/tx/0xdeadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcd",
},
];