diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cfb63fdc3..0028a4fa0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,12 @@ and this project adheres to ([#1299]) - cosmwasm-vm: A new import `abort` is created to abort contract execution when requested by the contract. ([#1299]) +- cosmwasm-std: Add new `ibc3` feature that allows to use IBC-Go V3 features, + like version negotiation and exposing relayer address to the contract. + Requires a compatible wasmd runtime (v0.27.0+) ([#1302]) [#1299]: https://github.com/CosmWasm/cosmwasm/pull/1299 +[#1302]: https://github.com/CosmWasm/cosmwasm/pull/1302 ## [1.0.0-rc.0] - 2022-05-05 diff --git a/contracts/ibc-reflect-send/src/ibc.rs b/contracts/ibc-reflect-send/src/ibc.rs index c6d395a0d3..dca8cbf78c 100644 --- a/contracts/ibc-reflect-send/src/ibc.rs +++ b/contracts/ibc-reflect-send/src/ibc.rs @@ -9,7 +9,7 @@ use crate::ibc_msg::{ }; use crate::state::{accounts, AccountData}; -pub const IBC_VERSION: &str = "ibc-reflect-v1"; +pub const IBC_APP_VERSION: &str = "ibc-reflect-v1"; // TODO: make configurable? /// packets live one hour @@ -23,18 +23,18 @@ pub fn ibc_channel_open(_deps: DepsMut, _env: Env, msg: IbcChannelOpenMsg) -> St if channel.order != IbcOrder::Ordered { return Err(StdError::generic_err("Only supports ordered channels")); } - if channel.version.as_str() != IBC_VERSION { + if channel.version.as_str() != IBC_APP_VERSION { return Err(StdError::generic_err(format!( "Must set version to `{}`", - IBC_VERSION + IBC_APP_VERSION ))); } if let Some(counter_version) = msg.counterparty_version() { - if counter_version != IBC_VERSION { + if counter_version != IBC_APP_VERSION { return Err(StdError::generic_err(format!( "Counterparty version must be `{}`", - IBC_VERSION + IBC_APP_VERSION ))); } } @@ -249,13 +249,14 @@ mod tests { // connect will run through the entire handshake to set up a proper connect and // save the account (tested in detail in `proper_handshake_flow`) fn connect(mut deps: DepsMut, channel_id: &str) { - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = + mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); // first we try to open with a valid handshake ibc_channel_open(deps.branch(), mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res = ibc_channel_connect(deps.branch(), mock_env(), handshake_connect).unwrap(); // this should send a WhoAmI request, which is received some blocks later @@ -284,14 +285,15 @@ mod tests { fn enforce_version_in_handshake() { let mut deps = setup(); - let wrong_order = mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_VERSION); + let wrong_order = + mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_APP_VERSION); ibc_channel_open(deps.as_mut(), mock_env(), wrong_order).unwrap_err(); let wrong_version = mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, "reflect"); ibc_channel_open(deps.as_mut(), mock_env(), wrong_version).unwrap_err(); let valid_handshake = - mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(deps.as_mut(), mock_env(), valid_handshake).unwrap(); } diff --git a/contracts/ibc-reflect-send/tests/integration.rs b/contracts/ibc-reflect-send/tests/integration.rs index 79d9860112..c0c2977b83 100644 --- a/contracts/ibc-reflect-send/tests/integration.rs +++ b/contracts/ibc-reflect-send/tests/integration.rs @@ -31,7 +31,7 @@ use cosmwasm_vm::testing::{ }; use cosmwasm_vm::{from_slice, Instance}; -use ibc_reflect_send::ibc::IBC_VERSION; +use ibc_reflect_send::ibc::IBC_APP_VERSION; use ibc_reflect_send::ibc_msg::{AcknowledgementMsg, PacketMsg, WhoAmIResponse}; use ibc_reflect_send::msg::{AccountResponse, AdminResponse, ExecuteMsg, InstantiateMsg, QueryMsg}; @@ -56,13 +56,13 @@ fn setup() -> Instance { // save the account (tested in detail in `proper_handshake_flow`) fn connect(deps: &mut Instance, channel_id: &str) { // open packet has no counterparty version, connect does - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); // first we try to open with a valid handshake ibc_channel_open(deps, mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res: IbcBasicResponse = ibc_channel_connect(deps, mock_env(), handshake_connect).unwrap(); // this should send a WhoAmI request, which is received some blocks later @@ -103,13 +103,14 @@ fn instantiate_works() { fn enforce_version_in_handshake() { let mut deps = setup(); - let wrong_order = mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_VERSION); + let wrong_order = mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_APP_VERSION); ibc_channel_open(&mut deps, mock_env(), wrong_order).unwrap_err(); let wrong_version = mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, "reflect"); ibc_channel_open(&mut deps, mock_env(), wrong_version).unwrap_err(); - let valid_handshake = mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_VERSION); + let valid_handshake = + mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(&mut deps, mock_env(), valid_handshake).unwrap(); } diff --git a/contracts/ibc-reflect/Cargo.toml b/contracts/ibc-reflect/Cargo.toml index 7a9a760a60..0622414f35 100644 --- a/contracts/ibc-reflect/Cargo.toml +++ b/contracts/ibc-reflect/Cargo.toml @@ -32,7 +32,7 @@ cranelift = ["cosmwasm-vm/cranelift"] backtraces = ["cosmwasm-std/backtraces", "cosmwasm-vm/backtraces"] [dependencies] -cosmwasm-std = { path = "../../packages/std", features = ["iterator", "staking", "stargate"] } +cosmwasm-std = { path = "../../packages/std", features = ["iterator", "ibc3"] } cosmwasm-storage = { path = "../../packages/storage", features = ["iterator"] } schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/contracts/ibc-reflect/schema/packet_msg.json b/contracts/ibc-reflect/schema/packet_msg.json index d32112a8b6..1517ce5597 100644 --- a/contracts/ibc-reflect/schema/packet_msg.json +++ b/contracts/ibc-reflect/schema/packet_msg.json @@ -153,30 +153,6 @@ }, "additionalProperties": false }, - { - "type": "object", - "required": [ - "staking" - ], - "properties": { - "staking": { - "$ref": "#/definitions/StakingMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "distribution" - ], - "properties": { - "distribution": { - "$ref": "#/definitions/DistributionMsg" - } - }, - "additionalProperties": false - }, { "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", "type": "object", @@ -240,55 +216,6 @@ } ] }, - "DistributionMsg": { - "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "set_withdraw_address" - ], - "properties": { - "set_withdraw_address": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "description": "The `withdraw_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "withdraw_delegator_reward" - ], - "properties": { - "withdraw_delegator_reward": { - "type": "object", - "required": [ - "validator" - ], - "properties": { - "validator": { - "description": "The `validator_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, "Empty": { "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", "type": "object" @@ -477,90 +404,6 @@ } } }, - "StakingMsg": { - "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "delegate" - ], - "properties": { - "delegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "undelegate" - ], - "properties": { - "undelegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "redelegate" - ], - "properties": { - "redelegate": { - "type": "object", - "required": [ - "amount", - "dst_validator", - "src_validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "dst_validator": { - "type": "string" - }, - "src_validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", "allOf": [ diff --git a/contracts/ibc-reflect/src/contract.rs b/contracts/ibc-reflect/src/contract.rs index db2b6d5cb3..a43e581461 100644 --- a/contracts/ibc-reflect/src/contract.rs +++ b/contracts/ibc-reflect/src/contract.rs @@ -1,9 +1,10 @@ use cosmwasm_std::{ entry_point, from_slice, to_binary, wasm_execute, BankMsg, Binary, CosmosMsg, Deps, DepsMut, - Empty, Env, Event, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, - IbcChannelOpenMsg, IbcOrder, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, - IbcReceiveResponse, MessageInfo, Order, QueryResponse, Reply, Response, StdError, StdResult, - SubMsg, SubMsgResponse, SubMsgResult, WasmMsg, + Empty, Env, Event, Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, + IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcOrder, IbcPacketAckMsg, + IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, MessageInfo, Order, + QueryResponse, Reply, Response, StdError, StdResult, SubMsg, SubMsgResponse, SubMsgResult, + WasmMsg, }; use crate::msg::{ @@ -12,7 +13,7 @@ use crate::msg::{ }; use crate::state::{accounts, accounts_read, config, pending_channel, Config}; -pub const IBC_VERSION: &str = "ibc-reflect-v1"; +pub const IBC_APP_VERSION: &str = "ibc-reflect-v1"; pub const RECEIVE_DISPATCH_ID: u64 = 1234; pub const INIT_CALLBACK_ID: u64 = 7890; @@ -116,29 +117,32 @@ pub fn query_list_accounts(deps: Deps) -> StdResult { #[entry_point] /// enforces ordering and versioing constraints -pub fn ibc_channel_open(_deps: DepsMut, _env: Env, msg: IbcChannelOpenMsg) -> StdResult<()> { +pub fn ibc_channel_open( + _deps: DepsMut, + _env: Env, + msg: IbcChannelOpenMsg, +) -> StdResult { let channel = msg.channel(); if channel.order != IbcOrder::Ordered { return Err(StdError::generic_err("Only supports ordered channels")); } - if channel.version.as_str() != IBC_VERSION { - return Err(StdError::generic_err(format!( - "Must set version to `{}`", - IBC_VERSION - ))); - } + // In ibcv3 we don't check the version string passed in the message + // and only check the counterparty version. if let Some(counter_version) = msg.counterparty_version() { - if counter_version != IBC_VERSION { + if counter_version != IBC_APP_VERSION { return Err(StdError::generic_err(format!( "Counterparty version must be `{}`", - IBC_VERSION + IBC_APP_VERSION ))); } } - Ok(()) + // We return the version we need (which could be different than the counterparty version) + Ok(Some(Ibc3ChannelOpenResponse { + version: IBC_APP_VERSION.to_string(), + })) } #[entry_point] @@ -365,13 +369,14 @@ mod tests { fn connect(mut deps: DepsMut, channel_id: &str, account: impl Into) { let account: String = account.into(); - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = + mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); // first we try to open with a valid handshake ibc_channel_open(deps.branch(), mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res = ibc_channel_connect(deps.branch(), mock_env(), handshake_connect).unwrap(); assert_eq!(1, res.messages.len()); assert_eq!(1, res.events.len()); @@ -408,14 +413,15 @@ mod tests { fn enforce_version_in_handshake() { let mut deps = setup(); - let wrong_order = mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_VERSION); + let wrong_order = + mock_ibc_channel_open_try("channel-12", IbcOrder::Unordered, IBC_APP_VERSION); ibc_channel_open(deps.as_mut(), mock_env(), wrong_order).unwrap_err(); let wrong_version = mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, "reflect"); ibc_channel_open(deps.as_mut(), mock_env(), wrong_version).unwrap_err(); let valid_handshake = - mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_open_try("channel-12", IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(deps.as_mut(), mock_env(), valid_handshake).unwrap(); } @@ -425,12 +431,13 @@ mod tests { let channel_id = "channel-1234"; // first we try to open with a valid handshake - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = + mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(deps.as_mut(), mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res = ibc_channel_connect(deps.as_mut(), mock_env(), handshake_connect).unwrap(); // and set up a reflect account assert_eq!(1, res.messages.len()); @@ -593,7 +600,7 @@ mod tests { assert_eq!(funds, balance); // close the channel - let channel = mock_ibc_channel_close_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let channel = mock_ibc_channel_close_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res = ibc_channel_close(deps.as_mut(), mock_env(), channel).unwrap(); // it pulls out all money from the reflect contract diff --git a/contracts/ibc-reflect/tests/integration.rs b/contracts/ibc-reflect/tests/integration.rs index f1a793ce7c..d28e3369a4 100644 --- a/contracts/ibc-reflect/tests/integration.rs +++ b/contracts/ibc-reflect/tests/integration.rs @@ -31,7 +31,7 @@ use cosmwasm_vm::testing::{ }; use cosmwasm_vm::{from_slice, Instance}; -use ibc_reflect::contract::{IBC_VERSION, RECEIVE_DISPATCH_ID}; +use ibc_reflect::contract::{IBC_APP_VERSION, RECEIVE_DISPATCH_ID}; use ibc_reflect::msg::{ AccountInfo, AccountResponse, AcknowledgementMsg, DispatchResponse, InstantiateMsg, ListAccountsResponse, PacketMsg, QueryMsg, ReflectExecuteMsg, @@ -77,12 +77,12 @@ fn connect( ) { let account: String = account.into(); // first we try to open with a valid handshake - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(deps, mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res: IbcBasicResponse = ibc_channel_connect(deps, mock_env(), handshake_connect).unwrap(); assert_eq!(1, res.messages.len()); assert_eq!(1, res.events.len()); @@ -120,13 +120,15 @@ fn instantiate_works() { fn enforce_version_in_handshake() { let mut deps = setup(); - let wrong_order = mock_ibc_channel_open_try("channel-1234", IbcOrder::Unordered, IBC_VERSION); + let wrong_order = + mock_ibc_channel_open_try("channel-1234", IbcOrder::Unordered, IBC_APP_VERSION); ibc_channel_open(&mut deps, mock_env(), wrong_order).unwrap_err(); let wrong_version = mock_ibc_channel_open_try("channel-1234", IbcOrder::Ordered, "reflect"); ibc_channel_open(&mut deps, mock_env(), wrong_version).unwrap_err(); - let valid_handshake = mock_ibc_channel_open_try("channel-1234", IbcOrder::Ordered, IBC_VERSION); + let valid_handshake = + mock_ibc_channel_open_try("channel-1234", IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(&mut deps, mock_env(), valid_handshake).unwrap(); } @@ -136,12 +138,12 @@ fn proper_handshake_flow() { let channel_id = "channel-432"; // first we try to open with a valid handshake - let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION); + let handshake_open = mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); ibc_channel_open(&mut deps, mock_env(), handshake_open).unwrap(); // then we connect (with counter-party version set) let handshake_connect = - mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION); + mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_APP_VERSION); let res: IbcBasicResponse = ibc_channel_connect(&mut deps, mock_env(), handshake_connect).unwrap(); // and set up a reflect account diff --git a/packages/std/Cargo.toml b/packages/std/Cargo.toml index 6092377a57..7893a98046 100644 --- a/packages/std/Cargo.toml +++ b/packages/std/Cargo.toml @@ -9,7 +9,7 @@ license = "Apache-2.0" readme = "README.md" [package.metadata.docs.rs] -features = ["stargate", "staking"] +features = ["stargate", "staking", "ibc3"] [features] default = ["iterator"] @@ -30,6 +30,9 @@ backtraces = [] # stargate enables stargate-dependent messages and queries, like raw protobuf messages # as well as ibc-related functionality stargate = [] +# ibc3 extends ibc messages with ibc-v3 only features. This should only be enabled on contracts +# that require these types. Without this, they get the smaller ibc-v1 API. +ibc3 = ["stargate"] [dependencies] base64 = "0.13.0" diff --git a/packages/std/src/exports.rs b/packages/std/src/exports.rs index b04b89c580..90f1880da4 100644 --- a/packages/std/src/exports.rs +++ b/packages/std/src/exports.rs @@ -15,8 +15,9 @@ use serde::de::DeserializeOwned; use crate::deps::OwnedDeps; #[cfg(feature = "stargate")] use crate::ibc::{ - IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, + IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, }; use crate::imports::{ExternalApi, ExternalQuerier, ExternalStorage}; use crate::memory::{alloc, consume_region, release_buffer, Region}; @@ -238,7 +239,7 @@ where /// - `E`: error type for responses #[cfg(feature = "stargate")] pub fn do_ibc_channel_open( - contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result<(), E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result, env_ptr: u32, msg_ptr: u32, ) -> u32 @@ -514,10 +515,10 @@ where #[cfg(feature = "stargate")] fn _do_ibc_channel_open( - contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result<(), E>, + contract_fn: &dyn Fn(DepsMut, Env, IbcChannelOpenMsg) -> Result, env_ptr: *mut Region, msg_ptr: *mut Region, -) -> ContractResult<()> +) -> ContractResult where Q: CustomQuery, E: ToString, diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 11c1973a4a..8f2505a4ec 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -6,6 +6,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::cmp::{Ord, Ordering, PartialOrd}; +#[cfg(feature = "ibc3")] +use crate::addresses::Addr; use crate::binary::Binary; use crate::coins::Coin; use crate::errors::StdResult; @@ -119,6 +121,7 @@ pub struct IbcChannel { pub endpoint: IbcEndpoint, pub counterparty_endpoint: IbcEndpoint, pub order: IbcOrder, + /// Note: in ibcv3 this may be "", in the IbcOpenChannel handshake messages pub version: String, /// The connection upon which this channel was created. If this is a multi-hop /// channel, we only expose the first hop. @@ -296,6 +299,19 @@ impl From for IbcChannel { } } +/// Note that this serializes as "null". +#[cfg(not(feature = "ibc3"))] +pub type IbcChannelOpenResponse = (); +/// This serializes either as "null" or a JSON object. +#[cfg(feature = "ibc3")] +pub type IbcChannelOpenResponse = Option; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Ibc3ChannelOpenResponse { + /// We can set the channel version to a different one than we were called with + pub version: String, +} + /// The message that is passed into `ibc_channel_connect` #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -391,12 +407,20 @@ impl From for IbcChannel { #[non_exhaustive] pub struct IbcPacketReceiveMsg { pub packet: IbcPacket, + #[cfg(feature = "ibc3")] + pub relayer: Addr, } impl IbcPacketReceiveMsg { + #[cfg(not(feature = "ibc3"))] pub fn new(packet: IbcPacket) -> Self { Self { packet } } + + #[cfg(feature = "ibc3")] + pub fn new(packet: IbcPacket, relayer: Addr) -> Self { + Self { packet, relayer } + } } /// The message that is passed into `ibc_packet_ack` @@ -405,15 +429,31 @@ impl IbcPacketReceiveMsg { pub struct IbcPacketAckMsg { pub acknowledgement: IbcAcknowledgement, pub original_packet: IbcPacket, + #[cfg(feature = "ibc3")] + pub relayer: Addr, } impl IbcPacketAckMsg { + #[cfg(not(feature = "ibc3"))] pub fn new(acknowledgement: IbcAcknowledgement, original_packet: IbcPacket) -> Self { Self { acknowledgement, original_packet, } } + + #[cfg(feature = "ibc3")] + pub fn new( + acknowledgement: IbcAcknowledgement, + original_packet: IbcPacket, + relayer: Addr, + ) -> Self { + Self { + acknowledgement, + original_packet, + relayer, + } + } } /// The message that is passed into `ibc_packet_timeout` @@ -421,12 +461,20 @@ impl IbcPacketAckMsg { #[non_exhaustive] pub struct IbcPacketTimeoutMsg { pub packet: IbcPacket, + #[cfg(feature = "ibc3")] + pub relayer: Addr, } impl IbcPacketTimeoutMsg { + #[cfg(not(feature = "ibc3"))] pub fn new(packet: IbcPacket) -> Self { Self { packet } } + + #[cfg(feature = "ibc3")] + pub fn new(packet: IbcPacket, relayer: Addr) -> Self { + Self { packet, relayer } + } } /// This is the return value for the majority of the ibc handlers. diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index 6f23bf0fb6..b3072e677b 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -35,9 +35,10 @@ pub use crate::errors::{ }; #[cfg(feature = "stargate")] pub use crate::ibc::{ - IbcAcknowledgement, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, - IbcChannelOpenMsg, IbcEndpoint, IbcMsg, IbcOrder, IbcPacket, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, IbcTimeout, IbcTimeoutBlock, + Ibc3ChannelOpenResponse, IbcAcknowledgement, IbcBasicResponse, IbcChannel, IbcChannelCloseMsg, + IbcChannelConnectMsg, IbcChannelOpenMsg, IbcChannelOpenResponse, IbcEndpoint, IbcMsg, IbcOrder, + IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + IbcTimeout, IbcTimeoutBlock, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record}; diff --git a/packages/std/src/mock.rs b/packages/std/src/mock.rs index f38e1544c0..3b0db5c1c6 100644 --- a/packages/std/src/mock.rs +++ b/packages/std/src/mock.rs @@ -330,23 +330,27 @@ pub fn mock_ibc_packet_recv( my_channel_id: &str, data: &impl Serialize, ) -> StdResult { - Ok(IbcPacketReceiveMsg::new(IbcPacket { - data: to_binary(data)?, - src: IbcEndpoint { - port_id: "their-port".to_string(), - channel_id: "channel-1234".to_string(), - }, - dest: IbcEndpoint { - port_id: "our-port".to_string(), - channel_id: my_channel_id.into(), + Ok(IbcPacketReceiveMsg::new( + IbcPacket { + data: to_binary(data)?, + src: IbcEndpoint { + port_id: "their-port".to_string(), + channel_id: "channel-1234".to_string(), + }, + dest: IbcEndpoint { + port_id: "our-port".to_string(), + channel_id: my_channel_id.into(), + }, + sequence: 27, + timeout: IbcTimeoutBlock { + revision: 1, + height: 12345678, + } + .into(), }, - sequence: 27, - timeout: IbcTimeoutBlock { - revision: 1, - height: 12345678, - } - .into(), - })) + #[cfg(feature = "ibc3")] + Addr::unchecked("relayer"), + )) } /// Creates a IbcPacket for testing ibc_packet_{ack,timeout}. You set a few key parameters that are @@ -384,7 +388,12 @@ pub fn mock_ibc_packet_ack( ) -> StdResult { let packet = mock_ibc_packet(my_channel_id, data)?; - Ok(IbcPacketAckMsg::new(ack, packet)) + Ok(IbcPacketAckMsg::new( + ack, + packet, + #[cfg(feature = "ibc3")] + Addr::unchecked("relayer"), + )) } /// Creates a IbcPacketTimeoutMsg for testing ibc_packet_timeout. You set a few key parameters that are @@ -395,7 +404,12 @@ pub fn mock_ibc_packet_timeout( my_channel_id: &str, data: &impl Serialize, ) -> StdResult { - mock_ibc_packet(my_channel_id, data).map(IbcPacketTimeoutMsg::new) + let packet = mock_ibc_packet(my_channel_id, data)?; + Ok(IbcPacketTimeoutMsg::new( + packet, + #[cfg(feature = "ibc3")] + Addr::unchecked("relayer"), + )) } /// The same type as cosmwasm-std's QuerierResult, but easier to reuse in diff --git a/packages/vm/Cargo.toml b/packages/vm/Cargo.toml index fc98a9c33f..d606602243 100644 --- a/packages/vm/Cargo.toml +++ b/packages/vm/Cargo.toml @@ -21,7 +21,7 @@ backtraces = [] iterator = ["cosmwasm-std/iterator"] staking = ["cosmwasm-std/staking"] # this enables all stargate-related functionality, including the ibc entry points -stargate = ["cosmwasm-std/stargate"] +stargate = ["cosmwasm-std/stargate", "cosmwasm-std/ibc3"] # Use cranelift backend instead of singlepass. This is required for development on Windows. cranelift = ["wasmer/cranelift"] # It's a bit unclear if interface_version_7 (CosmWasm 0.16) contracts are fully compatible diff --git a/packages/vm/src/calls.rs b/packages/vm/src/calls.rs index 7b2d6dfa2f..55ec230e5f 100644 --- a/packages/vm/src/calls.rs +++ b/packages/vm/src/calls.rs @@ -4,8 +4,9 @@ use wasmer::Val; use cosmwasm_std::{ContractResult, CustomMsg, Env, MessageInfo, QueryResponse, Reply, Response}; #[cfg(feature = "stargate")] use cosmwasm_std::{ - IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, + IbcChannelOpenMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, }; use crate::backend::{BackendApi, Querier, Storage}; @@ -218,7 +219,7 @@ pub fn call_ibc_channel_open( instance: &mut Instance, env: &Env, msg: &IbcChannelOpenMsg, -) -> VmResult> +) -> VmResult>> where A: BackendApi + 'static, S: Storage + 'static, @@ -227,7 +228,7 @@ where let env = to_vec(env)?; let msg = to_vec(msg)?; let data = call_ibc_channel_open_raw(instance, &env, &msg)?; - let result: ContractResult<()> = + let result: ContractResult> = from_slice(&data, deserialization_limits::RESULT_IBC_CHANNEL_OPEN)?; Ok(result) } diff --git a/packages/vm/src/testing/calls.rs b/packages/vm/src/testing/calls.rs index 286241b590..4c11640ed9 100644 --- a/packages/vm/src/testing/calls.rs +++ b/packages/vm/src/testing/calls.rs @@ -7,8 +7,9 @@ use serde::{de::DeserializeOwned, Serialize}; use cosmwasm_std::{ContractResult, CustomMsg, Env, MessageInfo, QueryResponse, Reply, Response}; #[cfg(feature = "stargate")] use cosmwasm_std::{ - IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, IbcPacketAckMsg, - IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, + Ibc3ChannelOpenResponse, IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, + IbcChannelOpenMsg, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, }; use crate::calls::{ @@ -144,7 +145,7 @@ pub fn ibc_channel_open( instance: &mut Instance, env: Env, msg: IbcChannelOpenMsg, -) -> ContractResult<()> +) -> ContractResult> where A: BackendApi + 'static, S: Storage + 'static,