diff --git a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json index 33fb5467c8..614690e809 100644 --- a/contracts/ibc-reflect-send/schema/ibc-reflect-send.json +++ b/contracts/ibc-reflect-send/schema/ibc-reflect-send.json @@ -393,6 +393,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -424,6 +456,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -462,6 +505,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/contracts/ibc-reflect-send/schema/packet_msg.json b/contracts/ibc-reflect-send/schema/packet_msg.json index ed5b77d0b8..ed4a17340e 100644 --- a/contracts/ibc-reflect-send/schema/packet_msg.json +++ b/contracts/ibc-reflect-send/schema/packet_msg.json @@ -331,6 +331,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -362,6 +394,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -400,6 +443,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/contracts/ibc-reflect-send/schema/raw/execute.json b/contracts/ibc-reflect-send/schema/raw/execute.json index db374275af..81d05d567e 100644 --- a/contracts/ibc-reflect-send/schema/raw/execute.json +++ b/contracts/ibc-reflect-send/schema/raw/execute.json @@ -382,6 +382,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -413,6 +445,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -451,6 +494,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/contracts/ibc-reflect-send/src/contract.rs b/contracts/ibc-reflect-send/src/contract.rs index 50d074f3a8..6502885f3c 100644 --- a/contracts/ibc-reflect-send/src/contract.rs +++ b/contracts/ibc-reflect-send/src/contract.rs @@ -81,6 +81,7 @@ pub fn handle_send_msgs( channel_id, data: to_binary(&packet)?, timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(), + packet_fee: None, }; let res = Response::new() @@ -109,6 +110,7 @@ pub fn handle_check_remote_balance( channel_id, data: to_binary(&packet)?, timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(), + packet_fee: None, }; let res = Response::new() @@ -157,6 +159,7 @@ pub fn handle_send_funds( to_address: remote_addr, amount, timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(), + packet_fee: None, }; let res = Response::new() diff --git a/contracts/ibc-reflect-send/src/ibc.rs b/contracts/ibc-reflect-send/src/ibc.rs index 76939acea8..5db64ac2b0 100644 --- a/contracts/ibc-reflect-send/src/ibc.rs +++ b/contracts/ibc-reflect-send/src/ibc.rs @@ -63,6 +63,7 @@ pub fn ibc_channel_connect( channel_id: channel_id.clone(), data: to_binary(&packet)?, timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(), + packet_fee: None, }; Ok(IbcBasicResponse::new() @@ -413,12 +414,14 @@ mod tests { to_address, amount, timeout, + packet_fee, }) => { assert_eq!(transfer_channel_id, channel_id.as_str()); assert_eq!(remote_addr, to_address.as_str()); assert_eq!(&coin(12344, "utrgd"), amount); assert!(timeout.block().is_none()); assert!(timeout.timestamp().is_some()); + assert!(packet_fee.is_none()); } o => panic!("unexpected message: {:?}", o), } diff --git a/contracts/ibc-reflect-send/tests/integration.rs b/contracts/ibc-reflect-send/tests/integration.rs index c0c2977b83..6e1d197021 100644 --- a/contracts/ibc-reflect-send/tests/integration.rs +++ b/contracts/ibc-reflect-send/tests/integration.rs @@ -234,12 +234,14 @@ fn send_remote_funds() { to_address, amount, timeout, + packet_fee, }) => { assert_eq!(transfer_channel_id, channel_id.as_str()); assert_eq!(remote_addr, to_address.as_str()); assert_eq!(&coin(12344, "utrgd"), amount); assert!(timeout.block().is_none()); assert!(timeout.timestamp().is_some()); + assert!(packet_fee.is_none()); } o => panic!("unexpected message: {:?}", o), } diff --git a/contracts/ibc-reflect/schema/packet_msg.json b/contracts/ibc-reflect/schema/packet_msg.json index 547c6fe054..c0fac668a3 100644 --- a/contracts/ibc-reflect/schema/packet_msg.json +++ b/contracts/ibc-reflect/schema/packet_msg.json @@ -318,6 +318,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -349,6 +381,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -387,6 +430,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/contracts/reflect/schema/raw/execute.json b/contracts/reflect/schema/raw/execute.json index 5460db7a9b..ddceb498dc 100644 --- a/contracts/reflect/schema/raw/execute.json +++ b/contracts/reflect/schema/raw/execute.json @@ -377,6 +377,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -408,6 +440,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -446,6 +489,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/contracts/reflect/schema/reflect.json b/contracts/reflect/schema/reflect.json index aa6f6da44c..5ab2abae6a 100644 --- a/contracts/reflect/schema/reflect.json +++ b/contracts/reflect/schema/reflect.json @@ -387,6 +387,38 @@ } ] }, + "IbcFee": { + "description": "An [ICS-29] IBC fee.\n\nThis is mapped to an [ibc.applications.fee.v1.Fee].\n\n[ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31", + "type": "object", + "required": [ + "ack", + "recv", + "timeout" + ], + "properties": { + "ack": { + "description": "The packet acknowledgement fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "recv": { + "description": "The packet receive fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + }, + "timeout": { + "description": "The packet timeout fee", + "type": "array", + "items": { + "$ref": "#/definitions/Coin" + } + } + } + }, "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)", "oneOf": [ @@ -418,6 +450,17 @@ "description": "exisiting channel to send the tokens over", "type": "string" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ @@ -456,6 +499,17 @@ "data": { "$ref": "#/definitions/Binary" }, + "packet_fee": { + "description": "When set, a [MsgPayPacketFee] with the provided fee is created and emitted before the packet is sent. `signer` gets filled automatically with the contract address. No relayer restrictions will be in place.\n\n[MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93", + "anyOf": [ + { + "$ref": "#/definitions/IbcFee" + }, + { + "type": "null" + } + ] + }, "timeout": { "description": "when packet times out, measured on remote chain", "allOf": [ diff --git a/packages/std/src/ibc.rs b/packages/std/src/ibc.rs index 1ce06432a6..c7a93060ec 100644 --- a/packages/std/src/ibc.rs +++ b/packages/std/src/ibc.rs @@ -36,6 +36,13 @@ pub enum IbcMsg { amount: Coin, /// when packet times out, measured on remote chain timeout: IbcTimeout, + /// When set, a [MsgPayPacketFee] with the provided fee is created and + /// emitted before the packet is sent. + /// `signer` gets filled automatically with the contract address. + /// No relayer restrictions will be in place. + /// + /// [MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93 + packet_fee: Option, }, /// Sends an IBC packet with given data over the existing channel. /// Data should be encoded in a format defined by the channel version, @@ -45,12 +52,35 @@ pub enum IbcMsg { data: Binary, /// when packet times out, measured on remote chain timeout: IbcTimeout, + /// When set, a [MsgPayPacketFee] with the provided fee is created and + /// emitted before the packet is sent. + /// `signer` gets filled automatically with the contract address. + /// No relayer restrictions will be in place. + /// + /// [MsgPayPacketFee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/tx.proto#L76-L93 + packet_fee: Option, }, /// This will close an existing channel that is owned by this contract. /// Port is auto-assigned to the contract's IBC port CloseChannel { channel_id: String }, } +/// An [ICS-29] IBC fee. +/// +/// This is mapped to an [ibc.applications.fee.v1.Fee]. +/// +/// [ICS-29]: https://github.com/cosmos/ibc-go/blob/v7.2.0/docs/middleware/ics29-fee/overview.md +/// [ibc.applications.fee.v1.Fee]: https://github.com/cosmos/ibc-go/blob/v7.2.0/proto/ibc/applications/fee/v1/fee.proto#L11-L31 +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)] +pub struct IbcFee { + /// The packet receive fee + pub recv: Vec, + /// The packet acknowledgement fee + pub ack: Vec, + /// The packet timeout fee + pub timeout: Vec, +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct IbcEndpoint { pub port_id: String, @@ -772,21 +802,43 @@ impl IbcReceiveResponse { #[cfg(test)] mod tests { + use std::vec; + + use crate::{coin, coins}; + use super::*; use serde_json_wasm::to_string; #[test] - // added this to check json format for go compat, as I was unsure how some messages are snake encoded - fn serialize_msg() { + // added this to check JSON format for Go compat, as I was unsure how some messages are snake encoded + fn ibc_msg_transfer_serialize() { + // without fee let msg = IbcMsg::Transfer { channel_id: "channel-123".to_string(), to_address: "my-special-addr".into(), amount: Coin::new(12345678, "uatom"), timeout: IbcTimeout::with_timestamp(Timestamp::from_nanos(1234567890)), + packet_fee: None, + }; + let encoded = to_string(&msg).unwrap(); + let expected = r#"{"transfer":{"channel_id":"channel-123","to_address":"my-special-addr","amount":{"denom":"uatom","amount":"12345678"},"timeout":{"block":null,"timestamp":"1234567890"},"packet_fee":null}}"#; + assert_eq!(encoded, expected); + + // with fee + let msg = IbcMsg::Transfer { + channel_id: "channel-123".to_string(), + to_address: "my-special-addr".into(), + amount: Coin::new(12345678, "uatom"), + timeout: IbcTimeout::with_timestamp(Timestamp::from_nanos(1234567890)), + packet_fee: Some(IbcFee { + recv: coins(123, "ucosm"), + ack: coins(42, "ucosm"), + timeout: vec![coin(12, "ucosm"), coin(17, "uwasm")], + }), }; let encoded = to_string(&msg).unwrap(); - let expected = r#"{"transfer":{"channel_id":"channel-123","to_address":"my-special-addr","amount":{"denom":"uatom","amount":"12345678"},"timeout":{"block":null,"timestamp":"1234567890"}}}"#; - assert_eq!(encoded.as_str(), expected); + let expected = r#"{"transfer":{"channel_id":"channel-123","to_address":"my-special-addr","amount":{"denom":"uatom","amount":"12345678"},"timeout":{"block":null,"timestamp":"1234567890"},"packet_fee":{"recv":[{"denom":"ucosm","amount":"123"}],"ack":[{"denom":"ucosm","amount":"42"}],"timeout":[{"denom":"ucosm","amount":"12"},{"denom":"uwasm","amount":"17"}]}}}"#; + assert_eq!(encoded, expected); } #[test]