Skip to content

Commit 2c6e84d

Browse files
author
Tomasz Kulik
committed
feat: Add TransferV2
1 parent 589d242 commit 2c6e84d

File tree

16 files changed

+1199
-70
lines changed

16 files changed

+1199
-70
lines changed

contracts/ibc-callbacks/schema/ibc-callbacks.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"type": "object",
2424
"required": [
2525
"channel_id",
26+
"channel_version",
2627
"timeout_seconds",
2728
"to_address"
2829
],
@@ -40,6 +41,10 @@
4041
"description": "The channel to send the packet through",
4142
"type": "string"
4243
},
44+
"channel_version": {
45+
"description": "IBC channel version",
46+
"type": "string"
47+
},
4348
"timeout_seconds": {
4449
"description": "The amount of seconds from now the transfer should timeout at",
4550
"type": "integer",

contracts/ibc-callbacks/schema/raw/execute.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"type": "object",
1313
"required": [
1414
"channel_id",
15+
"channel_version",
1516
"timeout_seconds",
1617
"to_address"
1718
],
@@ -29,6 +30,10 @@
2930
"description": "The channel to send the packet through",
3031
"type": "string"
3132
},
33+
"channel_version": {
34+
"description": "IBC channel version",
35+
"type": "string"
36+
},
3237
"timeout_seconds": {
3338
"description": "The amount of seconds from now the transfer should timeout at",
3439
"type": "integer",

contracts/ibc-callbacks/src/contract.rs

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use cosmwasm_std::{
22
entry_point, to_json_binary, Binary, Deps, DepsMut, Empty, Env, IbcBasicResponse,
33
IbcDestinationCallbackMsg, IbcDstCallback, IbcSourceCallbackMsg, IbcSrcCallback, IbcTimeout,
4-
MessageInfo, Response, StdError, StdResult, TransferMsgBuilder,
4+
MessageInfo, Response, StdError, StdResult, TransferMsgBuilder, TransferMsgBuilderV2,
55
};
66

77
use crate::msg::{CallbackType, ExecuteMsg, QueryMsg};
@@ -35,13 +35,15 @@ pub fn execute(
3535
channel_id,
3636
timeout_seconds,
3737
callback_type,
38+
channel_version,
3839
} => execute_transfer(
3940
env,
4041
info,
4142
to_address,
4243
channel_id,
4344
timeout_seconds,
4445
callback_type,
46+
channel_version,
4547
),
4648
}
4749
}
@@ -53,6 +55,7 @@ fn execute_transfer(
5355
channel_id: String,
5456
timeout_seconds: u32,
5557
callback_type: CallbackType,
58+
channel_version: String,
5659
) -> StdResult<Response> {
5760
let src_callback = IbcSrcCallback {
5861
address: env.contract.address,
@@ -62,30 +65,55 @@ fn execute_transfer(
6265
address: to_address.clone(),
6366
gas_limit: None,
6467
};
65-
let coin = match &*info.funds {
66-
[coin] if !coin.amount.is_zero() => coin,
68+
69+
let transfer_msg = match channel_version.as_str() {
70+
"V1" => {
71+
let coin = match &*info.funds {
72+
[coin] if !coin.amount.is_zero() => coin,
73+
_ => {
74+
return Err(StdError::generic_err(
75+
"Must send exactly one denom to trigger ics-20 transfer",
76+
))
77+
}
78+
};
79+
let builder = TransferMsgBuilder::new(
80+
channel_id,
81+
to_address.clone(),
82+
coin.clone(),
83+
IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)),
84+
);
85+
match callback_type {
86+
CallbackType::Both => builder
87+
.with_src_callback(src_callback)
88+
.with_dst_callback(dst_callback)
89+
.build(),
90+
CallbackType::Src => builder.with_src_callback(src_callback).build(),
91+
CallbackType::Dst => builder.with_dst_callback(dst_callback).build(),
92+
}
93+
}
94+
"V2" => {
95+
let builder = TransferMsgBuilderV2::new(
96+
channel_id,
97+
to_address.clone(),
98+
info.funds.into_iter().map(Into::into).collect(),
99+
IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)),
100+
);
101+
match callback_type {
102+
CallbackType::Both => builder
103+
.with_src_callback(src_callback)
104+
.with_dst_callback(dst_callback)
105+
.build(),
106+
CallbackType::Src => builder.with_src_callback(src_callback).build(),
107+
CallbackType::Dst => builder.with_dst_callback(dst_callback).build(),
108+
}
109+
}
67110
_ => {
68111
return Err(StdError::generic_err(
69-
"Must send exactly one denom to trigger ics-20 transfer",
112+
"Must specify \"V1\" or \"V2\" channel version",
70113
))
71114
}
72115
};
73116

74-
let builder = TransferMsgBuilder::new(
75-
channel_id,
76-
to_address.clone(),
77-
coin.clone(),
78-
IbcTimeout::with_timestamp(env.block.time.plus_seconds(timeout_seconds as u64)),
79-
);
80-
let transfer_msg = match callback_type {
81-
CallbackType::Both => builder
82-
.with_src_callback(src_callback)
83-
.with_dst_callback(dst_callback)
84-
.build(),
85-
CallbackType::Src => builder.with_src_callback(src_callback).build(),
86-
CallbackType::Dst => builder.with_dst_callback(dst_callback).build(),
87-
};
88-
89117
Ok(Response::new()
90118
.add_message(transfer_msg)
91119
.add_attribute("action", "execute"))

contracts/ibc-callbacks/src/msg.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ pub enum ExecuteMsg {
2020
/// Who should receive callbacks for the message
2121
#[serde(default)]
2222
callback_type: CallbackType,
23+
/// IBC channel version
24+
channel_version: String,
2325
},
2426
}
2527

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

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,25 @@
364364
"type": "object",
365365
"additionalProperties": false
366366
},
367+
"Forwarding": {
368+
"type": "object",
369+
"required": [
370+
"hops",
371+
"memo"
372+
],
373+
"properties": {
374+
"hops": {
375+
"type": "array",
376+
"items": {
377+
"$ref": "#/definitions/Hop"
378+
}
379+
},
380+
"memo": {
381+
"type": "string"
382+
}
383+
},
384+
"additionalProperties": false
385+
},
367386
"GovMsg": {
368387
"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<Response, StdError> { // ... 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<Response, StdError> { // ... 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), }, ], })) } ```",
369388
"oneOf": [
@@ -402,8 +421,24 @@
402421
}
403422
]
404423
},
424+
"Hop": {
425+
"type": "object",
426+
"required": [
427+
"channel_id",
428+
"port_id"
429+
],
430+
"properties": {
431+
"channel_id": {
432+
"type": "string"
433+
},
434+
"port_id": {
435+
"type": "string"
436+
}
437+
},
438+
"additionalProperties": false
439+
},
405440
"IbcMsg": {
406-
"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)",
441+
"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)",
407442
"oneOf": [
408443
{
409444
"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 @@
458493
},
459494
"additionalProperties": false
460495
},
496+
{
497+
"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.",
498+
"type": "object",
499+
"required": [
500+
"transfer_v2"
501+
],
502+
"properties": {
503+
"transfer_v2": {
504+
"type": "object",
505+
"required": [
506+
"channel_id",
507+
"forwarding",
508+
"timeout",
509+
"to_address",
510+
"tokens"
511+
],
512+
"properties": {
513+
"channel_id": {
514+
"description": "existing channel to send the tokens over",
515+
"type": "string"
516+
},
517+
"forwarding": {
518+
"$ref": "#/definitions/Forwarding"
519+
},
520+
"memo": {
521+
"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.",
522+
"type": [
523+
"string",
524+
"null"
525+
]
526+
},
527+
"timeout": {
528+
"description": "when packet times out, measured on remote chain",
529+
"allOf": [
530+
{
531+
"$ref": "#/definitions/IbcTimeout"
532+
}
533+
]
534+
},
535+
"to_address": {
536+
"description": "address on the remote chain to receive these tokens",
537+
"type": "string"
538+
},
539+
"tokens": {
540+
"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",
541+
"type": "array",
542+
"items": {
543+
"$ref": "#/definitions/Token"
544+
}
545+
}
546+
},
547+
"additionalProperties": false
548+
}
549+
},
550+
"additionalProperties": false
551+
},
461552
{
462553
"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.",
463554
"type": "object",
@@ -662,10 +753,37 @@
662753
}
663754
]
664755
},
756+
"Token": {
757+
"type": "object",
758+
"required": [
759+
"amount",
760+
"base",
761+
"trace"
762+
],
763+
"properties": {
764+
"amount": {
765+
"$ref": "#/definitions/Uint256"
766+
},
767+
"base": {
768+
"type": "string"
769+
},
770+
"trace": {
771+
"type": "array",
772+
"items": {
773+
"$ref": "#/definitions/Hop"
774+
}
775+
}
776+
},
777+
"additionalProperties": false
778+
},
665779
"Uint128": {
666780
"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); ```",
667781
"type": "string"
668782
},
783+
"Uint256": {
784+
"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); ```",
785+
"type": "string"
786+
},
669787
"Uint64": {
670788
"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); ```",
671789
"type": "string"

0 commit comments

Comments
 (0)