> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metalntwx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cross-Chain Messages

> How a contract call on Metal triggers a transaction on foreign chains

A finalized state change on Metal can trigger a transaction on another chain. The sending side is one contract call; the receiving side verifies a fixed-depth Merkle path against the message root committed in a light-client checkpoint, and dispatches the committed call exactly once.

## Send from Metal

Call `send` on the Metal outbox with the destination chain, the target contract, and the calldata to deliver:

```solidity theme={null}
interface IMetalOutbox {
    /// Emitted for relayers and indexers; verification never trusts it.
    event MessageSent(
        uint256 indexed nonce,
        uint64 indexed destinationChainId,
        address indexed target,
        address sender,
        bytes payload
    );

    /// Queue a cross-chain message. Returns its sequential nonce.
    function send(uint64 destinationChainId, address target, bytes calldata payload)
        external
        returns (uint256 nonce);
}
```

`send` appends a commitment as leaf `nonce` of an append-only Merkle tree whose composite root every Metal block header carries (and consensus validates):

```text theme={null}
leaf[nonce] = keccak256(abi.encode(
    metalChainId,        // source domain
    destinationChainId,  // destination domain
    nonce,
    msg.sender,          // authenticated Metal-side sender
    target,
    payload
))
```

The commitment binds the full execution domain. A message queued for one chain cannot replay on another, cannot be redirected to a different target, and cannot be executed with altered calldata or a forged sender.

> [!NOTE]
>
> The message is not actionable until its block is finalized. Track finality with `consensus_status`, or wait for the destination-side execution event.

## Execute on the destination chain

`MetalInbox.execute` takes the message fields plus the proof: the tree's leaf count at the checkpoint and a 32-element sibling path, both derivable from `MessageSent` events alone — no state queries, no archival node:

```solidity theme={null}
interface IMetalInbox {
    event MessageExecuted(uint256 indexed nonce, address indexed target, address sender);

    function execute(
        bytes32 checkpointBlockHash,   // an accepted MetalLightClient checkpoint
        uint256 nonce,
        address sender,                // Metal-side sender
        address target,
        bytes calldata payload,
        uint256 leafCount,             // tree size at the checkpoint
        bytes32[32] calldata path      // sibling path for leaf `nonce`
    ) external;

    /// The Metal-side sender of the message currently executing;
    /// zero outside of an execute call.
    function metalSender() external view returns (address);

    function consumed(uint256 nonce) external view returns (bool);
}
```

The inbox recomputes the leaf from the submitted fields, folds it up the index-ordered path, and requires the count-bound result to equal the checkpoint's message root before dispatching `target.call(payload)`. The leaf count is bound into the committed root, so it cannot be overstated to reach past the last message.

Execution semantics:

* **Exactly once.** A consumed nonce can never execute again, under any checkpoint.
* **Retryable on failure.** If the target reverts, the whole execution reverts and the nonce stays unconsumed, so the message can be retried. A target that always reverts simply never consumes its nonce.
* **Checkpoint-specific proofs.** An accepted checkpoint at or after the
  message's block can prove it. The sibling path and leaf count must match that
  checkpoint's message root. A proof remains usable against its original
  accepted checkpoint while the message is unconsumed.
* **Unordered delivery.** The inbox checks whether a nonce was consumed but
  does not require the previous nonce to execute first. Targets must enforce
  any application-level ordering requirement.

## Authenticate the caller

The target contract sees the inbox as `msg.sender`. To know who sent the message on Metal, read back through the inbox during execution:

```solidity theme={null}
contract MyReceiver {
    address immutable inbox;

    constructor(address inbox_) {
        inbox = inbox_;
    }

    function onMessage(uint256 value) external {
        require(msg.sender == inbox, "only inbox");
        address metalSender = IMetalInbox(msg.sender).metalSender();
        // authorize against metalSender ...
    }
}
```

> [!WARNING]
>
> Always gate the target function on the inbox address and authorize against `metalSender()`. Without the gate, anyone can call your target directly with arbitrary arguments.

## Relaying

Relayers rebuild the message tree from `MessageSent` events and select an
accepted checkpoint at or after the message's block. They build the proof
against that checkpoint's root and leaf count, then call `execute` on the inbox.
If no accepted checkpoint covers the message, they fetch a finality certificate
from a Metal node and submit `update` on the light client first. To use a later
checkpoint that includes additional messages, rebuild the proof for its tree.

Relaying is permissionless. Checkpoints and message proofs are verified
onchain, so relayers need no registration or stake. Relayers pay destination-
chain gas and use `MessageSent` events to construct the message proof.

The current destination-side `MetalLightClient` accepts only epoch `0`. It
cannot checkpoint later-epoch certificates without a verifier update.

Relayers submit checkpoints when messages need delivery. One checkpoint can
cover a batch of earlier messages, provided each message has a proof matching
that checkpoint's root and leaf count. Certificate gas is paid once per
checkpoint.

> [card] [Send messages from Metal](https://docs.metalntwx.com/build/interop/send-messages-from-metal.md)
>
> Follow message submission, proof construction, and delivery retries.

> [card] [Finality certificates](https://docs.metalntwx.com/reference/interop/finality-certificates.md)
>
> Fetching and verifying the witness a checkpoint is built from.

> [card] [Light Clients and Messages](https://docs.metalntwx.com/learn/interop/overview.md)
>
> The end-to-end path and trust model.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.