From 2c6e84d7f0b496c607f19b8e1235a968dd9feaa9 Mon Sep 17 00:00:00 2001 From: Tomasz Kulik Date: Mon, 27 Jan 2025 12:23:12 +0100 Subject: [PATCH] feat: Add TransferV2 --- .../ibc-callbacks/schema/ibc-callbacks.json | 5 + .../ibc-callbacks/schema/raw/execute.json | 5 + contracts/ibc-callbacks/src/contract.rs | 66 +++-- contracts/ibc-callbacks/src/msg.rs | 2 + .../schema/ibc-reflect-send.json | 120 ++++++++- .../schema/ibc/packet_msg.json | 120 ++++++++- .../ibc-reflect-send/schema/raw/execute.json | 120 ++++++++- .../ibc-reflect/schema/ibc/packet_msg.json | 120 ++++++++- contracts/reflect/schema/raw/execute.json | 120 ++++++++- contracts/reflect/schema/reflect.json | 120 ++++++++- packages/go-gen/src/schema.rs | 1 + packages/go-gen/tests/cosmwasm_std__IbcMsg.go | 118 +++++--- packages/std/src/ibc.rs | 74 ++++- packages/std/src/ibc/transfer_msg_builder.rs | 14 +- .../std/src/ibc/transfer_msg_builder_v2.rs | 252 ++++++++++++++++++ packages/std/src/lib.rs | 12 +- 16 files changed, 1199 insertions(+), 70 deletions(-) create mode 100644 packages/std/src/ibc/transfer_msg_builder_v2.rs diff --git a/contracts/ibc-callbacks/schema/ibc-callbacks.json b/contracts/ibc-callbacks/schema/ibc-callbacks.json index 6b34f4afc8..61a6a88756 100644 --- a/contracts/ibc-callbacks/schema/ibc-callbacks.json +++ b/contracts/ibc-callbacks/schema/ibc-callbacks.json @@ -23,6 +23,7 @@ "type": "object", "required": [ "channel_id", + "channel_version", "timeout_seconds", "to_address" ], @@ -40,6 +41,10 @@ "description": "The channel to send the packet through", "type": "string" }, + "channel_version": { + "description": "IBC channel version", + "type": "string" + }, "timeout_seconds": { "description": "The amount of seconds from now the transfer should timeout at", "type": "integer", diff --git a/contracts/ibc-callbacks/schema/raw/execute.json b/contracts/ibc-callbacks/schema/raw/execute.json index e5bed95bb4..c3c1bc297a 100644 --- a/contracts/ibc-callbacks/schema/raw/execute.json +++ b/contracts/ibc-callbacks/schema/raw/execute.json @@ -12,6 +12,7 @@ "type": "object", "required": [ "channel_id", + "channel_version", "timeout_seconds", "to_address" ], @@ -29,6 +30,10 @@ "description": "The channel to send the packet through", "type": "string" }, + "channel_version": { + "description": "IBC channel version", + "type": "string" + }, "timeout_seconds": { "description": "The amount of seconds from now the transfer should timeout at", "type": "integer", diff --git a/contracts/ibc-callbacks/src/contract.rs b/contracts/ibc-callbacks/src/contract.rs index cd2f269f26..a74543b72f 100644 --- a/contracts/ibc-callbacks/src/contract.rs +++ b/contracts/ibc-callbacks/src/contract.rs @@ -1,7 +1,7 @@ use cosmwasm_std::{ entry_point, to_json_binary, Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse, IbcDestinationCallbackMsg, IbcDstCallback, IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, - MessageInfo, Response, StdError, StdResult, TransferMsgBuilder, + MessageInfo, Response, StdError, StdResult, TransferMsgBuilder, TransferMsgBuilderV2, }; use crate::msg::{CallbackType, ExecuteMsg, QueryMsg}; @@ -35,6 +35,7 @@ pub fn execute( channel_id, timeout_seconds, callback_type, + channel_version, } => execute_transfer( env, info, @@ -42,6 +43,7 @@ pub fn execute( channel_id, timeout_seconds, callback_type, + channel_version, ), } } @@ -53,6 +55,7 @@ fn execute_transfer( channel_id: String, timeout_seconds: u32, callback_type: CallbackType, + channel_version: String, ) -> StdResult { let src_callback = IbcSrcCallback { address: env.contract.address, @@ -62,30 +65,55 @@ fn execute_transfer( address: to_address.clone(), gas_limit: None, }; - let coin = match &*info.funds { - [coin] if !coin.amount.is_zero() => coin, + + let transfer_msg = match channel_version.as_str() { + "V1" => { + let coin = match &*info.funds { + [coin] if !coin.amount.is_zero() => coin, + _ => { + return Err(StdError::generic_err( + "Must send exactly one denom to trigger ics-20 transfer", + )) + } + }; + let builder = TransferMsgBuilder::new( + channel_id, + to_address.clone(), + coin.clone(), + IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)), + ); + match callback_type { + CallbackType::Both => builder + .with_src_callback(src_callback) + .with_dst_callback(dst_callback) + .build(), + CallbackType::Src => builder.with_src_callback(src_callback).build(), + CallbackType::Dst => builder.with_dst_callback(dst_callback).build(), + } + } + "V2" => { + let builder = TransferMsgBuilderV2::new( + channel_id, + to_address.clone(), + info.funds.into_iter().map(Into::into).collect(), + IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)), + ); + match callback_type { + CallbackType::Both => builder + .with_src_callback(src_callback) + .with_dst_callback(dst_callback) + .build(), + CallbackType::Src => builder.with_src_callback(src_callback).build(), + CallbackType::Dst => builder.with_dst_callback(dst_callback).build(), + } + } _ => { return Err(StdError::generic_err( - "Must send exactly one denom to trigger ics-20 transfer", + "Must specify \"V1\" or \"V2\" channel version", )) } }; - let builder = TransferMsgBuilder::new( - channel_id, - to_address.clone(), - coin.clone(), - IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)), - ); - let transfer_msg = match callback_type { - CallbackType::Both => builder - .with_src_callback(src_callback) - .with_dst_callback(dst_callback) - .build(), - CallbackType::Src => builder.with_src_callback(src_callback).build(), - CallbackType::Dst => builder.with_dst_callback(dst_callback).build(), - }; - Ok(Response::new() .add_message(transfer_msg) .add_attribute("action", "execute")) diff --git a/contracts/ibc-callbacks/src/msg.rs b/contracts/ibc-callbacks/src/msg.rs index d5cdb38f96..8d6355d32c 100644 --- a/contracts/ibc-callbacks/src/msg.rs +++ b/contracts/ibc-callbacks/src/msg.rs @@ -20,6 +20,8 @@ pub enum ExecuteMsg { /// Who should receive callbacks for the message #[serde(default)] callback_type: CallbackType, + /// IBC channel version + channel_version: String, }, } diff --git a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json index 3c91ffab8e..e1a658496f 100644 --- a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json +++ b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json @@ -364,6 +364,25 @@ "type": "object", "additionalProperties": false }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -402,8 +421,24 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -458,6 +493,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -662,10 +753,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/ibc-reflect-send/schema/ibc/packet_msg.json b/contracts/ibc-reflect-send/schema/ibc/packet_msg.json index 974ced2dc5..28013e6d35 100644 --- a/contracts/ibc-reflect-send/schema/ibc/packet_msg.json +++ b/contracts/ibc-reflect-send/schema/ibc/packet_msg.json @@ -305,6 +305,25 @@ "type": "object", "additionalProperties": false }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -343,8 +362,24 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -399,6 +434,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -603,10 +694,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json index 8841eded49..ea1c9e93e3 100644 --- a/contracts/ibc-reflect-send/schema/raw/execute.json +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -353,6 +353,25 @@ "type": "object", "additionalProperties": false }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -391,8 +410,24 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -447,6 +482,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -651,10 +742,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/ibc-reflect/schema/ibc/packet_msg.json b/contracts/ibc-reflect/schema/ibc/packet_msg.json index eec0371bd4..bb5a66c993 100644 --- a/contracts/ibc-reflect/schema/ibc/packet_msg.json +++ b/contracts/ibc-reflect/schema/ibc/packet_msg.json @@ -334,6 +334,25 @@ "type": "object", "additionalProperties": false }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -403,6 +422,22 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcAcknowledgement": { "type": "object", "required": [ @@ -445,7 +480,7 @@ "additionalProperties": false }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -500,6 +535,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -743,10 +834,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index 60689b4e44..cc3326f952 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -407,6 +407,25 @@ } ] }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -476,6 +495,22 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcAcknowledgement": { "type": "object", "required": [ @@ -518,7 +553,7 @@ "additionalProperties": false }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -573,6 +608,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -978,10 +1069,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index 9a4c0e5364..3a7296df75 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -417,6 +417,25 @@ } ] }, + "Forwarding": { + "type": "object", + "required": [ + "hops", + "memo" + ], + "properties": { + "hops": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + }, + "memo": { + "type": "string" + } + }, + "additionalProperties": false + }, "GovMsg": { "description": "This message type allows the contract interact with the [x/gov] module in order to cast votes.\n\n[x/gov]: https://github.com/cosmos/cosmos-sdk/tree/v0.45.12/x/gov\n\n## Examples\n\nCast a simple vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); use cosmwasm_std::{GovMsg, VoteOption};\n\n#[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::Vote { proposal_id: 4, option: VoteOption::Yes, })) } ```\n\nCast a weighted vote:\n\n``` # use cosmwasm_std::{ # HexBinary, # Storage, Api, Querier, DepsMut, Deps, entry_point, Env, StdError, MessageInfo, # Response, QueryResponse, # }; # type ExecuteMsg = (); # #[cfg(feature = \"cosmwasm_1_2\")] use cosmwasm_std::{Decimal, GovMsg, VoteOption, WeightedVoteOption};\n\n# #[cfg(feature = \"cosmwasm_1_2\")] #[entry_point] pub fn execute( deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { // ... Ok(Response::new().add_message(GovMsg::VoteWeighted { proposal_id: 4, options: vec![ WeightedVoteOption { option: VoteOption::Yes, weight: Decimal::percent(65), }, WeightedVoteOption { option: VoteOption::Abstain, weight: Decimal::percent(35), }, ], })) } ```", "oneOf": [ @@ -486,6 +505,22 @@ } ] }, + "Hop": { + "type": "object", + "required": [ + "channel_id", + "port_id" + ], + "properties": { + "channel_id": { + "type": "string" + }, + "port_id": { + "type": "string" + } + }, + "additionalProperties": false + }, "IbcAcknowledgement": { "type": "object", "required": [ @@ -528,7 +563,7 @@ "additionalProperties": false }, "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", + "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points)", "oneOf": [ { "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", @@ -583,6 +618,62 @@ }, "additionalProperties": false }, + { + "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", + "type": "object", + "required": [ + "transfer_v2" + ], + "properties": { + "transfer_v2": { + "type": "object", + "required": [ + "channel_id", + "forwarding", + "timeout", + "to_address", + "tokens" + ], + "properties": { + "channel_id": { + "description": "existing channel to send the tokens over", + "type": "string" + }, + "forwarding": { + "$ref": "#/definitions/Forwarding" + }, + "memo": { + "description": "An optional memo. See the blog post [\"Moving Beyond Simple Token Transfers\"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information.\n\nThere is no difference between setting this to `None` or an empty string.\n\nThis field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead.", + "type": [ + "string", + "null" + ] + }, + "timeout": { + "description": "when packet times out, measured on remote chain", + "allOf": [ + { + "$ref": "#/definitions/IbcTimeout" + } + ] + }, + "to_address": { + "description": "address on the remote chain to receive these tokens", + "type": "string" + }, + "tokens": { + "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", + "type": "array", + "items": { + "$ref": "#/definitions/Token" + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", "type": "object", @@ -988,10 +1079,37 @@ } ] }, + "Token": { + "type": "object", + "required": [ + "amount", + "base", + "trace" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint256" + }, + "base": { + "type": "string" + }, + "trace": { + "type": "array", + "items": { + "$ref": "#/definitions/Hop" + } + } + }, + "additionalProperties": false + }, "Uint128": { "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", "type": "string" }, + "Uint256": { + "description": "An implementation of u256 that is using strings for JSON encoding/decoding, such that the full u256 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances out of primitive uint types or `new` to provide big endian bytes:\n\n``` # use cosmwasm_std::Uint256; let a = Uint256::from(258u128); let b = Uint256::new([ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8, ]); assert_eq!(a, b); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/packages/go-gen/src/schema.rs b/packages/go-gen/src/schema.rs index 71955dd63d..9b41461d1b 100644 --- a/packages/go-gen/src/schema.rs +++ b/packages/go-gen/src/schema.rs @@ -286,6 +286,7 @@ pub fn custom_type_of(ty: &str) -> Option<&str> { match ty { "Uint64" => Some("Uint64"), "Uint128" => Some("string"), + "Uint256" => Some("string"), "Int64" => Some("Int64"), "Int128" => Some("string"), "Binary" => Some("[]byte"), diff --git a/packages/go-gen/tests/cosmwasm_std__IbcMsg.go b/packages/go-gen/tests/cosmwasm_std__IbcMsg.go index 992b258393..7985170710 100644 --- a/packages/go-gen/tests/cosmwasm_std__IbcMsg.go +++ b/packages/go-gen/tests/cosmwasm_std__IbcMsg.go @@ -1,14 +1,41 @@ type TransferMsg struct { - Amount Coin `json:"amount"` - ChannelID string `json:"channel_id"` - Memo string `json:"memo,omitempty"` // this is not yet in wasmvm, but will be soon - Timeout IBCTimeout `json:"timeout"` - ToAddress string `json:"to_address"` + // packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20 + Amount Coin `json:"amount"` + // existing channel to send the tokens over + ChannelID string `json:"channel_id"` + // An optional memo. See the blog post ["Moving Beyond Simple Token Transfers"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information. + // + // There is no difference between setting this to `None` or an empty string. + // + // This field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead. + Memo string `json:"memo,omitempty"` + // when packet times out, measured on remote chain + Timeout IBCTimeout `json:"timeout"` + // address on the remote chain to receive these tokens + ToAddress string `json:"to_address"` +} +type TransferV2Msg struct { + // existing channel to send the tokens over + ChannelID string `json:"channel_id"` + Forwarding Forwarding `json:"forwarding"` + // An optional memo. See the blog post ["Moving Beyond Simple Token Transfers"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) for more information. + // + // There is no difference between setting this to `None` or an empty string. + // + // This field is only supported on chains with CosmWasm >= 2.0 and silently ignored on older chains. If you need support for both 1.x and 2.x chain with the same codebase, it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer protobuf encoder instead. + Memo string `json:"memo,omitempty"` + // when packet times out, measured on remote chain + Timeout IBCTimeout `json:"timeout"` + // address on the remote chain to receive these tokens + ToAddress string `json:"to_address"` + // packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20 + Tokens Array[Token] `json:"tokens"` } type SendPacketMsg struct { - ChannelID string `json:"channel_id"` - Data []byte `json:"data"` - Timeout IBCTimeout `json:"timeout"` + ChannelID string `json:"channel_id"` + Data []byte `json:"data"` + // when packet times out, measured on remote chain + Timeout IBCTimeout `json:"timeout"` } type WriteAcknowledgementMsg struct { // The acknowledgement to send back @@ -27,7 +54,9 @@ type PayPacketFeeMsg struct { Fee IBCFee `json:"fee"` // The port id on the chain where the packet is sent from (this chain). PortID string `json:"port_id"` - // Allowlist of relayer addresses that can receive the fee. This is currently not implemented and *must* be empty. + // Allowlist of relayer addresses that can receive the fee. An empty list means that any relayer can receive the fee. + // + // This is currently not implemented and *must* be empty. Relayers Array[string] `json:"relayers"` } type PayPacketFeeAsyncMsg struct { @@ -36,27 +65,53 @@ type PayPacketFeeAsyncMsg struct { Fee IBCFee `json:"fee"` // The port id on the chain where the packet is sent from (this chain). PortID string `json:"port_id"` - // Allowlist of relayer addresses that can receive the fee. This is currently not implemented and *must* be empty. + // Allowlist of relayer addresses that can receive the fee. An empty list means that any relayer can receive the fee. + // + // This is currently not implemented and *must* be empty. Relayers Array[string] `json:"relayers"` // The sequence number of the packet that should be incentivized. Sequence uint64 `json:"sequence"` } +// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 7 entry points) type IBCMsg struct { - Transfer *TransferMsg `json:"transfer,omitempty"` - SendPacket *SendPacketMsg `json:"send_packet,omitempty"` + // Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to. + Transfer *TransferMsg `json:"transfer,omitempty"` + // Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to. + TransferV2 *TransferV2Msg `json:"transfer_v2,omitempty"` + // Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this. + SendPacket *SendPacketMsg `json:"send_packet,omitempty"` + // Acknowledges a packet that this contract received over IBC. This allows acknowledging a packet that was not acknowledged yet in the `ibc_packet_receive` call. WriteAcknowledgement *WriteAcknowledgementMsg `json:"write_acknowledgement,omitempty"` - CloseChannel *CloseChannelMsg `json:"close_channel,omitempty"` - PayPacketFee *PayPacketFeeMsg `json:"pay_packet_fee,omitempty"` - PayPacketFeeAsync *PayPacketFeeAsyncMsg `json:"pay_packet_fee_async,omitempty"` + // This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port + CloseChannel *CloseChannelMsg `json:"close_channel,omitempty"` + // Incentivizes the next IBC packet sent after this message with a fee. Note that this does not necessarily have to be a packet sent by this contract. The fees are taken from the contract's balance immediately and locked until the packet is handled. + // + // # Example + // + // Most commonly, you will attach this message to a response right before sending a packet using [`IbcMsg::SendPacket`] or [`IbcMsg::Transfer`]. + // + // ```rust # use cosmwasm_std::{IbcMsg, IbcEndpoint, IbcFee, IbcTimeout, Coin, coins, CosmosMsg, Response, Timestamp}; + // + // let incentivize = IbcMsg::PayPacketFee { port_id: "transfer".to_string(), channel_id: "source-channel".to_string(), fee: IbcFee { receive_fee: coins(100, "token"), ack_fee: coins(201, "token"), timeout_fee: coins(200, "token"), }, relayers: vec![], }; let transfer = IbcMsg::Transfer { channel_id: "source-channel".to_string(), to_address: "receiver".to_string(), amount: Coin::new(100u32, "token"), timeout: IbcTimeout::with_timestamp(Timestamp::from_nanos(0)), memo: None, }; + // + // # #[cfg(feature = "stargate")] let _: Response = Response::new() .add_message(CosmosMsg::Ibc(incentivize)) .add_message(CosmosMsg::Ibc(transfer)); ``` + PayPacketFee *PayPacketFeeMsg `json:"pay_packet_fee,omitempty"` + // Incentivizes the existing IBC packet with the given port, channel and sequence with a fee. Note that this does not necessarily have to be a packet sent by this contract. The fees are taken from the contract's balance immediately and locked until the packet is handled. They are added to the existing fees on the packet. + PayPacketFeeAsync *PayPacketFeeAsyncMsg `json:"pay_packet_fee_async,omitempty"` } - -// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int) type Coin struct { - Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456" - Denom string `json:"denom"` // type, eg. "ATOM" + Amount string `json:"amount"` + Denom string `json:"denom"` +} +type Forwarding struct { + Hops Array[Hop] `json:"hops"` + Memo string `json:"memo"` +} +type Hop struct { + ChannelID string `json:"channel_id"` + PortID string `json:"port_id"` } - type IBCAcknowledgement struct { Data []byte `json:"data"` } @@ -66,22 +121,21 @@ type IBCFee struct { TimeoutFee Array[Coin] `json:"timeout_fee"` } -// IBCTimeout is the timeout for an IBC packet. At least one of block and timestamp is required. +// In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set. type IBCTimeout struct { - Block *IBCTimeoutBlock `json:"block,omitempty"` // in wasmvm, this does not have "omitempty" - // Nanoseconds since UNIX epoch - Timestamp *Uint64 `json:"timestamp,omitempty"` + Block *IBCTimeoutBlock `json:"block,omitempty"` + Timestamp *Uint64 `json:"timestamp,omitempty"` } -// IBCTimeoutBlock Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and -// freezing clients. -// Ordering is (revision_number, timeout_height) +// IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height) type IBCTimeoutBlock struct { - // block height after which the packet times out. - // the height within the given revision + // block height after which the packet times out. the height within the given revision Height uint64 `json:"height"` - // the version that the client is currently on - // (eg. after resetting the chain this could increment 1 as height drops to 0) + // the version that the client is currently on (e.g. after resetting the chain this could increment 1 as height drops to 0) Revision uint64 `json:"revision"` } +type Token struct { + Amount string `json:"amount"` + Base string `json:"base"` + Trace Array[Hop] `json:"trace"` +} diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 5612cf5ebb..52165dfbff 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -4,22 +4,60 @@ use core::cmp::{Ord, Ordering, PartialOrd}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::vec; use crate::coin::Coin; -use crate::prelude::*; use crate::results::{Attribute, CosmosMsg, Empty, Event, SubMsg}; use crate::StdResult; +use crate::{prelude::*, Uint256}; use crate::{to_json_binary, Binary}; use crate::{Addr, Timestamp}; mod callbacks; mod transfer_msg_builder; +mod transfer_msg_builder_v2; pub use callbacks::*; pub use transfer_msg_builder::*; +pub use transfer_msg_builder_v2::*; + +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct Token { + base: String, + trace: Vec, + amount: Uint256, +} + +impl From for Token { + fn from(w: Coin) -> Token { + Token { + base: w.denom, + trace: vec![], + amount: w.amount.into(), + } + } +} + +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)] +#[serde(rename_all = "snake_case")] +pub struct Forwarding { + hops: Vec, + memo: String, +} + +#[non_exhaustive] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct Hop { + port_id: String, + channel_id: String, +} /// These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts -/// (contracts that directly speak the IBC protocol via 6 entry points) +/// (contracts that directly speak the IBC protocol via 7 entry points) #[non_exhaustive] #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] @@ -52,6 +90,38 @@ pub enum IbcMsg { /// protobuf encoder instead. memo: Option, }, + /// Sends bank tokens owned by the contract to the given address on another chain. + /// The channel must already be established between the ibctransfer module on this chain + /// and a matching module on the remote chain. + /// We cannot select the port_id, this is whatever the local chain has bound the ibctransfer + /// module to. + TransferV2 { + /// existing channel to send the tokens over + channel_id: String, + /// address on the remote chain to receive these tokens + to_address: String, + /// packet data only supports one coin + /// https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20 + tokens: Vec, + /// when packet times out, measured on remote chain + timeout: IbcTimeout, + /// An optional memo. See the blog post + /// ["Moving Beyond Simple Token Transfers"](https://medium.com/the-interchain-foundation/moving-beyond-simple-token-transfers-d42b2b1dc29b) + /// for more information. + /// + /// There is no difference between setting this to `None` or an empty string. + /// + /// This field is only supported on chains with CosmWasm >= 2.0 and silently + /// ignored on older chains. + /// If you need support for both 1.x and 2.x chain with the same codebase, + /// it is recommended to use `CosmosMsg::Stargate` with a custom MsgTransfer + /// protobuf encoder instead. + memo: Option, + // a struct containing the list of next hops, + // determining where the tokens must be forwarded next, + // and the memo for the final hop + forwarding: Forwarding, + }, /// Sends an IBC packet with given data over the existing channel. /// Data should be encoded in a format defined by the channel version, /// and the module on the other side should know how to parse this. diff --git a/packages/std/src/ibc/transfer_msg_builder.rs b/packages/std/src/ibc/transfer_msg_builder.rs index 484ef4038b..830966eefe 100644 --- a/packages/std/src/ibc/transfer_msg_builder.rs +++ b/packages/std/src/ibc/transfer_msg_builder.rs @@ -7,21 +7,25 @@ use crate::{ #[derive(Clone, Debug, PartialEq, Eq)] pub struct EmptyMemo; #[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub struct WithMemo { - memo: String, + pub memo: String, } #[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub struct WithSrcCallback { - src_callback: IbcSrcCallback, + pub src_callback: IbcSrcCallback, } #[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub struct WithDstCallback { - dst_callback: IbcDstCallback, + pub dst_callback: IbcDstCallback, } #[derive(Clone, Debug, PartialEq, Eq)] +#[non_exhaustive] pub struct WithCallbacks { - src_callback: IbcSrcCallback, - dst_callback: IbcDstCallback, + pub src_callback: IbcSrcCallback, + pub dst_callback: IbcDstCallback, } pub trait MemoSource { diff --git a/packages/std/src/ibc/transfer_msg_builder_v2.rs b/packages/std/src/ibc/transfer_msg_builder_v2.rs new file mode 100644 index 0000000000..0202ab2dbe --- /dev/null +++ b/packages/std/src/ibc/transfer_msg_builder_v2.rs @@ -0,0 +1,252 @@ +use crate::{IbcDstCallback, IbcMsg, IbcSrcCallback, IbcTimeout}; + +use super::{ + EmptyMemo, Forwarding, MemoSource, Token, WithCallbacks, WithDstCallback, WithMemo, + WithSrcCallback, +}; + +impl TransferMsgBuilderV2 { + pub fn build(self) -> IbcMsg { + IbcMsg::TransferV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: self.memo.into_memo(), + forwarding: self.forwarding, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct TransferMsgBuilderV2 { + channel_id: String, + to_address: String, + tokens: Vec, + timeout: IbcTimeout, + memo: MemoData, + forwarding: Forwarding, +} + +impl TransferMsgBuilderV2 { + /// Creates a new transfer message with the given parameters and no memo. + pub fn new( + channel_id: impl Into, + to_address: impl Into, + tokens: Vec, + timeout: impl Into, + ) -> Self { + Self { + channel_id: channel_id.into(), + to_address: to_address.into(), + tokens, + timeout: timeout.into(), + memo: EmptyMemo, + forwarding: Forwarding::default(), + } + } + + /// Adds a memo text to the transfer message. + pub fn with_memo(self, memo: impl Into) -> TransferMsgBuilderV2 { + TransferMsgBuilderV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: WithMemo { memo: memo.into() }, + forwarding: self.forwarding, + } + } + + /// Adds an IBC source callback entry to the memo field. + /// Use this if you want to receive IBC callbacks on the source chain. + /// + /// For more info check out [`crate::IbcSourceCallbackMsg`]. + pub fn with_src_callback( + self, + src_callback: IbcSrcCallback, + ) -> TransferMsgBuilderV2 { + TransferMsgBuilderV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: WithSrcCallback { src_callback }, + forwarding: self.forwarding, + } + } + + /// Adds an IBC destination callback entry to the memo field. + /// Use this if you want to receive IBC callbacks on the destination chain. + /// + /// For more info check out [`crate::IbcDestinationCallbackMsg`]. + pub fn with_dst_callback( + self, + dst_callback: IbcDstCallback, + ) -> TransferMsgBuilderV2 { + TransferMsgBuilderV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: WithDstCallback { dst_callback }, + forwarding: self.forwarding, + } + } +} + +impl TransferMsgBuilderV2 { + /// Adds an IBC destination callback entry to the memo field. + /// Use this if you want to receive IBC callbacks on the destination chain. + /// + /// For more info check out [`crate::IbcDestinationCallbackMsg`]. + pub fn with_dst_callback( + self, + dst_callback: IbcDstCallback, + ) -> TransferMsgBuilderV2 { + TransferMsgBuilderV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: WithCallbacks { + src_callback: self.memo.src_callback, + dst_callback, + }, + forwarding: self.forwarding, + } + } +} + +impl TransferMsgBuilderV2 { + /// Adds an IBC source callback entry to the memo field. + /// Use this if you want to receive IBC callbacks on the source chain. + /// + /// For more info check out [`crate::IbcSourceCallbackMsg`]. + pub fn with_src_callback( + self, + src_callback: IbcSrcCallback, + ) -> TransferMsgBuilderV2 { + TransferMsgBuilderV2 { + channel_id: self.channel_id, + to_address: self.to_address, + tokens: self.tokens, + timeout: self.timeout, + memo: WithCallbacks { + src_callback, + dst_callback: self.memo.dst_callback, + }, + forwarding: self.forwarding, + } + } +} + +#[cfg(test)] +mod tests { + use crate::{coin, to_json_string, Addr, IbcCallbackRequest, Timestamp, Uint64}; + + use super::*; + + #[test] + fn test_transfer_msg_builder() { + let src_callback = IbcSrcCallback { + address: Addr::unchecked("src"), + gas_limit: Some(Uint64::new(12345)), + }; + let dst_callback = IbcDstCallback { + address: "dst".to_string(), + gas_limit: None, + }; + + let empty_memo_builder = TransferMsgBuilderV2::new( + "channel-0", + "cosmos1example", + vec![coin(10, "ucoin").into()], + Timestamp::from_seconds(12345), + ); + + let empty = empty_memo_builder.clone().build(); + let with_memo = empty_memo_builder.clone().with_memo("memo").build(); + + let with_src_callback_builder = empty_memo_builder + .clone() + .with_src_callback(src_callback.clone()); + let with_src_callback = with_src_callback_builder.clone().build(); + let with_dst_callback_builder = empty_memo_builder + .clone() + .with_dst_callback(dst_callback.clone()); + let with_dst_callback = with_dst_callback_builder.clone().build(); + + let with_both_callbacks1 = with_src_callback_builder + .with_dst_callback(dst_callback.clone()) + .build(); + + let with_both_callbacks2 = with_dst_callback_builder + .with_src_callback(src_callback.clone()) + .build(); + + // assert all the different messages + assert_eq!( + empty, + IbcMsg::TransferV2 { + channel_id: "channel-0".to_string(), + to_address: "cosmos1example".to_string(), + tokens: vec![coin(10, "ucoin").into()], + timeout: Timestamp::from_seconds(12345).into(), + memo: None, + forwarding: Forwarding::default() + } + ); + assert_eq!( + with_memo, + IbcMsg::TransferV2 { + channel_id: "channel-0".to_string(), + to_address: "cosmos1example".to_string(), + tokens: vec![coin(10, "ucoin").into()], + timeout: Timestamp::from_seconds(12345).into(), + memo: Some("memo".to_string()), + forwarding: Forwarding::default() + } + ); + assert_eq!( + with_src_callback, + IbcMsg::TransferV2 { + channel_id: "channel-0".to_string(), + to_address: "cosmos1example".to_string(), + tokens: vec![coin(10, "ucoin").into()], + timeout: Timestamp::from_seconds(12345).into(), + memo: Some( + to_json_string(&IbcCallbackRequest::source(src_callback.clone())).unwrap() + ), + forwarding: Forwarding::default() + } + ); + assert_eq!( + with_dst_callback, + IbcMsg::TransferV2 { + channel_id: "channel-0".to_string(), + to_address: "cosmos1example".to_string(), + tokens: vec![coin(10, "ucoin").into()], + timeout: Timestamp::from_seconds(12345).into(), + memo: Some( + to_json_string(&IbcCallbackRequest::destination(dst_callback.clone())).unwrap() + ), + forwarding: Forwarding::default() + } + ); + assert_eq!( + with_both_callbacks1, + IbcMsg::TransferV2 { + channel_id: "channel-0".to_string(), + to_address: "cosmos1example".to_string(), + tokens: vec![coin(10, "ucoin").into()], + timeout: Timestamp::from_seconds(12345).into(), + memo: Some( + to_json_string(&IbcCallbackRequest::both(src_callback, dst_callback)).unwrap() + ), + forwarding: Forwarding::default(), + } + ); + assert_eq!(with_both_callbacks1, with_both_callbacks2); + } +} diff --git a/packages/std/src/lib.rs b/packages/std/src/lib.rs index df970fa6eb..6c96b4acd6 100644 --- a/packages/std/src/lib.rs +++ b/packages/std/src/lib.rs @@ -70,12 +70,12 @@ pub use crate::eureka::{EurekaMsg, EurekaPayload}; pub use crate::hex_binary::HexBinary; pub use crate::ibc::IbcChannelOpenResponse; pub use crate::ibc::{ - Ibc3ChannelOpenResponse, IbcAckCallbackMsg, IbcAcknowledgement, IbcBasicResponse, - IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg, - IbcDestinationCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFee, IbcMsg, IbcOrder, IbcPacket, - IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, IbcReceiveResponse, - IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, IbcTimeoutCallbackMsg, - TransferMsgBuilder, + Forwarding, Hop, Ibc3ChannelOpenResponse, IbcAckCallbackMsg, IbcAcknowledgement, + IbcBasicResponse, IbcCallbackRequest, IbcChannel, IbcChannelCloseMsg, IbcChannelConnectMsg, + IbcChannelOpenMsg, IbcDestinationCallbackMsg, IbcDstCallback, IbcEndpoint, IbcFee, IbcMsg, + IbcOrder, IbcPacket, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg, + IbcReceiveResponse, IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout, IbcTimeoutBlock, + IbcTimeoutCallbackMsg, Token, TransferMsgBuilder, TransferMsgBuilderV2, }; #[cfg(feature = "iterator")] pub use crate::iterator::{Order, Record};