Skip to main content

Overview

TokenMessengerV2 is responsible for facilitating cross-chain USDC transfers by burning tokens on the source domain and minting them on the destination domain. V2 introduces fee mechanisms, finality thresholds, and optional hook execution. Contract Location: src/v2/TokenMessengerV2.sol

Key Features

New Features vs V1

  1. Fee Mechanism: Support for destination domain fees with maxFee parameter
  2. Minimum Fee Control: Configurable minimum fee requirements in basis points
  3. Finality Thresholds: Messages can specify minimum finality requirements
  4. Hook Execution: Optional hookData for custom logic on destination domain
  5. Destination Caller: Specify authorized caller on destination domain
  6. Denylist Support: Ability to denylist addresses from using the protocol

Constructor

constructor(
    address _messageTransmitter,
    uint32 _messageBodyVersion
)

Parameters

  • _messageTransmitter (address): Message transmitter address
  • _messageBodyVersion (uint32): Message body version

Initialization

struct TokenMessengerV2Roles {
    address owner;
    address rescuer;
    address feeRecipient;
    address denylister;
    address tokenMinter;
    address minFeeController;
}

function initialize(
    TokenMessengerV2Roles calldata roles,
    uint256 minFee_,
    uint32[] calldata remoteDomains_,
    bytes32[] calldata remoteTokenMessengers_
) external
Initializes the contract with roles and configuration. Reference: src/v2/TokenMessengerV2.sol:109

Parameters

  • roles (TokenMessengerV2Roles): Struct containing all role addresses
    • owner: Owner address (cannot be zero)
    • rescuer: Rescuer address
    • feeRecipient: Address to receive collected fees
    • denylister: Address with permission to manage denylist
    • tokenMinter: Local token minter address
    • minFeeController: Address with permission to set minimum fee
  • minFee_ (uint256): Initial minimum fee (in 1/1000 basis points)
  • remoteDomains_ (uint32[]): Array of remote domain IDs
  • remoteTokenMessengers_ (bytes32[]): Array of remote TokenMessenger addresses (must match remoteDomains_ length)

Requirements

  • Owner must be non-zero address
  • Remote domains and remote token messengers arrays must have equal length
  • All remote token messenger addresses must be non-zero

Core Functions

depositForBurn

function depositForBurn(
    uint256 amount,
    uint32 destinationDomain,
    bytes32 mintRecipient,
    address burnToken,
    bytes32 destinationCaller,
    uint256 maxFee,
    uint32 minFinalityThreshold
) external
Deposits and burns tokens from sender to be minted on destination domain. Reference: src/v2/TokenMessengerV2.sol:166

Parameters

  • amount (uint256): Amount of tokens to burn (must be nonzero)
  • destinationDomain (uint32): Destination domain to receive message on
  • mintRecipient (bytes32): Address of mint recipient on destination domain
  • burnToken (address): Token to burn amount of, on local domain
  • destinationCaller (bytes32): Authorized caller on the destination domain as bytes32. If equal to bytes32(0), any address can broadcast the message
  • maxFee (uint256): Maximum fee to pay on the destination domain, specified in units of burnToken
  • minFinalityThreshold (uint32): The minimum finality at which the burn message will be attested to

Requirements

  • Caller must not be denylisted
  • Amount must be nonzero
  • Mint recipient must be nonzero
  • Burn token must be supported
  • Destination domain must have a TokenMessenger registered
  • maxFee must be less than amount
  • maxFee must be >= amount * minFee / MIN_FEE_MULTIPLIER (if minFee > 0)
  • Sender must have sufficient balance and approval

Events

event DepositForBurn(
    address indexed burnToken,
    uint256 amount,
    address indexed depositor,
    bytes32 mintRecipient,
    uint32 destinationDomain,
    bytes32 destinationTokenMessenger,
    bytes32 destinationCaller,
    uint256 maxFee,
    uint32 indexed minFinalityThreshold,
    bytes hookData
);

depositForBurnWithHook

function depositForBurnWithHook(
    uint256 amount,
    uint32 destinationDomain,
    bytes32 mintRecipient,
    address burnToken,
    bytes32 destinationCaller,
    uint256 maxFee,
    uint32 minFinalityThreshold,
    bytes calldata hookData
) external
Deposits and burns tokens with optional hook data for execution on destination domain. Reference: src/v2/TokenMessengerV2.sol:210

Parameters

Same as depositForBurn, plus:
  • hookData (bytes): Hook data to append to burn message for interpretation on destination domain (must be non-empty)

Requirements

Same as depositForBurn, plus:
  • hookData must have length > 0

handleReceiveFinalizedMessage

function handleReceiveFinalizedMessage(
    uint32 remoteDomain,
    bytes32 sender,
    uint32 finalityThresholdExecuted,
    bytes calldata messageBody
) external returns (bool)
Handles an incoming finalized message received by the local MessageTransmitter. For a burn message, mints the associated token to the requested recipient on the local domain. Reference: src/v2/TokenMessengerV2.sol:245

Parameters

  • remoteDomain (uint32): The domain where the message originated from
  • sender (bytes32): The sender of the message (remote TokenMessenger)
  • finalityThresholdExecuted (uint32): The level of finality at which the message was attested (unused in finalized handler)
  • messageBody (bytes): The message body bytes

Returns

  • success (bool): True if successful

Requirements

  • Caller must be the local MessageTransmitter
  • Sender must be a registered remote TokenMessenger for the given domain

handleReceiveUnfinalizedMessage

function handleReceiveUnfinalizedMessage(
    uint32 remoteDomain,
    bytes32 sender,
    uint32 finalityThresholdExecuted,
    bytes calldata messageBody
) external returns (bool)
Handles an incoming unfinalized message received by the local MessageTransmitter. For a burn message, mints the associated token to the requested recipient on the local domain, less fees. Fees are separately minted to the currently set feeRecipient address. Reference: src/v2/TokenMessengerV2.sol:274

Parameters

  • remoteDomain (uint32): The domain where the message originated from
  • sender (bytes32): The sender of the message (remote TokenMessenger)
  • finalityThresholdExecuted (uint32): The level of finality at which the message was attested to
  • messageBody (bytes): The message body bytes

Returns

  • success (bool): True if successful

Requirements

  • Caller must be the local MessageTransmitter
  • Sender must be a registered remote TokenMessenger for the given domain
  • finalityThresholdExecuted must be >= TOKEN_MESSENGER_MIN_FINALITY_THRESHOLD (500)

Fee Management Functions

getMinFeeAmount

function getMinFeeAmount(uint256 amount) external view returns (uint256)
Returns the minimum fee for a given amount. Reference: src/v2/TokenMessengerV2.sol:299

Parameters

  • amount (uint256): The amount for which to calculate the minimum fee (must be > 1)

Returns

  • Minimum fee for the given amount

Formula

minFeeAmount = (amount * minFee) / MIN_FEE_MULTIPLIER
Where MIN_FEE_MULTIPLIER = 10,000,000 (enables 1/1000 basis point precision)

setFeeRecipient

function setFeeRecipient(address _feeRecipient) external
Sets the fee recipient address (owner only). Reference: src/v2/BaseTokenMessenger.sol:222

Parameters

  • _feeRecipient (address): Address of fee recipient (cannot be zero address)

Events

event FeeRecipientSet(address feeRecipient);

setMinFeeController

function setMinFeeController(address _minFeeController) external
Sets the minimum fee controller address (owner only). Reference: src/v2/BaseTokenMessenger.sol:232

Parameters

  • _minFeeController (address): Address of minimum fee controller (cannot be zero address)

Events

event MinFeeControllerSet(address minFeeController);

setMinFee

function setMinFee(uint256 _minFee) external
Sets the minimum fee for all transfers in 1/1000 basis points (min fee controller only). Reference: src/v2/BaseTokenMessenger.sol:242

Parameters

  • _minFee (uint256): Minimum fee (must be < MIN_FEE_MULTIPLIER)

Events

event MinFeeSet(uint256 minFee);

Denylist Functions

addToDenylist

function addToDenylist(address account) external
Adds an address to the denylist (denylister only). Denylisted addresses cannot call depositForBurn or depositForBurnWithHook.

removeFromDenylist

function removeFromDenylist(address account) external
Removes an address from the denylist (denylister only).

Remote TokenMessenger Management

addRemoteTokenMessenger

function addRemoteTokenMessenger(
    uint32 domain,
    bytes32 tokenMessenger
) external
Adds a TokenMessenger for a remote domain (owner only). Reference: src/v2/BaseTokenMessenger.sol:171

removeRemoteTokenMessenger

function removeRemoteTokenMessenger(uint32 domain) external
Removes the TokenMessenger for a remote domain (owner only). Reference: src/v2/BaseTokenMessenger.sol:182

Local Minter Management

addLocalMinter

function addLocalMinter(address newLocalMinter) external
Adds a minter for the local domain (owner only). Reference: src/v2/BaseTokenMessenger.sol:200

removeLocalMinter

function removeLocalMinter() external
Removes the minter for the local domain (owner only). Reference: src/v2/BaseTokenMessenger.sol:208

State Variables

Immutable

  • localMessageTransmitter (address): Local Message Transmitter address
  • messageBodyVersion (uint32): Version of message body format

Storage

  • localMinter (ITokenMinterV2): Local token minter contract
  • remoteTokenMessengers (mapping(uint32 => bytes32)): Valid TokenMessengers on remote domains
  • feeRecipient (address): Address to receive collected fees
  • minFeeController (address): Minimum fee controller address
  • minFee (uint256): Minimum fee for all transfers in 1/1000 basis points
  • MIN_FEE_MULTIPLIER (uint256): Constant value of 10,000,000 (1/1000 basis point precision)

Integration Example

// Approve tokens first
usdc.approve(address(tokenMessenger), amount);

// Deposit for burn with fee and finality
tokenMessenger.depositForBurn(
    1000000, // 1 USDC (6 decimals)
    destinationDomain,
    recipientAddress,
    address(usdc),
    bytes32(0), // Any caller
    5000, // Max fee: 0.005 USDC
    1000 // Confirmed finality
);

// With hook data for custom logic
tokenMessenger.depositForBurnWithHook(
    1000000,
    destinationDomain,
    recipientAddress,
    address(usdc),
    bytes32(0),
    5000,
    1000,
    customHookData // Interpreted on destination
);

Fee Calculation Example

If minFee = 5000 (0.05%):
Amount: 1,000,000 (1 USDC)
minFeeAmount = (1,000,000 * 5000) / 10,000,000 = 500 (0.0005 USDC)
The maxFee parameter must be >= minFeeAmount and < amount.

Event Signature Changes

The V2 DepositForBurn event includes additional parameters compared to V1:
  • destinationCaller (bytes32): Authorized caller specification
  • maxFee (uint256): Maximum fee willing to pay
  • minFinalityThreshold (uint32): Minimum finality requirement (indexed)
  • hookData (bytes): Optional hook data

Security Considerations

  1. Fee Validation: Max fee is validated to be less than amount and meet minimum fee requirements
  2. Denylist Protection: Denylisted addresses cannot initiate burns
  3. Caller Authorization: Optional destination caller restriction
  4. Finality Thresholds: Minimum finality of 500 required for unfinalized messages
  5. Message Expiration: Burn messages can include expiration blocks

Build docs developers (and LLMs) love