Building CCIP Messages from EVM to SVM

Introduction

This guide explains how to construct CCIP Messages from Ethereum Virtual Machine (EVM) chains (e.g. Ethereum) to SVM chains (e.g. Solana). We'll cover the message structure, required parameters, and implementation details for different message types including token transfers, arbitrary data messaging, and programmatic token transfers (data and tokens).

CCIP Message Structure

CCIP messages are built using the EVM2AnyMessage struct from the Client.sol library. The EVM2AnyMessage struct is defined as follows:

struct EVM2AnyMessage {
    bytes receiver;
    bytes data;
    EVMTokenAmount[] tokenAmounts;
    address feeToken;
    bytes extraArgs;
}

receiver

  • Definition:This is the receiver program ID that will execute the CCIP message
  • For token-only transfers: Should be set to the default value for the Pubkey type in Solana (11111111111111111111111111111111)
  • For arbitrary messaging or programmatic token transfers: Must be the exact program ID of the SVM program that implements the ccip_receive instruction

data

  • Definition: Contains the payload that will be passed to the receiving program
  • For token-only transfers: Empty (0x)
  • For arbitrary messaging or programmatic token transfers: Contains the data the receiver program will process
  • Encoding requirement: Must be encoded as a hex string with 0xĀ· prefix

tokenAmounts

  • Definition: An array of token addresses and amounts to transfer
  • For data-only messages: Must be an empty array
  • For token transfers or programmatic token transfers: Each entry specifies a token address and amount. Note: Check the CCIP Directory for the list of supported tokens on each lane

feeToken

  • Definition: Specifies which token to use for paying CCIP fees
  • For native gas token: Use address(0) to specify the source chain's native gas token (e.g. ETH on Ethereum)
  • For ERC-20 tokens: Can specify an ERC-20 token address for fee payment. Note: Check the CCIP Directory for the list of supported fee tokens on your source chain

extraArgs

The most critical component for SVM-bound messages is the SVMExtraArgsV1 structure:

struct SVMExtraArgsV1 {
    uint32 computeUnits;
    uint64 accountIsWritableBitmap;
    bool allowOutOfOrderExecution;
    bytes32 tokenReceiver;
    bytes32[] accounts;
}

bytes4 public constant SVM_EXTRA_ARGS_V1_TAG = 0x1f3b3aba;

Let's examine each field in detail:

computeUnits

Specifies the amount of compute units allowed for calling the ccip_receive instruction of the receiver program on SVM (similar to gas limit on EVM chains).

Understanding SVM Account Model

Unlike EVM chains where smart contracts manage their own storage, SVM blockchains (e.g. Solana) use an account-based architecture where:

  • All data is stored in accounts: There's no dedicated storage for programs
  • Programs are stateless: They can only read from and write to accounts passed to them
  • Explicit account access: Every account a program needs to access must be explicitly provided
  • Access permissions: Each account must be marked as either readable or writable

accounts

An array of 32-byte Solana public keys representing additional accounts required for execution.

accountIsWritableBitmap

A 64-bit bitmap indicating which accounts in the accounts array should be marked as writable.

Suppose your accounts array has 7 accounts and accounts at positions 1 and 2 need to be writable:

accounts[0]: Not writable (bit 0 = 0)
accounts[1]: Writable (bit 1 = 1)
accounts[2]: Writable (bit 2 = 1)
accounts[3]: Not writable (bit 3 = 0)
accounts[4]: Not writable (bit 4 = 0)
accounts[5]: Not writable (bit 5 = 0)
accounts[6]: Not writable (bit 6 = 0)

Binary: 0000110 = Decimal 6

const accountIsWritableBitmap = 6n; // or BigInt(6) in JavaScript/TypeScript

allowOutOfOrderExecution

MUST be set to true for SVM as a destination chain.

tokenReceiver

The Solana account that will initially receive tokens, represented as a 32-byte Solana public key.

For transfers to wallets or multi-sig wallets:

  • Set to the user's wallet address
  • Note: Do not use an Associated Token Account (ATA) as the tokenReceiver. Instead, use the user's wallet address directly. The ATA will be automatically derived by the CCIP nodes.

Message Encoding Requirements

When implementing CCIP from EVM to SVM, proper encoding of various elements is crucial for successful message delivery and processing.

Implementation by Message Type

Token Transfer

Use this configuration when sending only tokens from EVM to Solana:

{
  destinationChainSelector: SVM_CHAIN_SELECTOR,
  receiver: DEFAULT_PUBKEY,
  tokenAmounts: [{ token: tokenAddress, amount: tokenAmount }],
  feeToken: feeTokenAddress,
  data: "0x",
  extraArgs: {
    computeUnits: 0,
    allowOutOfOrderExecution: true,
    tokenReceiver: recipientAddress,
    accountIsWritableBitmap: 0,
    accounts: []
  }
}

Arbitrary Messaging

Use this configuration when sending only data messages to SVM:

{
  destinationChainSelector: SVM_CHAIN_SELECTOR,
  receiver: receiverProgramId,
  tokenAmounts: [],
  feeToken: feeTokenAddress,
  data: messageData,
  extraArgs: {
    computeUnits: determinedComputeUnits,
    allowOutOfOrderExecution: true,
    tokenReceiver: DEFAULT_PUBKEY,
    accountIsWritableBitmap: calculatedBitmap,
    accounts: [PDA, account, another program ID...]
  }
}

Programmatic Token Transfer (Data and Tokens)

Use this configuration when sending both tokens and data in a single message:

{
  destinationChainSelector: SVM_CHAIN_SELECTOR,
  receiver: receiverProgramId,
  tokenAmounts: [{ token: tokenAddress, amount: tokenAmount }],
  feeToken: feeTokenAddress,
  data: messageData,
  extraArgs: {
    computeUnits: determinedComputeUnits,
    allowOutOfOrderExecution: true,
    tokenReceiver: PDA,
    accountIsWritableBitmap: calculatedBitmap,
    accounts: [PDA, account, another program ID...]
  }
}

To see these concepts in action with step-by-step implementation guides, check out the following tutorials:

These tutorials provide complete, working examples using the concepts covered in this guide.

Get the latest Chainlink content straight to your inbox.