跳到主要内容

邮件分发 Hooks

邮件分发 Hooks 允许开发者通过邮件箱配置附加的原始链行为,使用通过邮件箱分发的消息内容。

这使得开发者能够集成第三方/本地桥接,进行额外的链承诺,或要求自定义费用,同时保持一致的单次调用邮件箱接口。

IPostDispatchHook 接口
// 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,
ARB_L2_TO_L1,
OP_L2_TO_L1
}

/**
* @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);
}

邮件分发

除了通过邮件箱分发的 messagepostDispatch 函数还接收一个 metadata 参数。metadata 参数从 dispatch 调用中传递,通过邮件箱未被修改。这允许开发者传递任何他们希望通过钩子传递的上下文。

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

如果 postDispatch 函数接收到的支付不足,可能会回滚。

信息

后处理钩子可能是可重放的。创建自定义钩子的开发者应实现安全检查以防止这种行为。这里 是一个示例实现。

报价处理(费用)

费用通常在 postDispatch 中收取,以覆盖诸如目标链交易提交和安全提供等成本。要获取相应 postDispatch 调用的报价,可以查询 quoteDispatch 函数。

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

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

转到实现钩子指南 这里

重写默认 hook 元数据

要重写默认元数据,有一个 dispatch 重载,接受一个可选的 metadata 参数。

信息

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

function dispatch(
uint32 destinationDomain,
bytes32 recipientAddress,
bytes calldata body,
bytes calldata defaultHookMetadata
) external payable returns (bytes32 messageId);

自定义的 metadata 将在传递给所需钩子的 quoteDispatchpostDispatch 函数之前,传递给默认钩子的 postDispatch 函数。

示例

StandardHookMetadata
// 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, "");
}
}
// 从 abstracttestnet 发送消息到 alephzeroevmtestnet 测试接收者
IMailbox mailbox = IMailbox("0x28f448885bEaaF662f8A9A6c9aF20fAd17A5a1DC");
mailbox.dispatch{value: msg.value}(
2039,
"0x0000000000000000000000009EC79CA89DeF61BFa2f38cD4fCC137b9e49d60dD",
bytes("Hello, world"),
StandardHookMetadata.overrideGasLimit(200000)
);

自定义钩子和元数据

在实现上述接口后,您可以通过在邮件箱中使用重载的 dispatch 调用来重写默认钩子及其元数据:

function dispatch(
uint32 destinationDomain,
bytes32 recipientAddress,
bytes calldata body,
bytes calldata customHookMetadata,
IPostDispatchHook customHook
) external payable returns (bytes32 messageId);

示例

// 从 abstracttestnet 发送消息到 alephzeroevmtestnet 测试接收者
IMailbox mailbox = IMailbox("0x28f448885bEaaF662f8A9A6c9aF20fAd17A5a1DC");
IPostDispatchHook merkleTree = IPostDispatchHook("0x7fa6009b59F139813eA710dB5496976eE8D80E64");
mailbox.dispatch(
2039,
"0x0000000000000000000000009EC79CA89DeF61BFa2f38cD4fCC137b9e49d60dD",
bytes("Hello, world"),
"0x", // 空元数据
merkleTree
);