Skip to main content

创建你自己的 Hook & ISM

Hooks和ISM之间具有互补关系:您可以从源头自定义行为,并且它们在目标上使用成对的ISM合约来验证您的自定义钩子行为。

您可以根据自己的需求实现和利用自己的钩子和ISM模式。您可以通过在源链上实现 IPostDispatchHook 接口,以及在目标链上实现 IInterchainSecurityModule 接口,来使用外部提供的桥接器,如Wormhole或Chainlink的CCIP。

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

/**
* @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);
IInterchainSecurityModule Interface
interface IInterchainSecurityModule {
enum Types {
UNUSED,
ROUTING,
AGGREGATION,
LEGACY_MULTISIG,
MERKLE_ROOT_MULTISIG,
MESSAGE_ID_MULTISIG,
NULL, // used with relayer carrying no metadata
CCIP_READ
}

/**
* @notice Returns an enum that represents the type of security model
* encoded by this ISM.
* @dev Relayers infer how to fetch and format metadata.
*/
function moduleType() external view returns (uint8);

/**
* @notice Defines a security model responsible for verifying interchain
* messages based on the provided metadata.
* @param _metadata Off-chain metadata provided by a relayer, specific to
* the security model encoded by the module (e.g. validator signatures)
* @param _message Hyperlane encoded interchain message
* @return True if the message was verified
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) external returns (bool);
}
info

Hooks目前期望元数据采用StandardHookMetadata library

你也可以继承我们的AbstractMessageIdAuthorizedIsm,它允许对中间的verifyMessageId函数调用进行访问控制,如果它是从授权的AbstractMessageIdAuthHook钩子接收到的,则将messageId设置为true并存储起来。这种模式目前在OpStackHook <> OpStackIsm 模式中使用。

Workflow

接口

在实现了上述接口之后,您可以通过使用我们邮箱中重载的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 bsctestnet TestRecipient
IMailbox mailbox = IMailbox("0xEf9F292fcEBC3848bF4bB92a96a04F9ECBb78E59");
IPostDispatchHook merkleTree = IPostDispatchHook("0x221FA9CBaFcd6c1C3d206571Cf4427703e023FFa");
mailbox.dispatch(
97,
"0x0000000000000000000000006489d13AcAd3B8dce4c5B31f375DE4f9451E7b38",
bytes("Hello, world"),
"0x", // empty metadata
merkleTree
);
  • 在源链上,

    • mailbox.dispatch()通过AbstractMessageIdAuthHook.postDispatch()调用您的自定义钩子。
    • _postDispatch检查latestDispatchedId是否是从钩子调用中分派的id,以确保邮箱是调用钩子的合约(因为调用postDispatch没有访问控制)。
    • _sendMessageId调用您的自定义外部桥接逻辑,例如调用CCIP路由合约。
  • 在目标链上,

    • 外部桥将调用verifyMessageId函数(受访问控制)并将messageId设置为verifiedMessages映射中的 true。
    • 在接收到消息后,邮箱将调用您的ISM合约(在您的接收者地址中指定),该合约将检查verifiedMessages映射中的messageId是否为true,并向邮箱返回true,反之亦然。
warning

AbstractMessageIdAuthorizedIsm可以通过postDispatch调用发送msg.value,我们利用verifiedMessages的小端 255 位来存储msg.value,并使用顶部位来表示messageId传递的实际接收情况。因此,您可以从源链发送高达2^255数量的原生代币,并且目标ISM只能在目标链上接收2^255 数量的原生代币。

访问控制

如果postDispatch必须只能使用刚刚发送的message调用,那么可以使用Mailbox上的latestDispatchedId函数来验证消息是否确实已经被发送。

info

这样做是为了支持组合,其中一个钩子可能会将message传递给另一个钩子,而不是使用require(mailbox == msg.sender)

为了方便起见,以下实用程序在MailboxClient中提供。

}

function _isLatestDispatched(bytes32 id) internal view returns (bool) {