Cross-Chain Token Setup: BurnMint with SPL Token Multisig Tutorial
This educational tutorial demonstrates how to create and configure cross-chain tokens using Chainlink's Cross-Chain Interoperability Protocol (CCIP) between Solana Devnet and Ethereum Sepolia using SPL token multisig concepts. You will learn to implement the SPL token multisig approach within Path A from the CCIP Cross-Chain Token Integration Guide.
Path A Mint Authority Options:
- Direct Transfer: Transfer mint authority directly to Pool Signer PDA - suitable for development and testing (see tutorial)
- Multisig Setup (this tutorial): Learn SPL token multisig concepts with Pool Signer PDA as a member - foundation for production systems
- Production Multisig: Enterprise-grade dual-layer governance with Squads + SPL multisig (see tutorial)
This tutorial focuses on demonstrating multisig architecture concepts, helping you understand governance controls while maintaining autonomous cross-chain token transfers through BurnMint token pools.
What You Will Build
This tutorial implements the SPL token multisig variant of Path A from the CCIP Cross-Chain Token Integration Guide. This approach is designed for learning multisig concepts and provides a foundation for production systems.
Cross-Chain Token Architecture
This tutorial implements the Burn and Mint token handling mechanism between Solana Devnet and Ethereum Sepolia with SPL token multisig governance. You'll deploy two BurnMint pools (one on each chain) that work together to maintain consistent token supply across chains while learning multisig architecture concepts.
How Burn and Mint Works:
- Source Chain: Burns tokens from sender's account
- CCIP Protocol: Transmits message cross-chain
- Destination Chain: Mints equivalent tokens to the receiver
Component Overview
| Component | Implementation | Authority Model |
|---|---|---|
| Ethereum Sepolia | ERC20 token with CCIP BurnMint pool | Multiple minters: EOA + Pool |
| Solana Devnet | SPL token with CCIP BurnMint pool | SPL Token Multisig: Pool Signer PDA + Admin wallet |
SPL Token Multisig Architecture
Key Approach: You will create an SPL token multisig that includes the Pool Signer PDA as a required member, enabling both autonomous CCIP operations and governance-controlled minting.
Educational Focus: This tutorial demonstrates multisig architecture concepts using a simplified 1-of-2 configuration for learning purposes.
Prerequisites
This tutorial uses a two-terminal workflow across two repositories. Install the system tools below, clone both repos, then complete environment setup before starting Phase 1.
System Requirements
- Node.js v22 or higher: Verify with
node -v(nvm recommended) - pnpm: Required for the BS58 generator (
npm install -g pnpm) - Solana CLI: Installation guide (includes
spl-token) - Git: For cloning repositories
- CCIP CLI: For cross-chain transfer testing in the final phase
Install the CCIP CLI globally:
npm install -g @chainlink/ccip-cli
ccip-cli --help
See the CCIP CLI documentation for RPC and wallet configuration.
Tutorial Workflow
| Terminal | Repository | Purpose | Commands |
|---|---|---|---|
| Terminal 1 | CCIP Solana BS58 Generator | Solana setup and configuration | pnpm bs58 |
| Terminal 2 | Smart Contract Examples (Hardhat) | EVM deploy and configuration | npx hardhat |
| Either | Global @chainlink/ccip-cli | Cross-chain transfer testing (final) | ccip-cli send |
Terminal 1: CCIP Solana BS58 Generator
Clone and install (skip git clone if you already have the repo):
git clone https://github.com/smartcontractkit/ccip-solana-bs58-generator.git
cd ccip-solana-bs58-generator
pnpm install
Configure Solana CLI for devnet:
First, check whether your environment is already set up:
solana config get
solana address
solana balance
If the RPC URL is already https://api.devnet.solana.com, your keypair path is correct, and you have sufficient SOL, skip to Terminal 2 setup below.
Otherwise, run only the steps you need:
# Set devnet (skip if config get already shows devnet)
solana config set --url https://api.devnet.solana.com
# Point to your keypair (skip if config get already shows the path you want)
solana config set --keypair ~/.config/solana/id.json
# Create a keypair only if the file does not exist yet
solana-keygen new --outfile ~/.config/solana/id.json
# Fund your wallet if balance is low
solana airdrop 2
solana balance
Terminal 2: Smart Contract Examples (Hardhat)
Clone, install, and compile (skip git clone if you already have the repo):
git clone https://github.com/smartcontractkit/smart-contract-examples.git
cd smart-contract-examples/ccip/cct/hardhat
npm install
npm run compile
Set up encrypted environment variables:
# Required at the start of each session
npx env-enc set-pw
# Verify existing variables (skip npx env-enc set if all required vars are already configured)
npx env-enc view
# Add or update variables only if missing
npx env-enc set
Required variables for Ethereum Sepolia:
ETHEREUM_SEPOLIA_RPC_URL: RPC endpoint from Alchemy or InfuraPRIVATE_KEY: Your testnet wallet private key (MetaMask export guide)ETHERSCAN_API_KEY: API key from Etherscan
Fund your EVM wallet:
- Acquire ETH on Ethereum Sepolia for transaction gas and CCIP fees (Chainlink faucet or Google Cloud Faucet)
- LINK is optional — use
--fee-token LINKon EVM → Solana sends if you prefer paying CCIP fees in LINK
Cross-Chain Transfers (CCIP CLI)
The final tutorial phase uses globally installed ccip-cli (not the BS58 generator):
- Solana → EVM: Run from Terminal 1 with
--wallet ~/.config/solana/id.json - EVM → Solana: Run from Terminal 2 (Hardhat directory). Prefer
--wallet hardhat:<name>(Hardhat keystore) so the signing key stays encrypted. Hardhat tasks load env-enc automatically;ccip-clidoes not. As an alternative, view the same key withnpx env-enc viewand exportPRIVATE_KEYmanually for the send command.
RPC endpoints (required for source and destination chains). You can provide them any of these ways — see CCIP CLI configuration:
- Command line: pass
--rpcon each command (repeat for multiple networks), or--rpcswith comma-separated URLs - Environment variables: export
RPC_*variables (e.g.,RPC_SEPOLIA,RPC_SOLANA_DEVNET) or the tutorial'sSOLANA_DEVNET_RPCandETHEREUM_SEPOLIA_RPC_URLexports - File: create a
.envfile in the directory where you runccip-cli(default--rpcs-file, one URL per line)
See the tutorial's Configure CCIP CLI section for the recommended --rpc examples.
Environment Variables
Variables use prefixes to prevent confusion across repositories and tools:
| Prefix | Usage | Examples |
|---|---|---|
ETH_* | Ethereum addresses | ETH_TOKEN_ADDRESS, ETH_POOL_ADDRESS |
SOL_* | Solana addresses | SOL_TOKEN_MINT, SOL_POOL_ADDRESS, SOL_WALLET_ADDRESS |
SOL_CCIP_* | Solana CCIP program IDs | SOL_CCIP_POOL_PROGRAM, SOL_CCIP_ROUTER, SOL_CCIP_FEE_QUOTER_PROGRAM |
Tutorial Approach
This tutorial provides step-by-step instructions with detailed explanations of what each command does and why. You'll work primarily in Terminal 1 (CCIP Solana BS58 Generator) with occasional switches to Terminal 2 (EVM).
Environment Variable Management: This tutorial uses phase-based variable files (e.g., ~/.phase1_vars, ~/.ccip_complete_vars) to eliminate manual variable re-entry when switching between terminals. Each phase saves its variables to files that subsequent phases can load automatically.
For detailed implementation code explanations, refer to:
- CCIP Solana BS58 Generator README: Solana CLI command details,
--executeEOA workflow, and options - Smart Contract Examples README: EVM implementation guide
EOA execution: In Terminal 1, append --execute to each pnpm bs58 command so your local Solana wallet signs and sends transactions directly. Set --authority to your wallet address ($SOL_ADMIN_WALLET). Read-only commands (get-state, get-chain-config, derive-accounts) do not use --execute.
Phase 1: Ethereum Sepolia Token Setup
In this step, you will use Hardhat tasks to deploy an ERC20 token contract and a corresponding burn and mint token pool on Ethereum Sepolia. The tasks interact with the BurnMintERC20 contract for token deployment and the BurnMintTokenPool contract for pool creation.
Current Terminal: Terminal 2 (Smart Contract Examples - Hardhat) Verify your location:
pwd
# Should show: .../smart-contract-examples/ccip/cct/hardhat
Step 1: Deploy ERC20 Token
Using the deployToken task, deploy a burnable and mintable ERC20 token on Ethereum Sepolia:
# Deploy BurnMint ERC20 token
npx hardhat deployToken \
--name "BnM AEM Token" \
--symbol BnMAEM \
--decimals 18 \
--verifycontract \
--network ethereumSepolia
2026-06-15T00:17:28.926Z info: 🚀 Deploying BurnMintERC20 to ethereumSepolia...
2026-06-15T00:17:28.927Z info: name: BnM AEM Token, symbol: BnMAEM
2026-06-15T00:17:32.119Z info: ⏳ Deployment tx: 0x12333b3fcf22399e49809fd1c0b7f83106f571569b3c03ecb5665fcab8c21f81
2026-06-15T00:17:32.120Z info: Waiting for 3 confirmation(s)...
2026-06-15T00:18:02.183Z info: ✅ Token deployed at: 0x45cfb05d6278715716023ebeec733c081ce9f822
2026-06-15T00:18:02.659Z info: Granting mint and burn roles to 0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA...
2026-06-15T00:18:03.729Z info: Waiting for 3 confirmation(s)...
2026-06-15T00:18:37.999Z info: ✅ Mint/Burn roles granted.
2026-06-15T00:18:38.000Z info: Verifying contract...
The contract at 0x45cfb05d6278715716023ebeec733c081ce9f822 has already been verified on Etherscan.
If you need to verify a partially verified contract, please use the --force flag.
Explorer: https://sepolia.etherscan.io/address/0x45cfb05d6278715716023ebeec733c081ce9f822#code
2026-06-15T00:18:40.891Z info: ✅ Token contract verified successfully
Export your token address for later use:
# Set token address from deployment
export ETH_TOKEN_ADDRESS="<YOUR_TOKEN_ADDRESS>"
Verify your token address:
echo "Token Address: $ETH_TOKEN_ADDRESS"
Token Address: 0x45cfb05d6278715716023ebeec733c081ce9f822
Step 2: Deploy Token Pool
In this step, you will use the deployTokenPool task to deploy a CCIP BurnMint token pool for the token on Ethereum Sepolia. This task interacts with the BurnMintTokenPool contract and grants the necessary mint and burn privileges to the pool.
# Deploy BurnMint pool
npx hardhat deployTokenPool \
--tokenaddress $ETH_TOKEN_ADDRESS \
--localtokendecimals 18 \
--pooltype burnMint \
--verifycontract \
--network ethereumSepolia
2026-06-15T00:20:36.040Z info: 🚀 Deploying burnMint pool on ethereumSepolia
2026-06-15T00:20:36.041Z info: Token: 0x45cfb05d6278715716023ebeec733c081ce9f822
2026-06-15T00:20:36.041Z info: Decimals: 18
2026-06-15T00:20:36.041Z info: Allowlist: None
2026-06-15T00:20:39.071Z info: ⏳ Deployment tx: 0x9a186e27de847cbb27e47d5bdabe352e18068a17c4fb259e40e8c2ec08532d0c
2026-06-15T00:20:39.072Z info: Waiting for 3 confirmation(s)...
2026-06-15T00:21:13.340Z info: ✅ Token pool deployed at: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
2026-06-15T00:21:13.341Z info: Granting mint and burn roles to 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f on token 0x45cfb05d6278715716023ebeec733c081ce9f822
2026-06-15T00:21:14.730Z info: Waiting for 3 confirmation(s)...
2026-06-15T00:21:49.003Z info: ✅ Mint/Burn roles granted
2026-06-15T00:21:49.003Z info: Verifying contract...
The contract at 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f has already been verified on Etherscan.
If you need to verify a partially verified contract, please use the --force flag.
Explorer: https://sepolia.etherscan.io/address/0x1df7ede88286c1ef95d024b311e12dc4b3106f1f#code
2026-06-15T00:21:52.270Z info: ✅ Token pool contract verified successfully
Export your pool address for later use:
# Set pool address from deployment
export ETH_POOL_ADDRESS="<YOUR_POOL_ADDRESS>"
Verify your pool address:
echo "Pool Address: $ETH_POOL_ADDRESS"
Pool Address: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
Step 3: Mint Tokens
In this step, you will use the mintTokens task to mint tokens on Ethereum Sepolia for your Externally Owned Account (EOA). Since you assigned mint and burn privileges to your EOA when deploying the tokens, you can now mint tokens for testing purposes. This ensures that you have enough tokens in your EOA to perform cross-chain transfers later.
# Mint initial token supply for testing
npx hardhat mintTokens \
--tokenaddress $ETH_TOKEN_ADDRESS \
--amount 1000000000000000000000 \
--network ethereumSepolia
2026-06-15T00:23:17.116Z info: 🪙 Minting 1000000000000000000000 BnMAEM to 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca...
2026-06-15T00:23:18.710Z info: ⏳ Mint tx: 0x7b02fe02f07744b977d4f099b734fa98f0e56bcf516c48c265cc393a7c5c7c8d
2026-06-15T00:23:18.710Z info: Waiting for 3 confirmation(s)...
2026-06-15T00:23:48.959Z info: ✅ Minted 1000000000000000000000 BnMAEM to 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca
2026-06-15T00:23:48.960Z info: Current balance of 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca: 1000000000000000000000 BnMAEM
Step 4: Claim Admin
In this step, you will use the claimAdmin task to register your EOA as the administrator for the deployed token on Ethereum Sepolia. This process involves calling the RegistryModuleOwnerCustom contract, which will fetch the CCIP admin of the token and set it up as the admin in the registry.
# Claim admin role
npx hardhat claimAdmin \
--tokenaddress $ETH_TOKEN_ADDRESS \
--network ethereumSepolia
2026-06-15T00:24:51.426Z info: 🎯 Claiming admin for 0x45cfb05d6278715716023ebeec733c081ce9f822 using getCCIPAdmin mode
2026-06-15T00:24:54.359Z info: ✅ Current wallet 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca is CCIP admin
2026-06-15T00:24:55.884Z info: 📤 TX sent: 0x59ee4f9880d5ee36187d7c89d3cca19b6f478fd58a9a7a35a9bfe0a77a8ea33f. Waiting for 3 confirmations...
2026-06-15T00:25:25.930Z info: ✅ Admin claimed for 0x45cfb05d6278715716023ebeec733c081ce9f822 on ethereumSepolia (3 confirmations)
Step 5: Accept Admin Role
In this step, you will use the acceptAdminRole task to accept the admin role for the deployed token on Ethereum Sepolia. Once you have claimed the role, accepting the role finalizes your control over the token administration.
# Accept admin role
npx hardhat acceptAdminRole \
--tokenaddress $ETH_TOKEN_ADDRESS \
--network ethereumSepolia
2026-06-15T00:26:00.427Z info: 🔄 Accepting admin role for 0x45cfb05d6278715716023ebeec733c081ce9f822 on ethereumSepolia...
2026-06-15T00:26:02.466Z info: Checking pending admin for 0x45cfb05d6278715716023ebeec733c081ce9f822...
2026-06-15T00:26:02.696Z info: ✅ Current wallet 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca is the pending admin
2026-06-15T00:26:02.696Z info: Accepting admin role...
2026-06-15T00:26:04.269Z info: 📤 TX sent: 0x2215a67879d31cde69e35516244395a115f7d24d42d94052c0c0f87a32b20130. Waiting for 3 confirmations...
2026-06-15T00:26:38.526Z info: ✅ Admin role accepted for 0x45cfb05d6278715716023ebeec733c081ce9f822 on ethereumSepolia (3 confirmations)
Save the Phase 1 variables for cross-terminal access:
# Save Phase 1 variables for cross-terminal use
cat > ~/.phase1_vars << EOF
export ETH_TOKEN_ADDRESS="$ETH_TOKEN_ADDRESS"
export ETH_POOL_ADDRESS="$ETH_POOL_ADDRESS"
EOF
echo "=== Phase 1 Complete - EVM Setup ==="
echo "✅ ETH Token: $ETH_TOKEN_ADDRESS"
echo "✅ ETH Pool: $ETH_POOL_ADDRESS"
echo "✅ Variables saved to ~/.phase1_vars"
=== Phase 1 Complete - EVM Setup ===
✅ ETH Token: 0x45cfb05d6278715716023ebeec733c081ce9f822
✅ ETH Pool: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
✅ Variables saved to ~/.phase1_vars
Phase 2: Solana Devnet Token Setup
In this phase, you will create an SPL token, initialize the CCIP token pool, and complete CCIP registration before** setting up the SPL token multisig. This sequence is critical because the self-service registration requires you to hold the mint authority.
Switch to Terminal 1 (CCIP Solana BS58 Generator) Verify your location:
pwd
# Should show: .../ccip-solana-bs58-generator
Load the Ethereum addresses from Phase 1 and set CCIP constants:
source ~/.phase1_vars
export SOL_ADMIN_WALLET=$(solana address)
export SOL_CCIP_POOL_PROGRAM="41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB"
export SOL_CCIP_ROUTER="Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C"
export SOL_CCIP_FEE_QUOTER_PROGRAM="FeeQPGkKDeRV1MgoYfMH6L8o3KeuYjwUZrgn4LRKfjHi"
export ETH_SEPOLIA_CHAIN_SELECTOR="16015286601757825753"
echo "Loaded Phase 1: ETH_TOKEN_ADDRESS=$ETH_TOKEN_ADDRESS"
echo "Admin Wallet: $SOL_ADMIN_WALLET"
Loaded Phase 1: ETH_TOKEN_ADDRESS=0x45cfb05d6278715716023ebeec733c081ce9f822
Admin Wallet: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Step 1: Create SPL Token
Create an SPL token with Metaplex metadata and initial supply using direct EOA execution:
# Create SPL token with Metaplex metadata and initial supply
pnpm bs58 --env devnet --execute spl-token \
--instruction create-mint \
--authority $SOL_ADMIN_WALLET \
--decimals 9 \
--with-metaplex true \
--name "AEM" \
--symbol "CCIP-AEM" \
--uri "https://cyan-pleasant-anteater-613.mypinata.cloud/ipfs/bafkreieirlwjqbtzniqsgcjebzexlcspcmvd4woh3ajvf2p4fuivkenw6i" \
--initial-supply 1000000000000 \
--recipient $SOL_ADMIN_WALLET
INFO [2026-06-15 06:00:21.843 +0530]: 🔍 Validating create mint parameters...
INFO [2026-06-15 06:00:21.844 +0530]: 📋 Token Program: spl-token (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)
INFO [2026-06-15 06:00:21.844 +0530]: 📋 Decimals: 9
INFO [2026-06-15 06:00:21.844 +0530]: 📋 Metaplex metadata enabled
INFO [2026-06-15 06:00:21.844 +0530]: Name: "AEM"
INFO [2026-06-15 06:00:21.844 +0530]: Symbol: "CCIP-AEM"
INFO [2026-06-15 06:00:21.844 +0530]: URI: https://cyan-pleasant-anteater-613.mypinata.cloud/ipfs/bafkreieirlwjqbtzniqsgcjebzexlcspcmvd4woh3ajvf2p4fuivkenw6i
INFO [2026-06-15 06:00:21.844 +0530]: 📋 Initial supply: 1000000000000 smallest units
INFO [2026-06-15 06:00:21.844 +0530]: 📋 Recipient: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:00:21.844 +0530]: ✅ Parameter validation completed
INFO [2026-06-15 06:00:21.844 +0530]: 🎨 Creating mint with Metaplex metadata...
INFO [2026-06-15 06:00:21.845 +0530]: 📋 Generated mint address: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
INFO [2026-06-15 06:00:21.845 +0530]: 📋 Mint seed: mint_1781483421844_6ifalj
INFO [2026-06-15 06:00:21.845 +0530]: 📋 Using token program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
INFO [2026-06-15 06:00:22.230 +0530]: 📋 Generated 3 instructions for mint + metadata creation
INFO [2026-06-15 06:00:22.230 +0530]: 💰 Adding initial supply mint instructions...
INFO [2026-06-15 06:00:22.232 +0530]: 📋 Creating ATA for recipient: 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
INFO [2026-06-15 06:00:22.232 +0530]: 📋 Will mint 1000000000000 smallest units to 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
INFO [2026-06-15 06:00:22.232 +0530]: 🔄 Building and simulating transaction...
INFO [2026-06-15 06:00:22.232 +0530]: 📋 Metadata PDA: AaBhXgiCdKj3gfjDn5fwg58unUcF8Q7wRwHbfdxLu1os
INFO [2026-06-15 06:00:22.425 +0530]: Transaction built successfully
instructionName: "spl-token.create_mint_with_metaplex"
transactionSize: "778 bytes"
base58Length: "1062 characters"
hexLength: "1556 characters"
accountCount: 2
signerCount: 1
computeUnits: 68049
INFO [2026-06-15 06:00:22.425 +0530]: Completed buildTransaction (spl-token.create_mint_with_metaplex)
durationMs: 193
INFO [2026-06-15 06:00:22.615 +0530]:
INFO [2026-06-15 06:00:22.615 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:00:22.615 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:00:22.615 +0530]: Instruction: spl-token.create_mint_with_metaplex
INFO [2026-06-15 06:00:22.615 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:00:22.615 +0530]:
INFO [2026-06-15 06:00:23.574 +0530]: Transaction confirmed successfully
signature: "2ETpQBQSCe5bYN7dXoyhhpwwrDz3P3SmsnVYsFMPuYddTk7qi8mneAJrpTRFoHDmWbv9ED1o7fHnnSz1ThsV8QS5"
attempt: 1
INFO [2026-06-15 06:00:23.574 +0530]:
INFO [2026-06-15 06:00:23.574 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:00:23.574 +0530]:
INFO [2026-06-15 06:00:23.574 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:00:23.574 +0530]: Instruction: spl-token.create_mint_with_metaplex
INFO [2026-06-15 06:00:23.574 +0530]: Signature: 2ETpQBQSCe5bYN7dXoyhhpwwrDz3P3SmsnVYsFMPuYddTk7qi8mneAJrpTRFoHDmWbv9ED1o7fHnnSz1ThsV8QS5
INFO [2026-06-15 06:00:23.574 +0530]: Explorer: https://explorer.solana.com/tx/2ETpQBQSCe5bYN7dXoyhhpwwrDz3P3SmsnVYsFMPuYddTk7qi8mneAJrpTRFoHDmWbv9ED1o7fHnnSz1ThsV8QS5?cluster=devnet
INFO [2026-06-15 06:00:23.574 +0530]:
INFO [2026-06-15 06:00:23.574 +0530]: ✅ Transaction simulation completed
Set the token mint variable:
# Copy the mint address from the command output above
export SOL_TOKEN_MINT="<REPLACE_WITH_YOUR_TOKEN_MINT_ADDRESS>"
Verify the variable:
echo "Token Mint: $SOL_TOKEN_MINT"
Token Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Step 2: Initialize CCIP Token Pool
Initialize a CCIP token pool for your SPL token. This creates the on-chain state for cross-chain operations and establishes the Pool Signer PDA that will become a multisig member.
# Initialize pool for your token
pnpm bs58 --env devnet --execute burnmint-token-pool \
--instruction initialize-pool \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET
🔄 Generating initialize (pool) transaction...
🔄 Building and simulating transaction...
INFO [2026-06-15 06:05:05.108 +0530]: Transaction built successfully
instructionName: "burnmint-token-pool.initialize"
transactionSize: "279 bytes"
base58Length: "380 characters"
hexLength: "558 characters"
accountCount: 7
signerCount: 1
computeUnits: 24318
INFO [2026-06-15 06:05:05.108 +0530]: Completed buildTransaction (burnmint-token-pool.initialize)
durationMs: 347
INFO [2026-06-15 06:05:05.266 +0530]:
INFO [2026-06-15 06:05:05.266 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:05:05.266 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:05:05.266 +0530]: Instruction: burnmint-token-pool.initialize
INFO [2026-06-15 06:05:05.266 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:05:05.266 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:05:06.299 +0530]: Transaction confirmed successfully
signature: "2FDvLxkNdTENjLWDkXrDtNYTWqCQwsRGJ7MkagY2B3teWdRxnPZyh1fgt4wihDkZQ7NxzXZ5e5DhQGi5p9oG3UMx"
attempt: 1
INFO [2026-06-15 06:05:06.299 +0530]:
INFO [2026-06-15 06:05:06.299 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:05:06.299 +0530]:
INFO [2026-06-15 06:05:06.299 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:05:06.299 +0530]: Instruction: burnmint-token-pool.initialize
INFO [2026-06-15 06:05:06.299 +0530]: Signature: 2FDvLxkNdTENjLWDkXrDtNYTWqCQwsRGJ7MkagY2B3teWdRxnPZyh1fgt4wihDkZQ7NxzXZ5e5DhQGi5p9oG3UMx
INFO [2026-06-15 06:05:06.299 +0530]: Explorer: https://explorer.solana.com/tx/2FDvLxkNdTENjLWDkXrDtNYTWqCQwsRGJ7MkagY2B3teWdRxnPZyh1fgt4wihDkZQ7NxzXZ5e5DhQGi5p9oG3UMx?cluster=devnet
INFO [2026-06-15 06:05:06.299 +0530]:
Step 3: Verify Pool Creation
Derive pool accounts using the read-only derive-accounts command:
# Derive Pool Signer PDA and Pool State PDA
pnpm bs58 --env devnet utils \
--instruction derive-accounts \
--program-type burnmint-token-pool \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT
🔍 Deriving burnmint-token-pool accounts...
INFO [2026-06-15 06:10:15.947 +0530]: Starting deriveAccounts command
command: "derive-accounts"
programType: "burnmint-token-pool"
programId: "41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB"
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
globalOptions: {
"environment": "devnet",
"resolvedRpcUrl": "https://api.devnet.solana.com"
}
📊 Derived Accounts:
1. Pool State PDA
Address: Fuu3EwnQkV4WUrcLj1atwEq4xbfkpgvXF5tMRYPg3nCm
Seeds: ["ccip_tokenpool_config", mint]
Bump: 255
Description: Main pool configuration account (created by initialize-pool)
2. Pool Signer PDA
Address: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
Seeds: ["ccip_tokenpool_signer", mint]
Bump: 255
Description: 🎯 CRITICAL: Autonomous mint/burn authority for cross-chain operations
3. Global Config PDA
Address: E4Bsi43kX3iwXAFia2ebm1mS5Xkmmdv3minZDnfo7Zzf
Seeds: ["config"]
Bump: 255
Description: Program-wide configuration settings
4. Pool Token ATA
Address: 5FbZe44bPUK5HZHcZF84Jy6uutQS3PpWCDCr8yuKCpqv
Seeds: [mint, pool_signer_pda, token_program]
Description: Pool's token account (owned by Pool Signer PDA)
🎯 CRITICAL ADDRESS FOR CROSS-CHAIN OPERATIONS:
Pool Signer PDA: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
↳ This address signs all mint/burn transactions autonomously
INFO [2026-06-15 06:10:16.348 +0530]: Detected SPL Token v1
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
INFO [2026-06-15 06:10:16.350 +0530]: ✅ Account derivation completed successfully
command: "derive-accounts"
Copy the Pool Signer PDA and Pool State PDA from the output, then export them:
export SOL_POOL_SIGNER_PDA="<REPLACE_WITH_YOUR_POOL_SIGNER_PDA>"
export SOL_POOL_CONFIG_PDA="<REPLACE_WITH_YOUR_POOL_STATE_PDA>"
Verify the variables:
echo "Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "Pool Config PDA: $SOL_POOL_CONFIG_PDA"
Pool Signer PDA: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
Pool Config PDA: Fuu3EwnQkV4WUrcLj1atwEq4xbfkpgvXF5tMRYPg3nCm
Step 4: Create Pool Token Account
Create an Associated Token Account (ATA) for the Pool Signer PDA. This ATA is required for the pool to hold and manage tokens during cross-chain transfer operations.
# Create ATA for Pool Signer PDA
spl-token create-account $SOL_TOKEN_MINT \
--owner $SOL_POOL_SIGNER_PDA \
--fee-payer $HOME/.config/solana/id.json
Creating account 5FbZe44bPUK5HZHcZF84Jy6uutQS3PpWCDCr8yuKCpqv
Signature: 2TPHNUMP5bxHfMuJd1xUo2oNgg9wSmStivpKXXkjumQpfLok68uQ4CvN9NZm1bLzuXAUpxbhsuwKVcdNuCzvVDQG
Step 5: Claim Admin
Register yourself as the CCIP administrator for the Solana token. This must be completed while you still hold the mint authority.
# Propose yourself as CCIP administrator (requires mint authority)
pnpm bs58 --env devnet --execute router \
--instruction owner-propose-administrator \
--program-id $SOL_CCIP_ROUTER \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET \
--token-admin-registry-admin $SOL_ADMIN_WALLET
🔄 Generating owner_propose_administrator transaction...
🔄 Building and simulating transaction...
INFO [2026-06-15 06:21:05.087 +0530]: Transaction built successfully
instructionName: "router.owner_propose_administrator"
transactionSize: "277 bytes"
base58Length: "377 characters"
hexLength: "554 characters"
accountCount: 5
signerCount: 1
computeUnits: 25731
INFO [2026-06-15 06:21:05.088 +0530]: Completed buildTransaction (router.owner_propose_administrator)
durationMs: 379
INFO [2026-06-15 06:21:05.251 +0530]:
INFO [2026-06-15 06:21:05.252 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:21:05.252 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:21:05.252 +0530]: Instruction: router.owner_propose_administrator
INFO [2026-06-15 06:21:05.252 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:21:05.252 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:21:06.039 +0530]: Transaction confirmed successfully
signature: "28884ViTfXiCsGh5dQAbA8WCNvyGf8XgFiTDFT7CnzzsjBteAR9yDVrkAtwo6Jn66vmPH2Cz55CUM7cSqprdGy1i"
attempt: 1
INFO [2026-06-15 06:21:06.039 +0530]:
INFO [2026-06-15 06:21:06.039 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:21:06.039 +0530]:
INFO [2026-06-15 06:21:06.039 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:21:06.039 +0530]: Instruction: router.owner_propose_administrator
INFO [2026-06-15 06:21:06.039 +0530]: Signature: 28884ViTfXiCsGh5dQAbA8WCNvyGf8XgFiTDFT7CnzzsjBteAR9yDVrkAtwo6Jn66vmPH2Cz55CUM7cSqprdGy1i
INFO [2026-06-15 06:21:06.039 +0530]: Explorer: https://explorer.solana.com/tx/28884ViTfXiCsGh5dQAbA8WCNvyGf8XgFiTDFT7CnzzsjBteAR9yDVrkAtwo6Jn66vmPH2Cz55CUM7cSqprdGy1i?cluster=devnet
INFO [2026-06-15 06:21:06.039 +0530]:
Step 6: Accept Admin Role
Accept the proposed administrator role to establish CCIP admin control:
# Accept the proposed administrator role
pnpm bs58 --env devnet --execute router \
--instruction accept-admin-role \
--program-id $SOL_CCIP_ROUTER \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET
🔄 Generating accept_admin_role_token_admin_registry transaction...
🔄 Building and simulating transaction...
INFO [2026-06-15 06:23:30.001 +0530]: Transaction built successfully
instructionName: "router.accept_admin_role_token_admin_registry"
transactionSize: "212 bytes"
base58Length: "289 characters"
hexLength: "424 characters"
accountCount: 4
signerCount: 1
computeUnits: 21454
INFO [2026-06-15 06:23:30.001 +0530]: Completed buildTransaction (router.accept_admin_role_token_admin_registry)
durationMs: 398
INFO [2026-06-15 06:23:30.188 +0530]:
INFO [2026-06-15 06:23:30.188 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:23:30.188 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:23:30.188 +0530]: Instruction: router.accept_admin_role_token_admin_registry
INFO [2026-06-15 06:23:30.188 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:23:30.188 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:23:31.062 +0530]: Transaction confirmed successfully
signature: "TzYbpW9M463X9j3ut7VUZ4KRcphUYqRPYJCTsLthgEcJvQhQXtekEbLChDk4VN1xPJxLW7MGqDGSYRdsfruC1Xe"
attempt: 1
INFO [2026-06-15 06:23:31.062 +0530]:
INFO [2026-06-15 06:23:31.062 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:23:31.062 +0530]:
INFO [2026-06-15 06:23:31.062 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:23:31.062 +0530]: Instruction: router.accept_admin_role_token_admin_registry
INFO [2026-06-15 06:23:31.062 +0530]: Signature: TzYbpW9M463X9j3ut7VUZ4KRcphUYqRPYJCTsLthgEcJvQhQXtekEbLChDk4VN1xPJxLW7MGqDGSYRdsfruC1Xe
INFO [2026-06-15 06:23:31.062 +0530]: Explorer: https://explorer.solana.com/tx/TzYbpW9M463X9j3ut7VUZ4KRcphUYqRPYJCTsLthgEcJvQhQXtekEbLChDk4VN1xPJxLW7MGqDGSYRdsfruC1Xe?cluster=devnet
INFO [2026-06-15 06:23:31.062 +0530]:
Step 7: Create SPL Token Multisig
Now that CCIP registration is complete, create the SPL token multisig that will serve as the mint authority:
# Create 1-of-2 multisig with Pool Signer PDA and admin wallet (tutorial setup)
pnpm bs58 --env devnet --execute spl-token \
--instruction create-multisig \
--authority $SOL_ADMIN_WALLET \
--seed "ccip-multisig-001" \
--mint $SOL_TOKEN_MINT \
--signers "[\"$SOL_POOL_SIGNER_PDA\",\"$SOL_ADMIN_WALLET\"]" \
--threshold 1
INFO [2026-06-15 06:28:57.267 +0530]: Detected SPL Token v1
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
📮 Derived SPL Token Multisig Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
💡 Address derived from: authority + sha256("ccip-multisig-001" + mint).hex().slice(0,32) + tokenProgram
INFO [2026-06-15 06:28:57.359 +0530]: 🔄 Building and simulating transaction...
INFO [2026-06-15 06:28:57.544 +0530]: Transaction built successfully
instructionName: "spl.create_multisig"
transactionSize: "367 bytes"
base58Length: "500 characters"
hexLength: "734 characters"
accountCount: 2
signerCount: 1
computeUnits: 317
INFO [2026-06-15 06:28:57.544 +0530]: Completed buildTransaction (spl.create_multisig)
durationMs: 185
INFO [2026-06-15 06:28:57.727 +0530]:
INFO [2026-06-15 06:28:57.727 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:28:57.727 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:28:57.727 +0530]: Instruction: spl.create_multisig
INFO [2026-06-15 06:28:57.727 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:28:57.727 +0530]:
INFO [2026-06-15 06:28:58.428 +0530]: Transaction confirmed successfully
signature: "4JCXtsukV7f4ggfWPRrrVA6kgoaMvwtR1gqAXNBYM9vHdNKKqqidF4rkKPMrURgCdL1yY4TMaU8KibkZm3836FwL"
attempt: 1
INFO [2026-06-15 06:28:58.428 +0530]:
INFO [2026-06-15 06:28:58.428 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:28:58.428 +0530]:
INFO [2026-06-15 06:28:58.428 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:28:58.428 +0530]: Instruction: spl.create_multisig
INFO [2026-06-15 06:28:58.428 +0530]: Signature: 4JCXtsukV7f4ggfWPRrrVA6kgoaMvwtR1gqAXNBYM9vHdNKKqqidF4rkKPMrURgCdL1yY4TMaU8KibkZm3836FwL
INFO [2026-06-15 06:28:58.428 +0530]: Explorer: https://explorer.solana.com/tx/4JCXtsukV7f4ggfWPRrrVA6kgoaMvwtR1gqAXNBYM9vHdNKKqqidF4rkKPMrURgCdL1yY4TMaU8KibkZm3836FwL?cluster=devnet
INFO [2026-06-15 06:28:58.428 +0530]:
INFO [2026-06-15 06:28:58.428 +0530]: ✅ Transaction simulation completed
Set the multisig address environment variable:
# Set multisig address from the output above
export SOL_MULTISIG_ADDRESS="<REPLACE_WITH_YOUR_MULTISIG_ADDRESS>"
Verify output:
echo "Multisig Address: $SOL_MULTISIG_ADDRESS"
Multisig Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
Step 8: Transfer Mint Authority to Multisig
Now transfer the mint authority from your wallet to the multisig:
# Transfer mint authority to multisig
pnpm bs58 --env devnet --execute spl-token \
--instruction transfer-mint-authority \
--authority $SOL_ADMIN_WALLET \
--mint $SOL_TOKEN_MINT \
--new-mint-authority $SOL_MULTISIG_ADDRESS
INFO [2026-06-15 06:31:24.796 +0530]: Detected SPL Token v1
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
INFO [2026-06-15 06:31:24.796 +0530]: 🔄 Building and simulating transaction...
INFO [2026-06-15 06:31:24.968 +0530]: Transaction built successfully
instructionName: "spl.transfer_mint_authority"
transactionSize: "173 bytes"
base58Length: "235 characters"
hexLength: "346 characters"
accountCount: 2
signerCount: 1
computeUnits: 125
INFO [2026-06-15 06:31:24.968 +0530]: Completed buildTransaction (spl.transfer_mint_authority)
durationMs: 171
INFO [2026-06-15 06:31:25.137 +0530]:
INFO [2026-06-15 06:31:25.137 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:31:25.137 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:31:25.137 +0530]: Instruction: spl.transfer_mint_authority
INFO [2026-06-15 06:31:25.137 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:31:25.137 +0530]:
INFO [2026-06-15 06:31:25.879 +0530]: Transaction confirmed successfully
signature: "3e1hdrQuhNfMYMYf3eNHVgajUoRmi9d9ajvyksKiJKnCoU6bTs5o5m2mToXrB3qe28WQSsnCZs2mMUAfWd2DV2m"
attempt: 1
INFO [2026-06-15 06:31:25.879 +0530]:
INFO [2026-06-15 06:31:25.879 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:31:25.879 +0530]:
INFO [2026-06-15 06:31:25.879 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:31:25.879 +0530]: Instruction: spl.transfer_mint_authority
INFO [2026-06-15 06:31:25.879 +0530]: Signature: 3e1hdrQuhNfMYMYf3eNHVgajUoRmi9d9ajvyksKiJKnCoU6bTs5o5m2mToXrB3qe28WQSsnCZs2mMUAfWd2DV2m
INFO [2026-06-15 06:31:25.879 +0530]: Explorer: https://explorer.solana.com/tx/3e1hdrQuhNfMYMYf3eNHVgajUoRmi9d9ajvyksKiJKnCoU6bTs5o5m2mToXrB3qe28WQSsnCZs2mMUAfWd2DV2m?cluster=devnet
INFO [2026-06-15 06:31:25.879 +0530]:
INFO [2026-06-15 06:31:25.879 +0530]: ✅ Transaction simulation completed
Step 9: Verify Multisig Configuration
Verify that the multisig has been properly configured and the mint authority has been transferred:
# Check token mint authority
spl-token display $SOL_TOKEN_MINT
# Check multisig details
spl-token display $SOL_MULTISIG_ADDRESS
SPL Token Mint
Address: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Supply: 1000000000000
Decimals: 9
Mint authority: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
Freeze authority: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
SPL Token Multisig
Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
M/N: 1/2
Signers:
1: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
2: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Save the Phase 2 variables for cross-terminal access:
# Save all variables from Phases 1 and 2 to complete vars file
cat > ~/.ccip_complete_vars << EOF
export ETH_TOKEN_ADDRESS="$ETH_TOKEN_ADDRESS"
export ETH_POOL_ADDRESS="$ETH_POOL_ADDRESS"
export SOL_TOKEN_MINT="$SOL_TOKEN_MINT"
export SOL_ADMIN_WALLET="$SOL_ADMIN_WALLET"
export SOL_CCIP_POOL_PROGRAM="$SOL_CCIP_POOL_PROGRAM"
export SOL_CCIP_ROUTER="$SOL_CCIP_ROUTER"
export SOL_CCIP_FEE_QUOTER_PROGRAM="$SOL_CCIP_FEE_QUOTER_PROGRAM"
export ETH_SEPOLIA_CHAIN_SELECTOR="$ETH_SEPOLIA_CHAIN_SELECTOR"
export SOL_POOL_SIGNER_PDA="$SOL_POOL_SIGNER_PDA"
export SOL_POOL_CONFIG_PDA="$SOL_POOL_CONFIG_PDA"
export SOL_MULTISIG_ADDRESS="$SOL_MULTISIG_ADDRESS"
EOF
echo "=== Phase 2 Complete - Solana Setup ==="
echo "✅ SOL Token: $SOL_TOKEN_MINT"
echo "✅ Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "✅ Multisig Address: $SOL_MULTISIG_ADDRESS"
echo "✅ Variables saved to ~/.ccip_complete_vars"
=== Phase 2 Complete - Solana Setup ===
✅ SOL Token: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
✅ Pool Signer PDA: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
✅ Multisig Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
✅ Variables saved to ~/.ccip_complete_vars
Phase 3: Cross-Chain Configuration
In this step, you will configure bidirectional connectivity between the token pools on both chains. Each chain uses different tools: Solana uses CCIP Solana BS58 Generator commands to configure its pool to recognize Ethereum tokens and pools, while Ethereum uses Hardhat tasks to configure its pool to recognize Solana tokens and pools.
Step 1: Configure Solana -> Ethereum
Initialize Chain Remote Configuration
In this step, you will initialize the configuration for Ethereum Sepolia as a remote chain. This creates the basic chain configuration with token information but without pool addresses (those will be added in the next step).
# Initialize remote chain configuration for Ethereum Sepolia
pnpm bs58 --env devnet --execute burnmint-token-pool \
--instruction init-chain-remote-config \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET \
--remote-chain-selector $ETH_SEPOLIA_CHAIN_SELECTOR \
--pool-addresses '[]' \
--token-address $ETH_TOKEN_ADDRESS \
--decimals 9
🔄 Generating initChainRemoteConfig transaction...
RPC URL: https://api.devnet.solana.com
Program ID: 41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB
Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Authority: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Remote Chain Selector: 16015286601757825753
Pool Addresses: 0 addresses (must be empty at init)
Token Address: 45cfb05d6278715716023ebeec733c081ce9f822
Decimals: 9
⚙️ Building transaction instruction...
✅ Instruction built successfully
🔄 Building and simulating transaction...
INFO [2026-06-15 06:34:38.867 +0530]: Starting initChainRemoteConfig command
command: "burnmint-token-pool.init-chain-remote-config"
programId: "41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB"
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
authority: "GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN"
remoteChainSelector: "16015286601757825753"
poolAddresses: "[]"
tokenAddress: "0x45cfb05d6278715716023ebeec733c081ce9f822"
decimals: "9"
globalOptions: {
"environment": "devnet",
"execute": true,
"resolvedRpcUrl": "https://api.devnet.solana.com",
"keypair": "/Users/syed-cll/.config/solana/id.json",
"_signerKeypair": {
"_keypair": {
"publicKey": {
"0": 230,
"1": 211,
"2": 30,
...
"29": 179,
"30": 114,
"31": 73
},
"secretKey": {
"0": 191,
"1": 198,
"2": 244,
...
"61": 179,
"62": 114,
"63": 73
}
}
}
}
INFO [2026-06-15 06:34:39.236 +0530]: Transaction built successfully
instructionName: "initChainRemoteConfig"
transactionSize: "293 bytes"
base58Length: "399 characters"
hexLength: "586 characters"
accountCount: 4
signerCount: 1
computeUnits: 13402
INFO [2026-06-15 06:34:39.237 +0530]: Completed buildTransaction (initChainRemoteConfig)
durationMs: 366
INFO [2026-06-15 06:34:39.406 +0530]:
INFO [2026-06-15 06:34:39.406 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:34:39.406 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:34:39.406 +0530]: Instruction: initChainRemoteConfig
INFO [2026-06-15 06:34:39.406 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:34:39.406 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:34:40.042 +0530]: Transaction confirmed successfully
signature: "5EWruYQEry3itWRUdSr57BprKnoPUqkBCfmMMNWBTNhTjTsRU2BX4y195aBCrmwHpJCxb6q2VB8WmnbEgkSwxhVq"
attempt: 1
INFO [2026-06-15 06:34:40.042 +0530]:
INFO [2026-06-15 06:34:40.042 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:34:40.042 +0530]:
INFO [2026-06-15 06:34:40.042 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:34:40.042 +0530]: Instruction: initChainRemoteConfig
INFO [2026-06-15 06:34:40.042 +0530]: Signature: 5EWruYQEry3itWRUdSr57BprKnoPUqkBCfmMMNWBTNhTjTsRU2BX4y195aBCrmwHpJCxb6q2VB8WmnbEgkSwxhVq
INFO [2026-06-15 06:34:40.042 +0530]: Explorer: https://explorer.solana.com/tx/5EWruYQEry3itWRUdSr57BprKnoPUqkBCfmMMNWBTNhTjTsRU2BX4y195aBCrmwHpJCxb6q2VB8WmnbEgkSwxhVq?cluster=devnet
INFO [2026-06-15 06:34:40.042 +0530]:
INFO [2026-06-15 06:34:40.042 +0530]: initChainRemoteConfig command completed successfully
command: "burnmint-token-pool.init-chain-remote-config"
transactionSize: "293 bytes"
computeUnits: 13402
Add Ethereum Pool Address
In this step, you will update the previously created chain configuration with the Ethereum pool address.
# Add Ethereum pool address to the configuration
pnpm bs58 --env devnet --execute burnmint-token-pool \
--instruction edit-chain-remote-config \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET \
--remote-chain-selector $ETH_SEPOLIA_CHAIN_SELECTOR \
--pool-addresses "[\"$ETH_POOL_ADDRESS\"]" \
--token-address $ETH_TOKEN_ADDRESS \
--decimals 9
🔄 Generating editChainRemoteConfig transaction...
RPC URL: https://api.devnet.solana.com
Program ID: 41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB
Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Authority: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Remote Chain Selector: 16015286601757825753
Pool Addresses: 1 addresses
Token Address: 45cfb05d6278715716023ebeec733c081ce9f822
Decimals: 9
⚙️ Building transaction instruction...
✅ Instruction built successfully
🔄 Building and simulating transaction...
INFO [2026-06-15 06:38:27.172 +0530]: Starting editChainRemoteConfig command
command: "burnmint-token-pool.edit-chain-remote-config"
programId: "41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB"
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
authority: "GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN"
remoteChainSelector: "16015286601757825753"
poolAddresses: "[\"0x1df7ede88286c1ef95d024b311e12dc4b3106f1f\"]"
tokenAddress: "0x45cfb05d6278715716023ebeec733c081ce9f822"
decimals: "9"
globalOptions: {
"environment": "devnet",
"execute": true,
"resolvedRpcUrl": "https://api.devnet.solana.com",
"keypair": "/Users/syed-cll/.config/solana/id.json",
"_signerKeypair": {
"_keypair": {
"publicKey": {
"0": 230,
"1": 211,
"2": 30,
...
"29": 179,
"30": 114,
"31": 73
},
"secretKey": {
"0": 191,
"1": 198,
"2": 244,
...
"61": 179,
"62": 114,
"63": 73
}
}
}
}
INFO [2026-06-15 06:38:27.594 +0530]: Transaction built successfully
instructionName: "editChainRemoteConfig"
transactionSize: "317 bytes"
base58Length: "432 characters"
hexLength: "634 characters"
accountCount: 4
signerCount: 1
computeUnits: 14533
INFO [2026-06-15 06:38:27.594 +0530]: Completed buildTransaction (editChainRemoteConfig)
durationMs: 419
INFO [2026-06-15 06:38:27.751 +0530]:
INFO [2026-06-15 06:38:27.751 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:38:27.751 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:38:27.751 +0530]: Instruction: editChainRemoteConfig
INFO [2026-06-15 06:38:27.751 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:38:27.751 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:38:28.818 +0530]: Transaction confirmed successfully
signature: "4mBP7guEZsjgyMD4HgR4xWjkhkEdYsuUVoGTk58srjZjKZyiXPHENy3yC9LgmEA6FVVVBmKZLtbZXRSkxxJ4v18X"
attempt: 1
INFO [2026-06-15 06:38:28.818 +0530]:
INFO [2026-06-15 06:38:28.818 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:38:28.818 +0530]:
INFO [2026-06-15 06:38:28.818 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:38:28.818 +0530]: Instruction: editChainRemoteConfig
INFO [2026-06-15 06:38:28.818 +0530]: Signature: 4mBP7guEZsjgyMD4HgR4xWjkhkEdYsuUVoGTk58srjZjKZyiXPHENy3yC9LgmEA6FVVVBmKZLtbZXRSkxxJ4v18X
INFO [2026-06-15 06:38:28.818 +0530]: Explorer: https://explorer.solana.com/tx/4mBP7guEZsjgyMD4HgR4xWjkhkEdYsuUVoGTk58srjZjKZyiXPHENy3yC9LgmEA6FVVVBmKZLtbZXRSkxxJ4v18X?cluster=devnet
INFO [2026-06-15 06:38:28.818 +0530]:
INFO [2026-06-15 06:38:28.818 +0530]: editChainRemoteConfig command completed successfully
command: "burnmint-token-pool.edit-chain-remote-config"
transactionSize: "317 bytes"
computeUnits: 14533
Verify Configuration
In this step, you will verify that the Solana pool configuration for Ethereum Sepolia has been set up correctly.
# Verify the chain configuration is complete
pnpm bs58 --env devnet burnmint-token-pool \
--instruction get-chain-config \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--remote-chain-selector $ETH_SEPOLIA_CHAIN_SELECTOR
🔍 Reading chain configuration...
RPC URL: https://api.devnet.solana.com
Program ID: 41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB
Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Remote Chain Selector: 16015286601757825753
Chain Config PDA: DpoFzuYGtBmSPPrjmC19RqAMQY5MaUxxAGY3HH97sxcZ
✅ Chain config account found
📊 Chain Configuration for Remote Chain: 16015286601757825753
Program Information:
Program Type: Burnmint Token Pool
Program ID: 41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB
Chain Config PDA: DpoFzuYGtBmSPPrjmC19RqAMQY5MaUxxAGY3HH97sxcZ
Local Token (Solana):
Mint Address: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Decimals: 9
Note: Rate limits below use these decimals
Remote Token (Destination Chain):
Token Address: 0x00000000000000000000000045cfb05d6278715716023ebeec733c081ce9f822 (32 bytes)
Token Decimals: 9
Pool Addresses: 1 address(es)
1. 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f (20 bytes)
Inbound Rate Limit: (in local token units)
Enabled: false
Capacity: N/A (disabled)
Rate: N/A (disabled)
Current Tokens: N/A (disabled)
Last Updated: N/A (disabled)
Outbound Rate Limit: (in local token units)
Enabled: false
Capacity: N/A (disabled)
Rate: N/A (disabled)
Current Tokens: N/A (disabled)
Last Updated: N/A (disabled)
INFO [2026-06-15 06:39:56.677 +0530]: getChainConfig command completed successfully
command: "burnmint-token-pool.get-chain-config"
Step 2: Configure Ethereum → Solana
Switch to Terminal 2 (Smart Contract Examples)
pwd
# Should show: .../smart-contract-examples/ccip/cct/hardhat
Load all variables from previous phases:
source ~/.ccip_complete_vars
echo "Loaded variables:"
echo "ETH_TOKEN_ADDRESS=$ETH_TOKEN_ADDRESS"
echo "ETH_POOL_ADDRESS=$ETH_POOL_ADDRESS"
echo "SOL_TOKEN_MINT=$SOL_TOKEN_MINT"
echo "Pool Config PDA: $SOL_POOL_CONFIG_PDA"
echo "Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "Multisig Address: $SOL_MULTISIG_ADDRESS"
echo "Admin Wallet: $SOL_ADMIN_WALLET"
echo "Pool Program: $SOL_CCIP_POOL_PROGRAM"
Loaded variables:
ETH_TOKEN_ADDRESS=0x45cfb05d6278715716023ebeec733c081ce9f822
ETH_POOL_ADDRESS=0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
SOL_TOKEN_MINT=AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Pool Config PDA: Fuu3EwnQkV4WUrcLj1atwEq4xbfkpgvXF5tMRYPg3nCm
Pool Signer PDA: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
Multisig Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
Admin Wallet: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Pool Program: 41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB
Configure Remote Chain
In this step, you will use the applyChainUpdates Hardhat task to configure the Ethereum pool to recognize the Solana token and pool. This tells the Ethereum pool which Solana pool (via its Pool Config PDA) and token it should interact with for cross-chain transfers.
# Configure Ethereum pool to recognize Solana chain
npx hardhat applyChainUpdates \
--pooladdress $ETH_POOL_ADDRESS \
--remotechain solanaDevnet \
--remotepooladdresses $SOL_POOL_CONFIG_PDA \
--remotetokenaddress $SOL_TOKEN_MINT \
--network ethereumSepolia
2026-06-15T01:14:32.717Z info: === Starting Chain Update Configuration ===
2026-06-15T01:14:32.718Z info: 🔹 Local network: ethereumSepolia
2026-06-15T01:14:32.718Z info: 🔹 Pool address: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
2026-06-15T01:14:32.718Z info: 🔹 Remote chain: solanaDevnet
2026-06-15T01:14:32.718Z info: 🔹 Remote chain family: svm
2026-06-15T01:14:32.718Z info: 🔹 Remote chain selector: 16423721717087811551
2026-06-15T01:14:34.133Z info: ✅ All addresses validated successfully
2026-06-15T01:14:34.572Z info: ✅ Using signer: 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca
2026-06-15T01:14:34.827Z info: ✅ Connected to TokenPool contract
2026-06-15T01:14:34.828Z info: Remote pool 1: Fuu3EwnQkV4WUrcLj1atwEq4xbfkpgvXF5tMRYPg3nCm → 0xdd90a8c837c128a246eb979efaa4a83325b4cfb673e9573b1a848c4f1871bf3e
2026-06-15T01:14:34.828Z info: === Rate Limiter Configuration ===
2026-06-15T01:14:34.828Z info: Outbound enabled: false
2026-06-15T01:14:34.828Z info: Inbound enabled: false
2026-06-15T01:14:34.829Z info: === Executing applyChainUpdates() ===
2026-06-15T01:14:36.517Z info: 📤 TX sent: 0x2ae005781238feda7b6e0b6df0b3d63a0ecf3db001e4e52db03ac7423de31f58
2026-06-15T01:14:36.517Z info: Waiting for 3 confirmations...
2026-06-15T01:15:14.989Z info: ✅ Chain update applied successfully on ethereumSepolia (3 confirmations)!
Verify Remote Chain Configuration
Verify that the Ethereum pool is correctly configured to recognize the Solana chain:
# Verify Ethereum pool configuration
npx hardhat getPoolConfig \
--pooladdress $ETH_POOL_ADDRESS \
--network ethereumSepolia
2026-06-15T01:15:48.322Z info: 📊 Fetching pool configuration for 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f on ethereumSepolia...
2026-06-15T01:15:49.927Z info:
Fetching pool configuration for: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
2026-06-15T01:15:50.182Z info:
--- Pool Basic Information ---
2026-06-15T01:15:50.182Z info: Rate Limit Admin: 0x0000000000000000000000000000000000000000
2026-06-15T01:15:50.182Z info: Router Address: 0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59
2026-06-15T01:15:50.182Z info: Token Address: 0x45cFB05d6278715716023EbeeC733C081Ce9F822
2026-06-15T01:15:50.182Z info: Allow List Enabled: false
2026-06-15T01:15:50.182Z info:
Supported Remote Chains: 1
2026-06-15T01:15:50.417Z info:
--- Remote Chain: solanaDevnet ---
2026-06-15T01:15:50.419Z info: Remote Pool Addresses:
2026-06-15T01:15:50.420Z info: 1. Fuu3EwnQkV4WUrcLj1atwEq4xbfkpgvXF5tMRYPg3nCm
2026-06-15T01:15:50.420Z info: Remote Token Address: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
2026-06-15T01:15:50.420Z info: Outbound Rate Limiter:
2026-06-15T01:15:50.420Z info: Enabled: false
2026-06-15T01:15:50.420Z info: Capacity: 0
2026-06-15T01:15:50.420Z info: Rate: 0
2026-06-15T01:15:50.420Z info: Inbound Rate Limiter:
2026-06-15T01:15:50.420Z info: Enabled: false
2026-06-15T01:15:50.420Z info: Capacity: 0
2026-06-15T01:15:50.420Z info: Rate: 0
2026-06-15T01:15:50.420Z info:
✅ Pool configuration fetched successfully.
Phase 4: Pool Registration
In this step, you will register the token pools with their respective tokens on both chains. This is the final configuration step that enables cross-chain operations by linking tokens to their pools in the CCIP registry.
Pool registration works differently on each platform:
- Ethereum: Links the token directly to its pool contract address
- Solana: Links the token to an Address Lookup Table containing all necessary pool accounts
Step 1: Ethereum Sepolia Pool Registration
Stay in Terminal 2 (Smart Contract Examples)
pwd
# Should show: .../smart-contract-examples/ccip/cct/hardhat
In this step, you will use the setPool Hardhat task to register the BurnMint token pool with the token in Ethereum's TokenAdminRegistry contract. This function sets the pool contract address for the token, enabling it for CCIP cross-chain transfers. Only the token administrator can call this function.
# Register token pool with TokenAdminRegistry contract
npx hardhat setPool \
--tokenaddress $ETH_TOKEN_ADDRESS \
--pooladdress $ETH_POOL_ADDRESS \
--network ethereumSepolia
2026-06-15T01:17:08.864Z info: 🔗 Setting pool for token 0x45cfb05d6278715716023ebeec733c081ce9f822 on ethereumSepolia...
2026-06-15T01:17:11.131Z info: 🔹 Using signer: 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca
2026-06-15T01:17:11.131Z info: Using TokenAdminRegistry: 0x95F29FEE11c5C55d26cCcf1DB6772DE953B37B82
2026-06-15T01:17:11.376Z info: Checking token configuration for 0x45cfb05d6278715716023ebeec733c081ce9f822...
2026-06-15T01:17:11.593Z info: Token 0x45cfb05d6278715716023ebeec733c081ce9f822 current admin: 0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA
2026-06-15T01:17:11.594Z info: ✅ Current wallet 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca is the token administrator
2026-06-15T01:17:11.594Z info: Setting pool 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f for token 0x45cfb05d6278715716023ebeec733c081ce9f822...
2026-06-15T01:17:13.162Z info: 📤 TX sent: 0xa53042f185709effbb9c81acdf030cf3fd10b1b1b6801bba775f3b5528788612. Waiting for 3 confirmations...
2026-06-15T01:17:51.632Z info: ✅ Pool successfully set for token 0x45cfb05d6278715716023ebeec733c081ce9f822 → 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f on ethereumSepolia (3 confirmations)
Step 2: Solana Devnet Pool Registration
Switch to Terminal 1 (CCIP Solana BS58 Generator)
pwd
# Should show: .../ccip-solana-bs58-generator
Create Address Lookup Table
Create an Address Lookup Table (ALT) containing all required CCIP accounts plus your multisig address:
# Create ALT with 10 base CCIP addresses + multisig address
pnpm bs58 --env devnet --execute router \
--instruction create-lookup-table \
--program-id $SOL_CCIP_ROUTER \
--fee-quoter-program-id $SOL_CCIP_FEE_QUOTER_PROGRAM \
--pool-program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET \
--additional-addresses "[\"$SOL_MULTISIG_ADDRESS\"]"
🔄 Generating create_lookup_table transaction...
INFO [2026-06-15 06:48:38.306 +0530]: Detected SPL Token v1
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
🔄 Building and simulating transaction...
INFO [2026-06-15 06:48:38.589 +0530]: Transaction built successfully
instructionName: "router.create_lookup_table"
transactionSize: "557 bytes"
base58Length: "760 characters"
hexLength: "1114 characters"
accountCount: 4
signerCount: 2
computeUnits: 19419
INFO [2026-06-15 06:48:38.589 +0530]: Completed buildTransaction (router.create_lookup_table)
durationMs: 190
INFO [2026-06-15 06:48:38.772 +0530]:
INFO [2026-06-15 06:48:38.772 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:48:38.773 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:48:38.773 +0530]: Instruction: router.create_lookup_table
INFO [2026-06-15 06:48:38.773 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:48:38.773 +0530]:
📮 Derived Lookup Table Address: Ff9asmT33cvZ4y2Y82Dd7ig3M72w7usJ2iZmV7p6d2uR
INFO [2026-06-15 06:48:39.728 +0530]: Transaction confirmed successfully
signature: "5JM3Yd6fK77Nc4EQioHsYHqgPCs2ap5rrzJNoyjp2b79xSpXfgxAdEDBohLfyGA8JQNrYnjuEuZj4u8y7ZNtkUAd"
attempt: 1
INFO [2026-06-15 06:48:39.728 +0530]:
INFO [2026-06-15 06:48:39.728 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:48:39.728 +0530]:
INFO [2026-06-15 06:48:39.728 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:48:39.728 +0530]: Instruction: router.create_lookup_table
INFO [2026-06-15 06:48:39.728 +0530]: Signature: 5JM3Yd6fK77Nc4EQioHsYHqgPCs2ap5rrzJNoyjp2b79xSpXfgxAdEDBohLfyGA8JQNrYnjuEuZj4u8y7ZNtkUAd
INFO [2026-06-15 06:48:39.728 +0530]: Explorer: https://explorer.solana.com/tx/5JM3Yd6fK77Nc4EQioHsYHqgPCs2ap5rrzJNoyjp2b79xSpXfgxAdEDBohLfyGA8JQNrYnjuEuZj4u8y7ZNtkUAd?cluster=devnet
INFO [2026-06-15 06:48:39.728 +0530]:
Set ALT environment variable:
export SOL_ALT_ADDRESS="<REPLACE_WITH_YOUR_ALT_ADDRESS>"
Verify output:
echo "ALT Address: $SOL_ALT_ADDRESS"
ALT Address: Ff9asmT33cvZ4y2Y82Dd7ig3M72w7usJ2iZmV7p6d2uR
Register Pool with Router
Register your token pool with the CCIP Router using the Address Lookup Table:
# Register pool with CCIP Router using the ALT
pnpm bs58 --env devnet --execute router \
--instruction set-pool \
--program-id $SOL_CCIP_ROUTER \
--mint $SOL_TOKEN_MINT \
--authority $SOL_ADMIN_WALLET \
--pool-lookup-table $SOL_ALT_ADDRESS \
--writable-indexes "[3,4,7]"
🔄 Generating set_pool transaction...
🔄 Building and simulating transaction...
INFO [2026-06-15 06:50:12.996 +0530]: Transaction built successfully
instructionName: "router.set_pool"
transactionSize: "252 bytes"
base58Length: "343 characters"
hexLength: "504 characters"
accountCount: 5
signerCount: 1
computeUnits: 38867
INFO [2026-06-15 06:50:12.996 +0530]: Completed buildTransaction (router.set_pool)
durationMs: 373
INFO [2026-06-15 06:50:13.168 +0530]:
INFO [2026-06-15 06:50:13.168 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:50:13.168 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:50:13.168 +0530]: Instruction: router.set_pool
INFO [2026-06-15 06:50:13.168 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:50:13.168 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:50:14.102 +0530]: Transaction confirmed successfully
signature: "okCJy5JwUePaxpAfvynevv3n8qWL5ZdeHhYtr3VrWHokYG89yc2u4vkdHu3q9yyUy7VeaZH87wqcgtk67TBW5cT"
attempt: 1
INFO [2026-06-15 06:50:14.102 +0530]:
INFO [2026-06-15 06:50:14.102 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:50:14.103 +0530]:
INFO [2026-06-15 06:50:14.103 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:50:14.103 +0530]: Instruction: router.set_pool
INFO [2026-06-15 06:50:14.103 +0530]: Signature: okCJy5JwUePaxpAfvynevv3n8qWL5ZdeHhYtr3VrWHokYG89yc2u4vkdHu3q9yyUy7VeaZH87wqcgtk67TBW5cT
INFO [2026-06-15 06:50:14.103 +0530]: Explorer: https://explorer.solana.com/tx/okCJy5JwUePaxpAfvynevv3n8qWL5ZdeHhYtr3VrWHokYG89yc2u4vkdHu3q9yyUy7VeaZH87wqcgtk67TBW5cT?cluster=devnet
INFO [2026-06-15 06:50:14.103 +0530]:
Save the complete configuration including the ALT address:
cat >> ~/.ccip_complete_vars << EOF
export SOL_ALT_ADDRESS="$SOL_ALT_ADDRESS"
EOF
echo "=== Complete Configuration Saved ==="
echo "✅ ALT Address: $SOL_ALT_ADDRESS"
echo "✅ All variables saved to ~/.ccip_complete_vars"
echo "✅ Ready for cross-chain testing"
=== Complete Configuration Saved ===
✅ ALT Address: Ff9asmT33cvZ4y2Y82Dd7ig3M72w7usJ2iZmV7p6d2uR
✅ All variables saved to ~/.ccip_complete_vars
✅ Ready for cross-chain testing
Phase 5: Pre-Transfer Setup
Before validating your configuration, complete final setup steps.
Stay in Terminal 1 (CCIP Solana BS58 Generator)
pwd
# Should show: .../ccip-solana-bs58-generator
Step 1: Delegate Token Authority
Delegate token approval to the CCIP fee-billing signer PDA, which enables CCIP to transfer tokens on your behalf when sending cross-chain messages.
# Derive the CCIP fee-billing signer PDA
export SOL_CCIP_FEE_BILLING_SIGNER=$(solana find-program-derived-address $SOL_CCIP_ROUTER string:fee_billing_signer | head -1)
echo "SOL_CCIP_FEE_BILLING_SIGNER=$SOL_CCIP_FEE_BILLING_SIGNER"
SOL_CCIP_FEE_BILLING_SIGNER=2AjuzTy6z2webxEUu7eZ1DkAyLagZaqH2dgzhbBYjJiG
Approve the fee-billing signer to transfer tokens from your ATA:
# --amount is u64 max (2^64 - 1): max delegation for CCIP fee billing
pnpm bs58 --env devnet --execute spl-token \
--instruction approve \
--authority $SOL_ADMIN_WALLET \
--mint $SOL_TOKEN_MINT \
--delegate $SOL_CCIP_FEE_BILLING_SIGNER \
--amount 18446744073709551615
🔍 Detecting token program...
INFO [2026-06-15 06:55:03.915 +0530]: Starting approve command
command: "spl-token.approve"
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
delegate: "2AjuzTy6z2webxEUu7eZ1DkAyLagZaqH2dgzhbBYjJiG"
authority: "GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN"
amount: "18446744073709551615"
globalOptions: {
"environment": "devnet",
"execute": true,
"resolvedRpcUrl": "https://api.devnet.solana.com",
"keypair": "/Users/syed-cll/.config/solana/id.json",
"_signerKeypair": {
"_keypair": {
"publicKey": {
"0": 230,
"1": 211,
"2": 30,
...
"29": 179,
"30": 114,
"31": 73
},
"secretKey": {
"0": 191,
"1": 198,
"2": 244,
...
"61": 179,
"62": 114,
"63": 73
}
}
}
}
✅ Detected token program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
🔍 Auto-deriving Associated Token Account...
✅ Derived ATA: 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
🔄 Generating approve transaction...
RPC URL: https://api.devnet.solana.com
Token Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Token Account: 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
Delegate: 2AjuzTy6z2webxEUu7eZ1DkAyLagZaqH2dgzhbBYjJiG
Authority (Token Account Owner): GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Amount: 18446744073709551615
⚙️ Building transaction instruction...
✅ Instruction built successfully
🔄 Building and simulating transaction...
INFO [2026-06-15 06:55:04.288 +0530]: Detected SPL Token v1
mint: "AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7"
programId: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
INFO [2026-06-15 06:55:04.446 +0530]: Transaction built successfully
instructionName: "approve"
transactionSize: "180 bytes"
base58Length: "245 characters"
hexLength: "360 characters"
accountCount: 3
signerCount: 1
computeUnits: 123
INFO [2026-06-15 06:55:04.447 +0530]: Completed buildTransaction (approve)
durationMs: 157
INFO [2026-06-15 06:55:04.604 +0530]:
INFO [2026-06-15 06:55:04.604 +0530]: 🖊️ EXECUTE MODE — signing & sending on devnet
INFO [2026-06-15 06:55:04.604 +0530]: Signer: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
INFO [2026-06-15 06:55:04.604 +0530]: Instruction: approve
INFO [2026-06-15 06:55:04.604 +0530]: RPC: https://api.devnet.solana.com
INFO [2026-06-15 06:55:04.605 +0530]:
✅ Transaction simulation completed
INFO [2026-06-15 06:55:05.412 +0530]: Transaction confirmed successfully
signature: "5hocYyLtzifa1M8DktwYJUbNR4fKU4wQVMWfTNMhBFCMfLh4cSkBb9bHsSf8FN6K7Zy6jEtg7PtPmrQ18zYZkug9"
attempt: 1
INFO [2026-06-15 06:55:05.412 +0530]:
INFO [2026-06-15 06:55:05.412 +0530]: 🎉 Transaction executed successfully!
INFO [2026-06-15 06:55:05.412 +0530]:
INFO [2026-06-15 06:55:05.412 +0530]: 📋 Execution Details:
INFO [2026-06-15 06:55:05.412 +0530]: Instruction: approve
INFO [2026-06-15 06:55:05.412 +0530]: Signature: 5hocYyLtzifa1M8DktwYJUbNR4fKU4wQVMWfTNMhBFCMfLh4cSkBb9bHsSf8FN6K7Zy6jEtg7PtPmrQ18zYZkug9
INFO [2026-06-15 06:55:05.412 +0530]: Explorer: https://explorer.solana.com/tx/5hocYyLtzifa1M8DktwYJUbNR4fKU4wQVMWfTNMhBFCMfLh4cSkBb9bHsSf8FN6K7Zy6jEtg7PtPmrQ18zYZkug9?cluster=devnet
INFO [2026-06-15 06:55:05.412 +0530]:
INFO [2026-06-15 06:55:05.413 +0530]: approve command completed successfully
command: "spl-token.approve"
transactionSize: "180 bytes"
computeUnits: 123
Step 2: Verify Delegation
Check that your token account is delegated to the fee-billing signer:
# Find your Associated Token Account (ATA) address
export SOL_TOKEN_ACCOUNT=$(spl-token accounts $SOL_TOKEN_MINT --owner $SOL_ADMIN_WALLET --addresses-only)
echo "SOL_TOKEN_ACCOUNT=$SOL_TOKEN_ACCOUNT"
SOL_TOKEN_ACCOUNT=9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
Display token account and delegation status:
spl-token display $SOL_TOKEN_ACCOUNT
SPL Token Account
Address: 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
Program: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Balance: 1000
Decimals: 9
Mint: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Owner: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
State: Initialized
Delegation:
Delegate: 2AjuzTy6z2webxEUu7eZ1DkAyLagZaqH2dgzhbBYjJiG
Allowance: 18446744073.709551615
Close authority: (not set)
Phase 6: Test Cross-Chain Transfers
Validate your configuration, then execute bidirectional token transfers using the CCIP CLI.
Step 1: Load Complete Configuration
source ~/.ccip_complete_vars
echo "=== Configuration Validation ==="
echo "✅ ETH Token: $ETH_TOKEN_ADDRESS"
echo "✅ ETH Pool: $ETH_POOL_ADDRESS"
echo "✅ SOL Token: $SOL_TOKEN_MINT"
echo "✅ Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "✅ Multisig Address: $SOL_MULTISIG_ADDRESS"
echo "✅ ALT Address: $SOL_ALT_ADDRESS"
echo "✅ Admin Wallet: $SOL_ADMIN_WALLET"
=== Configuration Validation ===
✅ ETH Token: 0x45cfb05d6278715716023ebeec733c081ce9f822
✅ ETH Pool: 0x1df7ede88286c1ef95d024b311e12dc4b3106f1f
✅ SOL Token: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
✅ Pool Signer PDA: 5LZUPpzMudPAX6BNaDrzjPE28YuGbQArvJucM2f7JJMe
✅ Multisig Address: A4SnwAxQnfuMn5DcZbipwawAfDz3aAosw81ujdSq543C
✅ ALT Address: Ff9asmT33cvZ4y2Y82Dd7ig3M72w7usJ2iZmV7p6d2uR
✅ Admin Wallet: GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN
Step 2: Verify Solana Pool and Chain Config
# Verify pool state
pnpm bs58 --env devnet burnmint-token-pool \
--instruction get-state \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT
# Verify Ethereum Sepolia remote chain config
pnpm bs58 --env devnet burnmint-token-pool \
--instruction get-chain-config \
--program-id $SOL_CCIP_POOL_PROGRAM \
--mint $SOL_TOKEN_MINT \
--remote-chain-selector $ETH_SEPOLIA_CHAIN_SELECTOR
# Verify mint authority is the multisig
spl-token display $SOL_TOKEN_MINT
# Verify token balance and delegation
spl-token balance $SOL_TOKEN_MINT
Confirm the following:
- Pool owner matches
$SOL_ADMIN_WALLET - Mint authority is the SPL token multisig (
$SOL_MULTISIG_ADDRESS) with Pool Signer PDA as a signer - Remote chain config includes your
$ETH_POOL_ADDRESSand$ETH_TOKEN_ADDRESS - Token delegation is set to the fee-billing signer
- Your wallet holds tokens for transfer testing
Step 3: Verify Ethereum Pool (Terminal 2)
Switch to Terminal 2 (Smart Contract Examples - Hardhat):
npx hardhat getPoolConfig \
--pooladdress $ETH_POOL_ADDRESS \
--network ethereumSepolia
Confirm the Ethereum pool recognizes Solana Devnet with your $SOL_POOL_CONFIG_PDA and $SOL_TOKEN_MINT.
Configure CCIP CLI
Export these RPC URLs once before your first transfer:
export SOLANA_DEVNET_RPC="https://api.devnet.solana.com"
export ETHEREUM_SEPOLIA_RPC_URL="<YOUR_ETHEREUM_SEPOLIA_RPC_URL>"
export ETH_CCIP_ROUTER="0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59"
Use the same ETHEREUM_SEPOLIA_RPC_URL from your env-enc setup in Terminal 2 (npx env-enc view). On ccip-cli send, the source chain RPC quotes fees and submits the transaction; for token-only transfers in this tutorial, that is the only RPC strictly required to send. Pass both RPCs on cross-chain commands anyway: the destination RPC is required for ccip-cli show --wait and for optional send features such as --estimate-gas-limit or send --wait.
Transfer Solana → Ethereum
Terminal 1 (CCIP Solana BS58 Generator):
source ~/.ccip_complete_vars
export ETH_RECEIVER_ADDRESS="<YOUR_ETHEREUM_RECEIVER_ADDRESS>"
ccip-cli send \
-s solana-devnet \
-r $SOL_CCIP_ROUTER \
-d ethereum-testnet-sepolia \
--to $ETH_RECEIVER_ADDRESS \
-t $SOL_TOKEN_MINT=0.001 \
--wallet ~/.config/solana/id.json \
--rpc $SOLANA_DEVNET_RPC \
--rpc $ETHEREUM_SEPOLIA_RPC_URL
Fee: 55271173n = 0.055271173 SOL
🚀 Sending message to 0x8c244f0b2164e6a3bed74ab429b0ebd661bb14ca @ ethereum-testnet-sepolia , tx => 25n99NMQhYqP7ikkGW5Tkn6dAqfEaUYRTYh4JsVCNATrEpe39Bjnu6Cm6q1uKpAwZswQZBrc9gkpRtRS1D2MXjxV, messageId => 0xe4e131424902af9f4b72634372b088831cc91e50079251e8200e9106731f6a4c
Using rate-limited fetch for public solana nodes, commands may be slow
Lane:
┌────────────────┬────────────────────────────────────────────────┬────────────────────────────┐
│ (index) │ source │ dest │
├────────────────┼────────────────────────────────────────────────┼────────────────────────────┤
│ name │ 'solana-devnet' │ 'ethereum-testnet-sepolia' │
│ chainId │ 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG' │ 11155111 │
│ chainSelector │ 16423721717087811551n │ 16015286601757825753n │
│ onRamp/version │ 'Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C' │ '1.6.0' │
└────────────────┴────────────────────────────────────────────────┴────────────────────────────┘
Request (source):
┌──────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├──────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ messageId │ '0xe4e131424902af9f4b72634372b088831cc91e50079251e8200e9106731f6a4c' │
│ origin │ 'GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN' │
│ sender │ 'GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN' │
│ receiver │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │
│ sequenceNumber │ 3076 │
│ nonce │ '0 => allow out-of-order exec' │
│ gasLimit │ 0n │
│ transactionHash │ '25n99NMQhYqP7ikkGW5Tkn6dAqfEaUYRTYh4JsVCNATrEpe39Bjnu6Cm6q1uKpAwZswQZBrc9gkpRtRS1D2MXjxV' │
│ logIndex │ 34 │
│ blockNumber │ 469500512 │
│ timestamp │ '2026-06-15 01:31:03 (2s ago)' │
│ finalized │ '11s left' │
│ fee │ '0.055271173 SOL' │
│ tokens │ '0.001 CCIP-AEM' │
│ data │ '0x' │
│ feeValueJuels │ 481763587000000000n │
│ allowOutOfOrderExecution │ true │
└──────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────┘
CCIP Explorer: https://ccip.chain.link/msg/0xe4e131424902af9f4b72634372b088831cc91e50079251e8200e9106731f6a4c
The -t flag uses human-readable amounts (0.001 tokens with 9 decimals = 1,000,000 smallest units).
# Replace with the transaction hash or message ID from the send output
ccip-cli show <TX_HASH_OR_MESSAGE_ID> --wait \
--rpc $SOLANA_DEVNET_RPC \
--rpc $ETHEREUM_SEPOLIA_RPC_URL
Using rate-limited fetch for public solana nodes, commands may be slow
Lane:
┌────────────────┬────────────────────────────────────────────────┬────────────────────────────┐
│ (index) │ source │ dest │
├────────────────┼────────────────────────────────────────────────┼────────────────────────────┤
│ name │ 'solana-devnet' │ 'ethereum-testnet-sepolia' │
│ chainId │ 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG' │ 11155111 │
│ chainSelector │ 16423721717087811551n │ 16015286601757825753n │
│ onRamp/version │ 'Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C' │ '1.6.2' │
└────────────────┴────────────────────────────────────────────────┴────────────────────────────┘
Request (source):
┌────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ messageId │ '0xe4e131424902af9f4b72634372b088831cc91e50079251e8200e9106731f6a4c' │
│ origin │ 'GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN' │
│ sender │ 'GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN' │
│ receiver │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │
│ sequenceNumber │ 3076 │
│ nonce │ '0 => allow out-of-order exec' │
│ gasLimit │ 0n │
│ transactionHash │ '25n99NMQhYqP7ikkGW5Tkn6dAqfEaUYRTYh4JsVCNATrEpe39Bjnu6Cm6q1uKpAwZswQZBrc9gkpRtRS1D2MXjxV' │
│ logIndex │ 1 │
│ blockNumber │ 469500512 │
│ timestamp │ '2026-06-15 01:31:03 (47s ago)' │
│ finalized │ true │
│ fee │ '0.055271173 SOL' │
│ tokens │ '0.001 CCIP-AEM' │
│ fees.fixedFeesDetails.tokenAddress │ 'So11111111111111111111111111111111111111112' │
│ fees.fixedFeesDetails.totalAmount │ 55271173n │
│ finality │ 0n │
│ finalityType │ 'FINALIZED' │
│ routerAddress │ 'Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C' │
│ allowOutOfOrderExecution │ true │
│ status │ 'SOURCE_FINALIZED' │
│ readyForManualExecution │ false │
│ receiptTransactionHash │ null │
│ receiptTimestamp │ undefined │
│ deliveryTime │ null │
│ offRamp │ '0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0' │
└────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────┘
CCIP Explorer: https://ccip.chain.link/msg/0xe4e131424902af9f4b72634372b088831cc91e50079251e8200e9106731f6a4c
[SENT] Waiting for source chain finalization...
[SOURCE_FINALIZED] Source chain finalized
[SOURCE_FINALIZED] Waiting for commit on destination chain...
[COMMITTED] Commit report accepted on destination chain
┌─────────────────┬──────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├─────────────────┼──────────────────────────────────────────────────────────────────────┤
│ merkleRoot │ '0x9e110e42e6882b066e5c3e7bd4b50a7273297462ab1135825a20fd54c3d69d6b' │
│ min │ 3076 │
│ max │ 3076 │
│ origin │ '0xc03BfDf1C576bc3720DcD45B6B4EF6A0aEf4dfe6' │
│ contract │ '0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0' │
│ transactionHash │ '0x61b70445f7b1f90bd17d6e197364df7aed9c4f4d6873e81fda5e8e3784be8934' │
│ blockNumber │ 11062234 │
│ timestamp │ '2026-06-15 01:31:48 (45s after request)' │
└─────────────────┴──────────────────────────────────────────────────────────────────────┘
[BLESSED] Waiting for execution on destination chain...
[SUCCESS] Message executed on destination chain
┌─────────────────┬──────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├─────────────────┼──────────────────────────────────────────────────────────────────────┤
│ state │ '✅ success' │
│ gasUsed │ 81076 │
│ origin │ '0xF482Bd4AE751DEDA88bf48937A8CA38D8Da21522' │
│ contract │ '0x0820f975ce90EE5c508657F0C58b71D1fcc85cE0' │
│ transactionHash │ '0x73e8d2d350aa63fab1f49d3fe80c61aa86dae3b8913d3be1d59cfe24b2deef37' │
│ logIndex │ 488 │
│ blockNumber │ 11062237 │
│ timestamp │ '2026-06-15 01:32:24 (1m21s after request)' │
└─────────────────┴──────────────────────────────────────────────────────────────────────┘
Transfer Ethereum → Solana
Switch to Terminal 2 (Smart Contract Examples - Hardhat):
ccip-cli does not load Hardhat env-enc automatically. Run these commands from the Hardhat project directory. Prefer Hardhat keystore over exporting a private key in plain text.
source ~/.ccip_complete_vars
ccip-cli send \
-s ethereum-testnet-sepolia \
-r $ETH_CCIP_ROUTER \
-d solana-devnet \
--to $SOL_ADMIN_WALLET \
-t $ETH_TOKEN_ADDRESS=1.0 \
--wallet hardhat:<YOUR_KEYSTORE_ACCOUNT_NAME> \
--rpc $ETHEREUM_SEPOLIA_RPC_URL \
--rpc $SOLANA_DEVNET_RPC
Use the keystore account name from your Hardhat project (see Hardhat keystore). This keeps the signing key encrypted instead of in shell history.
source ~/.ccip_complete_vars
# ccip-cli does not read env-enc — view and export the same key used in Phase 1
npx env-enc view
export PRIVATE_KEY="<YOUR_PRIVATE_KEY_FROM_ENV_ENC>"
ccip-cli send \
-s ethereum-testnet-sepolia \
-r $ETH_CCIP_ROUTER \
-d solana-devnet \
--to $SOL_ADMIN_WALLET \
-t $ETH_TOKEN_ADDRESS=1.0 \
--rpc $ETHEREUM_SEPOLIA_RPC_URL \
--rpc $SOLANA_DEVNET_RPC
Do not commit or share the exported key. Prefer the Hardhat keystore tab for production-like workflows.
For token-only transfers to Solana, --to is the destination wallet that receives minted tokens. CCIP fees are paid in native Sepolia ETH by default — ensure your wallet has sufficient ETH for gas and fees.
ccip-cli show <TX_HASH_OR_MESSAGE_ID> --wait \
--rpc $ETHEREUM_SEPOLIA_RPC_URL \
--rpc $SOLANA_DEVNET_RPC
Lane:
┌────────────────┬──────────────────────────────────────────────┬────────────────────────────────────────────────┐
│ (index) │ source │ dest │
├────────────────┼──────────────────────────────────────────────┼────────────────────────────────────────────────┤
│ name │ 'ethereum-testnet-sepolia' │ 'solana-devnet' │
│ chainId │ 11155111 │ 'EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG' │
│ chainSelector │ 16015286601757825753n │ 16423721717087811551n │
│ onRamp/version │ '0x23a5084Fa78104F3DF11C63Ae59fcac4f6AD9DeE' │ '1.6.0' │
└────────────────┴──────────────────────────────────────────────┴────────────────────────────────────────────────┘
Request (source):
┌────────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├────────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ messageId │ '0xc64e289c9a0a9b3bff7f2bfe98996ef56dc138f7fdc500541e60b009ab7d98d3' │
│ origin │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │
│ sender │ '0x8C244f0B2164E6A3BED74ab429B0ebd661Bb14CA' │
│ receiver │ '11111111111111111111111111111111' │
│ sequenceNumber │ 10199 │
│ nonce │ '0 => allow out-of-order exec' │
│ computeUnits │ 0n │
│ transactionHash │ '0xbf28e47f97c0320fef0fbc31ea01a2c6c10c00b538b868da7b1eafca37a1c622' │
│ logIndex │ 891 │
│ blockNumber │ 11062259 │
│ timestamp │ '2026-06-15 01:36:48 (16m4s ago)' │
│ finalized │ true │
│ fee │ '0.000351018193797698 WETH' │
│ tokens │ '1.0 BnMAEM' │
│ accounts │ undefined │
│ fees.fixedFeesDetails.tokenAddress │ '0x097D90c9d3E0B50Ca60e1ae45F6A81010f9FB534' │
│ fees.fixedFeesDetails.totalAmount │ 351018193797698n │
│ finality │ 0n │
│ finalityType │ 'FINALIZED' │
│ routerAddress │ '0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59' │
│ accountIsWritableBitmap │ 0n │
│ allowOutOfOrderExecution │ true │
│ tokenReceiver │ 'GY3V5RAtSxoJf2dZGqAbzaSxDyXWb8RPMWQdv1mC5PXN' │
│ status │ 'SUCCESS' │
│ readyForManualExecution │ false │
│ receiptTransactionHash │ '2gtGHy8tqeyHgDGLm7AntoGC2V9yBfpQwTZKoaDozMDfCvWgNSJVEr3BiTn4z8W2fzHkPrbxzmxQG7ThWgExV2fR' │
│ receiptTimestamp │ '2026-06-15 01:51:40' │
│ deliveryTime │ 892000n │
│ offRamp │ 'offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm' │
└────────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────────────────┘
CCIP Explorer: https://ccip.chain.link/msg/0xc64e289c9a0a9b3bff7f2bfe98996ef56dc138f7fdc500541e60b009ab7d98d3
[SENT] Waiting for source chain finalization...
Using rate-limited fetch for public solana nodes, commands may be slow
[SOURCE_FINALIZED] Source chain finalized
[SOURCE_FINALIZED] Waiting for commit on destination chain...
[SUCCESS] Message executed on destination chain
┌─────────────────┬────────────────────────────────────────────────────────────────────────────────────────────┐
│ (index) │ Values │
├─────────────────┼────────────────────────────────────────────────────────────────────────────────────────────┤
│ state │ '✅ success' │
│ origin │ 'DeJbuwyora8jj76hMbypp2v59MUa9vgPo9DPEnMDdJnC' │
│ contract │ 'offqSMQWgQud6WJz694LRzkeN5kMYpCHTpXQr3Rkcjm' │
│ transactionHash │ '2gtGHy8tqeyHgDGLm7AntoGC2V9yBfpQwTZKoaDozMDfCvWgNSJVEr3BiTn4z8W2fzHkPrbxzmxQG7ThWgExV2fR' │
│ logIndex │ 23 │
│ blockNumber │ 469503780 │
│ timestamp │ '2026-06-15 01:51:40 (14m52s after request)' │
└─────────────────┴────────────────────────────────────────────────────────────────────────────────────────────┘
Congratulations! Your cross-chain token infrastructure with SPL token multisig governance is fully configured on both chains.
Optional: Verify Mint Authority Control
Demonstrate Manual Minting Through Multisig
This optional section demonstrates that transferring mint authority to the multisig doesn't mean "losing control" - you can still mint tokens manually through the Admin Wallet (the non-PDA signer in your multisig). This proves the multisig setup is working correctly and that you retain administrative capabilities.
# Demonstrate manual minting through the multisig
# This proves you haven't "lost" mint authority - it's just managed through the multisig
spl-token mint $SOL_TOKEN_MINT 1 \
--owner $SOL_MULTISIG_ADDRESS \
--multisig-signer $HOME/.config/solana/id.json
Minting 1 tokens
Token: AgHA2wyaRnjL5Jjnk1PirfXA2n3fF6w6t8RhRCG9pqp7
Recipient: 9Xv8WtoN9EpBfSjqWVoQfrf4qc5CMSvBmM5Hu9jApYhc
Signature: 47EdSs3eUrbd6VB4W9iJzTMj81q9pyom38Nw4gyHpzqYDqMJQ6SqyKTs9csSvGp3BZvR5kVuxJnFTKX3DFGxpwyU
Verify Transaction on Solana Explorer:
https://explorer.solana.com/tx/4dYQyf8oTWojuVKNQdPNkdPLVwdJcGCbekW3sXP7ZdTd7UVksft9ekKLDWtkE4rgUvuTtFeTRNGWpgmF7HJNFJ3J?cluster=devnet
The successful transaction on Solana Explorer confirms that the multisig mint operation executed properly, proving that mint authority is retained and functional through the multisig structure.