# Cross-Chain Token Setup: BurnMint with Direct Mint Authority Transfer
Source: https://docs.chain.link/ccip/tutorials/svm/cross-chain-tokens/direct-mint-authority
Last Updated: 2026-06-15

> For the complete documentation index, see [llms.txt](/llms.txt).

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](/ccip/concepts/cross-chain-token/svm/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](/ccip/concepts/cross-chain-token/svm/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.

### Cross-Chain Token Architecture

This tutorial implements the **[Burn and Mint](/ccip/concepts/cross-chain-token/overview#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

### 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   | Single mint authority: Pool Signer PDA |

### 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](/ccip/concepts/cross-chain-token/overview#token-handling-mechanisms).

> **CAUTION: Development Environment Approach**
>
> **Important**: This tutorial transfers mint authority directly to the Pool Signer PDA for simplicity. This approach is
> designed for **development and testing environments only**.

**Key Authority Model Differences:**

- **Ethereum**: Your EOA retains mint privileges while the pool gets additional mint/burn roles

- **Solana**: Complete mint authority
  transfer to Pool Signer PDA (SPL tokens allow only one mint authority) **For production deployments**:
  - Learn more about [Production Multisig Tutorial](/ccip/tutorials/svm/cross-chain-tokens/production-multisig-tutorial) - Enterprise-grade dual-layer governance
  - Learn more about [Mint Authority Management](/ccip/concepts/cross-chain-token/svm/token-pools#mint-authority-management) for detailed security considerations.

## 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](https://www.npmjs.com/package/nvm) recommended)
- **pnpm**: Required for the BS58 generator (`npm install -g pnpm`)
- **Solana CLI**: [Installation guide](https://docs.solana.com/cli/install-solana-cli-tools) (includes `spl-token`)
- **Git**: For cloning repositories
- **CCIP CLI**: For cross-chain transfer testing in the final phase

Install the [CCIP CLI](https://github.com/smartcontractkit/ccip-tools-ts) globally:

```bash
npm install -g @chainlink/ccip-cli
ccip-cli --help
```

See the [CCIP CLI documentation](https://docs.chain.link/ccip/tools/cli/) for RPC and wallet configuration.

### Tutorial Workflow

| Terminal       | Repository                                                                                                                  | Purpose                              | Commands        |
| -------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------- |
| **Terminal 1** | [CCIP Solana BS58 Generator](https://github.com/smartcontractkit/ccip-solana-bs58-generator)                                | Solana setup and configuration       | `pnpm bs58`     |
| **Terminal 2** | [Smart Contract Examples (Hardhat)](https://github.com/smartcontractkit/smart-contract-examples/tree/main/ccip/cct/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):

```bash
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:

```bash
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](#terminal-2-smart-contract-examples-hardhat) below.

Otherwise, run only the steps you need:

```bash
# 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
```

> **NOTE: Direct Execution**
>
> Append `--execute` to **mutating** `pnpm bs58` commands in Terminal 1 so your local wallet signs and sends
> transactions. **Read-only** commands (`get-state`, `get-chain-config`, `derive-accounts`) omit `--execute`. See the
> [CCIP Solana BS58 Generator
> README](https://github.com/smartcontractkit/ccip-solana-bs58-generator/blob/main/README.md) for command syntax.

### Terminal 2: Smart Contract Examples (Hardhat)

**Clone, install, and compile** (skip `git clone` if you already have the repo):

```bash
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:**

```bash
# 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](https://www.alchemy.com/) or [Infura](https://www.infura.io/)
- `PRIVATE_KEY`: Your testnet wallet private key ([MetaMask export guide](https://support.metamask.io/managing-my-wallet/secret-recovery-phrase-and-private-keys/how-to-export-an-accounts-private-key/))
- `ETHERSCAN_API_KEY`: API key from [Etherscan](https://docs.etherscan.io/getting-started/viewing-api-usage-statistics)

**Fund your EVM wallet:**

- Acquire **ETH** on Ethereum Sepolia for transaction gas and CCIP fees ([Chainlink faucet](https://faucets.chain.link/) or [Google Cloud Faucet](https://cloud.google.com/application/web3/faucet/ethereum/sepolia))
- **LINK** is optional — use `--fee-token LINK` on 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](https://hardhat.org/docs/plugins/hardhat-keystore)) so the signing key stays encrypted. Hardhat tasks load env-enc automatically; `ccip-cli` does not. As an alternative, view the same key with `npx env-enc view` and export `PRIVATE_KEY` manually for the send command.

**RPC endpoints** (required for source and destination chains). You can provide them any of these ways — see [CCIP CLI configuration](https://docs.chain.link/ccip/tools/cli/configuration):

- **Command line:** pass `--rpc` on each command (repeat for multiple networks), or `--rpcs` with comma-separated URLs
- **Environment variables:** export `RPC_*` variables (e.g., `RPC_SEPOLIA`, `RPC_SOLANA_DEVNET`) or the tutorial's `SOLANA_DEVNET_RPC` and `ETHEREUM_SEPOLIA_RPC_URL` exports
- **File:** create a `.env` file in the directory where you run `ccip-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` |

> **NOTE: Two-Terminal Workflow**
>
> Keep both terminal windows open throughout the tutorial. Switch between the CCIP Solana BS58 Generator (Terminal 1)
> and the Hardhat project (Terminal 2) as each phase indicates. Cross-chain transfer commands use `ccip-cli` from the
> terminal that matches the source chain.

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

- **[CCIP Solana BS58 Generator README](https://github.com/smartcontractkit/ccip-solana-bs58-generator/blob/main/README.md)**: Solana CLI command details, `--execute` EOA workflow, and options
- **[Smart Contract Examples README](https://github.com/smartcontractkit/smart-contract-examples/blob/main/ccip/cct/hardhat/README.md)**: 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_WALLET_ADDRESS`). Read-only commands (`get-state`, `get-chain-config`, `derive-accounts`) do not use `--execute`.

## Phase 1: Ethereum Sepolia Token Setup

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

> **NOTE: Terminal Context**
>
> **Current Terminal: Terminal 2** (Smart Contract Examples - Hardhat) Verify your location:

```bash
pwd
# Should show: .../smart-contract-examples/ccip/cct/hardhat
```

### Step 1: Deploy ERC20 Token

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

Set the token address variable:

### Step 2: Deploy BurnMint Token Pool

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

Set the pool address variable:

### Step 3: Mint Initial Token Supply

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

### 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

#### Accept Admin Role

### Step 5: Save Phase 1 Variables

Save your EVM configuration for use in later phases:

## Phase 2: Solana Devnet Token Setup

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

> **NOTE: Terminal Context**
>
> **Switch to Terminal 1** (CCIP Solana BS58 Generator) Verify your location:

```bash
pwd
# Should show: .../ccip-solana-bs58-generator
```

### Step 1: Prepare Environment

Load EVM variables from Phase 1 and set Solana CCIP constants:

### Step 2: Create SPL Token

Create an SPL token with metadata and initial supply using direct EOA execution:

Set the token mint variable:

### Step 3: Initialize CCIP Token Pool

Initialize the token pool configuration on Solana:

Save the Pool Signer PDA and Pool Config PDA. Derive them from the onchain pool configuration:

Copy the **Pool Signer PDA** and **Pool State PDA** addresses from the output, then export them:

### Step 4: 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.

### Step 5: Register as CCIP Administrator

#### Propose Admin

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

#### 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.

### Step 6: Transfer Mint Authority to Pool Signer PDA

> **CAUTION: Critical Step: Mint Authority Transfer**
>
> **This is the defining step** of the direct mint authority approach. You're transferring complete mint authority to the Pool Signer PDA, which:

- **Enables**: Autonomous cross-chain minting for incoming transfers
- **Removes**: Your ability to mint additional tokens directly
- **Is Irreversible**: Cannot be undone in this tutorial setup

**Important**: Ensure you have sufficient tokens for testing before proceeding. The SPL token creation in Step 1 already minted tokens to your wallet, so you're ready to continue.

Verify the authority transfer:

### Step 7: Save Phase 2 Variables

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

## Phase 3: Cross-Chain Configuration

Configure bidirectional connectivity between your token pools on both chains.

### Step 1: Configure Solana Pool

**Stay in Terminal 1** (CCIP Solana BS58 Generator)

Load the Ethereum addresses from Phase 1:

#### 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).

#### 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.

### Step 2: Configure Ethereum Pool

**Switch to Terminal 2 (Smart Contract Examples)**

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

#### Load Variables from Previous Phases

Load all variables needed for EVM cross-chain configuration:

#### 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.

## 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)**

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

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

### Step 2: Register Solana Pool

**Switch to Terminal 1** (CCIP Solana BS58 Generator)

```bash
pwd
# Should show: .../ccip-solana-bs58-generator
```

Load variables from previous phases:

```bash
source ~/.phase1_vars
source ~/.phase2_vars
```

#### Create Address Lookup Table

Address Lookup Tables (ALT) optimize Solana transactions by compressing addresses. With EOA execution, create and populate the ALT in one step:

Save the 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.

### Step 3: Save Complete Configuration

Save all variables for the testing phase:

## Phase 5: Pre-Transfer Setup

Before validating your configuration, complete final setup steps.

### Step 1: Verify Pool Signer PDA

Confirm the Pool Signer PDA matches your saved configuration:

Compare the onchain **Pool Signer** with your saved variable:

### Step 2: Delegate Token Authority

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

Approve the fee-billing signer to transfer tokens from your ATA:

### Step 3: Verify Delegation

Check that your token account is delegated to the fee-billing signer:

Display token account and delegation status:

## Phase 6: Test Cross-Chain Transfers

Validate your configuration, then execute bidirectional token transfers using the CCIP CLI.

> **NOTE: Cross-Chain Transfers with CCIP CLI**
>
> Use [`@chainlink/ccip-cli`](https://github.com/smartcontractkit/ccip-tools-ts) for bidirectional token transfers. Run Solana → EVM sends from Terminal 1 and EVM → Solana sends from Terminal 2. See the [CCIP CLI documentation](https://docs.chain.link/ccip/tools/cli/) for full options.

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

```bash
pwd
# Should show: .../ccip-solana-bs58-generator
```

### Step 1: Load Complete Configuration

### Step 2: Verify Solana Pool and Chain Config

### Step 3: Verify Ethereum Pool (Terminal 2)

**Switch to Terminal 2** (Smart Contract Examples - Hardhat):

```bash
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:

```bash
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`.

> **NOTE: RPC and wallet configuration**
>
> Repeat `--rpc` for multiple networks, or use `--rpcs` with comma-separated URLs. Alternatively, set `RPC_*` environment variables or a `.env` file — see [CCIP CLI configuration](https://docs.chain.link/ccip/tools/cli/configuration). Solana sends use `--wallet ~/.config/solana/id.json`. EVM sends: prefer `--wallet hardhat:<name>` from the Hardhat project directory ([Hardhat keystore](https://hardhat.org/docs/plugins/hardhat-keystore)); alternatively export `PRIVATE_KEY` manually after `npx env-enc view` (Hardhat tasks load env-enc automatically, but `ccip-cli` does not). See [CCIP CLI wallet configuration](https://docs.chain.link/ccip/tools/cli/configuration#wallet-configuration).

### Transfer Solana → Ethereum

**Terminal 1** (CCIP Solana BS58 Generator):

The `-t` flag uses human-readable amounts (0.001 tokens with 9 decimals = 1,000,000 smallest units).

### 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](https://hardhat.org/docs/plugins/hardhat-keystore) over exporting a private key in plain text.

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.

> **NOTE: Pay fees in LINK (optional)**
>
> Add `--fee-token LINK` to pay CCIP fees in LINK instead of ETH (Sepolia LINK:
> `0x779877A7B0D9E8603169DdbD7836e478b4624789`).

**Congratulations!** Your cross-chain token infrastructure is fully configured on both chains.

## 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** (CCIP Solana BS58 Generator)

```bash
# Verify pool configuration and status
pnpm bs58 --env devnet burnmint-token-pool \
  --instruction get-state \
  --program-id $SOL_CCIP_POOL_PROGRAM \
  --mint $SOL_TOKEN_MINT
```

**What this shows:**

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

### Solana Chain Configuration

**Terminal 1** (CCIP Solana BS58 Generator)

```bash
# Verify cross-chain configuration with Ethereum Sepolia
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
```

**What this shows:**

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

### Solana Token Balance

**Terminal 1** (CCIP Solana BS58 Generator)

```bash
# 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)**

```bash
# Verify Ethereum pool configuration
npx hardhat getPoolConfig \
  --pooladdress $ETH_POOL_ADDRESS \
  --network ethereumSepolia
```

**What this shows:**

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

### Cross-Chain Transfer Status

**Both Terminals**

```bash
# 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)

> **CAUTION: Educational Example Disclaimer**
>
> This page includes an educational example to use a Chainlink system, product, or service and is provided to
> demonstrate how to interact with Chainlink's systems, products, and services to integrate them into your own. This
> template is provided "AS IS" and "AS AVAILABLE" without warranties of any kind, it has not been audited, and it may be
> missing key checks or error handling to make the usage of the system, product or service more clear. Do not use the
> code in this example in a production environment without completing your own audits and application of best practices.
> Neither Chainlink Labs, the Chainlink Foundation, nor Chainlink node operators are responsible for unintended outputs
> that are generated due to errors in code.