Skip to content

Commit d1de10f

Browse files
authored
Merge pull request #2196 from CosmWasm/co/ibc-fees
IBC Fees messages
2 parents 8f8f0ef + 39e31c1 commit d1de10f

File tree

15 files changed

+289
-25
lines changed

15 files changed

+289
-25
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ and this project adheres to
1414
These functions are meant to be used similarly to their JSON counterparts.
1515
[MessagePack](https://msgpack.org) is a more compact, binary encoding.
1616
([#2118])
17+
- cosmwasm-std: Add `IbcMsg::{PayPacketFee, PayPacketFeeAsync}` and
18+
`IbcQuery::FeeEnabledChannel` to allow contracts to incentivize IBC packets
19+
using IBC Fees. ([#2196])
1720

1821
[#2118]: https://github.com/CosmWasm/cosmwasm/pull/2118
22+
[#2196]: https://github.com/CosmWasm/cosmwasm/pull/2196
1923

2024
### Changed
2125

contracts/ibc-reflect/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ cranelift = ["cosmwasm-vm/cranelift"]
3030

3131
[dependencies]
3232
cosmwasm-schema = { path = "../../packages/schema" }
33-
cosmwasm-std = { path = "../../packages/std", features = ["iterator", "stargate", "cosmwasm_2_1"] }
33+
cosmwasm-std = { path = "../../packages/std", features = ["iterator", "stargate", "cosmwasm_2_2"] }
3434
schemars = "0.8.12"
3535
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
3636

3737
[dev-dependencies]
38-
cosmwasm-vm = { path = "../../packages/vm", default-features = false, features = ["iterator", "stargate"] }
38+
cosmwasm-vm = { path = "../../packages/vm", default-features = false, features = [
39+
"iterator",
40+
"stargate",
41+
] }

contracts/ibc-reflect/schema/ibc/packet_msg.json

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,35 @@
415415
},
416416
"additionalProperties": false
417417
},
418+
"IbcFee": {
419+
"type": "object",
420+
"required": [
421+
"ack_fee",
422+
"receive_fee",
423+
"timeout_fee"
424+
],
425+
"properties": {
426+
"ack_fee": {
427+
"type": "array",
428+
"items": {
429+
"$ref": "#/definitions/Coin"
430+
}
431+
},
432+
"receive_fee": {
433+
"type": "array",
434+
"items": {
435+
"$ref": "#/definitions/Coin"
436+
}
437+
},
438+
"timeout_fee": {
439+
"type": "array",
440+
"items": {
441+
"$ref": "#/definitions/Coin"
442+
}
443+
}
444+
},
445+
"additionalProperties": false
446+
},
418447
"IbcMsg": {
419448
"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)",
420449
"oneOf": [
@@ -566,6 +595,93 @@
566595
}
567596
},
568597
"additionalProperties": false
598+
},
599+
{
600+
"description": "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.\n\n# Example\n\nMost commonly, you will attach this message to a response right before sending a packet using [`IbcMsg::SendPacket`] or [`IbcMsg::Transfer`].\n\n```rust # use cosmwasm_std::{IbcMsg, IbcEndpoint, IbcFee, IbcTimeout, Coin, coins, CosmosMsg, Response, Timestamp};\n\nlet 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, };\n\n# #[cfg(feature = \"stargate\")] let _: Response = Response::new() .add_message(CosmosMsg::Ibc(incentivize)) .add_message(CosmosMsg::Ibc(transfer)); ```",
601+
"type": "object",
602+
"required": [
603+
"pay_packet_fee"
604+
],
605+
"properties": {
606+
"pay_packet_fee": {
607+
"type": "object",
608+
"required": [
609+
"channel_id",
610+
"fee",
611+
"port_id",
612+
"relayers"
613+
],
614+
"properties": {
615+
"channel_id": {
616+
"description": "The channel id on the chain where the packet is sent from (this chain).",
617+
"type": "string"
618+
},
619+
"fee": {
620+
"$ref": "#/definitions/IbcFee"
621+
},
622+
"port_id": {
623+
"description": "The port id on the chain where the packet is sent from (this chain).",
624+
"type": "string"
625+
},
626+
"relayers": {
627+
"description": "Allowlist of relayer addresses that can receive the fee. An empty list means that any relayer can receive the fee.\n\nThis is currently not implemented and *must* be empty.",
628+
"type": "array",
629+
"items": {
630+
"type": "string"
631+
}
632+
}
633+
},
634+
"additionalProperties": false
635+
}
636+
},
637+
"additionalProperties": false
638+
},
639+
{
640+
"description": "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.",
641+
"type": "object",
642+
"required": [
643+
"pay_packet_fee_async"
644+
],
645+
"properties": {
646+
"pay_packet_fee_async": {
647+
"type": "object",
648+
"required": [
649+
"channel_id",
650+
"fee",
651+
"port_id",
652+
"relayers",
653+
"sequence"
654+
],
655+
"properties": {
656+
"channel_id": {
657+
"description": "The channel id on the chain where the packet is sent from (this chain).",
658+
"type": "string"
659+
},
660+
"fee": {
661+
"$ref": "#/definitions/IbcFee"
662+
},
663+
"port_id": {
664+
"description": "The port id on the chain where the packet is sent from (this chain).",
665+
"type": "string"
666+
},
667+
"relayers": {
668+
"description": "Allowlist of relayer addresses that can receive the fee. An empty list means that any relayer can receive the fee.\n\nThis is currently not implemented and *must* be empty.",
669+
"type": "array",
670+
"items": {
671+
"type": "string"
672+
}
673+
},
674+
"sequence": {
675+
"description": "The sequence number of the packet that should be incentivized.",
676+
"type": "integer",
677+
"format": "uint64",
678+
"minimum": 0.0
679+
}
680+
},
681+
"additionalProperties": false
682+
}
683+
},
684+
"additionalProperties": false
569685
}
570686
]
571687
},

contracts/reflect/schema/raw/query.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@
357357
"additionalProperties": false
358358
},
359359
"IbcQuery": {
360-
"description": "These are queries to the various IBC modules to see the state of the contract's IBC connection. These will return errors if the contract is not \"ibc enabled\"",
360+
"description": "These are queries to the various IBC modules to see the state of the contract's IBC connection. Most of these will return errors if the contract is not \"ibc enabled\".",
361361
"oneOf": [
362362
{
363363
"description": "Gets the Port ID the current contract is bound to.\n\nReturns a `PortIdResponse`.",

contracts/reflect/schema/reflect.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1450,7 +1450,7 @@
14501450
"additionalProperties": false
14511451
},
14521452
"IbcQuery": {
1453-
"description": "These are queries to the various IBC modules to see the state of the contract's IBC connection. These will return errors if the contract is not \"ibc enabled\"",
1453+
"description": "These are queries to the various IBC modules to see the state of the contract's IBC connection. Most of these will return errors if the contract is not \"ibc enabled\".",
14541454
"oneOf": [
14551455
{
14561456
"description": "Gets the Port ID the current contract is bound to.\n\nReturns a `PortIdResponse`.",

packages/go-gen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ release = false
1010

1111
[dependencies]
1212
cosmwasm-std = { version = "2.1.1", path = "../std", features = [
13-
"cosmwasm_2_1",
13+
"cosmwasm_2_2",
1414
"staking",
1515
"stargate",
1616
] }

packages/go-gen/tests/cosmwasm_std__IbcMsg.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,34 @@ type WriteAcknowledgementMsg struct {
2121
type CloseChannelMsg struct {
2222
ChannelID string `json:"channel_id"`
2323
}
24+
type PayPacketFeeMsg struct {
25+
// The channel id on the chain where the packet is sent from (this chain).
26+
ChannelID string `json:"channel_id"`
27+
Fee IBCFee `json:"fee"`
28+
// The port id on the chain where the packet is sent from (this chain).
29+
PortID string `json:"port_id"`
30+
// Allowlist of relayer addresses that can receive the fee. This is currently not implemented and *must* be empty.
31+
Relayers Array[string] `json:"relayers"`
32+
}
33+
type PayPacketFeeAsyncMsg struct {
34+
// The channel id on the chain where the packet is sent from (this chain).
35+
ChannelID string `json:"channel_id"`
36+
Fee IBCFee `json:"fee"`
37+
// The port id on the chain where the packet is sent from (this chain).
38+
PortID string `json:"port_id"`
39+
// Allowlist of relayer addresses that can receive the fee. This is currently not implemented and *must* be empty.
40+
Relayers Array[string] `json:"relayers"`
41+
// The sequence number of the packet that should be incentivized.
42+
Sequence uint64 `json:"sequence"`
43+
}
2444

2545
type IBCMsg struct {
2646
Transfer *TransferMsg `json:"transfer,omitempty"`
2747
SendPacket *SendPacketMsg `json:"send_packet,omitempty"`
2848
WriteAcknowledgement *WriteAcknowledgementMsg `json:"write_acknowledgement,omitempty"`
2949
CloseChannel *CloseChannelMsg `json:"close_channel,omitempty"`
50+
PayPacketFee *PayPacketFeeMsg `json:"pay_packet_fee,omitempty"`
51+
PayPacketFeeAsync *PayPacketFeeAsyncMsg `json:"pay_packet_fee_async,omitempty"`
3052
}
3153

3254
// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
@@ -38,6 +60,11 @@ type Coin struct {
3860
type IBCAcknowledgement struct {
3961
Data []byte `json:"data"`
4062
}
63+
type IBCFee struct {
64+
AckFee Array[Coin] `json:"ack_fee"`
65+
ReceiveFee Array[Coin] `json:"receive_fee"`
66+
TimeoutFee Array[Coin] `json:"timeout_fee"`
67+
}
4168

4269
// IBCTimeout is the timeout for an IBC packet. At least one of block and timestamp is required.
4370
type IBCTimeout struct {

packages/go-gen/tests/cosmwasm_std__IbcQuery.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@ type ChannelQuery struct {
1515
// optional argument
1616
PortID string `json:"port_id,omitempty"`
1717
}
18+
type FeeEnabledChannelQuery struct {
19+
ChannelID string `json:"channel_id"`
20+
PortID string `json:"port_id,omitempty"`
21+
}
1822

1923
// IBCQuery defines a query request from the contract into the chain.
2024
// This is the counterpart of [IbcQuery](https://github.com/CosmWasm/cosmwasm/blob/v0.14.0-beta1/packages/std/src/ibc.rs#L61-L83).
2125
type IBCQuery struct {
22-
PortID *PortIDQuery `json:"port_id,omitempty"`
23-
ListChannels *ListChannelsQuery `json:"list_channels,omitempty"`
24-
Channel *ChannelQuery `json:"channel,omitempty"`
26+
PortID *PortIDQuery `json:"port_id,omitempty"`
27+
ListChannels *ListChannelsQuery `json:"list_channels,omitempty"`
28+
Channel *ChannelQuery `json:"channel,omitempty"`
29+
FeeEnabledChannel *FeeEnabledChannelQuery `json:"fee_enabled_channel,omitempty"`
2530
}

packages/std/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ license = "Apache-2.0"
99
readme = "README.md"
1010

1111
[package.metadata.docs.rs]
12-
features = ["abort", "stargate", "staking", "cosmwasm_2_1"]
12+
features = ["abort", "stargate", "staking", "cosmwasm_2_2"]
1313

1414
[features]
1515
default = ["iterator", "abort", "std"]
@@ -48,6 +48,9 @@ cosmwasm_2_0 = ["cosmwasm_1_4"]
4848
# This enables functionality that is only available on 2.1 chains.
4949
# It adds verification and key recovery for the secp256r1 elliptic curve.
5050
cosmwasm_2_1 = ["cosmwasm_2_0"]
51+
# This enables functionality that is only available on 2.2 chains.
52+
# It adds `IbcMsg::PayPacketFee` and `IbcMsg::PayPacketFeeAsync`.
53+
cosmwasm_2_2 = ["cosmwasm_2_1"]
5154

5255
[dependencies]
5356
base64 = "0.22.0"

packages/std/src/exports.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,45 +35,49 @@ use crate::{CustomMsg, Deps, DepsMut, MessageInfo};
3535
// See `docs/CAPABILITIES.md` for more details.
3636
#[cfg(feature = "iterator")]
3737
#[no_mangle]
38-
extern "C" fn requires_iterator() -> () {}
38+
extern "C" fn requires_iterator() {}
3939

4040
#[cfg(feature = "staking")]
4141
#[no_mangle]
42-
extern "C" fn requires_staking() -> () {}
42+
extern "C" fn requires_staking() {}
4343

4444
#[cfg(feature = "stargate")]
4545
#[no_mangle]
46-
extern "C" fn requires_stargate() -> () {}
46+
extern "C" fn requires_stargate() {}
4747

4848
#[cfg(feature = "cosmwasm_1_1")]
4949
#[no_mangle]
50-
extern "C" fn requires_cosmwasm_1_1() -> () {}
50+
extern "C" fn requires_cosmwasm_1_1() {}
5151

5252
#[cfg(feature = "cosmwasm_1_2")]
5353
#[no_mangle]
54-
extern "C" fn requires_cosmwasm_1_2() -> () {}
54+
extern "C" fn requires_cosmwasm_1_2() {}
5555

5656
#[cfg(feature = "cosmwasm_1_3")]
5757
#[no_mangle]
58-
extern "C" fn requires_cosmwasm_1_3() -> () {}
58+
extern "C" fn requires_cosmwasm_1_3() {}
5959

6060
#[cfg(feature = "cosmwasm_1_4")]
6161
#[no_mangle]
62-
extern "C" fn requires_cosmwasm_1_4() -> () {}
62+
extern "C" fn requires_cosmwasm_1_4() {}
6363

6464
#[cfg(feature = "cosmwasm_2_0")]
6565
#[no_mangle]
66-
extern "C" fn requires_cosmwasm_2_0() -> () {}
66+
extern "C" fn requires_cosmwasm_2_0() {}
6767

6868
#[cfg(feature = "cosmwasm_2_1")]
6969
#[no_mangle]
70-
extern "C" fn requires_cosmwasm_2_1() -> () {}
70+
extern "C" fn requires_cosmwasm_2_1() {}
71+
72+
#[cfg(feature = "cosmwasm_2_2")]
73+
#[no_mangle]
74+
extern "C" fn requires_cosmwasm_2_2() {}
7175

7276
/// interface_version_* exports mark which Wasm VM interface level this contract is compiled for.
7377
/// They can be checked by cosmwasm_vm.
7478
/// Update this whenever the Wasm VM interface breaks.
7579
#[no_mangle]
76-
extern "C" fn interface_version_8() -> () {}
80+
extern "C" fn interface_version_8() {}
7781

7882
/// allocate reserves the given number of bytes in wasm memory and returns a pointer
7983
/// to a Region defining this data. This space is managed by the calling process

0 commit comments

Comments
 (0)