Skip to main content

Post-Dispatch Hooks

Post-dispatch hooks allow developers to configure additional origin chain behavior with message content dispatched via the Mailbox.

This allows developers to integrate third party/native bridges, make additional chain commitments, or require custom fees all while maintaining a consistent single-call Mailbox interface.

IPostDispatchHook Interface
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/

interface IPostDispatchHook {
enum Types {
UNUSED,
ROUTING,
AGGREGATION,
MERKLE_TREE,
INTERCHAIN_GAS_PAYMASTER,
FALLBACK_ROUTING,
ID_AUTH_ISM,
PAUSABLE,
PROTOCOL_FEE,
LAYER_ZERO_V1,
Rate_Limited_Hook
}

/**
* @notice Returns an enum that represents the type of hook
*/
function hookType() external view returns (uint8);

/**
* @notice Returns whether the hook supports metadata
* @param metadata metadata
* @return Whether the hook supports metadata
*/
function supportsMetadata(
bytes calldata metadata
) external view returns (bool);

/**
* @notice Post action after a message is dispatched via the Mailbox
* @param metadata The metadata required for the hook
* @param message The message passed from the Mailbox.dispatch() call
*/
function postDispatch(
bytes calldata metadata,
bytes calldata message
) external payable;

/**
* @notice Compute the payment required by the postDispatch call
* @param metadata The metadata required for the hook
* @param message The message passed from the Mailbox.dispatch() call
* @return Quoted payment for the postDispatch call
*/
function quoteDispatch(
bytes calldata metadata,
bytes calldata message
) external view returns (uint256);
}

Post Dispatch

In addition to the message dispatched via the Mailbox, the postDispatch function receives a metadata parameter. The metadata parameter is passed from the dispatch call through the Mailbox unmodified. This allows developers to pass any context they wish through to the hook.

 * @param message The message passed from the Mailbox.dispatch() call
*/
function postDispatch(
bytes calldata metadata,

If the postDispatch function receives insufficient payment, it may revert.

Quote Dispatch (Fees)

Fees are often charged in postDispatch to cover costs such as destination chain transaction submission and security provisioning. To receive a quote for a corresponding postDispatch call, you can query the quoteDispatch function.

 * @return Quoted payment for the postDispatch call
*/
function quoteDispatch(
bytes calldata metadata,

The Mailbox has a quoteDispatch function that returns the aggregate fee required for a dispatch call to be successful.

Move to implementing a hook guide here

Overridding default Hook Metadata

To override the default metadata, there is a dispatch overload that takes an optional metadata parameter.

info

Hooks currently expect metadata to be formatted with the StandardHookMetadata library.

function dispatch(
uint32 destinationDomain,
bytes32 recipientAddress,
bytes calldata messageBody,
bytes calldata hookMetadata
) external payable override returns (bytes32) {

The custom metadata will be passed to the required hook's quoteDispatch and postDispatch functions, before being passed to the default hook's postDispatch function.

Examples

StandardHookMetadata Library
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >=0.8.0;

/*@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@ HYPERLANE @@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@@
@@@@@@@@@ @@@@@@@@*/

/**
* Format of metadata:
*
* [0:2] variant
* [2:34] msg.value
* [34:66] Gas limit for message (IGP)
* [66:86] Refund address for message (IGP)
* [86:] Custom metadata
*/
library StandardHookMetadata {
struct Metadata {
uint16 variant;
uint256 msgValue;
uint256 gasLimit;
address refundAddress;
}

uint8 private constant VARIANT_OFFSET = 0;
uint8 private constant MSG_VALUE_OFFSET = 2;
uint8 private constant GAS_LIMIT_OFFSET = 34;
uint8 private constant REFUND_ADDRESS_OFFSET = 66;
uint256 private constant MIN_METADATA_LENGTH = 86;

uint16 public constant VARIANT = 1;

/**
* @notice Returns the variant of the metadata.
* @param _metadata ABI encoded standard hook metadata.
* @return variant of the metadata as uint8.
*/
function variant(bytes calldata _metadata) internal pure returns (uint16) {
if (_metadata.length < VARIANT_OFFSET + 2) return 0;
return uint16(bytes2(_metadata[VARIANT_OFFSET:VARIANT_OFFSET + 2]));
}

/**
* @notice Returns the specified value for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback value.
* @return Value for the message as uint256.
*/
function msgValue(
bytes calldata _metadata,
uint256 _default
) internal pure returns (uint256) {
if (_metadata.length < MSG_VALUE_OFFSET + 32) return _default;
return
uint256(bytes32(_metadata[MSG_VALUE_OFFSET:MSG_VALUE_OFFSET + 32]));
}

/**
* @notice Returns the specified gas limit for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback gas limit.
* @return Gas limit for the message as uint256.
*/
function gasLimit(
bytes calldata _metadata,
uint256 _default
) internal pure returns (uint256) {
if (_metadata.length < GAS_LIMIT_OFFSET + 32) return _default;
return
uint256(bytes32(_metadata[GAS_LIMIT_OFFSET:GAS_LIMIT_OFFSET + 32]));
}

/**
* @notice Returns the specified refund address for the message.
* @param _metadata ABI encoded standard hook metadata.
* @param _default Default fallback refund address.
* @return Refund address for the message as address.
*/
function refundAddress(
bytes calldata _metadata,
address _default
) internal pure returns (address) {
if (_metadata.length < REFUND_ADDRESS_OFFSET + 20) return _default;
return
address(
bytes20(
_metadata[REFUND_ADDRESS_OFFSET:REFUND_ADDRESS_OFFSET + 20]
)
);
}

/**
* @notice Returns any custom metadata.
* @param _metadata ABI encoded standard hook metadata.
* @return Custom metadata.
*/
function getCustomMetadata(
bytes calldata _metadata
) internal pure returns (bytes calldata) {
if (_metadata.length < MIN_METADATA_LENGTH) return _metadata[0:0];
return _metadata[MIN_METADATA_LENGTH:];
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _msgValue msg.value for the message.
* @param _gasLimit Gas limit for the message.
* @param _refundAddress Refund address for the message.
* @param _customMetadata Additional metadata to include in the standard hook metadata.
* @return ABI encoded standard hook metadata.
*/
function formatMetadata(
uint256 _msgValue,
uint256 _gasLimit,
address _refundAddress,
bytes memory _customMetadata
) internal pure returns (bytes memory) {
return
abi.encodePacked(
VARIANT,
_msgValue,
_gasLimit,
_refundAddress,
_customMetadata
);
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _msgValue msg.value for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideMsgValue(
uint256 _msgValue
) internal view returns (bytes memory) {
return formatMetadata(_msgValue, uint256(0), msg.sender, "");
}

/**
* @notice Formats the specified gas limit and refund address into standard hook metadata.
* @param _gasLimit Gas limit for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideGasLimit(
uint256 _gasLimit
) internal view returns (bytes memory) {
return formatMetadata(uint256(0), _gasLimit, msg.sender, "");
}

/**
* @notice Formats the specified refund address into standard hook metadata.
* @param _refundAddress Refund address for the message.
* @return ABI encoded standard hook metadata.
*/
function overrideRefundAddress(
address _refundAddress
) internal pure returns (bytes memory) {
return formatMetadata(uint256(0), uint256(0), _refundAddress, "");
}
}
// send message from alfajores to bsctestnet TestRecipient
IMailbox mailbox = IMailbox("0xEf9F292fcEBC3848bF4bB92a96a04F9ECBb78E59");
mailbox.dispatch{value: msg.value}(
97,
"0x0000000000000000000000006489d13AcAd3B8dce4c5B31f375DE4f9451E7b38",
bytes("Hello, world"),
StandardHookMetadata.overrideGasLimit(200000)
);

Custom hook and metadata

After implementing the above interfaces, you can override default hook along the hook metadata by using the overloaded dispatch call in our mailbox:

function dispatch(
uint32 destinationDomain,
bytes32 recipientAddress,
bytes calldata messageBody,
bytes calldata metadata,
IPostDispatchHook hook
) public payable virtual returns (bytes32) {

Examples

// send message from alfajores to bsctestnet TestRecipient
IMailbox mailbox = IMailbox("0xEf9F292fcEBC3848bF4bB92a96a04F9ECBb78E59");
IPostDispatchHook merkleTree = IPostDispatchHook("0x221FA9CBaFcd6c1C3d206571Cf4427703e023FFa");
mailbox.dispatch(
97,
"0x0000000000000000000000006489d13AcAd3B8dce4c5B31f375DE4f9451E7b38",
bytes("Hello, world"),
"0x", // empty metadata
merkleTree
);