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 魔法豆
每月下载量 685
555KB
6K SLoC
CosmWasm
ICA 控制器合约
这是一个与对方链上的 ica/host 模块通信的
CosmWasm
智能合约,用于创建和管理一个跨链账户。此合约还可以根据跨链账户交易的结果执行回调。由于这是一个完整的 ICA 控制器实现,因此此合约部署所在的链不需要启用 ICA 模块。此外,对方链也不需要支持 CosmWasm
。
有关此合约的文档网站在此处:这里.
目录
用法
以下是对合约功能的简要概述。(您还可以在 e2e
目录中查看合约在端到端测试中的各种使用方式。)
创建跨链账户
此合约提供了两种创建跨链账户的方法
- 使用
InstantiateMsg
- 使用
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_options
的 ExecuteMsg::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: None
的 ExecuteMsg::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并将结果发送回此合约。
注意,如果同时提供了messages
和queries
,则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 Accounts,Nomos 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
合约的参考实现。以下是一些此合约的限制
- 合约无法创建多个跨链账户。它只能创建一个。
致谢
非常感谢Art3mix和CyberHoward的所有有益讨论。还要感谢0xekez,他们的cw-ibc-example工作,这对于CosmWasm
IBC端点和interchaintest是一个很好的参考。
依赖项
~18MB
~375K SLoC