secret_cosmwasm_std/results/
submessages.rs1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::Binary;
5
6use super::{CosmosMsg, Empty, Event};
7
8#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
12#[serde(rename_all = "snake_case")]
13pub enum ReplyOn {
14 Always,
16 Error,
18 Success,
20 Never,
22}
23
24#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
31pub struct SubMsg<T = Empty> {
32 pub id: u64,
35 pub msg: CosmosMsg<T>,
36 pub gas_limit: Option<u64>,
38 pub reply_on: ReplyOn,
39}
40
41pub const UNUSED_MSG_ID: u64 = 0;
43
44impl<T> SubMsg<T> {
45 pub fn new(msg: impl Into<CosmosMsg<T>>) -> Self {
47 SubMsg {
48 id: UNUSED_MSG_ID,
49 msg: msg.into(),
50 reply_on: ReplyOn::Never,
51 gas_limit: None,
52 }
53 }
54
55 pub fn reply_on_success(msg: impl Into<CosmosMsg<T>>, id: u64) -> Self {
57 Self::reply_on(msg.into(), id, ReplyOn::Success)
58 }
59
60 pub fn reply_on_error(msg: impl Into<CosmosMsg<T>>, id: u64) -> Self {
62 Self::reply_on(msg.into(), id, ReplyOn::Error)
63 }
64
65 pub fn reply_always(msg: impl Into<CosmosMsg<T>>, id: u64) -> Self {
67 Self::reply_on(msg.into(), id, ReplyOn::Always)
68 }
69
70 pub fn with_gas_limit(mut self, limit: u64) -> Self {
84 self.gas_limit = Some(limit);
85 self
86 }
87
88 fn reply_on(msg: CosmosMsg<T>, id: u64, reply_on: ReplyOn) -> Self {
89 SubMsg {
90 id,
91 msg,
92 reply_on,
93 gas_limit: None,
94 }
95 }
96}
97
98#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
101pub struct Reply {
102 pub id: u64,
105 pub result: SubMsgResult,
106}
107
108#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
141#[serde(rename_all = "snake_case")]
142pub enum SubMsgResult {
143 Ok(SubMsgResponse),
144 #[serde(rename = "error")]
147 Err(String),
148}
149
150impl SubMsgResult {
153 pub fn into_result(self) -> Result<SubMsgResponse, String> {
156 Result::<SubMsgResponse, String>::from(self)
157 }
158
159 pub fn unwrap(self) -> SubMsgResponse {
160 self.into_result().unwrap()
161 }
162
163 pub fn unwrap_err(self) -> String {
164 self.into_result().unwrap_err()
165 }
166
167 pub fn is_ok(&self) -> bool {
168 matches!(self, SubMsgResult::Ok(_))
169 }
170
171 pub fn is_err(&self) -> bool {
172 matches!(self, SubMsgResult::Err(_))
173 }
174}
175
176impl<E: ToString> From<Result<SubMsgResponse, E>> for SubMsgResult {
177 fn from(original: Result<SubMsgResponse, E>) -> SubMsgResult {
178 match original {
179 Ok(value) => SubMsgResult::Ok(value),
180 Err(err) => SubMsgResult::Err(err.to_string()),
181 }
182 }
183}
184
185impl From<SubMsgResult> for Result<SubMsgResponse, String> {
186 fn from(original: SubMsgResult) -> Result<SubMsgResponse, String> {
187 match original {
188 SubMsgResult::Ok(value) => Ok(value),
189 SubMsgResult::Err(err) => Err(err),
190 }
191 }
192}
193
194#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
197pub struct SubMsgResponse {
198 pub events: Vec<Event>,
199 pub data: Option<Binary>,
200}
201
202#[deprecated(note = "Renamed to SubMsgResponse")]
203pub type SubMsgExecutionResponse = SubMsgResponse;
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use crate::{from_slice, to_vec, StdError, StdResult};
209
210 #[test]
211 fn sub_msg_result_serialization_works() {
212 let result = SubMsgResult::Ok(SubMsgResponse {
213 data: None,
214 events: vec![],
215 });
216 assert_eq!(
217 &to_vec(&result).unwrap(),
218 br#"{"ok":{"events":[],"data":null}}"#
219 );
220
221 let result = SubMsgResult::Ok(SubMsgResponse {
222 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
223 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
224 });
225
226 println!("deubgggg: {:?}", result);
227
228 assert_eq!(
229 &to_vec(&result).unwrap(),
230 br#"{"ok":{"events":[{"type":"wasm","attributes":[{"key":"fo","value":"ba","encrypted":true}]}],"data":"MTIzCg=="}}"#
231 );
232
233 let result: SubMsgResult = SubMsgResult::Err("broken".to_string());
234 assert_eq!(&to_vec(&result).unwrap(), b"{\"error\":\"broken\"}");
235 }
236
237 #[test]
238 fn sub_msg_result_deserialization_works() {
239 let result: SubMsgResult = from_slice(br#"{"ok":{"events":[],"data":null}}"#).unwrap();
240 assert_eq!(
241 result,
242 SubMsgResult::Ok(SubMsgResponse {
243 events: vec![],
244 data: None,
245 })
246 );
247
248 let result: SubMsgResult = from_slice(
249 br#"{"ok":{"events":[{"type":"wasm","attributes":[{"key":"fo","value":"ba","encrypted":true}]}],"data":"MTIzCg=="}}"#).unwrap();
250 assert_eq!(
251 result,
252 SubMsgResult::Ok(SubMsgResponse {
253 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
254 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
255 })
256 );
257
258 let result: SubMsgResult = from_slice(br#"{"error":"broken"}"#).unwrap();
259 assert_eq!(result, SubMsgResult::Err("broken".to_string()));
260
261 let parse: StdResult<SubMsgResult> = from_slice(br#"{"unrelated":321,"error":"broken"}"#);
263 match parse.unwrap_err() {
264 StdError::ParseErr { .. } => {}
265 err => panic!("Unexpected error: {:?}", err),
266 }
267 let parse: StdResult<SubMsgResult> = from_slice(br#"{"error":"broken","unrelated":321}"#);
268 match parse.unwrap_err() {
269 StdError::ParseErr { .. } => {}
270 err => panic!("Unexpected error: {:?}", err),
271 }
272 }
273
274 #[test]
275 fn sub_msg_result_unwrap_works() {
276 let response = SubMsgResponse {
277 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
278 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
279 };
280 let success = SubMsgResult::Ok(response.clone());
281 assert_eq!(success.unwrap(), response);
282 }
283
284 #[test]
285 #[should_panic]
286 fn sub_msg_result_unwrap_panicks_for_err() {
287 let failure = SubMsgResult::Err("broken".to_string());
288 let _ = failure.unwrap();
289 }
290
291 #[test]
292 fn sub_msg_result_unwrap_err_works() {
293 let failure = SubMsgResult::Err("broken".to_string());
294 assert_eq!(failure.unwrap_err(), "broken");
295 }
296
297 #[test]
298 #[should_panic]
299 fn sub_msg_result_unwrap_err_panics_for_ok() {
300 let response = SubMsgResponse {
301 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
302 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
303 };
304 let success = SubMsgResult::Ok(response);
305 let _ = success.unwrap_err();
306 }
307
308 #[test]
309 fn sub_msg_result_is_ok_works() {
310 let success = SubMsgResult::Ok(SubMsgResponse {
311 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
312 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
313 });
314 let failure = SubMsgResult::Err("broken".to_string());
315 assert!(success.is_ok());
316 assert!(!failure.is_ok());
317 }
318
319 #[test]
320 fn sub_msg_result_is_err_works() {
321 let success = SubMsgResult::Ok(SubMsgResponse {
322 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
323 events: vec![Event::new("wasm").add_attribute("fo", "ba")],
324 });
325 let failure = SubMsgResult::Err("broken".to_string());
326 assert!(failure.is_err());
327 assert!(!success.is_err());
328 }
329
330 #[test]
331 fn sub_msg_result_can_convert_from_core_result() {
332 let original: Result<SubMsgResponse, StdError> = Ok(SubMsgResponse {
333 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
334 events: vec![],
335 });
336 let converted: SubMsgResult = original.into();
337 assert_eq!(
338 converted,
339 SubMsgResult::Ok(SubMsgResponse {
340 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
341 events: vec![],
342 })
343 );
344
345 let original: Result<SubMsgResponse, StdError> = Err(StdError::generic_err("broken"));
346 let converted: SubMsgResult = original.into();
347 assert_eq!(
348 converted,
349 SubMsgResult::Err("Generic error: broken".to_string())
350 );
351 }
352
353 #[test]
354 fn sub_msg_result_can_convert_to_core_result() {
355 let original = SubMsgResult::Ok(SubMsgResponse {
356 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
357 events: vec![],
358 });
359 let converted: Result<SubMsgResponse, String> = original.into();
360 assert_eq!(
361 converted,
362 Ok(SubMsgResponse {
363 data: Some(Binary::from_base64("MTIzCg==").unwrap()),
364 events: vec![],
365 })
366 );
367
368 let original = SubMsgResult::Err("went wrong".to_string());
369 let converted: Result<SubMsgResponse, String> = original.into();
370 assert_eq!(converted, Err("went wrong".to_string()));
371 }
372}