Cross-Chain Token Setup: BurnMint with Direct Mint Authority Transfer

This comprehensive tutorial demonstrates how to create and configure cross-chain tokens using Chainlink's Cross-Chain Interoperability Protocol (CCIP) between Solana Devnet and Ethereum Sepolia. You will implement the direct mint authority transfer approach within Path A from the CCIP Cross-Chain Token Integration Guide.

What You Will Build

This tutorial implements the direct mint authority transfer variant of Path A from the CCIP Cross-Chain Token Integration Guide. This approach is designed for development and testing environments where you transfer complete mint authority to the Pool Signer PDA for simplified setup.

ComponentImplementationAuthority Model
Ethereum SepoliaERC20 token with CCIP BurnMint poolMultiple minters: EOA + Pool
Solana DevnetSPL token with CCIP BurnMint poolSingle mint authority: Pool Signer PDA

Prerequisites

This tutorial requires setting up two different repositories in separate terminal windows. Follow the setup instructions for both environments before proceeding.

Development Environment Requirements

System Requirements:

  • Anchor and Solana CLI Tools: Install following the installation guide. Requires Rust to be installed.
  • Node.js v20 or higher: Use the nvm package to install and manage versions. Verify with node -v
  • Yarn: For dependency management
  • Git: For cloning repositories

Terminal 1: Solana Starter Kit Setup

Clone and setup the Solana Starter Kit:

git clone https://github.com/smartcontractkit/solana-starter-kit.git && cd solana-starter-kit

Install dependencies:

yarn install

Configure your Solana environment:

# Set Solana CLI to use devnet
solana config set --url https://api.devnet.solana.com

# Set your keypair (create one if needed)
solana config set --keypair ~/.config/solana/id.json

# If you do not have a keypair, create one:
solana-keygen new --outfile ~/.config/solana/id.json

Fund your Solana wallet:

# Get your wallet address
solana address

# Request SOL from the devnet faucet
solana airdrop 2

Verify your setup:

# Check your SOL balance
solana balance

# Verify you are on devnet
solana config get

Terminal 2: Smart Contract Examples Setup

Clone the repository and navigate to the Hardhat project:

git clone https://github.com/smartcontractkit/smart-contract-examples.git
cd smart-contract-examples/ccip/cct/hardhat

Install and compile dependencies:

npm install
npm run compile

Set up encrypted environment variables:

# Set encryption password
npx env-enc set-pw

# Configure environment variables
npx env-enc set

Required environment variables for Ethereum Sepolia:

Fund your wallet:

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 (Solana) 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 deeper technical implementation details, refer to:

What You'll Implement

This tutorial implements the Burn and Mint token handling mechanism between Solana Devnet and Ethereum Sepolia. You'll deploy two BurnMint pools (one on each chain) that work together to maintain consistent token supply across chains.

How Burn and Mint Works:

  1. Source Chain: Burns tokens from sender's account
  2. CCIP Protocol: Transmits message cross-chain
  3. Destination Chain: Mints equivalent tokens to the receiver

Authority Model Differences:

  • Ethereum: Your EOA + Pool both have mint privileges (multiple minters supported)
  • Solana: Pool Signer PDA has exclusive mint authority (single authority constraint)

For complete details on token handling mechanisms, see Token Handling Mechanisms.

Phase 1: Ethereum Sepolia Token Setup

In this phase, you'll deploy and configure your ERC20 token with CCIP BurnMint pools on Ethereum Sepolia.

Step 1: Deploy ERC20 Token

Deploy a burnable and mintable ERC20 token that will serve as your cross-chain asset:

# Deploy BurnMint ERC20 token with verification

npx hardhat deployToken \
  --name "BnM Cross-Chain Token" \
--symbol "BnMAEM" \
  --decimals 18 \
  --verifycontract true \
  --network sepolia

Set the token address variable:

# REPLACE with your actual deployed token address
export ETH_TOKEN_ADDRESS="<INSERT_YOUR_TOKEN_ADDRESS_HERE>"

Verify it's set correctly:

echo "Ethereum Token: $ETH_TOKEN_ADDRESS"

Step 2: Deploy BurnMint Token Pool

Deploy a CCIP token pool that will manage burning and minting operations:

# Deploy BurnMint pool for your token
npx hardhat deployTokenPool \
  --tokenaddress $ETH_TOKEN_ADDRESS \
  --localtokendecimals 18 \
  --pooltype burnMint \
  --verifycontract true \
  --network sepolia

Set the pool address variable:

# REPLACE with your actual deployed pool address
export ETH_POOL_ADDRESS="<INSERT_YOUR_POOL_ADDRESS_HERE>"

Verify both addresses are set:

echo "Ethereum Token: $ETH_TOKEN_ADDRESS"
echo "Ethereum Pool: $ETH_POOL_ADDRESS"

Step 3: Mint Initial Token Supply

Mint tokens to your wallet for testing cross-chain transfers:

# Mint 1000 tokens (with 18 decimals)
npx hardhat mintTokens \
  --tokenaddress $ETH_TOKEN_ADDRESS \
  --amount 1000000000000000000000 \
  --network sepolia

Step 4: Register as CCIP Administrator

Register yourself as the CCIP administrator for your token. This two-step process (claim + accept) ensures secure ownership transfer:

Claim Admin Role

# Claim admin role for your token
npx hardhat claimAdmin \
  --tokenaddress $ETH_TOKEN_ADDRESS \
  --network sepolia

Accept Admin Role

# Accept the admin role to finalize
npx hardhat acceptAdminRole \
  --tokenaddress $ETH_TOKEN_ADDRESS \
  --network sepolia

Step 5: Save Phase 1 Variables

Save your EVM configuration for use in later phases:

# 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 2: Solana Devnet Token Setup

Now we'll create and configure the Solana side of your cross-chain token system.

Step 1: Create SPL Token

Create an SPL token with metadata support:

# Create SPL token with default configuration
yarn svm:token:create

Set the token mint variable:

# REPLACE with your actual token mint address
export SOL_TOKEN_MINT="<INSERT_YOUR_MINT_ADDRESS_HERE>"
export CCIP_POOL_PROGRAM="41FGToCmdaWa1dgZLKFAjvmx6e6AjVTX7SVRibvsMGVB"

Verify the variables:

# Verify variables
echo "Solana Token Mint: $SOL_TOKEN_MINT"
echo "CCIP Pool Program: $CCIP_POOL_PROGRAM"

Step 2: Initialize CCIP Token Pool

Initialize the token pool configuration on Solana:

# Initialize CCIP pool for your token
yarn svm:pool:initialize \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM

Save the Pool Signer PDA and Pool Config PDA from the output:

# REPLACE with your Pool Signer PDA from the output
export SOL_POOL_SIGNER_PDA="<INSERT_YOUR_POOL_SIGNER_PDA_HERE>"

# Also save the Pool Config PDA for later use
export SOL_POOL_CONFIG_PDA="<INSERT_YOUR_POOL_CONFIG_PDA_HERE>"

Verify the variables:

echo "Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "Pool Config PDA: $SOL_POOL_CONFIG_PDA"

Step 3: Create Pool Token Account

In this step, you will 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 token account for Pool Signer PDA
yarn svm:pool:create-token-account \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM

Step 4: Register as CCIP Administrator

Propose Admin

In this step, you will propose yourself as the CCIP administrator for the Solana token.

# Propose yourself as administrator
yarn svm:admin:propose-administrator \
  --token-mint $SOL_TOKEN_MINT

Accept Admin

In this step, you will accept the administrator role for the Solana token. This process establishes your control over the token's CCIP configuration on Solana.

# Accept the administrator role
yarn svm:admin:accept-admin-role \
  --token-mint $SOL_TOKEN_MINT

Step 5: Transfer Mint Authority to Pool Signer PDA

# Transfer mint authority to Pool Signer PDA
spl-token authorize $SOL_TOKEN_MINT mint $SOL_POOL_SIGNER_PDA

Verify the authority transfer

spl-token display $SOL_TOKEN_MINT

Step 6: Save Phase 2 Variables

Save your Solana configuration for use in cross-chain setup:

# Save Phase 2 variables for cross-terminal use
cat > ~/.phase2_vars << EOF
export SOL_TOKEN_MINT="$SOL_TOKEN_MINT"
export SOL_POOL_SIGNER_PDA="$SOL_POOL_SIGNER_PDA"
export SOL_POOL_CONFIG_PDA="$SOL_POOL_CONFIG_PDA"
export CCIP_POOL_PROGRAM="$CCIP_POOL_PROGRAM"
EOF

echo "=== Phase 2 Complete - Solana Setup ==="
echo "โœ… SOL Token: $SOL_TOKEN_MINT"
echo "โœ… Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "โœ… Pool Config PDA: $SOL_POOL_CONFIG_PDA"
echo "โœ… Variables saved to ~/.phase2_vars"

Phase 3: Cross-Chain Configuration

Configure bidirectional connectivity between your token pools on both chains.

Step 1: Configure Solana Pool

Stay in Terminal 1 (Solana Starter Kit)

Load the Ethereum addresses from Phase 1:

# Load Phase 1 variables
source ~/.phase1_vars

# Verify all variables are available
echo "โœ… ETH Token: $ETH_TOKEN_ADDRESS"
echo "โœ… ETH Pool: $ETH_POOL_ADDRESS"
echo "โœ… SOL Token: $SOL_TOKEN_MINT"
echo "โœ… SOL Pool Program: $CCIP_POOL_PROGRAM"

Configure Remote Chain

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
yarn svm:pool:init-chain-remote-config \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM \
  --remote-chain ethereum-sepolia \
  --token-address $ETH_TOKEN_ADDRESS \
  --decimals 9

Add Remote Pool Address

In this step, you will use update the previously created chain configuration with the Ethereum pool address. This completes the configuration by telling the Solana pool which Ethereum pool it should interact with for cross-chain transfers.

# Add Ethereum pool address to configuration
yarn svm:pool:edit-chain-remote-config \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM \
  --remote-chain ethereum-sepolia \
  --pool-addresses $ETH_POOL_ADDRESS \
  --token-address $ETH_TOKEN_ADDRESS \
  --decimals 9

Step 2: Configure Ethereum Pool

Switch to Terminal 2 (Smart Contract Examples)

pwd
# Should output: ../smart-contract-examples/ccip/cct/hardhat

Load Variables from Previous Phases

Load all variables needed for EVM cross-chain configuration:

# Load Phase 1 and Phase 2 variables
source ~/.phase1_vars
source ~/.phase2_vars

# Verify all variables are loaded
echo "โœ… ETH Token: $ETH_TOKEN_ADDRESS"
echo "โœ… ETH Pool: $ETH_POOL_ADDRESS"
echo "โœ… SOL Token: $SOL_TOKEN_MINT"
echo "โœ… SOL Pool Config PDA: $SOL_POOL_CONFIG_PDA"
echo "โœ… Pool Program: $CCIP_POOL_PROGRAM"

Configure Remote Chain

In this step, you will 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 sepolia

Phase 4: Pool Registration

Register your token pools with their respective Token Admin Registries to enable cross-chain operations.

Step 1: Register Ethereum Pool

Stay in Terminal 2 (Smart Contract Examples)

pwd
# Should output: ../smart-contract-examples/ccip/cct/hardhat

Register the BurnMint token pool with your token in the TokenAdminRegistry:

# Register the pool with your token
npx hardhat setPool \
  --tokenaddress $ETH_TOKEN_ADDRESS \
  --pooladdress $ETH_POOL_ADDRESS \
  --network sepolia

Step 2: Register Solana Pool

Switch to Terminal 1 (Solana Starter Kit)

pwd
# Should show ../solana-starter-kit

Create Address Lookup Table

Address Lookup Tables (ALT) optimize Solana transactions by compressing addresses.

# Create ALT for your token configuration
yarn svm:admin:create-alt \
  --token-mint $SOL_TOKEN_MINT \
  --pool-program $CCIP_POOL_PROGRAM

Save the ALT address:

Replace with your ALT address from the output:

export SOL_ALT_ADDRESS="<INSERT_YOUR_ALT_ADDRESS>"

Verify the ALT address is set correctly:

echo "ALT Address: $SOL_ALT_ADDRESS"

Register Solana Pool

In this step, you will register the token pool with Solana's Router TokenAdminRegistry. This instruction sets the Address Lookup Table as the pool definition for the token, enabling it for CCIP cross-chain transfers. The writable_indices parameter specifies which accounts in the ALT need write access during transactions.

# Register pool with token admin registry
yarn svm:admin:set-pool \
  --token-mint $SOL_TOKEN_MINT \
  --lookup-table $SOL_ALT_ADDRESS \
  --writable-indices 3,4,7

Step 3: Save Complete Configuration

Save all variables for the testing phase:

# Save complete configuration for testing
cat > ~/.ccip_complete_vars << EOF
# Phase 1 - EVM
export ETH_TOKEN_ADDRESS="$ETH_TOKEN_ADDRESS"
export ETH_POOL_ADDRESS="$ETH_POOL_ADDRESS"

# Phase 2 - Solana
export SOL_TOKEN_MINT="$SOL_TOKEN_MINT"
export SOL_POOL_SIGNER_PDA="$SOL_POOL_SIGNER_PDA"
export SOL_POOL_CONFIG_PDA="$SOL_POOL_CONFIG_PDA"
export CCIP_POOL_PROGRAM="$CCIP_POOL_PROGRAM"

# Phase 5 - ALT
export SOL_ALT_ADDRESS="$SOL_ALT_ADDRESS"
EOF

echo "=== Complete Configuration Saved ==="
echo "โœ… All variables saved to ~/.ccip_complete_vars"
echo "โœ… Ready for cross-chain testing"

Phase 5: Pre-Transfer Setup

Before testing transfers, complete final setup steps.

Step 1: Get Pool Signer PDA

Extract the Pool Signer PDA for reference:

# Get the Pool Signer PDA
yarn svm:pool:get-pool-signer \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM

Confirm this matches your previously saved PDA:

echo "Saved Pool Signer PDA: $SOL_POOL_SIGNER_PDA"
echo "Current Pool Signer PDA: BwzTc3R77vf1dS4kj3JX8YGpCvjsg91vBDgyKJfeBkue"

Step 2: Delegate Token Authority

In this step, you will delegate token approval to the fee-billing signer PDA, which is what enables CCIP to transfer tokens on your behalf when sending cross-chain messages.

# Delegate burn authority to Pool Signer PDA
yarn svm:token:delegate \
  --token-mint $SOL_TOKEN_MINT

Step 3: Verify Delegate

Check the previous step to verify the token is delegated to the Pool Signer PDA:

# Verify token balance and authorities
yarn svm:token:check \
  --token-mint $SOL_TOKEN_MINT

Phase 6: Testing Cross-Chain Transfers

In this step, you will test bidirectional token transfers to verify your setup.

Confirm you are in the correct directory (Terminal 1):

pwd
# Should output: ../solana-starter-kit

Step 1: Load Complete Configuration

Before testing, ensure all variables are available in your current terminal:

# Load complete configuration
source ~/.ccip_complete_vars

# Verify all variables for testing
echo "=== Testing Environment Ready ==="
echo "โœ… ETH Token: $ETH_TOKEN_ADDRESS"
echo "โœ… SOL Token: $SOL_TOKEN_MINT"
echo "โœ… ALT Address: $SOL_ALT_ADDRESS"
echo "โœ… Ready for cross-chain transfers"

Step 2: Transfer Solana โ†’ Ethereum

In Terminal 1 (Solana Starter Kit)

# Transfer 1 token from Solana to Ethereum
yarn svm:token-transfer \
  --token-mint $SOL_TOKEN_MINT \
  --token-amount 1000000 \
  --receiver <YOUR_ETHEREUM_ADDRESS>

Replace <YOUR_ETHEREUM_ADDRESS> with your Ethereum wallet address.

Step 3: Transfer Ethereum โ†’ Solana

# Transfer 1 token from Ethereum to Solana
yarn evm:transfer \
  --token $ETH_TOKEN_ADDRESS \
  --amount 1000000000000000000 \
  --token-receiver <YOUR_SOLANA_ADDRESS>

Replace <YOUR_SOLANA_ADDRESS> with your Solana wallet address.

Reference: Verification Commands

Use these commands to verify your setup at any point during the tutorial. Each section focuses on a specific component of your cross-chain configuration.

Solana Pool Verification

Terminal 1 (Solana Starter Kit)

# Verify pool configuration and status
yarn svm:pool:get-info \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM

What this shows:

  • Pool configuration details
  • Pool signer PDA information
  • Token account balances
  • Pool operational status

Solana Chain Configuration

Terminal 1 (Solana Starter Kit)

# Verify cross-chain configuration with Ethereum
yarn svm:pool:get-chain-config \
  --token-mint $SOL_TOKEN_MINT \
  --burn-mint-pool-program $CCIP_POOL_PROGRAM \
  --remote-chain ethereum-sepolia

What this shows:

  • Remote chain configuration
  • Token address mappings
  • Pool address mappings
  • Cross-chain connectivity status

Solana Token Balance

Terminal 1 (Solana Starter Kit)

# Check your token balance
spl-token balance $SOL_TOKEN_MINT

What this shows:

  • Current token balance in your wallet
  • Token account details
  • Delegation status

Ethereum Pool Verification

Terminal 2 (Smart Contract Examples)

# Verify Ethereum pool configuration
npx hardhat getPoolConfig \
  --pooladdress $ETH_POOL_ADDRESS \
  --network sepolia

What this shows:

  • Pool contract configuration
  • Remote chain settings
  • Rate limiting parameters
  • Pool operational status

Cross-Chain Transfer Status

Both Terminals

# Monitor CCIP message status (replace with your message ID)
# From the transfer output, look for: "Message ID: 0x..."
# Then visit: https://ccip.chain.link/msg/0x...

What this shows:

  • Transfer execution status
  • Cross-chain message progress
  • Completion confirmation
  • Error details (if any)

What's next

Get the latest Chainlink content straight to your inbox.