Skip to main content

CCIP Read ISM

使用CcipReadIsm为开发人员验证链间消息提供了很大的灵活性。最终,每一种其他类型的ISM都可以实现为CCIP Read ISM,因此,当构建新的ISM时,我们鼓励构建CCIP Read ISM,因为所有中继集成工作已经完成。

对于CCIP Read ISM要记住的一个警告是,它们确实引入了对外部(到区块链)但自托管的API的依赖。如果这对您的用例来说是一个困难的障碍,您可能需要考虑其他消息验证技术。

在构建CCIP Read ISM之前,您有必要熟悉CCIP Read specification。该规范描述了一种通用协议,允许EVM兼容链上的智能合约查询和消费链下数据。

它是如何工作的

中继器会持续监听从Hyperlane Mailboxes发出的Dispatch事件。当消息被中继器发送和接收时,中继器将向目的ISM查询如何处理该消息以及是否交付成功的信息。

info

正确的moduleType变量需要在你的ISM上设置,以便中继知道这是一个CCIP Read ISM。为了确保正确配置,你可以从@hyperlane-xyz/core中的AbstractCcipReadIsm继承。

然后,中继器将在ISM上调用getOffchainVerifyInfo(bytes)函数来传递消息的内容。当出现下面 interface部分描述的OffchainLookup错误时,该函数应该恢复。

中继器将查询此还原消息中指定的端点,并将提供的响应和原始消息传递给目的地Mailboxprocess(bytes,bytes)函数。

接口

CcipReadIsm必须实现ICcipReadIsm接口,并且应该扩展AbstractCcipReadIsm,这是一个方便的协议,可以正确设置moduleType

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

import {IInterchainSecurityModule} from "../IInterchainSecurityModule.sol";

interface ICcipReadIsm is IInterchainSecurityModule {
/// @dev https://eips.ethereum.org/EIPS/eip-3668
/// @param sender the address of the contract making the call, usually address(this)
/// @param urls the URLs to query for offchain data
/// @param callData context needed for offchain service to service request
/// @param callbackFunction function selector to call with offchain information
/// @param extraData additional passthrough information to call callbackFunction with
error OffchainLookup(
address sender,
string[] urls,
bytes callData,
bytes4 callbackFunction,
bytes extraData
);

/**
* @notice Reverts with the data needed to query information offchain
* and be submitted via the origin mailbox
* @dev See https://eips.ethereum.org/EIPS/eip-3668 for more information
* @param _message data that will help construct the offchain query
*/
function getOffchainVerifyInfo(bytes calldata _message) external view;
}

配置

在开发CCIP Read ISM时,ChainlinkISM是一个很好的参考例子。ChainlinkISM用一组Chainlink oracle初始化,并验证所提供的价格feed数据是否已经由部分签名者进行了签名。

API

根据CCIP Read,链下API需要返回带有表单的JSON数据,

{
"data": "..."
}

中继器会将这个data属性作为metadata参数传递给Mailbox.Process (bytes metadata, bytes message)。

请注意,在链式ISM的情况下,数据的接收方也充当验证ISM,data只是发送的原始交易,以提交具有相关签名的价格数据。message属性有些多余。

合约

在设置ISM时,getOffchainVerifyInfoverify函数是需要指定的重要函数。

  • getOffchainVerifyInfo函数应该返回一个OffchainLookup错误,指示中继器查询给定的API端点。OffchainLookup错误允许提供一组API端点,因此你可以强制执行你想要的任何级别的冗余

  • verify必须获取提供的metadata并验证其合法性。同样,在为您自己的ISM开发此逻辑时,ChainlinkISM实现是一个非常棒的参考。

下面是CCIP Read ISM的示例,其中ISM也是消息的接收者,根据链链接ISM。

pragma solidity ^0.8.13;

import {AbstractCcipReadIsm} from "@hyperlane-xyz/core/contracts/isms/ccip-read/AbstractCcipReadIsm.sol";
import {IInterchainSecurityModule, ISpecifiesInterchainSecurityModule} from "@hyperlane-xyz/core/contracts/interfaces/IInterchainSecurityModule.sol";
import {IMailbox} from "@hyperlane-xyz/core/contracts/interfaces/IMailbox.sol";
import {Message} from "@hyperlane-xyz/core/contracts/libs/Message.sol";

contract MyCcipReadIsm is AbstractCcipReadIsm, ISpecifiesInterchainSecurityModule {
using Message for bytes;
IMailbox mailbox;

...

/**
* No-op, everything happens in the verify function
*/
function handle(uint32, bytes32, bytes calldata _report) public {}


/**
* @param _metadata ABI encoded module metadata
* @param _message Formatted Hyperlane message (see Message.sol).
*/
function verify(
bytes calldata _metadata,
bytes calldata _message
) external returns (bool) {
...
}

function interchainSecurityModule()
external
view
returns (IInterchainSecurityModule)
{
return IInterchainSecurityModule(address(this));
}

function getOffchainVerifyInfo(
bytes calldata _message
) external view override {
revert OffchainLookup(
address(this),
offchainUrls,
_message,
MyCcipReadIsm.process.selector,
_message
);
}

/**
* Provided for full CCIP Read specification compatibility. Relayers
* will call the Mailbox directly regardless of the selector specified
* in the `OffchainLookup` error
*/
function process(
bytes calldata _metadata,
bytes calldata _message
) external {
mailbox.process(_metadata, _message);
}
}