Documentation Index
Fetch the complete documentation index at: https://mintlify.com/circlefin/evm-cctp-contracts/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The IMessageHandler interface defines the contract for receiving and processing cross-chain messages on the destination domain. Contracts implementing this interface can handle messages forwarded from the MessageReceiver after validation.
Interface Definition
IMessageHandler (V1)
interface IMessageHandler {
function handleReceiveMessage(
uint32 sourceDomain,
bytes32 sender,
bytes calldata messageBody
) external returns (bool);
}
Source: src/interfaces/IMessageHandler.sol:31
IMessageHandlerV2
V2 introduces finality awareness with separate handlers for finalized and unfinalized messages:
interface IMessageHandlerV2 {
function handleReceiveFinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool);
function handleReceiveUnfinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool);
}
Source: src/interfaces/v2/IMessageHandlerV2.sol:35
Functions
handleReceiveMessage
function handleReceiveMessage(
uint32 sourceDomain,
bytes32 sender,
bytes calldata messageBody
) external returns (bool);
Handles an incoming message from a Receiver on the destination domain.
Parameters:
sourceDomain - The source domain ID where the message originated
sender - The address of the message sender on the source domain (as bytes32)
messageBody - The raw bytes of the message payload
Returns:
success - True if the message was processed successfully, false otherwise
handleReceiveFinalizedMessage (V2)
function handleReceiveFinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool);
Handles incoming finalized messages (finality threshold >= 2000).
Parameters:
sourceDomain - The source domain ID where the message originated
sender - The address of the message sender on the source domain (as bytes32)
finalityThresholdExecuted - The finality threshold at which the message was attested (>= 2000)
messageBody - The raw bytes of the message payload
Returns:
success - True if successful, false otherwise
handleReceiveUnfinalizedMessage (V2)
function handleReceiveUnfinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool);
Handles incoming unfinalized messages (finality threshold < 2000).
Parameters:
sourceDomain - The source domain ID where the message originated
sender - The address of the message sender on the source domain (as bytes32)
finalityThresholdExecuted - The finality threshold at which the message was attested (< 2000)
messageBody - The raw bytes of the message payload
Returns:
success - True if successful, false otherwise
When to Implement
Implement IMessageHandler when your contract needs to:
- Receive and process cross-chain messages from CCTP
- Handle token transfers with custom logic on the destination chain
- Act as the recipient endpoint in cross-chain communication
- Process burn messages for token minting operations
Implementation Example
The TokenMessenger contract provides a reference implementation:
contract TokenMessenger is IMessageHandler, Rescuable {
IMessageTransmitter public immutable localMessageTransmitter;
ITokenMinter public localMinter;
uint32 public immutable messageBodyVersion;
mapping(uint32 => bytes32) public remoteTokenMessengers;
function handleReceiveMessage(
uint32 remoteDomain,
bytes32 sender,
bytes calldata messageBody
)
external
override
onlyLocalMessageTransmitter
onlyRemoteTokenMessenger(remoteDomain, sender)
returns (bool)
{
// Parse the burn message
bytes29 _msg = messageBody.ref(0);
_msg._validateBurnMessageFormat();
require(
_msg._getVersion() == messageBodyVersion,
"Invalid message body version"
);
// Extract message fields
bytes32 _mintRecipient = _msg._getMintRecipient();
bytes32 _burnToken = _msg._getBurnToken();
uint256 _amount = _msg._getAmount();
// Mint tokens to recipient
ITokenMinter _localMinter = _getLocalMinter();
_mintAndWithdraw(
address(_localMinter),
remoteDomain,
_burnToken,
Message.bytes32ToAddress(_mintRecipient),
_amount
);
return true;
}
}
Source: src/TokenMessenger.sol:313
Key Implementation Requirements
Security Validations
-
Caller Verification - Only accept calls from the registered MessageTransmitter:
modifier onlyLocalMessageTransmitter() {
require(
msg.sender == address(localMessageTransmitter),
"Invalid message transmitter"
);
_;
}
-
Sender Verification - Validate the remote sender is authorized:
modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) {
require(
_isRemoteTokenMessenger(domain, tokenMessenger),
"Remote TokenMessenger unsupported"
);
_;
}
-
Message Format Validation - Validate message structure and version before processing
Message Processing
- Parse the message body according to the expected format
- Extract relevant parameters (recipient, amount, token, etc.)
- Execute the intended action (mint tokens, trigger hooks, etc.)
- Return true on success, false on failure
V2 Enhancements
Version 2 introduces finality awareness:
- Finalized Messages (threshold >= 2000): Messages with strong finality guarantees
- Unfinalized Messages (threshold < 2000): Messages with probabilistic finality
Implementations can apply different handling logic based on finality:
function handleReceiveFinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool) {
// Process with full confidence - finality guaranteed
_processWithFullConfidence(messageBody);
return true;
}
function handleReceiveUnfinalizedMessage(
uint32 sourceDomain,
bytes32 sender,
uint32 finalityThresholdExecuted,
bytes calldata messageBody
) external returns (bool) {
// Process with caution - may require additional confirmations
_processWithCaution(messageBody, finalityThresholdExecuted);
return true;
}
- IReceiver - Receives and validates messages before forwarding to handlers
- ITokenMinter - Mints and burns tokens in response to cross-chain transfers
- IRelayer - Sends messages from source to destination domains