# Token Transfers: SVM to EVM
Source: https://docs.chain.link/ccip/tutorials/svm/source/token-transfers
Last Updated: 2025-05-19


This tutorial demonstrates how to transfer tokens from a Solana Virtual Machine (SVM) to an Ethereum Virtual Machine (EVM) chain using Chainlink CCIP. You will learn how to build a CCIP message on Solana, send it to the CCIP router, and verify the transfer on the destination chain.

> \*\*NOTE: Prerequisites\*\*
>
>
>
> Make sure you have completed all steps in the [SVM to EVM Prerequisites](/ccip/tutorials/svm/source/prerequisites)
> guide before beginning this tutorial.

## Introduction

This tutorial covers transferring tokens from Solana Devnet to Ethereum Sepolia without any additional data payload or program execution. When you transfer tokens using CCIP:

1. Tokens are burned or locked in pools on the source pool
2. Equivalent tokens are minted or released from the destination pool
3. The process is managed by CCIP

## What You Will Build

In this tutorial, you will:

- Configure a CCIP message for token-only transfers
- Send BnM test tokens from Solana Devnet to an Ethereum Sepolia address
- Pay for CCIP transaction fees using native SOL
- Monitor and verify your cross-chain transfer

> \*\*NOTE: Minimum Requirements\*\*
>
>
>
> To successfully complete this tutorial, ensure you have:
>
> - SOL for transaction fees
> - BnM tokens to transfer
> - Properly configured Solana wallet with keypair
> - All delegation approvals completed
>
> All these requirements are covered in the [prerequisites guide](/ccip/tutorials/svm/source/prerequisites).

## Understanding Token Transfers from SVM to EVM

This tutorial focuses on token-only transfers from your wallet on Solana Devnet to an address on Ethereum Sepolia. Key points specific to token-only transfers:

- **Burn and Mint**: In this tutorial, tokens are burned on Solana Devnet, and equivalent tokens are minted on Ethereum Sepolia
- **Fee Payment**: Transaction fees are paid in native SOL on Solana plus CCIP fees for cross-chain processing. Note that you can pay for CCIP fees using LINK or wrapped SOL
- **Token Delegation**: Requires pre-delegation of token authority to allow the CCIP Router to transfer your tokens

## CCIP Message Configuration

The most important part of implementing a token transfer is configuring the CCIP message correctly. Here's the key configuration from the script:

```typescript
const CCIP_MESSAGE_CONFIG: CCIPMessageConfig = {
  destinationChainSelector: CHAIN_SELECTORS[ChainId.ETHEREUM_SEPOLIA].toString(),
  evmReceiverAddress: "0x9d087fC03ae39b088326b67fA3C788236645b717", // Change this to your Ethereum address

  // Token transfers configuration - supports multiple tokens
  tokenAmounts: [
    {
      tokenMint: config.tokenMint, // BnM token on Solana Devnet
      amount: "10000000", // 0.01 tokens with 9 decimals
    },
  ],

  // Fee configuration
  feeToken: ConfigFeeTokenType.NATIVE, // Use SOL for fees

  // Message data (empty for token transfers)
  messageData: "", // Empty data for token transfer only

  // Extra arguments configuration
  extraArgs: {
    gasLimit: 0, // No execution on destination for token transfers
    allowOutOfOrderExecution: true, // Allow out-of-order execution
  },
}
```

### Customizing the Receiver Address

To send tokens to your own Ethereum wallet, you must update the destination address in the script:

1. Open the file `ccip-scripts/svm/router/1_token-transfer.ts` in the starter kit
2. Locate the `CCIP_MESSAGE_CONFIG` object
3. Edit the value of the `evmReceiverAddress` property to your Ethereum wallet address

### Critical Configuration Settings

When setting up your CCIP message for token transfers, these parameters are crucial:

- `gasLimit`: **MUST** be 0 for token-only transfers
- `evmReceiverAddress`: Must be a valid Ethereum address (starting with "0x")
- `messageData`: Empty string for token-only transfers

### Understanding the Configuration Fields

- **`destinationChainSelector`**: CCIP identifier for the destination chain (Ethereum Sepolia)
- **`evmReceiverAddress`**: Ethereum wallet address that will receive the tokens
- **`tokenAmounts`**: Array of tokens to transfer with their amounts
  - `tokenMint`: The Solana token mint address (BnM token: `7AC59PVvR64EoMnLX45FHnJAYzPsxdViyYBsaGEQPFvh`)
  - `amount`: Token amount in raw format (10000000 = 0.01 BnM with 9 decimals)
- **`feeToken`**: Token used to pay CCIP fees (NATIVE = SOL)
- **`messageData`**: Empty for token-only transfers
- **`extraArgs`**: Additional configuration for cross-chain execution
  - `gasLimit`: Set to 0 for token transfers (no execution needed)
  - `allowOutOfOrderExecution`: Set to true to allow out of order execution. **Note**: This is mandatory when sending CCIP messages from Solana as the source chain.

## Customizing Your Token Transfer

### Customize Token Amount

The token amount format needs to account for token decimals:

- Solana BnM has 9 decimals
- `10000000` represents 0.01 BnM (10,000,000 / 10^9)

## How the Script Works

The token transfer script handles the interaction with the CCIP Router program without requiring you to write any code. Here's what happens behind the scenes:

1. **Context Initialization**:
   - The script initializes the Solana connection
   - Loads your keypair
   - Sets up CCIP configuration

2. **Balance Validation**:
   - Checks SOL balance (minimum 0.005 SOL required)
   - Validates token balances for all tokens being transferred
   - Verifies token delegation approvals

3. **Fee Calculation**:
   - Queries the Router program to calculate cross-chain fees
   - Validates sufficient balance for fees

4. **Message Construction**:
   - Builds the `SVM2AnyMessage` structure with token amounts, receiver, etc.
   - Encodes the message according to CCIP standards
   - Sets extra arguments for Ethereum compatibility

5. **Transaction Building**:
   - Builds the CCIP send transaction with all necessary accounts
   - Includes all token accounts in the correct order

6. **Execution**:
   - Signs and sends the transaction to the Solana Devnet network
   - Parses the transaction result to extract the message ID
   - Provides links to track the cross-chain message

## Source Code Reference

For those interested in implementation details, the script is thoroughly documented with step-by-step comments. You can examine the complete source code at `ccip-scripts/svm/router/1_token-transfer.ts` in the starter kit repository to understand the precise mechanics of building and sending CCIP messages from Solana.

## Running the Token Transfer

### Prerequisites Check

Before running the script:

1. Ensure you've completed all steps in the [prerequisites guide](/ccip/tutorials/svm/source/prerequisites)
2. Verify your token delegations are set up correctly: `yarn svm:token:check`
3. Make sure you have sufficient SOL and BnM token balances

### Execute the Script

Run the script using one of the following options:

```bash
yarn svm:token-transfer
```

### Understanding the Output

When the script executes successfully, you'll see output similar to this:

```
==== Environment Information ====

[2025-05-01T20:46:55.790Z] Wallet public key: EPUjBP3Xf76K1VKsDSc6GupBWE8uykNksCLJgXZn87CB
[2025-05-01T20:46:55.791Z]
==== Wallet Balance Information ====
[2025-05-01T20:46:59.331Z] SOL Balance: 13.224536955 SOL
[2025-05-01T20:46:59.332Z] Lamports Balance: 13224536955 lamports
[2025-05-01T20:46:59.332Z]
==== CCIP Router Information ====
[2025-05-01T20:46:59.332Z] CCIP Router Program ID: Ccip842gzYHhvdDkSyi2YVCoAWPbYJoApMFzSxQroE9C
[2025-05-01T20:46:59.332Z] Fee Quoter Program ID: FeeQPGkKDeRV1MgoYfMH6L8o3KeuYjwUZrgn4LRKfjHi
[2025-05-01T20:46:59.332Z] RMN Remote Program ID: RmnXLft1mSEwDgMKu2okYuHkiazxntFFcZFrrcXxYg7
[2025-05-01T20:46:59.332Z]
==== CCIP Send Configuration ====
[2025-05-01T20:46:59.332Z] Destination Chain Selector: 16015286601757825753
[2025-05-01T20:46:59.332Z] Receiver Address: 0x9d087fC03ae39b088326b67fA3C788236645b717
[2025-05-01T20:46:59.332Z]
==== Token Transfer Details ====
[2025-05-01T20:46:59.333Z] Getting mint account info for 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6 to determine token program ID...
[2025-05-01T20:46:59.467Z] Detected Token-2022 Program: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
[2025-05-01T20:46:59.467Z] Fetching token decimals for 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6
[2025-05-01T20:46:59.607Z] Token 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6 has 9 decimals
[2025-05-01T20:46:59.639Z] Token 1: 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6
[2025-05-01T20:46:59.639Z] Amount 1: 10000000 raw units (0,01 tokens with 9 decimals)
[2025-05-01T20:46:59.639Z] Fee Token: native
[2025-05-01T20:46:59.639Z]
==== Fee Token Configuration ====
[2025-05-01T20:46:59.639Z] Using native SOL as fee token
[2025-05-01T20:46:59.639Z] No gasLimit provided in extraArgs, using default value: 0
[2025-05-01T20:46:59.641Z]
==== CCIP Message Request Created ====
[2025-05-01T20:46:59.641Z]
==== Compute Budget Configuration ====
[2025-05-01T20:46:59.642Z] Added compute budget instruction with limit: 1400000 units
[2025-05-01T20:46:59.642Z]
==== Fee Calculation ====
[2025-05-01T20:46:59.642Z] Calculating fee for this transaction...
[2025-05-01T20:46:59.642Z] Calculating fee for destination chain 16015286601757825753
[2025-05-01T20:46:59.950Z] Fee calculation complete: 9716055 tokens
[2025-05-01T20:46:59.950Z] Estimated fee: 0.009716055 SOL
[2025-05-01T20:46:59.951Z] Fee in Juels: 97863982000000000
[2025-05-01T20:46:59.951Z]
==== Balance Validation ====
[2025-05-01T20:47:00.085Z] SOL Balance: 13.224536955 SOL
[2025-05-01T20:47:00.085Z]
==== Token Balance Validation ====
[2025-05-01T20:47:00.085Z] Getting mint account info for 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6 to determine token program ID...
[2025-05-01T20:47:00.220Z] Detected Token-2022 Program: TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
[2025-05-01T20:47:00.220Z] Fetching token decimals for 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6
[2025-05-01T20:47:00.358Z] Token 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6 has 9 decimals
[2025-05-01T20:47:00.359Z] Validating token 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6: 0,01 tokens (10000000 raw units)
[2025-05-01T20:47:00.509Z] ✅ Balance validation passed for token: 3PjyGzj1jGVgHSKS4VR1Hr1memm63PmN8L9rtPDKwzZ6
[2025-05-01T20:47:00.510Z] ✅ All balance validations passed. Proceeding with transaction.
[2025-05-01T20:47:00.511Z]
==== Sending CCIP Message ====
[2025-05-01T20:47:00.511Z] ⏳ This may take a minute...
[2025-05-01T20:47:00.512Z] Sending CCIP message to destination chain 16015286601757825753
[2025-05-01T20:47:00.512Z] Building accounts for CCIP send to chain 16015286601757825753
[2025-05-01T20:47:02.693Z] CCIP message sent successfully: 51Tpaa5Hxu4dwRNeHr7wqPwkXmroq1bDKSUmVHHPtNbDEhJ6b7Sf9Wkzuau9qDDfh34MKDWPtuMRaq3WGdt9Qz3L
[2025-05-01T20:47:02.694Z] Parsing CCIP message sent event for transaction: 51Tpaa5Hxu4dwRNeHr7wqPwkXmroq1bDKSUmVHHPtNbDEhJ6b7Sf9Wkzuau9qDDfh34MKDWPtuMRaq3WGdt9Qz3L
[2025-05-01T20:47:02.863Z] Successfully extracted messageId: 0xf5a11db94f15b15b77d582e4a0ed3ff709b2fbf2464d1c7d1ed73620000260d9
[2025-05-01T20:47:02.863Z]
==== CCIP Message Sent Successfully ====
[2025-05-01T20:47:02.863Z] Transaction signature: 51Tpaa5Hxu4dwRNeHr7wqPwkXmroq1bDKSUmVHHPtNbDEhJ6b7Sf9Wkzuau9qDDfh34MKDWPtuMRaq3WGdt9Qz3L
[2025-05-01T20:47:02.863Z] Message ID: 0xf5a11db94f15b15b77d582e4a0ed3ff709b2fbf2464d1c7d1ed73620000260d9
[2025-05-01T20:47:02.863Z] Open the CCIP explorer: https://ccip.chain.link/msg/0xf5a11db94f15b15b77d582e4a0ed3ff709b2fbf2464d1c7d1ed73620000260d9
[2025-05-01T20:47:02.863Z]
View transaction on explorer:
[2025-05-01T20:47:02.863Z] https://explorer.solana.com/tx/51Tpaa5Hxu4dwRNeHr7wqPwkXmroq1bDKSUmVHHPtNbDEhJ6b7Sf9Wkzuau9qDDfh34MKDWPtuMRaq3WGdt9Qz3L?cluster=devnet
```

The output provides important information to track your transfer:

- **Environment Information**: Your Solana configuration and wallet details
- **Wallet Balance**: Confirms you have sufficient SOL
- **CCIP Router Information**: The program IDs used for the transaction
- **Token Transfer Details**: The tokens and amounts being transferred
- **Fee Calculation**: The estimated fees of the cross-chain transfer
- **Balance Validation**: Confirmation that all required balances are sufficient
- **Transaction Details**: The signature, message ID, and explorer links

## Verification and Monitoring

After sending your token transfer, you'll need to track it across chains:

1. **Track progress with Message ID**: Use the CCIP Explorer link provided in the output to track your message status:

   ```
   https://ccip.chain.link/msg/YOUR_MESSAGE_ID
   ```

2. **Solana Explorer**: Verify the transaction on Solana:

   ```
   https://explorer.solana.com/tx/YOUR_TRANSACTION_SIGNATURE?cluster=devnet
   ```

3. **Ethereum Explorer**: Once the transfer is successful, verify token receipt on Ethereum:
   ```
   https://sepolia.etherscan.io/address/YOUR_ETHEREUM_ADDRESS
   ```
   Look for the transferred token in the "Token Transfers" section.

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