Skip to content

Commit 5204a89

Browse files
authored
Merge pull request #2099 from CosmWasm/chipshort/convert-response
Add custom message conversion
2 parents 4dec802 + 2afd3f6 commit 5204a89

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,16 @@ and this project adheres to
2121
- cosmwasm-std: Implement `&T + T` and `&T op &T` for `Uint64`, `Uint128`,
2222
`Uint256` and `Uint512`; improve panic message for `Uint64::add` and
2323
`Uint512::add` ([#2092])
24+
- cosmwasm-std: Add `{CosmosMsg,SubMsg,Response}::change_custom` to change the
25+
custom message type ([#2099])
2426

2527
[#1983]: https://github.com/CosmWasm/cosmwasm/pull/1983
2628
[#2057]: https://github.com/CosmWasm/cosmwasm/pull/2057
2729
[#2058]: https://github.com/CosmWasm/cosmwasm/pull/2058
2830
[#2068]: https://github.com/CosmWasm/cosmwasm/pull/2068
2931
[#2075]: https://github.com/CosmWasm/cosmwasm/pull/2075
3032
[#2092]: https://github.com/CosmWasm/cosmwasm/pull/2092
33+
[#2099]: https://github.com/CosmWasm/cosmwasm/pull/2099
3134

3235
### Changed
3336

packages/std/src/results/cosmos_msg.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,32 @@ pub enum CosmosMsg<T = Empty> {
5858
Gov(GovMsg),
5959
}
6060

61+
impl<T> CosmosMsg<T> {
62+
/// Convert this this [`CosmosMsg<T>`] to a [`CosmosMsg<U>`] with a different custom message type.
63+
/// This allows easier interactions between code written for a specific chain and
64+
/// code written for multiple chains.
65+
/// If this is the [`CosmosMsg::Custom`] variant, the function returns `None`.
66+
pub fn change_custom<U>(self) -> Option<CosmosMsg<U>> {
67+
Some(match self {
68+
CosmosMsg::Bank(msg) => CosmosMsg::Bank(msg),
69+
CosmosMsg::Custom(_) => return None,
70+
#[cfg(feature = "staking")]
71+
CosmosMsg::Staking(msg) => CosmosMsg::Staking(msg),
72+
#[cfg(feature = "staking")]
73+
CosmosMsg::Distribution(msg) => CosmosMsg::Distribution(msg),
74+
#[cfg(feature = "stargate")]
75+
CosmosMsg::Stargate { type_url, value } => CosmosMsg::Stargate { type_url, value },
76+
#[cfg(feature = "cosmwasm_2_0")]
77+
CosmosMsg::Any(msg) => CosmosMsg::Any(msg),
78+
#[cfg(feature = "stargate")]
79+
CosmosMsg::Ibc(msg) => CosmosMsg::Ibc(msg),
80+
CosmosMsg::Wasm(msg) => CosmosMsg::Wasm(msg),
81+
#[cfg(feature = "stargate")]
82+
CosmosMsg::Gov(msg) => CosmosMsg::Gov(msg),
83+
})
84+
}
85+
}
86+
6187
/// The message types of the bank module.
6288
///
6389
/// See https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto
@@ -664,4 +690,31 @@ mod tests {
664690
);
665691
}
666692
}
693+
694+
#[test]
695+
fn change_custom_works() {
696+
#[derive(Debug, PartialEq, Eq, Clone)]
697+
struct Custom {
698+
_a: i32,
699+
}
700+
let send = BankMsg::Send {
701+
to_address: "you".to_string(),
702+
amount: coins(1015, "earth"),
703+
};
704+
// Custom to Empty
705+
let msg: CosmosMsg<Custom> = send.clone().into();
706+
let msg2: CosmosMsg<Empty> = msg.change_custom().unwrap();
707+
assert_eq!(msg2, CosmosMsg::Bank(send.clone()));
708+
let custom = CosmosMsg::Custom(Custom { _a: 5 });
709+
let converted = custom.change_custom::<Empty>();
710+
assert_eq!(converted, None);
711+
712+
// Empty to Custom
713+
let msg: CosmosMsg<Empty> = send.clone().into();
714+
let msg2: CosmosMsg<Custom> = msg.change_custom().unwrap();
715+
assert_eq!(msg2, CosmosMsg::Bank(send));
716+
let empty = CosmosMsg::Custom(Empty {});
717+
let converted = empty.change_custom::<Custom>();
718+
assert_eq!(converted, None);
719+
}
667720
}

packages/std/src/results/response.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,23 @@ impl<T> Response<T> {
232232
self.data = Some(data.into());
233233
self
234234
}
235+
236+
/// Convert this [`Response<T>`] to a [`Response<U>`] with a different custom message type.
237+
/// This allows easier interactions between code written for a specific chain and
238+
/// code written for multiple chains.
239+
/// If this contains a [`CosmosMsg::Custom`] submessage, the function returns `None`.
240+
pub fn change_custom<U>(self) -> Option<Response<U>> {
241+
Some(Response {
242+
messages: self
243+
.messages
244+
.into_iter()
245+
.map(|msg| msg.change_custom())
246+
.collect::<Option<Vec<_>>>()?,
247+
attributes: self.attributes,
248+
events: self.events,
249+
data: self.data,
250+
})
251+
}
235252
}
236253

237254
#[cfg(test)]
@@ -370,4 +387,38 @@ mod tests {
370387
let expected = Response::<Empty>::new().add_events(events);
371388
assert_eq!(expected, actual);
372389
}
390+
391+
#[test]
392+
fn change_custom_works() {
393+
let response: Response<Empty> = Response {
394+
messages: vec![SubMsg::new(BankMsg::Send {
395+
to_address: "address".to_string(),
396+
amount: coins(123, "earth"),
397+
})],
398+
attributes: vec![Attribute::new("foo", "bar")],
399+
events: vec![Event::new("our_event").add_attribute("msg", "hello")],
400+
data: None,
401+
};
402+
let converted_resp: Response<String> = response.clone().change_custom().unwrap();
403+
assert_eq!(
404+
converted_resp.messages,
405+
vec![SubMsg::new(BankMsg::Send {
406+
to_address: "address".to_string(),
407+
amount: coins(123, "earth"),
408+
})]
409+
);
410+
assert_eq!(converted_resp.attributes, response.attributes);
411+
assert_eq!(converted_resp.events, response.events);
412+
assert_eq!(converted_resp.data, response.data);
413+
414+
// response with custom message
415+
let response = Response {
416+
messages: vec![SubMsg::new(CosmosMsg::Custom(Empty {}))],
417+
attributes: vec![Attribute::new("foo", "bar")],
418+
events: vec![Event::new("our_event").add_attribute("msg", "hello")],
419+
data: None,
420+
};
421+
422+
assert_eq!(response.change_custom::<String>(), None);
423+
}
373424
}

packages/std/src/results/submessages.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ impl<T> SubMsg<T> {
148148
gas_limit: None,
149149
}
150150
}
151+
152+
/// Convert this [`SubMsg<T>`] to a [`SubMsg<U>`] with a different generic type.
153+
/// This allows easier interactions between code written for a specific chain and
154+
/// code written for multiple chains.
155+
/// If this is a [`CosmosMsg::Custom`] submessage, the function returns `None`.
156+
pub fn change_custom<U>(self) -> Option<SubMsg<U>> {
157+
Some(SubMsg {
158+
id: self.id,
159+
payload: self.payload,
160+
msg: self.msg.change_custom::<U>()?,
161+
gas_limit: self.gas_limit,
162+
reply_on: self.reply_on,
163+
})
164+
}
151165
}
152166

153167
/// The result object returned to `reply`. We always get the ID from the submessage

0 commit comments

Comments
 (0)