Skip to main content

Overview

MessageTransmitterV2 is the core contract responsible for sending and receiving cross-chain messages in CCTP V2. It inherits from BaseMessageTransmitter and introduces finality threshold functionality, allowing messages to be attested at different levels of finality. Contract Location: src/v2/MessageTransmitterV2.sol

Key Features

New Features vs V1

  1. Finality Thresholds: Messages can specify minimum finality requirements and are attested at specific finality levels
  2. Destination Caller: Messages can specify an authorized caller on the destination domain
  3. Enhanced Message Format: V2 message format includes minFinalityThreshold and finalityThresholdExecuted fields
  4. Dual Message Handlers: Separate handling for finalized vs unfinalized messages

Finality Threshold Levels

  • FINALITY_THRESHOLD_FINALIZED (2000): Messages at or above this threshold are considered finalized
  • FINALITY_THRESHOLD_CONFIRMED (1000): Messages at or above this threshold are considered confirmed
  • TOKEN_MESSENGER_MIN_FINALITY_THRESHOLD (500): Minimum threshold accepted by TokenMessenger

Constructor

constructor(
    uint32 _localDomain,
    uint32 _version
)

Parameters

  • _localDomain (uint32): Domain of the chain on which the contract is deployed
  • _version (uint32): Message format version

Initialization

function initialize(
    address owner_,
    address pauser_,
    address rescuer_,
    address attesterManager_,
    address[] calldata attesters_,
    uint256 signatureThreshold_,
    uint256 maxMessageBodySize_
) external
Initializes the contract with role assignments and configuration.

Parameters

  • owner_ (address): Owner address (cannot be zero address)
  • pauser_ (address): Pauser address
  • rescuer_ (address): Rescuer address
  • attesterManager_ (address): AttesterManager address (cannot be zero address)
  • attesters_ (address[]): Set of attesters to enable
  • signatureThreshold_ (uint256): Signature threshold (must not exceed number of attesters)
  • maxMessageBodySize_ (uint256): Maximum message body size (must be greater than zero)

Requirements

  • Owner and attester manager must be non-zero addresses
  • Signature threshold must not exceed the number of enabled attesters
  • Max message body size must be greater than zero

Core Functions

sendMessage

function sendMessage(
    uint32 destinationDomain,
    bytes32 recipient,
    bytes32 destinationCaller,
    uint32 minFinalityThreshold,
    bytes calldata messageBody
) external
Sends a message to the destination domain and recipient. Reference: src/v2/MessageTransmitterV2.sol:143

Parameters

  • destinationDomain (uint32): Domain of destination chain
  • recipient (bytes32): Address of message recipient on destination chain as bytes32
  • destinationCaller (bytes32): Authorized caller on the destination domain as bytes32. If equal to bytes32(0), any address can broadcast the message
  • minFinalityThreshold (uint32): The minimum finality level at which the message should be attested to
  • messageBody (bytes): Contents of the message

Requirements

  • Contract must not be paused
  • Destination domain cannot be the local domain
  • Message body length must not exceed maxMessageBodySize
  • Recipient must be nonzero

Events

event MessageSent(bytes message);
Emitted when a new message is dispatched.

receiveMessage

function receiveMessage(
    bytes calldata message,
    bytes calldata attestation
) external returns (bool success)
Receives and processes a cross-chain message. Messages can only be broadcast once for a given nonce. Reference: src/v2/MessageTransmitterV2.sol:206

Parameters

  • message (bytes): Message bytes
  • attestation (bytes): Concatenated 65-byte signature(s) of the message, in increasing order of the attester address recovered from signatures

Returns

  • success (bool): True if successful

Message Format

FieldBytesTypeIndex
version4uint320
sourceDomain4uint324
destinationDomain4uint328
nonce32bytes3212
sender32bytes3244
recipient32bytes3276
destinationCaller32bytes32108
minFinalityThreshold4uint32140
finalityThresholdExecuted4uint32144
messageBodydynamicbytes148

Attestation Format

A valid attestation is the concatenated 65-byte signature(s) of exactly signatureThreshold signatures, in increasing order of attester address. Important: If the attester addresses recovered from signatures are not in increasing order, signature verification will fail. Duplicate signatures will also cause verification to fail.

Requirements

  • Contract must not be paused
  • Message must pass attestation signature verification
  • Destination domain must match local domain
  • If destination caller is specified, it must match msg.sender
  • Message version must match contract version
  • Nonce must not have been used previously

Behavior

Depending on the finalityThresholdExecuted value:
  • If finalityThresholdExecuted < FINALITY_THRESHOLD_FINALIZED: Calls handleReceiveUnfinalizedMessage() on the recipient
  • If finalityThresholdExecuted >= FINALITY_THRESHOLD_FINALIZED: Calls handleReceiveFinalizedMessage() on the recipient

Events

event MessageReceived(
    address indexed caller,
    uint32 sourceDomain,
    bytes32 indexed nonce,
    bytes32 sender,
    uint32 indexed finalityThresholdExecuted,
    bytes messageBody
);
Emitted when a new message is received.

Inherited Functions

From BaseMessageTransmitter:
  • setMaxMessageBodySize(): Sets the maximum message body size (owner only)
  • pause(): Pauses the contract (pauser only)
  • unpause(): Unpauses the contract (pauser only)
  • updatePauser(): Updates the pauser address (owner only)
  • updateRescuer(): Updates the rescuer address (owner only)
  • enableAttester(): Enables an attester (attester manager only)
  • disableAttester(): Disables an attester (attester manager only)
  • setSignatureThreshold(): Sets the signature threshold (attester manager only)

State Variables

Immutable

  • localDomain (uint32): Domain of the chain on which the contract is deployed
  • version (uint32): Message format version

Storage

  • maxMessageBodySize (uint256): Maximum size of message body in bytes
  • usedNonces (mapping(bytes32 => uint256)): Mapping of nonce to usage status (0 = unused, 1 = used)

Integration Example

// Send a message with high finality requirement
messageTransmitter.sendMessage(
    destinationDomain,
    recipientAddress,
    bytes32(0), // Any caller can receive
    2000, // Require finalized threshold
    messageBody
);

// Receive a message
bool success = messageTransmitter.receiveMessage(
    message,
    attestation
);

Security Considerations

  1. Nonce Replay Protection: Each nonce can only be used once
  2. Attestation Verification: Signatures must be in increasing order by attester address
  3. Domain Validation: Messages can only be sent to domains different from the local domain
  4. Caller Authorization: Optional destination caller restriction for enhanced security
  5. Finality Requirements: Minimum finality thresholds ensure appropriate security levels

Build docs developers (and LLMs) love