The Metalayer requires that protocol developers implement two contracts - one on the source chain, and another on the destination chain. This pattern
is the same regardless of if the developer is intending to perform a read or a write.
Both contracts interact with the MetalayerRouter contract on each chain — and on both sides, the developer should allowlist the specific MetalayerRouter contract
on the local chain as part of their protocol’s configuration.
Sending the Message on the Source Chain
On the souce chain, the sending contract calls the dispatch
function on the
MetalayerRouter contract. This function takes in the destination domain, recipient address, reads, write call data, and a boolean indicating whether or not
to wait for finality on the source chainbefore relaying the message.
/**
* @notice Dispatches a message to the destination domain & recipient with the given reads and write.
* @dev Convenience function for EVM chains.
* @param _destinationDomain Domain of destination chain
* @param _recipientAddress Address of recipient on destination chain as bytes32
* @param _reads Read operations
* @param _writeCallData The raw bytes to be called on the recipient address.
* @param _finalityState What sort of finality we should wait for before the message is valid. Currently only have 0 for instant, 1 for final.
* @param _gasLimit The gas limit for the submission transaction on the destination chain
*/
function dispatch(
uint32 _destinationDomain,
address _recipientAddress,
ReadOperation[] memory _reads, // can be empty
bytes memory _writeCallData,
FinalityState _finalityState,
uint256 _gasLimit
) external payable;
/**
* @notice Computes quote for dipatching a message to the destination domain & recipient
* using the default hook and empty metadata.
* @param destinationDomain Domain of destination chain
* @param recipientAddress Address of recipient on destination chain as bytes32
* @param messageBody Raw bytes content of message body
* @return fee The payment required to dispatch the message
*/
function quoteDispatch(uint32 destinationDomain, bytes32 recipientAddress, bytes calldata messageBody)
external
view
returns (uint256 fee);
Gas Payment
The quoteGasPayment
function is used to calculate the amount of gas that will be paid for the message. This function takes in the destination domain and the gas limit, and returns the amount of gas that is needed to relay the message.
This gas payment covers the cost of relaying the message as well as the gas cost of the message delivery on the destination chain. It also works for relaying messsages to chains with a different gas token than the token on your local chain. The mayment should be included in the value that is sent to the dispatch
function.
Receiving the Message on the Destination Chain
On the destination chain, the receiving contract must implement the IMetalayerRecipient
interface. The MetalayerRouter
on the destination chain will call the handle
function on the recipient contract in order to deliver the message.
/**
* @notice Represents a cross-chain read operation
* @dev Used to specify what data should be read from other chains.
* The read operations are only compatible with EVM chains, so the
* target is packed as an address to save bytes.
*/
struct ReadOperation {
/// @notice The domain ID of the chain to read from
uint32 domain;
/// @notice The address of the contract to read from
address target;
/// @notice The calldata to execute on the target contract
bytes callData;
}
interface IMetalayerRecipient {
/**
* @notice Handles an incoming message from another chain via Metalayer
* @dev This function is called by the MetalayerRouter when a message is delivered
* @param _origin The domain ID of the chain where the message originated
* @param _sender The address of the contract that sent the message on the origin chain
* @param _message The payload of the message to be handled
* @param _reads Array of read operations that were requested in the original message
* @param _readResults Array of results from the read operations, provided by the relayer
* @custom:security The caller must be the MetalayerRouter contract
*/
function handle(
uint32 _origin,
bytes32 _sender,
bytes calldata _message,
ReadOperation[] calldata _reads,
bytes[] calldata _readResults
) external payable;
}