Onchain Architecture - Overview (TON)
TON as Source Chain
On the TON source blockchain, a user or another contract initiates a cross-chain message by sending a CCIPSend internal message to the CCIP Router contract. The Router validates that sufficient TON is attached for gas and forwards the message to the appropriate OnRamp contract. The OnRamp assigns a unique message ID, deploys an ephemeral SendExecutor{id} contract to isolate fee validation, and instructs it to call the FeeQuoter for a price check. Once the FeeQuoter confirms the fee, the SendExecutor reports back to the OnRamp, which then assigns a sequence number and emits a chain log (ExtOutLogMessage) containing the full CCIPSend payload. This external log is observed offchain by the Committing DON, which relays the message to the destination blockchain.
TON as Destination Chain
On the TON destination blockchain, the OffRamp contract receives two types of OCR3 reports from the offchain DONs. The Committing DON submits a Commit report containing a Merkle root of batched messages. The OffRamp verifies the OCR3 signatures, deploys an ephemeral MerkleRoot{id} contract to track per-message execution state for that root, and emits a CommitReportAccepted log. The Executing DON observes this log along with the original source chain messages, and for each message submits an Execute report. The OffRamp sends a Validate message to the relevant MerkleRoot{id} contract to verify the Merkle proof and mark the message as in-progress. The MerkleRoot{id} replies with ExecuteValidated, after which the OffRamp deploys (or reuses) an ephemeral ReceiveExecutor{id} to track the delivery state. The ReceiveExecutor{id} dispatches the message back to the OffRamp, which routes it via the Router to the Receiver contract. The Receiver processes the data and sends a CCIPReceiveConfirm back through the Router and OffRamp, which forwards a Confirm to the ReceiveExecutor{id}. On success, the ReceiveExecutor{id} reports NotifySuccess to the OffRamp, which emits an ExecutionStateChanged log marking the message as Success.
Key Components
Source Chain:
Destination Chain:
| Component | Ownership | Role |
|---|---|---|
| Sender | External (User/Contract) | A user wallet or a custom contract that initiates a cross-chain message on the source chain by sending CCIPSend to the Router. |
| Receiver | External (User/Contract) | A custom contract on the destination chain that receives CCIPReceive from the Router, sends back a CCIPReceiveConfirm, and processes the message data. |
| Router | CCIP | The primary entry point for both sending and receiving. On the source chain it validates the attached TON, checks for sufficient gas, and forwards to the OnRamp. On the destination chain it routes executed messages from the OffRamp to the Receiver and relays the confirmation back. The Router also acts as the RMN Remote: it stores the set of cursed subjects, accepts Router_RMNRemoteCurse and Router_RMNRemoteUncurse messages from the authorized RMN admin, and propagates the updated curse state to all registered OffRamp contracts via OffRamp_UpdateCursedSubjects. |
| OnRamp | CCIP | Processes outbound messages. Assigns a message ID, deploys a SendExecutor{id} for fee validation, assigns a sequence number on success, and emits a chain log (CCIPSend) observed by the offchain DONs. |
SendExecutor{id} | CCIP | An ephemeral contract deployed by the OnRamp per outgoing message. It calls FeeQuoter for fee validation, verifies the sender attached enough TON to cover the CCIP fee, and reports the result back to the OnRamp. It is destroyed after reporting. |
| FeeQuoter | CCIP | Stores destination-chain fee configuration, fee token prices, and premium multipliers. Validates the CCIPSend request and returns the computed fee or a validation error to the SendExecutor{id}. |
| OffRamp | CCIP | Receives OCR3 Commit and Execute reports from the DONs. On commit, deploys a MerkleRoot{id} and emits CommitReportAccepted. On execute, validates each message via the MerkleRoot{id}, orchestrates delivery through a ReceiveExecutor{id} and the Router, and emits ExecutionStateChanged. Maintains a local cache of cursed subjects, updated by the Router whenever the RMN admin curses or un-curses a subject. This cache is checked synchronously during every Commit and Execute call. |
MerkleRoot{id} | CCIP | An ephemeral contract deployed once per committed Merkle root. Stores the two-bit execution state for every message in the root, verifies Merkle proofs, and gates retries. Destroyed when all messages in the root reach Success. |
ReceiveExecutor{id} | CCIP | An ephemeral contract deployed (or reused on retry) per incoming message. Holds the message content and its delivery state (Untouched, Execute, ExecuteFailed, Success). Dispatches delivery back to the OffRamp and tracks the confirmation or bounce result. |
Typical Lifecycle of a Message
Source Blockchain (TON)
This outlines the process when initiating a CCIP transaction from the TON blockchain.
-
Preparation
- The Sender prepares the CCIP message, including:
- Receiver: An encoded destination address (e.g., a 20-byte EVM address).
- Data payload: Arbitrary bytes to be delivered to the receiver contract.
- Destination chain selector: Identifies the target blockchain.
- Extra arguments: Destination-specific parameters such as a gas limit for EVM chains.
- The fee can be queried in two ways:
- Onchain: Send a
Router_GetValidatedFeemessage to theRouter, which relays to theFeeQuotervia theOnRamp. TheRouterresponds withRouter_MessageValidated(orRouter_MessageValidationFailed) containing the computed fee. - Offchain: Call the
validatedFeegetter directly on theFeeQuotercontract.
- Onchain: Send a
- The fee is paid in native TON. The Sender must attach the CCIP fee plus additional TON to cover internal message forwarding gas costs.
- The Sender prepares the CCIP message, including:
-
Sending
- The Sender sends a
CCIPSendinternal message to theRouter, attaching the required TON. - The
Routervalidates that sufficient TON is attached and forwards the message to theOnRamp. - The
OnRampassigns a message ID, then deploys aSendExecutor{id}contract with a deterministic address derived from theOnRampaddress and a randomizedid. It sends anExecutemessage to theSendExecutor{id}containing the fullCCIPSendpayload. - The
SendExecutor{id}sendsGetValidatedFeeto theFeeQuoter. If the fee is valid and the sender attached sufficient TON, theFeeQuoterreplies withMessageValidated. TheSendExecutor{id}then destroys itself and reportsExecutorFinishedSuccessfullyto theOnRamp, returning any remaining balance. - If the fee is insufficient or validation fails, the
FeeQuoterreplies withMessageValidationFailedand theSendExecutor{id}reportsExecutorFinishedWithError, triggering a rejection path back through theOnRampandRouterto the Sender (CCIPSendNACK). - On success, the
OnRampassigns a sequence number and emits a chain log (ExtOutLogMessage) containing the sequencedCCIPSendmessage. The Sender receives aCCIPSendACKwith the unused TON.
- The Sender sends a
-
Initial Offchain Processing
- The Committing DON observes the
CCIPSendchain log emitted by theOnRampand begins batching messages offchain to prepare a Merkle root for commitment on the destination chain.
- The Committing DON observes the
Destination Blockchain (TON)
This outlines the process when TON is the receiving chain for a CCIP message.
-
Commit Phase
- The Committing DON submits a
CommitOCR3 report to theOffRamp, containing a Merkle root covering a batch of sequenced messages and any price updates. - The
OffRampverifies the source chain is enabled and checks its locally cached cursed subjects. If the source chain is cursed, the report is rejected. - The
OffRampdeploys aMerkleRoot{id}contract initialized with the Merkle root and the expected message sequence range, and advances the next expected sequence number. - If the report includes price updates that are newer than the latest recorded OCR sequence number, the
OffRampforwards them to theFeeQuoter. - The
OffRampverifies the Committing DON's OCR3 signatures and emits anOCR3Base_Transmittedlog. Signature verification is enabled for the Commit plugin and required. RMN BLS signature verification over blessed Merkle roots is not performed on TON; curse protection is provided exclusively through theRouter's curse mechanism. - The
OffRampemits aCommitReportAcceptedlog, signaling that the root is stored and messages are ready for execution.
- The Committing DON submits a
-
Secondary Offchain Processing
- The Executing DON observes the
CommitReportAcceptedlog on the destination chain and the original source chain logs. For each message in the committed batch, it computes the Merkle proof and submits a separateExecuteOCR3 report.
- The Executing DON observes the
-
Execution Phase
- The
OffRampreceives theExecutereport and immediately checks its locally cached cursed subjects. If the source chain is cursed, execution is rejected before any further processing. - The
OffRampverifies the source chain is enabled and computes a metadata hash from the source chain selector, destination chain selector, and the known OnRamp address. This hash is used together with the Merkle proof to reconstruct and verify the committed root, ensuring the message has not been tampered with. The Execute plugin does not perform OCR3 signature verification; signature verification is disabled for the Execute plugin by configuration. - The
OffRampsends aValidatemessage to theMerkleRoot{id}contract corresponding to this root. - The
MerkleRoot{id}verifies the Merkle proof, checks that the message has not already been executed (state must beUntouched), marks it asInProgress, and replies withExecuteValidated. If this is the last message in the root, theMerkleRoot{id}destroys itself. - The
OffRampemitsExecutionStateChangedwith stateInProgress, then deploys (or reuses on retry) aReceiveExecutor{id}for the message. It sendsInitExecuteto theReceiveExecutor{id}. - The
ReceiveExecutor{id}sendsDispatchValidatedback to theOffRampand sets its state toExecute. - The
OffRampsendsRouteMessageto theRouter, which forwards aCCIPReceiveinternal message to the Receiver contract. TheCCIPReceivepayload includes theexecId,messageId, source chain selector, sender address, and data. - The Receiver verifies that the sender is the
Router, sends backCCIPReceiveConfirm{execId}to theRouter, and processes the message data. - The
RouterforwardsCCIPReceiveConfirmto theOffRamp, which sendsConfirmto theReceiveExecutor{id}. - The
ReceiveExecutor{id}verifies the confirm came from theOffRampand that the original sender matches the Receiver. It sets its state toSuccess, destroys itself, and repliesNotifySuccessto theOffRamp. - The
OffRampemitsExecutionStateChangedwith stateSuccess.
- The
-
Failure and Retry
- If the Receiver bounces the
CCIPReceivemessage (fails to process it), theRoutersendsCCIPReceiveBouncedto theOffRamp. TheOffRampforwardsBouncedto theReceiveExecutor{id}, which sets its state toExecuteFailedand reportsNotifyFailure. TheOffRampemitsExecutionStateChangedwith stateFailureand callsMarkState(Failure)on theMerkleRoot{id}. - Failed messages can be retried. The
MerkleRoot{id}allows a transition fromFailureback toInProgresson a subsequentValidatecall, and the existingReceiveExecutor{id}is reused for the retry attempt. Manual execution is also supported permissionlessly after a configured time delay. For more information, read the manual execution page.
- If the Receiver bounces the