API Version: v1.6.0

CCIP v1.6.0 TON Messages API Reference

Messages

This section details the data structures used for sending and receiving CCIP messages on TON. TON contracts communicate exclusively through internal messages — structured binary cells encoded using TL-B (Type Language — Binary) serialization. Each message type is identified by a 32-bit opcode.


Outbound Messages (TON → EVM)

Router_CCIPSend

Opcode: 0x31768d95

The primary message to send a cross-chain message from TON to a destination chain. Send this to the CCIP Router contract with sufficient TON attached to cover the CCIP fee plus a gas reserve.

struct (0x31768d95) Router_CCIPSend {
    queryID: uint64;
    destChainSelector: uint64;
    receiver: CrossChainAddress;
    data: cell;
    tokenAmounts: SnakedCell;
    feeToken: address?;
    extraArgs: cell;
}

Fields

FieldTypeDescription
queryIDuint64A unique identifier for this send request. Typically the wallet seqno. Returned in ACK/NACK responses.
destChainSelectoruint64The CCIP chain selector of the destination chain.
receiverCrossChainAddressThe 32-byte address of the receiver on the destination chain. For EVM destinations, left-pad the 20-byte address with 12 zero bytes.
datacellArbitrary payload to deliver to the receiver contract.
tokenAmountsSnakedCell<TokenAmount>Token transfers to include. Pass an empty cell — token transfers are not yet supported on TON.
feeTokenaddress?Fee token address. Currently only native TON is supported; pass the wrapped native address or null.
extraArgscellEncoded extra arguments. See GenericExtraArgsV2.

Value to attach

When sending Router_CCIPSend, you must attach enough TON to cover:

  1. The CCIP fee (query validatedFeeCell on the FeeQuoter beforehand)
  2. A gas reserve for execution on TON (~0.5 TON recommended, add a 10% buffer to the fee)

Responses

The Router sends one of two responses back to the queryID sender:

MessageOpcodeMeaning
Router_MessageSent0x6513f8e1Message accepted. Contains the messageId.
Router_MessageRejected0x8ae25114Message rejected. Contains the error exit code.

CrossChainAddress

A length-prefixed byte slice used to encode destination chain addresses. The first byte is the length (in bytes), followed by the address bytes.

// 1-byte length prefix + up to 64 address bytes
type CrossChainAddress = slice;

EVM encoding

For EVM destination addresses (20 bytes), encode as 32 bytes by left-padding with 12 zero bytes:

// TypeScript encoding from the TON Starter Kit
export function encodeEVMAddress(evmAddr: string): Buffer {
  const addrBytes = Buffer.from(evmAddr.slice(2), "hex")
  return Buffer.concat([Buffer.alloc(12, 0), addrBytes])
}

Inbound Messages (EVM → TON)

Any2TVMMessage

The message structure delivered to a TON receiver contract by the CCIP OffRamp (via the Router). Your receiver receives this wrapped inside a Receiver_CCIPReceive message.

struct Any2TVMMessage {
    messageId: uint256;
    sourceChainSelector: uint64;
    sender: CrossChainAddress;
    data: cell;
    tokenAmounts: cell?;
}

Fields

FieldTypeDescription
messageIduint256Unique identifier for the CCIP message.
sourceChainSelectoruint64CCIP chain selector of the source chain. Use this to verify the sender chain in your receiver.
senderCrossChainAddressAddress of the sender on the source chain.
datacellThe arbitrary payload sent from the source chain.
tokenAmountscell?Reserved for future token transfer support. Currently unused.

Extra Args

GenericExtraArgsV2

Tag: 0x181dcf10

Used when sending a CCIP message from TON to an EVM-based destination chain. Encodes the gas limit (in EVM gas units) to allocate for execution on the destination chain.

// nolint:opcode: hex encoded bytes4(keccak256("CCIP EVMExtraArgsV2"))
struct (0x181dcf10) GenericExtraArgsV2 {
    gasLimit: uint256?;
    allowOutOfOrderExecution: bool;
}

Fields

FieldTypeDescription
gasLimituint256?Gas limit for execution on the destination EVM chain, in EVM gas units (e.g., 100_000). Must not exceed the maximum configured on the destination chain. Pass null to use the default.
allowOutOfOrderExecutionboolIf true, this message may be executed out of order relative to other messages from the same sender. Set to true for most use cases.

TL-B encoding

// From the TON Starter Kit utils.ts
export function buildExtraArgsForEVM(gasLimitEVMUnits: number, allowOutOfOrderExecution: boolean): Cell {
  return beginCell()
    .storeUint(0x181dcf10, 32)          // GenericExtraArgsV2 tag
    .storeBit(true)                      // gasLimit IS present
    .storeUint(gasLimitEVMUnits, 256)   // gasLimit value
    .storeBit(allowOutOfOrderExecution) // allowOutOfOrderExecution
    .endCell()
}

EVM → TON: gasLimit in nanoTON

When sending from an EVM chain to TON, the gasLimit field in GenericExtraArgsV2 represents the TON execution budget in nanoTON (not EVM gas units). This value is forwarded by the OffRamp to your receiver contract as the attached value.

// EVM → TON: gasLimit is in nanoTON
// 100_000_000n = 0.1 TON
export function buildExtraArgsForTON(gasLimitNanoTON: bigint | number, allowOutOfOrderExecution: boolean): Uint8Array {
  const encoded = ethers.AbiCoder.defaultAbiCoder().encode(
    ["uint256", "bool"],
    [gasLimitNanoTON, allowOutOfOrderExecution]
  )
  return ethers.getBytes(ethers.concat(["0x181dcf10", encoded]))
}

RampMessageHeader

Metadata embedded in outbound ramp messages. Not directly constructed by users but visible in emitted events.

struct RampMessageHeader {
    messageId: uint256;
    sourceChainSelector: uint64;
    destChainSelector: uint64;
    sequenceNumber: uint64;
    nonce: uint64;
}

Get the latest Chainlink content straight to your inbox.