实施指南
一个新的链架构的 Hyperlane 实现由以下部分组成:
在开始之前,建议先查看协议文档。
1. 合约
以下描述了 Hyperlane 协议的链上合约规范。它使用 Solidity 类型以便于理解,但所有内容都应可推广到其他语言。
address
应被解释为本地链的地址类型。payable
描述允许调用者传递本地代币的函数。- 确保所有重要状态变化都正确发出事件。
- 清楚地记录任何与参考实现的偏差及其理由。
一些需要考虑的事项
字节表示:
- 请注意,不同链可能有不同的本地类型来表示字节。例如,StarkNet 使用 felt252 作为合约地址,这可能无法完全容纳其他链使用的 32 字节地址。
- 在处理跨链地址时,实施适当的转换 和验证机制。
序列化:
- 请密切关注消息字段的序列化方式,特别是对于可变长度数据(如消息体)。
- 确保所使用的序列化方法(例如,abi.encodePacked 等效)在不同链实现中表现一致。
消息
消息是 Hyperlane 协议使用的核心数据结构。它是一个打包的数据结构,包含了从一个域路由消息到另一个域所需的所有信息。
struct Message {
// 原始和目标邮箱的版本
uint8 version,
// 唯一标识消息的随机数
uint32 nonce,
// 原链的域
uint32 origin,
// 原链上发送者的地址
bytes32 sender,
// 目标链的域
uint32 destination,
// 目标链上接收者的地址
bytes32 recipient,
// 消息体的原始字节
bytes body
}
邮箱
邮箱是开发者发送和接收消息的入口点。确保 localDomain
是不可变的,以防止未经授权的更改,这可能会危及跨链安全。
实现:
信息
除了默认和自定义钩子,Hyperlane 引入了 必需钩子 的概念,用于对所有调度进行后处理。确保在默认或自定义钩子之前调用必需钩子。
调度
将消息调度到目标域和接收者。
function dispatch(
// 目标链的域
uint32 destination,
// 目标链上接收者的地址(以 bytes32 表示)
bytes32 recipient,
// 消息体的原始字节内容
bytes body
) returns (
// 插入到邮箱的默克尔树中的消息 ID
bytes32 messageId
);
将消息调度到目标域和接收者,并提供默认钩子的元数据。
function dispatch(
// 目标链的域
uint32 destination,
// 目标链上接收者的地址(以 bytes32 表示)
bytes32 recipient,
// 消息体的原始字节内容
bytes body,
// 默认后调度钩子使用的元数据
bytes defaultHookMetadata
) returns (
// 插入到邮箱的默克尔树中的消息 ID
bytes32 messageId
);
将消息调度到目标域和接收者,并提供自定义钩子使用的元数据,以替代默认钩子。
function dispatch(
// 目标链的域
uint32 destination,
// 目标链上接收者的地址(以 bytes32 表示)
bytes32 recipient,
// 消息体的原始字节内容
bytes body,
// 自定义后调度钩子使用的元数据
bytes customHookMetadata,
// 自定义钩子以替代默认钩子
IPostDispatchHook customHook
) returns (
// 插入到邮箱的默克尔树中的消息 ID
bytes32 messageId
);
处理
尝试将 message
交付给其接收者。通过接收者的 ISM 验证 message
,使用提供的 metadata
。
function process(
// ISM 用于验证消息的元数据。
bytes metadata,
// 字节打包的消息
bytes message
);
latestDispatchedId
返回用于后调度钩子身份验证的最新调度消息 ID。
function latestDispatchedId() public view returns (bytes32);