Building CCIP Messages from EVM to TON

Introduction

This guide explains how to construct CCIP messages from Ethereum Virtual Machine (EVM) chains (e.g., Ethereum Sepolia, Arbitrum Sepolia) to the TON blockchain. It covers the message structure, required parameters, and implementation details for sending arbitrary data payloads to a Tolk smart contract on TON.

CCIP Message Structure

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

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

receiver

  • Definition: The encoded TON address of the smart contract on TON that will receive and process the CCIP message.
  • Encoding: TON addresses must be encoded into a 36-byte format: 4 bytes for the workchain identifier (big-endian signed int32) followed by 32 bytes for the account hash. Use the encodeTONAddress helper shown below.

data

  • Definition: The raw bytes payload delivered to the ccipReceive entry point on the TON destination contract.
  • For arbitrary messaging: Contains the custom data payload your receiver will process.
  • Encoding: Pass raw bytes directly — do not use hexlify. Use ethers.toUtf8Bytes() for string payloads.

tokenAmounts

  • Definition: An array of token addresses and amounts to transfer.
  • Current support: EVM-to-TON currently supports arbitrary messaging only. Set tokenAmounts to an empty array ([]).

feeToken

  • Definition: Specifies which token to use for paying CCIP fees.
  • Native gas token: Use ethers.ZeroAddress (address(0)) to pay with the source chain's native token (e.g., ETH on Ethereum Sepolia).
  • LINK: Specify the LINK token address on your source chain. See the CCIP Directory for token addresses.

extraArgs

For TON-bound messages, the extraArgs parameter is a byte string composed of the 4-byte GenericExtraArgsV2 tag (0x181dcf10) prepended to the ABI-encoded values (uint256 gasLimit, bool allowOutOfOrderExecution). This format matches the GenericExtraArgsV2 specification.

gasLimit

  • Definition: The amount of nanoTON reserved for execution on the TON destination chain.
  • Units: This value is denominated in nanoTON, not EVM gas units. 1 TON = 1,000,000,000 nanoTON. A starting value of 100_000_000n (0.1 TON) covers most receive operations. Any unused nanoTON is returned to the contract.
  • Usage: Increase this value if your receiver performs heavy computation. Determine the right amount through testing.

allowOutOfOrderExecution

  • Definition: A boolean required by the TON lane.
  • Usage: Must be set to true when TON is the destination chain.

Implementation by Message Type

Arbitrary Messaging

Use this configuration when sending a data payload to a custom smart contract on TON.

{
  destinationChainSelector: TON_TESTNET_CHAIN_SELECTOR,
  receiver: encodedTONAddress,    // 36-byte encoded TON contract address
  tokenAmounts: [],               // Empty — token transfers not yet supported
  feeToken: feeTokenAddress,      // address(0) for native, LINK address for LINK
  data: rawBytesPayload,          // ethers.toUtf8Bytes(...) — do NOT hexlify
  extraArgs: {
    gasLimit: 100_000_000n,       // 0.1 TON in nanoTON
    allowOutOfOrderExecution: true
  }
}

To see these concepts in action with a step-by-step implementation guide, check out the following tutorial:

Get the latest Chainlink content straight to your inbox.