Skip to main content

Post-Dispatch Hooks

Post-dispatch hooks允许开发人员配置额外的源链行为,通过邮箱分发消息内容。

这允许开发人员在维护一致的单次调用邮箱接口的同时,集成第三方/本地桥,作出额外的链承诺,或要求自定义费用。

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
}

/**
* @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

除了通过邮箱发送的message之外,postDispatch函数还接收一个metadata参数。metadata参数从dispatch调用通过未修改的Mailbox传递。这允许开发人员将任何上下文传递给钩子。

function postDispatch(
bytes calldata metadata,
bytes calldata message
) external payable;

如果'postDispatch'函数收到的付款不足,它可能会回滚。

Quote Dispatch (Fees)

通常在postDispatch中收取费用,以支付目的地链交易提交和安全配置等成本。要接收相应postDispatch调用的报价,可以查询quoteDispatch函数。

function quoteDispatch(
bytes calldata metadata,
bytes calldata message
) external view returns (uint256);

邮箱有一个quoteDispatch 函数,用于返回成功调用dispatch所需的总费用。

转到实现钩子指南这里

覆盖默认钩子元数据

为了覆盖默认的元数据,有一个dispatch重载,它接受一个可选的metadata参数。

info

Hooks目前期望使用StandardHookMetadata library格式化元数据。

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

自定义的metadata将被传递给所需钩子的quoteDispatchpostDispatch函数,然后再传递给默认钩子的postDispatch函数。

示例

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 the specified refund address for the message.
* @param _metadata ABI encoded standard hook metadata.
* @return Refund address for the message as address.
*/
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 fuji TestRecipient
IMailbox mailbox = IMailbox("0xEf9F292fcEBC3848bF4bB92a96a04F9ECBb78E59");
mailbox.dispatch{value: msg.value}(
43113,
"0x00000000000000000000000044a7e1d76fD8AfA244AdE7278336E3D5C658D398",
bytes("Hello, world"),
StandardHookMetadata.overrideGasLimit(200000)
);

自定义钩子和元数据

在实现了上面的接口之后,你可以通过在我们的邮箱中重载的dispatch调用来覆盖钩子元数据中的默认钩子:

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

示例

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