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
| Field | Type | Description |
|---|---|---|
queryID | uint64 | A unique identifier for this send request. Typically the wallet seqno. Returned in ACK/NACK responses. |
destChainSelector | uint64 | The CCIP chain selector of the destination chain. |
receiver | CrossChainAddress | The 32-byte address of the receiver on the destination chain. For EVM destinations, left-pad the 20-byte address with 12 zero bytes. |
data | cell | Arbitrary payload to deliver to the receiver contract. |
tokenAmounts | SnakedCell<TokenAmount> | Token transfers to include. Pass an empty cell — token transfers are not yet supported on TON. |
feeToken | address? | Fee token address. Currently only native TON is supported; pass the wrapped native address or null. |
extraArgs | cell | Encoded extra arguments. See GenericExtraArgsV2. |
Value to attach
When sending Router_CCIPSend, you must attach enough TON to cover:
- The CCIP fee (query
validatedFeeCellon the FeeQuoter beforehand) - 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:
| Message | Opcode | Meaning |
|---|---|---|
Router_MessageSent | 0x6513f8e1 | Message accepted. Contains the messageId. |
Router_MessageRejected | 0x8ae25114 | Message 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
| Field | Type | Description |
|---|---|---|
messageId | uint256 | Unique identifier for the CCIP message. |
sourceChainSelector | uint64 | CCIP chain selector of the source chain. Use this to verify the sender chain in your receiver. |
sender | CrossChainAddress | Address of the sender on the source chain. |
data | cell | The arbitrary payload sent from the source chain. |
tokenAmounts | cell? | 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
| Field | Type | Description |
|---|---|---|
gasLimit | uint256? | 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. |
allowOutOfOrderExecution | bool | If 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;
}