#contract #cosmwasm #channel #cosmwasm-contracts #account #ica #host

bin+lib cw-ica-controller

这是一个CosmWasm实现的ICS-27跨链账户控制器

12个版本 (6个重大更新)

0.20.0 2024年8月13日
0.6.1 2024年7月21日
0.6.0 2024年6月18日
0.5.0 2024年2月5日
0.1.1 2023年7月16日

#1001 in 魔法豆

Download history 123/week @ 2024-05-06 181/week @ 2024-05-13 32/week @ 2024-05-20 4/week @ 2024-06-03 52/week @ 2024-06-10 819/week @ 2024-06-17 42/week @ 2024-06-24 5/week @ 2024-07-01 317/week @ 2024-07-15 129/week @ 2024-07-22 215/week @ 2024-07-29 24/week @ 2024-08-05

每月下载量 685

MIT/Apache

555KB
6K SLoC

Go 3.5K SLoC // 0.2% comments Rust 2.5K SLoC // 0.0% comments

CosmWasm ICA 控制器合约

E2E Status Tag License: Apache-2.0

cw-ica-controller

这是一个与对方链上的 ica/host 模块通信的 CosmWasm 智能合约,用于创建和管理一个跨链账户。此合约还可以根据跨链账户交易的结果执行回调。由于这是一个完整的 ICA 控制器实现,因此此合约部署所在的链不需要启用 ICA 模块。此外,对方链也不需要支持 CosmWasm

有关此合约的文档网站在此处:这里.

目录

用法

以下是对合约功能的简要概述。(您还可以在 e2e 目录中查看合约在端到端测试中的各种使用方式。)

创建跨链账户

此合约提供了两种创建跨链账户的方法

  1. 使用 InstantiateMsg
  2. 使用 ExecuteMsg::CreateChannel

使用 InstantiateMsg

此合约仅接受自身发送的 MsgChannelOpenInit 消息。中继器永远不能使用此合约发起通道握手。

InstantiateMsg 总是发起通道握手,这就是为什么 channel_open_init_options 字段不是可选的。

/// The message to instantiate the ICA controller contract.
#[cw_serde]
pub struct InstantiateMsg {
    /// The address of the owner of the ICA application.
    /// If not specified, the sender is the owner.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub owner: Option<String>,
    /// The options to initialize the IBC channel upon contract instantiation.
    pub channel_open_init_options: options::ChannelOpenInitOptions,
    /// The contract address that the channel and packet lifecycle callbacks are sent to.
    /// If not specified, then no callbacks are sent.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub send_callbacks_to: Option<String>,
}

使用 ExecuteMsg::CreateChannel

如果 InstantiateMsg 中的 channel_open_init_options 字段格式错误,导致无法成功握手,合约所有者可以提交一个带有新的 channel_open_init_optionsExecuteMsg::CreateChannel

pub enum ExecuteMsg {
    /// `CreateChannel` makes the contract submit a stargate MsgChannelOpenInit to the chain.
    /// This is a wrapper around [`options::ChannelOpenInitOptions`] and thus requires the
    /// same fields. If not specified, then the options specified in the contract instantiation
    /// are used.
    CreateChannel {
        /// The options to initialize the IBC channel.
        /// If not specified, the options specified in the contract instantiation are used.
        /// Must be `None` if the sender is not the owner.
        #[serde(skip_serializing_if = "Option::is_none")]
        channel_open_init_options: Option<options::ChannelOpenInitOptions>,
    },

    // ...
}

如果通道因超时而关闭,合约所有者可以提交一个带有 channel_open_init_options: NoneExecuteMsg::CreateChannel 来创建一个与上次通道开启相同的 channel_open_init_options。有关通道关闭和重启的更多信息,请参阅此处

执行跨链账户交易

ExecuteMsg::SendCosmosMsgs 用于提交要发送到主链的包。它接受要发送到主链的 cosmwasm_std::CosmosMsg。 (合约然后将这些消息转换为 protobuf 消息并发送到主链。您可以使用 CosmosMsg::Stargate 执行任何自定义消息。)

CosmWasm 合约中,CosmosMsg 用于在合约部署的链上执行交易。在此合约中,我们使用 CosmosMsg 在主链(对方链)上执行交易。这是通过将 CosmosMsg 转换为 protobuf ICA 交易来实现的。然后,ICA 交易被发送到主链。主链执行 ICA 交易并将结果发送回此合约。

此执行消息允许用户提交一个 cosmwasm_std::CosmosMsg 数组,然后由合约将其转换为原子 ICA 交易。

pub enum ExecuteMsg {
    // ...

    /// `SendCosmosMsgs` converts the provided array of [`CosmosMsg`] to an ICA tx and sends them to the ICA host.
    /// [`CosmosMsg::Stargate`] and [`CosmosMsg::Wasm`] are only supported if the [`TxEncoding`](crate::ibc::types::metadata::TxEncoding) is [`TxEncoding::Protobuf`](crate::ibc::types::metadata::TxEncoding).
    ///
    /// **This is the recommended way to send messages to the ICA host.**
    SendCosmosMsgs {
        /// The stargate messages to convert and send to the ICA host.
        #[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
        messages: Vec<CosmosMsg>,
        /// The stargate queries to convert and send to the ICA host.
        /// The queries are executed after the messages.
        #[cfg(feature = "query")]
        #[serde(skip_serializing_if = "Vec::is_empty")]
        #[serde(default)]
        #[serde_as(deserialize_as = "serde_with::DefaultOnNull")]
        queries: Vec<cosmwasm_std::QueryRequest<cosmwasm_std::Empty>>,
        /// Optional memo to include in the ibc packet.
        #[serde(skip_serializing_if = "Option::is_none")]
        packet_memo: Option<String>,
        /// Optional timeout in seconds to include with the ibc packet.
        /// If not specified, the [default timeout](crate::ibc::types::packet::DEFAULT_TIMEOUT_SECONDS) is used.
        #[serde(skip_serializing_if = "Option::is_none")]
        timeout_seconds: Option<u64>,
    },

    // ...
}

CosmosMsg::Stargate 允许用户将任何 protobuf 消息提交到主链。)

以下是一个示例执行消息,它将代币委托给主链上的验证器,然后对提案进行投票(原子化)。

{
  "send_cosmos_msgs":{
    "messages":[
      {
        "staking":{
          "delegate":{
            "validator":"validatorAddress",
            "amount":{
              "denom":"uatom",
              "amount":"10000000"
            }
          }
        }
      },
      {
        "gov":{
          "vote":{
            "proposal_id":1,
            "vote":"yes"
          }
        }
      }
    ]
  }
}

查询主链

此合约还支持查询主链。为此,您可以提交一个带有查询字段填写好的 ExecuteMsg::SendCosmosMsgs。查询总是在消息之后执行,并且其结果被反序列化并返回在 回调 中。

此功能仅在主链(对方链)运行在 ibc-go v7.5+ 时才有效。如果主链在旧版本上,则包将返回错误确认。

CosmosMsg类似,在CosmWasm合约中,使用QueryRequest来执行合约部署链上的查询。在这个合约中,我们使用QueryRequest作为在宿主(对方)链上的交易来执行查询。这是通过将QueryRequests转换为protobuf ICA tx来实现的。然后,ICA tx被发送到宿主链。宿主链执行ICA tx并将结果发送回此合约。

注意,如果同时提供了messagesqueries,则queries将在messages之后执行。

messages不同,并非所有查询请求都受到支持,因为在CosmosSDK中,查询执行通常不是确定的。有关受支持的查询请求的文档,请参阅此处

执行回调

此合约支持外部合约回调。有关受支持的回调信息,请参阅src/types/callbacks.rs。此合约目前仅支持将回调发送到单个合约。您可以在实例化时注册回调合约地址,或稍后使用ExecuteMsg::UpdateCallbackAddress更新它。

回调合约必须在它的ExecuteMsg枚举中包含以下变体

use cosmwasm_schema::cw_serde;
use cw_ica_controller::types::callbacks::IcaControllerCallbackMsg;

#[cw_serde]
pub enum ExecuteMsg {
    // ... other variants

    /// The callback message from the ICA controller contract.
    ReceiveIcaCallback(IcaControllerCallbackMsg),
}

请注意,这个crate还包括一个proc-macro,可以将ReceiveIcaCallback变体添加到ExecuteMsg枚举中。这是通过将以下宏添加到回调合约来实现的

use cosmwasm_schema::cw_serde;
use cw_ica_controller::helpers::ica_callback_execute;

#[ica_callback_execute]
#[cw_serde]
/// This is the execute message of the contract.
pub enum ExecuteMsg {
    // ... other variants
}

任何将cw-ica-controller作为库导入的合约都需要禁用cw-ica-controller crate的default-features。这是因为cw-ica-controller crate的default-features包括了CosmWasm入口点。

[dependencies]
cw-ica-controller = { version = "0.6.0", default-features = false }

通道关闭和重新打开

通道关闭

如果ICA通道是有序的,那么由于超时的数据包,ICA通道可能会关闭。否则,用户可以通过提交ExecuteMsg::CloseChannel消息来关闭通道。

通道重启

如果ICA通道关闭,合约随后可以创建一个新的具有相同跨链账户地址的通道,并继续使用相同的跨链账户。为此,您需要提交一个ExecuteMsg::CreateChannel。请注意,在创建新通道时可以更改channel_open_init_options。如果用户想更改通道的顺序,这很有用。

演示

本项目在Injective Illuminate Hackathon和XION ABSTRACTATHON获奖项目Tokenized Interchain AccountsNomos Abstraction on Xion中使用。

注入式启迪黑客松

每个NFT控制一个跨链账户。以下是本项目的演示

XION ABSTRACTATHON

使用Nomos SDK和ICA控制器在Injective上从Xion购买和出售NFT

构建

我们使用cosmwasm/optimizer docker镜像来构建合约。此项目使用just作为任务运行器。要安装just,请运行以下命令

cargo install just

要构建合约,请运行以下命令

just build-optimize

测试

此存储库中有两种测试:单元测试和端到端测试。单元测试位于src目录中的Rust文件内。端到端测试位于e2e目录。

单元测试

一般来说,单元测试用于测试握手的验证函数,以及测试序列化和反序列化是否正确工作。要运行单元测试,请运行

just unit-tests

端到端测试

端到端测试用于测试合约在模拟生产环境中的功能。为了测试它是否能够执行通道握手、发送数据包和执行回调。我们通过运行两个本地链来实现这一点,一个用于合约,另一个用于宿主链。然后使用中继器执行通道握手和发送数据包。合约然后根据数据包的结果执行回调。有关端到端测试的更多信息,请参阅e2e目录中的Readme

发布

此合约遵循语义版本控制,但有以下偏差

  • 主版本号将在合约审计后才标记。
  • 所有API破坏性更改和大多数状态机破坏性更改将导致次版本号升级。

限制

此合约不打算在生产环境中使用。它旨在作为如何构建一个可以与golang ica/host模块通信的CosmWasm合约的参考实现。以下是一些此合约的限制

  • 合约无法创建多个跨链账户。它只能创建一个。

致谢

非常感谢Art3mixCyberHoward的所有有益讨论。还要感谢0xekez,他们的cw-ibc-example工作,这对于CosmWasm IBC端点和interchaintest是一个很好的参考。

依赖项

~18MB
~375K SLoC