CCTPHelper
Title: CCTPHelper
Author: Malda Protocol
Helper for building/sending/receiving CCTP v2 messages and encoding/decoding hook payloads.
State Variables
TOKEN_MESSENGER
Circle TokenMessenger (v2) used to burn tokens and attach hook data.
address public immutable TOKEN_MESSENGER
MESSAGE_TRANSMITTER
Circle MessageTransmitter (v2) used to validate and receive messages with attestations.
address public immutable MESSAGE_TRANSMITTER
acceptedTokens
Token allowlist for burns via CCTP.
mapping(address token => bool isAccepted) public acceptedTokens
Functions
constructor
Constructor for the CCTPHelper contract.
constructor(address _tokenMessenger, address _messageTransmitter) ;
Parameters
| Name | Type | Description |
|---|---|---|
_tokenMessenger | address | Address of the TokenMessenger contract. |
_messageTransmitter | address | Address of the MessageTransmitter contract. |
createAndBurn
Burns tokens via CCTP v2 and returns the decoded message struct plus its encoded representation.
function createAndBurn(
address _token,
uint256 _amount,
uint32 _dstDomain,
bytes32 _receiver,
bytes memory _payload,
uint32 _srcDomain
) internal returns (CCTPMessage memory msgData, bytes memory encoded);
Parameters
| Name | Type | Description |
|---|---|---|
_token | address | Token to burn. |
_amount | uint256 | Amount to burn. |
_dstDomain | uint32 | Destination CCTP domain. |
_receiver | bytes32 | Receiver bytes32 (typically the bridge address encoded). |
_payload | bytes | App payload to attach as hook data. |
_srcDomain | uint32 | Source CCTP domain. |
Returns
| Name | Type | Description |
|---|---|---|
msgData | CCTPMessage | Parsed message struct (nonce is 0 for v2). |
encoded | bytes | Packed encoding of msgData produced by _encodeMsg. |
handleDestinationMsg
Validates a CCTP message+attestation via Circle and decodes the embedded hook payload into a CCTPMessage.
function handleDestinationMsg(bytes calldata cctpMessage, bytes calldata attestation)
internal
returns (CCTPMessage memory msgData);
Parameters
| Name | Type | Description |
|---|---|---|
cctpMessage | bytes | Raw CCTP message bytes. |
attestation | bytes | Circle attestation proving message validity. |
Returns
| Name | Type | Description |
|---|---|---|
msgData | CCTPMessage | Decoded app-level message extracted from the hook payload. |
_toBytes32
Converts an address to a left-padded bytes32 representation.
function _toBytes32(address addr) internal pure returns (bytes32);
Parameters
| Name | Type | Description |
|---|---|---|
addr | address | Address to convert. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes32 | Encoded bytes32. |
_burnSrc
Burns tokens via CCTP v2 and returns the nonce.
function _burnSrc(address _token, uint256 _amount, uint32 _dstDomain, bytes32 _receiver, bytes memory _payload)
private
returns (uint64 nonce);
Parameters
| Name | Type | Description |
|---|---|---|
_token | address | Token to burn. |
_amount | uint256 | Amount to burn. |
_dstDomain | uint32 | Destination CCTP domain. |
_receiver | bytes32 | Receiver bytes32 (typically the bridge address encoded). |
_payload | bytes | App payload to attach as hook data. |
Returns
| Name | Type | Description |
|---|---|---|
nonce | uint64 | Nonce of the burn. |
_encodeMsg
Encodes a CCTPMessage into a compact, packed byte format. Layout (all fields big-endian where applicable):
- [ 0 .. 0] : uint8 payloadId (fixed = 1)
- [ 1 .. 32] : bytes32 token (ERC20 address left-padded to 32 bytes)
- [ 33 .. 64] : uint256 amount
- [ 65 .. 68] : uint32 srcChain (CCTP domain / chain id)
- [ 69 .. 72] : uint32 dstChain
- [ 73 .. 80] : uint64 nonce (0 for CCTP v2; kept for compatibility)
- [ 81 .. 112] : bytes32 from (sender address left-padded)
- [113 .. 144] : bytes32 receiver (receiver address or arbitrary 32 bytes)
- [145 .. 146] : uint16 payloadLen (length of
payloadbelow) - [147 .. end] : bytes payload (opaque app-level payload) Minimum length with empty payload is therefore 147 bytes.
Encodes a CCTPMessage into a compact, packed byte format.
function _encodeMsg(CCTPMessage memory message) private pure returns (bytes memory);
Parameters
| Name | Type | Description |
|---|---|---|
message | CCTPMessage | CCTPMessage to encode. |
Returns
| Name | Type | Description |
|---|---|---|
<none> | bytes | encoded Encoded packed representation of the message. |
_decodeMsg
Decodes bytes produced by _encodeMsg back into a CCTPMessage.
Expects exactly the layout documented above:
- Reverts with CCTPHelper_MsgTooShort if the buffer is shorter than the fixed header (147 bytes).
- Reverts with CCTPHelper_PayloadMismatch if
payloadId != 1. - Reverts with CCTPHelper_LengthMismatch if the trailing bytes length
does not match the embedded
payloadLen. Numeric fields are read as big-endian from the high bits of a 32-byte word: - uint32 values are taken from the highest 4 bytes of the word (shr(224, ...)).
- uint64 values are taken from the highest 8 bytes of the word (shr(192, ...)).
- uint16 values are taken from the highest 2 bytes of the word (shr(240, ...)).
The
payloadbytes are copied verbatim into a new bytes array.
Decodes bytes produced by _encodeMsg back into a CCTPMessage.
function _decodeMsg(bytes memory encoded) private pure returns (CCTPMessage memory message);
Parameters
| Name | Type | Description |
|---|---|---|
encoded | bytes | Encoded packed representation of the message. |
Returns
| Name | Type | Description |
|---|---|---|
message | CCTPMessage | Decoded CCTPMessage. |
Events
BurnInitiated
Emitted after a burn is initiated via TokenMessenger.
event BurnInitiated(
address indexed token,
uint256 amount,
uint32 dstDomain,
bytes32 indexed recipient,
uint64 indexed nonce,
bytes payload
);
Parameters
| Name | Type | Description |
|---|---|---|
token | address | The ERC20 token burned. |
amount | uint256 | The amount burned. |
dstDomain | uint32 | The destination CCTP domain. |
recipient | bytes32 | The destination recipient (bytes32). |
nonce | uint64 | Always 0 for CCTP v2 (kept for compatibility). |
payload | bytes | Hook payload passed to Circle. |
MessageCreated
Emitted when an app-level message payload is constructed and encoded.
event MessageCreated(
bytes32 indexed token,
uint256 amount,
uint32 indexed srcDomain,
uint32 indexed dstDomain,
uint64 nonce,
bytes32 from,
bytes32 receiver,
bytes payload,
bytes encodedMessage
);
Parameters
| Name | Type | Description |
|---|---|---|
token | bytes32 | Token address (bytes32 encoded). |
amount | uint256 | Amount burned. |
srcDomain | uint32 | Source CCTP domain. |
dstDomain | uint32 | Destination CCTP domain. |
nonce | uint64 | Always 0 for CCTP v2 (kept for compatibility). |
from | bytes32 | Sender (bytes32 encoded). |
receiver | bytes32 | Receiver (bytes32). |
payload | bytes | App payload. |
encodedMessage | bytes | Encoded packed representation produced by _encodeMsg. |
MessageReceived
Emitted after a message is received/validated by Circle and decoded into the app payload.
event MessageReceived(
uint64 indexed nonce,
uint32 indexed srcDomain,
uint32 indexed dstDomain,
uint256 amount,
bytes32 receiver,
bytes payload
);
Parameters
| Name | Type | Description |
|---|---|---|
nonce | uint64 | Always 0 for CCTP v2 (kept for compatibility). |
srcDomain | uint32 | Source CCTP domain. |
dstDomain | uint32 | Destination CCTP domain. |
amount | uint256 | Amount received. |
receiver | bytes32 | Receiver (bytes32). |
payload | bytes | App payload. |
Errors
CCTPHelper_AmountZero
error CCTPHelper_AmountZero();
CCTPHelper_AddressZero
error CCTPHelper_AddressZero();
CCTPHelper_TokenNotAccepted
error CCTPHelper_TokenNotAccepted();
CCTPHelper_ReceiveFailed
error CCTPHelper_ReceiveFailed();
CCTPHelper_LengthMismatch
error CCTPHelper_LengthMismatch();
CCTPHelper_PayloadMismatch
error CCTPHelper_PayloadMismatch();
CCTPHelper_MsgTooShort
error CCTPHelper_MsgTooShort();
Structs
CCTPMessage
Struct used to encode and decode the app-level hook payload carried by CCTP v2.
struct CCTPMessage {
bytes32 token; // ERC20 token address left-padded to 32 bytes
uint256 amount;
uint32 srcChain; // CCTP domain on source
uint32 dstChain; // CCTP domain on destination
uint64 nonce; // always 0 for v2; kept for compatibility
bytes32 from; // msg.sender on source (left-padded)
bytes32 receiver; // receiver/caller bytes32
bytes payload; // opaque app payload
}