Skip to main content
The Message library defines the format for cross-chain messages in CCTP. Messages use a fixed-size header with a dynamic message body, leveraging TypedMemView for efficient memory operations.

Message Structure

Messages contain metadata about the cross-chain transfer and routing information:
uint32
required
Message format version (4 bytes)
uint32
required
Domain identifier of the source chain (4 bytes)
uint32
required
Domain identifier of the destination chain (4 bytes)
uint64
required
Destination-specific nonce for replay protection (8 bytes)
In V2, this is expanded to bytes32 (32 bytes)
bytes32
required
Address of sender on source chain as bytes32 (32 bytes, starting at index 20)
bytes32
required
Address of recipient on destination chain as bytes32 (32 bytes, starting at index 52)
bytes32
required
Address authorized to call receiveMessage on destination chain (32 bytes, starting at index 84)Set to bytes32(0) to allow any caller
bytes
required
Dynamic bytes payload containing the burn message or custom data (starting at index 116)

Memory Layout (V1)

Fields use specific padding: uintNN fields are left-padded, and bytesNN fields are right-padded. This ensures fixed-size encoding and prevents hash collisions.

Message V2 Format

Version 2 introduces additional fields for finality control:

V2 Key Differences

  • nonce: Expanded from uint64 (8 bytes) to bytes32 (32 bytes)
  • minFinalityThreshold: Minimum finality level required for attestation
  • finalityThresholdExecuted: Finality level at which message was executed

Encoding Functions

Format Message (V1)

Source: ~/workspace/source/src/messages/Message.sol:66-87
Packs all message fields into a single bytes array using abi.encodePacked.

Format Message for Relay (V2)

Source: ~/workspace/source/src/messages/v2/MessageV2.sol:78-101
Formats a V2 message with empty nonce and finalityThresholdExecuted (set during attestation).

Decoding Functions

All getter functions use TypedMemView for zero-copy operations:

V1 Getters

V2 Getters

V2 uses _get prefix and includes additional fields:

Address Conversion

Convert between EVM addresses and bytes32:

Address to Bytes32

Source: ~/workspace/source/src/messages/Message.sol:146-148
Left-pads the address with zeros to create a bytes32 value.

Bytes32 to Address

Source: ~/workspace/source/src/messages/Message.sol:156-158
Different bytes32 values can map to the same address due to truncation. If uniqueness is required, validate that the first 12 bytes are zero-padding.

Validation

V1 Validation

Source: ~/workspace/source/src/messages/Message.sol:164-170
Ensures message is at least 116 bytes (minimum header size).

V2 Validation

Source: ~/workspace/source/src/messages/v2/MessageV2.sol:170-176
Ensures message is at least 148 bytes (V2 minimum header size).

TypedMemView Usage

Messages use the TypedMemView library for efficient, zero-copy memory operations:
  • bytes29: Efficient memory view type that avoids copying data
  • indexUint(): Reads uint values at specific byte offsets
  • index(): Reads bytes32 values at specific byte offsets
  • slice(): Creates sub-views without copying data

Example Usage

Encoding a Message

Decoding a Message

See Also