1use serde::de::DeserializeOwned;
2use wasmer::Value;
3
4use cosmwasm_std::{
5 ContractResult, CustomMsg, Env, IbcBasicResponse, IbcDestinationCallbackMsg,
6 IbcSourceCallbackMsg, MessageInfo, MigrateInfo, QueryResponse, Reply, Response,
7};
8
9#[cfg(any(feature = "stargate", feature = "ibc2"))]
10use cosmwasm_std::IbcReceiveResponse;
11
12#[cfg(feature = "stargate")]
13use cosmwasm_std::{
14 Ibc3ChannelOpenResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
15 IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
16};
17
18use crate::backend::{BackendApi, Querier, Storage};
19use crate::conversion::ref_to_u32;
20use crate::errors::{VmError, VmResult};
21use crate::instance::Instance;
22use crate::serde::{from_slice, to_vec};
23#[cfg(feature = "ibc2")]
24use cosmwasm_std::{
25 Ibc2PacketAckMsg, Ibc2PacketReceiveMsg, Ibc2PacketSendMsg, Ibc2PacketTimeoutMsg,
26};
27
28mod read_limits {
35 const MI: usize = 1024 * 1024;
37 pub const RESULT_INSTANTIATE: usize = 64 * MI;
39 pub const RESULT_EXECUTE: usize = 64 * MI;
41 pub const RESULT_MIGRATE: usize = 64 * MI;
43 pub const RESULT_SUDO: usize = 64 * MI;
45 pub const RESULT_REPLY: usize = 64 * MI;
47 pub const RESULT_QUERY: usize = 64 * MI;
49 #[cfg(feature = "stargate")]
51 pub const RESULT_IBC_CHANNEL_OPEN: usize = 64 * MI;
52 #[cfg(feature = "stargate")]
54 pub const RESULT_IBC_CHANNEL_CONNECT: usize = 64 * MI;
55 #[cfg(feature = "stargate")]
57 pub const RESULT_IBC_CHANNEL_CLOSE: usize = 64 * MI;
58 #[cfg(any(feature = "stargate", feature = "ibc2"))]
60 pub const RESULT_IBC_PACKET_RECEIVE: usize = 64 * MI;
61 #[cfg(any(feature = "stargate", feature = "ibc2"))]
63 pub const RESULT_IBC_PACKET_ACK: usize = 64 * MI;
64 #[cfg(any(feature = "stargate", feature = "ibc2"))]
66 pub const RESULT_IBC_PACKET_TIMEOUT: usize = 64 * MI;
67 pub const RESULT_IBC_SOURCE_CALLBACK: usize = 64 * MI;
69 pub const RESULT_IBC_DESTINATION_CALLBACK: usize = 64 * MI;
71 #[cfg(feature = "ibc2")]
72 pub const RESULT_IBC2_PACKET_SEND: usize = 64 * MI;
73}
74
75mod deserialization_limits {
80 const KI: usize = 1024;
82 pub const RESULT_INSTANTIATE: usize = 256 * KI;
84 pub const RESULT_EXECUTE: usize = 256 * KI;
86 pub const RESULT_MIGRATE: usize = 256 * KI;
88 pub const RESULT_SUDO: usize = 256 * KI;
90 pub const RESULT_REPLY: usize = 256 * KI;
92 pub const RESULT_QUERY: usize = 256 * KI;
94 #[cfg(feature = "stargate")]
96 pub const RESULT_IBC_CHANNEL_OPEN: usize = 256 * KI;
97 #[cfg(feature = "stargate")]
99 pub const RESULT_IBC_CHANNEL_CONNECT: usize = 256 * KI;
100 #[cfg(feature = "stargate")]
102 pub const RESULT_IBC_CHANNEL_CLOSE: usize = 256 * KI;
103 #[cfg(any(feature = "stargate", feature = "ibc2"))]
105 pub const RESULT_IBC_PACKET_RECEIVE: usize = 256 * KI;
106 #[cfg(feature = "stargate")]
108 pub const RESULT_IBC_PACKET_ACK: usize = 256 * KI;
109 #[cfg(any(feature = "stargate", feature = "ibc2"))]
111 pub const RESULT_IBC_PACKET_TIMEOUT: usize = 256 * KI;
112 pub const RESULT_IBC_SOURCE_CALLBACK: usize = 256 * KI;
114 pub const RESULT_IBC_DESTINATION_CALLBACK: usize = 256 * KI;
116 #[cfg(feature = "ibc2")]
118 pub const RESULT_IBC2_PACKET_SEND: usize = 256 * KI;
119}
120
121pub fn call_instantiate<A, S, Q, U>(
122 instance: &mut Instance<A, S, Q>,
123 env: &Env,
124 info: &MessageInfo,
125 msg: &[u8],
126) -> VmResult<ContractResult<Response<U>>>
127where
128 A: BackendApi + 'static,
129 S: Storage + 'static,
130 Q: Querier + 'static,
131 U: DeserializeOwned + CustomMsg,
132{
133 let env = to_vec(env)?;
134 let info = to_vec(info)?;
135 let data = call_instantiate_raw(instance, &env, &info, msg)?;
136 let result: ContractResult<Response<U>> =
137 from_slice(&data, deserialization_limits::RESULT_INSTANTIATE)?;
138 Ok(result)
139}
140
141pub fn call_execute<A, S, Q, U>(
142 instance: &mut Instance<A, S, Q>,
143 env: &Env,
144 info: &MessageInfo,
145 msg: &[u8],
146) -> VmResult<ContractResult<Response<U>>>
147where
148 A: BackendApi + 'static,
149 S: Storage + 'static,
150 Q: Querier + 'static,
151 U: DeserializeOwned + CustomMsg,
152{
153 let env = to_vec(env)?;
154 let info = to_vec(info)?;
155 let data = call_execute_raw(instance, &env, &info, msg)?;
156 let result: ContractResult<Response<U>> =
157 from_slice(&data, deserialization_limits::RESULT_EXECUTE)?;
158 Ok(result)
159}
160
161pub fn call_migrate<A, S, Q, U>(
162 instance: &mut Instance<A, S, Q>,
163 env: &Env,
164 msg: &[u8],
165) -> VmResult<ContractResult<Response<U>>>
166where
167 A: BackendApi + 'static,
168 S: Storage + 'static,
169 Q: Querier + 'static,
170 U: DeserializeOwned + CustomMsg,
171{
172 let env = to_vec(env)?;
173 let data = call_migrate_raw(instance, &env, msg)?;
174 let result: ContractResult<Response<U>> =
175 from_slice(&data, deserialization_limits::RESULT_MIGRATE)?;
176 Ok(result)
177}
178
179pub fn call_migrate_with_info<A, S, Q, U>(
180 instance: &mut Instance<A, S, Q>,
181 env: &Env,
182 msg: &[u8],
183 migrate_info: &MigrateInfo,
184) -> VmResult<ContractResult<Response<U>>>
185where
186 A: BackendApi + 'static,
187 S: Storage + 'static,
188 Q: Querier + 'static,
189 U: DeserializeOwned + CustomMsg,
190{
191 let env = to_vec(env)?;
192 let migrate_info = to_vec(migrate_info)?;
193 let data = call_migrate_with_info_raw(instance, &env, msg, &migrate_info)?;
194 let result: ContractResult<Response<U>> =
195 from_slice(&data, deserialization_limits::RESULT_MIGRATE)?;
196 Ok(result)
197}
198
199pub fn call_sudo<A, S, Q, U>(
200 instance: &mut Instance<A, S, Q>,
201 env: &Env,
202 msg: &[u8],
203) -> VmResult<ContractResult<Response<U>>>
204where
205 A: BackendApi + 'static,
206 S: Storage + 'static,
207 Q: Querier + 'static,
208 U: DeserializeOwned + CustomMsg,
209{
210 let env = to_vec(env)?;
211 let data = call_sudo_raw(instance, &env, msg)?;
212 let result: ContractResult<Response<U>> =
213 from_slice(&data, deserialization_limits::RESULT_SUDO)?;
214 Ok(result)
215}
216
217pub fn call_reply<A, S, Q, U>(
218 instance: &mut Instance<A, S, Q>,
219 env: &Env,
220 msg: &Reply,
221) -> VmResult<ContractResult<Response<U>>>
222where
223 A: BackendApi + 'static,
224 S: Storage + 'static,
225 Q: Querier + 'static,
226 U: DeserializeOwned + CustomMsg,
227{
228 let env = to_vec(env)?;
229 let msg = to_vec(msg)?;
230 let data = call_reply_raw(instance, &env, &msg)?;
231 let result: ContractResult<Response<U>> =
232 from_slice(&data, deserialization_limits::RESULT_REPLY)?;
233 Ok(result)
234}
235
236pub fn call_query<A, S, Q>(
237 instance: &mut Instance<A, S, Q>,
238 env: &Env,
239 msg: &[u8],
240) -> VmResult<ContractResult<QueryResponse>>
241where
242 A: BackendApi + 'static,
243 S: Storage + 'static,
244 Q: Querier + 'static,
245{
246 let env = to_vec(env)?;
247 let data = call_query_raw(instance, &env, msg)?;
248 let result: ContractResult<QueryResponse> =
249 from_slice(&data, deserialization_limits::RESULT_QUERY)?;
250 if let ContractResult::Ok(binary_response) = &result {
252 serde_json::from_slice::<serde_json::Value>(binary_response.as_slice())
253 .map_err(|e| VmError::generic_err(format!("Query response must be valid JSON. {e}")))?;
254 }
255
256 Ok(result)
257}
258
259#[cfg(feature = "stargate")]
260pub fn call_ibc_channel_open<A, S, Q>(
261 instance: &mut Instance<A, S, Q>,
262 env: &Env,
263 msg: &IbcChannelOpenMsg,
264) -> VmResult<ContractResult<Option<Ibc3ChannelOpenResponse>>>
265where
266 A: BackendApi + 'static,
267 S: Storage + 'static,
268 Q: Querier + 'static,
269{
270 let env = to_vec(env)?;
271 let msg = to_vec(msg)?;
272 let data = call_ibc_channel_open_raw(instance, &env, &msg)?;
273 let result: ContractResult<Option<Ibc3ChannelOpenResponse>> =
274 from_slice(&data, deserialization_limits::RESULT_IBC_CHANNEL_OPEN)?;
275 Ok(result)
276}
277
278#[cfg(feature = "stargate")]
279pub fn call_ibc_channel_connect<A, S, Q, U>(
280 instance: &mut Instance<A, S, Q>,
281 env: &Env,
282 msg: &IbcChannelConnectMsg,
283) -> VmResult<ContractResult<IbcBasicResponse<U>>>
284where
285 A: BackendApi + 'static,
286 S: Storage + 'static,
287 Q: Querier + 'static,
288 U: DeserializeOwned + CustomMsg,
289{
290 let env = to_vec(env)?;
291 let msg = to_vec(msg)?;
292 let data = call_ibc_channel_connect_raw(instance, &env, &msg)?;
293 let result = from_slice(&data, deserialization_limits::RESULT_IBC_CHANNEL_CONNECT)?;
294 Ok(result)
295}
296
297#[cfg(feature = "stargate")]
298pub fn call_ibc_channel_close<A, S, Q, U>(
299 instance: &mut Instance<A, S, Q>,
300 env: &Env,
301 msg: &IbcChannelCloseMsg,
302) -> VmResult<ContractResult<IbcBasicResponse<U>>>
303where
304 A: BackendApi + 'static,
305 S: Storage + 'static,
306 Q: Querier + 'static,
307 U: DeserializeOwned + CustomMsg,
308{
309 let env = to_vec(env)?;
310 let msg = to_vec(msg)?;
311 let data = call_ibc_channel_close_raw(instance, &env, &msg)?;
312 let result = from_slice(&data, deserialization_limits::RESULT_IBC_CHANNEL_CLOSE)?;
313 Ok(result)
314}
315
316#[cfg(feature = "stargate")]
317pub fn call_ibc_packet_receive<A, S, Q, U>(
318 instance: &mut Instance<A, S, Q>,
319 env: &Env,
320 msg: &IbcPacketReceiveMsg,
321) -> VmResult<ContractResult<IbcReceiveResponse<U>>>
322where
323 A: BackendApi + 'static,
324 S: Storage + 'static,
325 Q: Querier + 'static,
326 U: DeserializeOwned + CustomMsg,
327{
328 let env = to_vec(env)?;
329 let msg = to_vec(msg)?;
330 let data = call_ibc_packet_receive_raw(instance, &env, &msg)?;
331 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_RECEIVE)?;
332 Ok(result)
333}
334
335#[cfg(feature = "stargate")]
336pub fn call_ibc_packet_ack<A, S, Q, U>(
337 instance: &mut Instance<A, S, Q>,
338 env: &Env,
339 msg: &IbcPacketAckMsg,
340) -> VmResult<ContractResult<IbcBasicResponse<U>>>
341where
342 A: BackendApi + 'static,
343 S: Storage + 'static,
344 Q: Querier + 'static,
345 U: DeserializeOwned + CustomMsg,
346{
347 let env = to_vec(env)?;
348 let msg = to_vec(msg)?;
349 let data = call_ibc_packet_ack_raw(instance, &env, &msg)?;
350 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_ACK)?;
351 Ok(result)
352}
353
354#[cfg(feature = "stargate")]
355pub fn call_ibc_packet_timeout<A, S, Q, U>(
356 instance: &mut Instance<A, S, Q>,
357 env: &Env,
358 msg: &IbcPacketTimeoutMsg,
359) -> VmResult<ContractResult<IbcBasicResponse<U>>>
360where
361 A: BackendApi + 'static,
362 S: Storage + 'static,
363 Q: Querier + 'static,
364 U: DeserializeOwned + CustomMsg,
365{
366 let env = to_vec(env)?;
367 let msg = to_vec(msg)?;
368 let data = call_ibc_packet_timeout_raw(instance, &env, &msg)?;
369 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_TIMEOUT)?;
370 Ok(result)
371}
372
373pub fn call_ibc_source_callback<A, S, Q, U>(
374 instance: &mut Instance<A, S, Q>,
375 env: &Env,
376 msg: &IbcSourceCallbackMsg,
377) -> VmResult<ContractResult<IbcBasicResponse<U>>>
378where
379 A: BackendApi + 'static,
380 S: Storage + 'static,
381 Q: Querier + 'static,
382 U: DeserializeOwned + CustomMsg,
383{
384 let env = to_vec(env)?;
385 let msg = to_vec(msg)?;
386 let data = call_ibc_source_callback_raw(instance, &env, &msg)?;
387 let result = from_slice(&data, deserialization_limits::RESULT_IBC_SOURCE_CALLBACK)?;
388 Ok(result)
389}
390
391pub fn call_ibc_destination_callback<A, S, Q, U>(
392 instance: &mut Instance<A, S, Q>,
393 env: &Env,
394 msg: &IbcDestinationCallbackMsg,
395) -> VmResult<ContractResult<IbcBasicResponse<U>>>
396where
397 A: BackendApi + 'static,
398 S: Storage + 'static,
399 Q: Querier + 'static,
400 U: DeserializeOwned + CustomMsg,
401{
402 let env = to_vec(env)?;
403 let msg = to_vec(msg)?;
404 let data = call_ibc_destination_callback_raw(instance, &env, &msg)?;
405 let result = from_slice(
406 &data,
407 deserialization_limits::RESULT_IBC_DESTINATION_CALLBACK,
408 )?;
409 Ok(result)
410}
411
412pub fn call_instantiate_raw<A, S, Q>(
415 instance: &mut Instance<A, S, Q>,
416 env: &[u8],
417 info: &[u8],
418 msg: &[u8],
419) -> VmResult<Vec<u8>>
420where
421 A: BackendApi + 'static,
422 S: Storage + 'static,
423 Q: Querier + 'static,
424{
425 instance.set_storage_readonly(false);
426 call_raw(
427 instance,
428 "instantiate",
429 &[env, info, msg],
430 read_limits::RESULT_INSTANTIATE,
431 )
432}
433
434pub fn call_execute_raw<A, S, Q>(
437 instance: &mut Instance<A, S, Q>,
438 env: &[u8],
439 info: &[u8],
440 msg: &[u8],
441) -> VmResult<Vec<u8>>
442where
443 A: BackendApi + 'static,
444 S: Storage + 'static,
445 Q: Querier + 'static,
446{
447 instance.set_storage_readonly(false);
448 call_raw(
449 instance,
450 "execute",
451 &[env, info, msg],
452 read_limits::RESULT_EXECUTE,
453 )
454}
455
456pub fn call_migrate_raw<A, S, Q>(
459 instance: &mut Instance<A, S, Q>,
460 env: &[u8],
461 msg: &[u8],
462) -> VmResult<Vec<u8>>
463where
464 A: BackendApi + 'static,
465 S: Storage + 'static,
466 Q: Querier + 'static,
467{
468 instance.set_storage_readonly(false);
469 call_raw(
470 instance,
471 "migrate",
472 &[env, msg],
473 read_limits::RESULT_MIGRATE,
474 )
475}
476
477pub fn call_migrate_with_info_raw<A, S, Q>(
487 instance: &mut Instance<A, S, Q>,
488 env: &[u8],
489 msg: &[u8],
490 migrate_info: &[u8],
491) -> VmResult<Vec<u8>>
492where
493 A: BackendApi + 'static,
494 S: Storage + 'static,
495 Q: Querier + 'static,
496{
497 instance.set_storage_readonly(false);
498 call_raw(
499 instance,
500 "migrate",
501 &[env, msg, migrate_info],
502 read_limits::RESULT_MIGRATE,
503 )
504 .or_else(|err| {
505 if matches!(err, VmError::FunctionArityMismatch { .. }) {
506 call_raw(
507 instance,
508 "migrate",
509 &[env, msg],
510 read_limits::RESULT_MIGRATE,
511 )
512 } else {
513 Err(err)
514 }
515 })
516}
517
518pub fn call_sudo_raw<A, S, Q>(
521 instance: &mut Instance<A, S, Q>,
522 env: &[u8],
523 msg: &[u8],
524) -> VmResult<Vec<u8>>
525where
526 A: BackendApi + 'static,
527 S: Storage + 'static,
528 Q: Querier + 'static,
529{
530 instance.set_storage_readonly(false);
531 call_raw(instance, "sudo", &[env, msg], read_limits::RESULT_SUDO)
532}
533
534pub fn call_reply_raw<A, S, Q>(
537 instance: &mut Instance<A, S, Q>,
538 env: &[u8],
539 msg: &[u8],
540) -> VmResult<Vec<u8>>
541where
542 A: BackendApi + 'static,
543 S: Storage + 'static,
544 Q: Querier + 'static,
545{
546 instance.set_storage_readonly(false);
547 call_raw(instance, "reply", &[env, msg], read_limits::RESULT_REPLY)
548}
549
550pub fn call_query_raw<A, S, Q>(
553 instance: &mut Instance<A, S, Q>,
554 env: &[u8],
555 msg: &[u8],
556) -> VmResult<Vec<u8>>
557where
558 A: BackendApi + 'static,
559 S: Storage + 'static,
560 Q: Querier + 'static,
561{
562 instance.set_storage_readonly(true);
563 call_raw(instance, "query", &[env, msg], read_limits::RESULT_QUERY)
564}
565
566#[cfg(feature = "stargate")]
567pub fn call_ibc_channel_open_raw<A, S, Q>(
568 instance: &mut Instance<A, S, Q>,
569 env: &[u8],
570 msg: &[u8],
571) -> VmResult<Vec<u8>>
572where
573 A: BackendApi + 'static,
574 S: Storage + 'static,
575 Q: Querier + 'static,
576{
577 instance.set_storage_readonly(false);
578 call_raw(
579 instance,
580 "ibc_channel_open",
581 &[env, msg],
582 read_limits::RESULT_IBC_CHANNEL_OPEN,
583 )
584}
585
586#[cfg(feature = "stargate")]
587pub fn call_ibc_channel_connect_raw<A, S, Q>(
588 instance: &mut Instance<A, S, Q>,
589 env: &[u8],
590 msg: &[u8],
591) -> VmResult<Vec<u8>>
592where
593 A: BackendApi + 'static,
594 S: Storage + 'static,
595 Q: Querier + 'static,
596{
597 instance.set_storage_readonly(false);
598 call_raw(
599 instance,
600 "ibc_channel_connect",
601 &[env, msg],
602 read_limits::RESULT_IBC_CHANNEL_CONNECT,
603 )
604}
605
606#[cfg(feature = "stargate")]
607pub fn call_ibc_channel_close_raw<A, S, Q>(
608 instance: &mut Instance<A, S, Q>,
609 env: &[u8],
610 msg: &[u8],
611) -> VmResult<Vec<u8>>
612where
613 A: BackendApi + 'static,
614 S: Storage + 'static,
615 Q: Querier + 'static,
616{
617 instance.set_storage_readonly(false);
618 call_raw(
619 instance,
620 "ibc_channel_close",
621 &[env, msg],
622 read_limits::RESULT_IBC_CHANNEL_CLOSE,
623 )
624}
625
626#[cfg(feature = "stargate")]
627pub fn call_ibc_packet_receive_raw<A, S, Q>(
628 instance: &mut Instance<A, S, Q>,
629 env: &[u8],
630 msg: &[u8],
631) -> VmResult<Vec<u8>>
632where
633 A: BackendApi + 'static,
634 S: Storage + 'static,
635 Q: Querier + 'static,
636{
637 instance.set_storage_readonly(false);
638 call_raw(
639 instance,
640 "ibc_packet_receive",
641 &[env, msg],
642 read_limits::RESULT_IBC_PACKET_RECEIVE,
643 )
644}
645
646#[cfg(feature = "stargate")]
647pub fn call_ibc_packet_ack_raw<A, S, Q>(
648 instance: &mut Instance<A, S, Q>,
649 env: &[u8],
650 msg: &[u8],
651) -> VmResult<Vec<u8>>
652where
653 A: BackendApi + 'static,
654 S: Storage + 'static,
655 Q: Querier + 'static,
656{
657 instance.set_storage_readonly(false);
658 call_raw(
659 instance,
660 "ibc_packet_ack",
661 &[env, msg],
662 read_limits::RESULT_IBC_PACKET_ACK,
663 )
664}
665
666#[cfg(feature = "stargate")]
667pub fn call_ibc_packet_timeout_raw<A, S, Q>(
668 instance: &mut Instance<A, S, Q>,
669 env: &[u8],
670 msg: &[u8],
671) -> VmResult<Vec<u8>>
672where
673 A: BackendApi + 'static,
674 S: Storage + 'static,
675 Q: Querier + 'static,
676{
677 instance.set_storage_readonly(false);
678 call_raw(
679 instance,
680 "ibc_packet_timeout",
681 &[env, msg],
682 read_limits::RESULT_IBC_PACKET_TIMEOUT,
683 )
684}
685
686#[cfg(feature = "ibc2")]
687pub fn call_ibc2_packet_ack<A, S, Q, U>(
688 instance: &mut Instance<A, S, Q>,
689 env: &Env,
690 msg: &Ibc2PacketAckMsg,
691) -> VmResult<ContractResult<IbcBasicResponse<U>>>
692where
693 A: BackendApi + 'static,
694 S: Storage + 'static,
695 Q: Querier + 'static,
696 U: DeserializeOwned + CustomMsg,
697{
698 let env = to_vec(env)?;
699 let msg = to_vec(msg)?;
700 let data = call_ibc2_packet_ack_raw(instance, &env, &msg)?;
701 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_ACK)?;
702 Ok(result)
703}
704
705#[cfg(feature = "ibc2")]
706pub fn call_ibc2_packet_ack_raw<A, S, Q>(
707 instance: &mut Instance<A, S, Q>,
708 env: &[u8],
709 msg: &[u8],
710) -> VmResult<Vec<u8>>
711where
712 A: BackendApi + 'static,
713 S: Storage + 'static,
714 Q: Querier + 'static,
715{
716 instance.set_storage_readonly(false);
717 call_raw(
718 instance,
719 "ibc2_packet_ack",
720 &[env, msg],
721 read_limits::RESULT_IBC_PACKET_ACK,
722 )
723}
724
725#[cfg(feature = "ibc2")]
726pub fn call_ibc2_packet_receive_raw<A, S, Q>(
727 instance: &mut Instance<A, S, Q>,
728 env: &[u8],
729 msg: &[u8],
730) -> VmResult<Vec<u8>>
731where
732 A: BackendApi + 'static,
733 S: Storage + 'static,
734 Q: Querier + 'static,
735{
736 instance.set_storage_readonly(false);
737 call_raw(
738 instance,
739 "ibc2_packet_receive",
740 &[env, msg],
741 read_limits::RESULT_IBC_PACKET_RECEIVE,
742 )
743}
744
745#[cfg(feature = "ibc2")]
746pub fn call_ibc2_packet_timeout<A, S, Q, U>(
747 instance: &mut Instance<A, S, Q>,
748 env: &Env,
749 msg: &Ibc2PacketTimeoutMsg,
750) -> VmResult<ContractResult<IbcBasicResponse<U>>>
751where
752 A: BackendApi + 'static,
753 S: Storage + 'static,
754 Q: Querier + 'static,
755 U: DeserializeOwned + CustomMsg,
756{
757 let env = to_vec(env)?;
758 let msg = to_vec(msg)?;
759 let data = call_ibc2_packet_timeout_raw(instance, &env, &msg)?;
760 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_TIMEOUT)?;
761 Ok(result)
762}
763
764#[cfg(feature = "ibc2")]
765pub fn call_ibc2_packet_timeout_raw<A, S, Q>(
766 instance: &mut Instance<A, S, Q>,
767 env: &[u8],
768 msg: &[u8],
769) -> VmResult<Vec<u8>>
770where
771 A: BackendApi + 'static,
772 S: Storage + 'static,
773 Q: Querier + 'static,
774{
775 instance.set_storage_readonly(false);
776 call_raw(
777 instance,
778 "ibc2_packet_timeout",
779 &[env, msg],
780 read_limits::RESULT_IBC_PACKET_TIMEOUT,
781 )
782}
783
784#[cfg(feature = "ibc2")]
785pub fn call_ibc2_packet_send_raw<A, S, Q>(
786 instance: &mut Instance<A, S, Q>,
787 env: &[u8],
788 msg: &[u8],
789) -> VmResult<Vec<u8>>
790where
791 A: BackendApi + 'static,
792 S: Storage + 'static,
793 Q: Querier + 'static,
794{
795 instance.set_storage_readonly(false);
796 call_raw(
797 instance,
798 "ibc2_packet_send",
799 &[env, msg],
800 read_limits::RESULT_IBC2_PACKET_SEND,
801 )
802}
803
804#[cfg(feature = "ibc2")]
805pub fn call_ibc2_packet_send<A, S, Q, U>(
806 instance: &mut Instance<A, S, Q>,
807 env: &Env,
808 msg: &Ibc2PacketSendMsg,
809) -> VmResult<ContractResult<IbcBasicResponse<U>>>
810where
811 A: BackendApi + 'static,
812 S: Storage + 'static,
813 Q: Querier + 'static,
814 U: DeserializeOwned + CustomMsg,
815{
816 let env = to_vec(env)?;
817 let msg = to_vec(msg)?;
818 let data = call_ibc2_packet_send_raw(instance, &env, &msg)?;
819 let result = from_slice(&data, deserialization_limits::RESULT_IBC2_PACKET_SEND)?;
820 Ok(result)
821}
822
823pub fn call_ibc_source_callback_raw<A, S, Q>(
824 instance: &mut Instance<A, S, Q>,
825 env: &[u8],
826 msg: &[u8],
827) -> VmResult<Vec<u8>>
828where
829 A: BackendApi + 'static,
830 S: Storage + 'static,
831 Q: Querier + 'static,
832{
833 instance.set_storage_readonly(false);
834 call_raw(
835 instance,
836 "ibc_source_callback",
837 &[env, msg],
838 read_limits::RESULT_IBC_SOURCE_CALLBACK,
839 )
840}
841
842pub fn call_ibc_destination_callback_raw<A, S, Q>(
843 instance: &mut Instance<A, S, Q>,
844 env: &[u8],
845 msg: &[u8],
846) -> VmResult<Vec<u8>>
847where
848 A: BackendApi + 'static,
849 S: Storage + 'static,
850 Q: Querier + 'static,
851{
852 instance.set_storage_readonly(false);
853 call_raw(
854 instance,
855 "ibc_destination_callback",
856 &[env, msg],
857 read_limits::RESULT_IBC_DESTINATION_CALLBACK,
858 )
859}
860
861pub(crate) fn call_raw<A, S, Q>(
864 instance: &mut Instance<A, S, Q>,
865 name: &str,
866 args: &[&[u8]],
867 result_max_length: usize,
868) -> VmResult<Vec<u8>>
869where
870 A: BackendApi + 'static,
871 S: Storage + 'static,
872 Q: Querier + 'static,
873{
874 let mut arg_region_ptrs = Vec::<Value>::with_capacity(args.len());
875 for arg in args {
876 let region_ptr = instance.allocate(arg.len())?;
877 instance.write_memory(region_ptr, arg)?;
878 arg_region_ptrs.push(region_ptr.into());
879 }
880 let result = instance.call_function1(name, &arg_region_ptrs)?;
881 let res_region_ptr = ref_to_u32(&result)?;
882 let data = instance.read_memory(res_region_ptr, result_max_length)?;
883 instance.deallocate(res_region_ptr)?;
885 Ok(data)
886}
887
888#[cfg(feature = "ibc2")]
889pub fn call_ibc2_packet_receive<A, S, Q, U>(
890 instance: &mut Instance<A, S, Q>,
891 env: &Env,
892 msg: &Ibc2PacketReceiveMsg,
893) -> VmResult<ContractResult<IbcReceiveResponse<U>>>
894where
895 A: BackendApi + 'static,
896 S: Storage + 'static,
897 Q: Querier + 'static,
898 U: DeserializeOwned + CustomMsg,
899{
900 let env = to_vec(env)?;
901 let msg = to_vec(msg)?;
902 let data = call_ibc2_packet_receive_raw(instance, &env, &msg)?;
903 let result = from_slice(&data, deserialization_limits::RESULT_IBC_PACKET_RECEIVE)?;
904 Ok(result)
905}
906
907#[cfg(test)]
908mod tests {
909 use super::*;
910 use crate::testing::{
911 mock_env, mock_info, mock_instance, mock_instance_with_options, MockInstanceOptions,
912 };
913 use cosmwasm_std::{coins, from_json, to_json_string, Addr, Empty};
914 use sha2::{Digest, Sha256};
915
916 static HACKATOM: &[u8] = include_bytes!("../testdata/hackatom.wasm");
917 static HACKATOM_1_3: &[u8] = include_bytes!("../testdata/hackatom_1.3.wasm");
918 static CYBERPUNK: &[u8] = include_bytes!("../testdata/cyberpunk.wasm");
919 static FLOATY2: &[u8] = include_bytes!("../testdata/floaty_2.0.wasm");
920 static EMPTY: &[u8] = include_bytes!("../testdata/empty.wasm");
921
922 #[test]
923 fn call_instantiate_works() {
924 let mut instance = mock_instance(HACKATOM, &[]);
925
926 let info = mock_info(&instance.api().addr_make("creator"), &coins(1000, "earth"));
928 let verifier = instance.api().addr_make("verifies");
929 let beneficiary = instance.api().addr_make("benefits");
930 let msg = format!(r#"{{"verifier": "{verifier}", "beneficiary": "{beneficiary}"}}"#);
931 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg.as_bytes())
932 .unwrap()
933 .unwrap();
934 }
935
936 #[test]
937 fn call_instantiate_handles_missing_export() {
938 let mut deps = mock_instance(EMPTY, &[]);
939
940 let msg = Empty {};
941 let info = mock_info("creator", &coins(1000, "earth"));
942
943 let serialized_msg = to_vec(&msg).unwrap();
944 let err =
945 call_instantiate::<_, _, _, Empty>(&mut deps, &mock_env(), &info, &serialized_msg)
946 .unwrap_err();
947
948 assert!(matches!(
949 err,
950 VmError::ResolveErr {
951 msg,
952 ..
953 }
954 if msg == "Could not get export: Missing export instantiate"
955 ));
956 }
957
958 #[test]
959 fn call_execute_works() {
960 let mut instance = mock_instance(HACKATOM, &[]);
961
962 let info = mock_info(&instance.api().addr_make("creator"), &coins(1000, "earth"));
964 let verifier = instance.api().addr_make("verifies");
965 let beneficiary = instance.api().addr_make("benefits");
966 let msg = format!(r#"{{"verifier": "{verifier}", "beneficiary": "{beneficiary}"}}"#);
967 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg.as_bytes())
968 .unwrap()
969 .unwrap();
970
971 let info = mock_info(&verifier, &coins(15, "earth"));
973 let msg = br#"{"release":{"denom":"earth"}}"#;
974 call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg)
975 .unwrap()
976 .unwrap();
977 }
978
979 #[test]
980 fn call_execute_runs_out_of_gas() {
981 let mut instance = mock_instance(CYBERPUNK, &[]);
982
983 let info = mock_info("creator", &[]);
985 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#)
986 .unwrap()
987 .unwrap();
988
989 let info = mock_info("looper", &[]);
991 let msg = br#"{"cpu_loop":{}}"#;
992 let err =
993 call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err();
994 assert!(matches!(err, VmError::GasDepletion { .. }));
995 }
996
997 #[test]
998 fn call_execute_handles_panic() {
999 let mut instance = mock_instance(CYBERPUNK, &[]);
1000
1001 let info = mock_info("creator", &[]);
1002 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#)
1003 .unwrap()
1004 .unwrap();
1005
1006 let info = mock_info("troll", &[]);
1008 let msg = br#"{"panic":{}}"#;
1009 let err =
1010 call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err();
1011 match err {
1012 VmError::RuntimeErr { msg, .. } => {
1013 assert!(
1014 msg.contains("RuntimeError: Aborted: panicked at src/contract.rs:"),
1015 "Unexpected error msg: {msg}"
1016 )
1017 }
1018 err => panic!("Unexpected error: {err:?}"),
1019 }
1020 }
1021
1022 #[test]
1023 fn call_execute_handles_unreachable() {
1024 let mut instance = mock_instance(CYBERPUNK, &[]);
1025
1026 let info = mock_info("creator", &[]);
1027 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#)
1028 .unwrap()
1029 .unwrap();
1030
1031 let info = mock_info("troll", &[]);
1033 let msg = br#"{"unreachable":{}}"#;
1034 let err =
1035 call_execute::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg).unwrap_err();
1036 match err {
1037 VmError::RuntimeErr { msg, .. } => {
1038 assert!(msg.contains("RuntimeError: unreachable"))
1039 }
1040 err => panic!("Unexpected error: {err:?}"),
1041 }
1042 }
1043
1044 #[test]
1045 fn call_migrate_works() {
1046 let mut instance = mock_instance(
1047 HACKATOM_1_3, &[],
1049 );
1050
1051 let info = mock_info(&instance.api().addr_make("creator"), &coins(1000, "earth"));
1053 let verifier = instance.api().addr_make("verifies");
1054 let beneficiary = instance.api().addr_make("benefits");
1055 let msg = format!(r#"{{"verifier": "{verifier}", "beneficiary": "{beneficiary}"}}"#);
1056 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg.as_bytes())
1057 .unwrap()
1058 .unwrap();
1059
1060 let someone_else = instance.api().addr_make("someone else");
1062 let msg = format!(r#"{{"verifier": "{someone_else}"}}"#);
1063 let _res = call_migrate::<_, _, _, Empty>(&mut instance, &mock_env(), msg.as_bytes())
1064 .unwrap()
1065 .unwrap();
1066
1067 let msg = br#"{"verifier":{}}"#;
1069 let contract_result = call_query(&mut instance, &mock_env(), msg).unwrap();
1070 let query_response = contract_result.unwrap();
1071 assert_eq!(
1072 query_response,
1073 format!(r#"{{"verifier":"{}"}}"#, someone_else).as_bytes(),
1074 );
1075 }
1076
1077 #[test]
1078 fn call_migrate_with_info_works_for_classic_migrate_signature() {
1079 let mut instance = mock_instance(
1080 HACKATOM_1_3, &[],
1082 );
1083
1084 let info = mock_info(&instance.api().addr_make("creator"), &coins(1000, "earth"));
1086 let verifier = instance.api().addr_make("verifies");
1087 let beneficiary = instance.api().addr_make("benefits");
1088 let msg = format!(r#"{{"verifier": "{verifier}", "beneficiary": "{beneficiary}"}}"#);
1089 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg.as_bytes())
1090 .unwrap()
1091 .unwrap();
1092
1093 let someone_else = instance.api().addr_make("someone else");
1095 let msg = format!(r#"{{"verifier": "{someone_else}"}}"#);
1096 let migrate_info = MigrateInfo {
1097 sender: Addr::unchecked(someone_else.clone()),
1098 old_migrate_version: Some(33),
1099 };
1100 let _res = call_migrate_with_info::<_, _, _, Empty>(
1101 &mut instance,
1102 &mock_env(),
1103 msg.as_bytes(),
1104 &migrate_info,
1105 )
1106 .unwrap()
1107 .unwrap();
1108
1109 let msg = br#"{"verifier":{}}"#;
1111 let contract_result = call_query(&mut instance, &mock_env(), msg).unwrap();
1112 let query_response = contract_result.unwrap();
1113 assert_eq!(
1114 query_response,
1115 format!(r#"{{"verifier":"{}"}}"#, someone_else).as_bytes(),
1116 );
1117 }
1118
1119 #[test]
1120 fn call_query_works() {
1121 let mut instance = mock_instance(HACKATOM, &[]);
1122
1123 let info = mock_info(&instance.api().addr_make("creator"), &coins(1000, "earth"));
1125 let verifier = instance.api().addr_make("verifies");
1126 let beneficiary = instance.api().addr_make("benefits");
1127 let msg = format!(r#"{{"verifier": "{verifier}", "beneficiary": "{beneficiary}"}}"#);
1128 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, msg.as_bytes())
1129 .unwrap()
1130 .unwrap();
1131
1132 let msg = br#"{"verifier":{}}"#;
1134 let contract_result = call_query(&mut instance, &mock_env(), msg).unwrap();
1135 let query_response = contract_result.unwrap();
1136 assert_eq!(
1137 query_response,
1138 format!("{{\"verifier\":\"{verifier}\"}}").as_bytes()
1139 );
1140 }
1141
1142 #[test]
1143 fn float_instrs_are_deterministic() {
1144 #[derive(Debug, serde::Serialize, serde::Deserialize)]
1145 #[serde(rename_all = "snake_case")]
1146 pub enum Value {
1147 U32(u32),
1148 U64(u64),
1149 F32(u32),
1150 F64(u64),
1151 }
1152
1153 let mut instance = mock_instance_with_options(
1154 FLOATY2,
1155 MockInstanceOptions {
1156 gas_limit: u64::MAX,
1157 memory_limit: None,
1158 ..Default::default()
1159 },
1160 );
1161
1162 let info = mock_info("creator", &[]);
1164 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#)
1165 .unwrap()
1166 .unwrap();
1167
1168 let msg = br#"{"instructions":{}}"#;
1170 let contract_result = call_query(&mut instance, &mock_env(), msg)
1171 .unwrap()
1172 .unwrap();
1173 let instructions: Vec<String> = from_json(contract_result).unwrap();
1174 assert_eq!(instructions.len(), 70);
1176
1177 const RUNS_PER_INSTRUCTION: u64 = 150;
1178 let mut hasher = Sha256::new();
1179 for instr in &instructions {
1180 for seed in 0..RUNS_PER_INSTRUCTION {
1181 let args: Vec<Value> = from_json(
1183 call_query(
1184 &mut instance,
1185 &mock_env(),
1186 format!(
1187 r#"{{"random_args_for":{{ "instruction": "{instr}", "seed": {seed}}}}}"#
1188 )
1189 .as_bytes(),
1190 )
1191 .unwrap()
1192 .unwrap(),
1193 )
1194 .unwrap();
1195
1196 let args = to_json_string(&args).unwrap();
1198 let msg: String = format!(
1199 r#"{{"run":{{
1200 "instruction": "{instr}",
1201 "args": {args}
1202 }}}}"#
1203 );
1204 let result = match call_query(&mut instance, &mock_env(), msg.as_bytes()) {
1207 Ok(ContractResult::Ok(r)) => format!("{:?}", from_json::<Value>(&r).unwrap()),
1208 Err(VmError::RuntimeErr { msg, .. }) => msg,
1209 e => panic!("unexpected error: {e:?}"),
1210 };
1211 hasher.update(format!("{instr}{seed}{result}").as_bytes());
1213 }
1214 }
1215 let hash = Digest::finalize(hasher);
1216 assert_eq!(
1217 hex::encode(hash.as_slice()),
1218 "95f70fa6451176ab04a9594417a047a1e4d8e2ff809609b8f81099496bee2393"
1219 );
1220 }
1221
1222 #[cfg(feature = "stargate")]
1223 mod ibc {
1224 use super::*;
1225 use crate::testing::{MockApi, MockQuerier, MockStorage};
1226 use cosmwasm_std::testing::mock_ibc_packet_timeout;
1227 use cosmwasm_std::testing::{
1228 mock_ibc_channel_close_init, mock_ibc_channel_connect_ack, mock_ibc_channel_open_init,
1229 mock_ibc_packet_ack, mock_ibc_packet_recv, mock_wasmd_attr,
1230 };
1231 use cosmwasm_std::{
1232 Event, IbcAckCallbackMsg, IbcAcknowledgement, IbcOrder, IbcTimeoutCallbackMsg, ReplyOn,
1233 SubMsgResponse, SubMsgResult,
1234 };
1235 static IBC_REFLECT: &[u8] = include_bytes!("../testdata/ibc_reflect.wasm");
1236 static IBC_CALLBACKS: &[u8] = include_bytes!("../testdata/ibc_callbacks.wasm");
1237 const IBC_VERSION: &str = "ibc-reflect-v1";
1238
1239 fn setup(
1240 instance: &mut Instance<MockApi, MockStorage, MockQuerier>,
1241 channel_id: &str,
1242 account: &str,
1243 ) {
1244 let info = mock_info("creator", &[]);
1246 let msg = br#"{"reflect_code_id":77}"#;
1247 call_instantiate::<_, _, _, Empty>(instance, &mock_env(), &info, msg)
1248 .unwrap()
1249 .unwrap();
1250 let handshake_open =
1252 mock_ibc_channel_open_init(channel_id, IbcOrder::Ordered, IBC_VERSION);
1253 call_ibc_channel_open(instance, &mock_env(), &handshake_open)
1254 .unwrap()
1255 .unwrap();
1256 let handshake_connect =
1258 mock_ibc_channel_connect_ack(channel_id, IbcOrder::Ordered, IBC_VERSION);
1259 let res: IbcBasicResponse = call_ibc_channel_connect::<_, _, _, Empty>(
1260 instance,
1261 &mock_env(),
1262 &handshake_connect,
1263 )
1264 .unwrap()
1265 .unwrap();
1266 assert_eq!(1, res.messages.len());
1267 assert_eq!(
1268 res.events,
1269 [Event::new("ibc").add_attribute("channel", "connect")]
1270 );
1271 assert_eq!(ReplyOn::Success, res.messages[0].reply_on);
1272 let id = res.messages[0].id;
1273 let payload = res.messages[0].payload.clone();
1274 let event = Event::new("instantiate").add_attributes(vec![
1275 mock_wasmd_attr("_contract_address", account),
1277 ]);
1278 #[allow(deprecated)]
1280 let response = Reply {
1281 id,
1282 payload,
1283 gas_used: 1234567,
1284 result: SubMsgResult::Ok(SubMsgResponse {
1285 events: vec![event],
1286 msg_responses: vec![],
1287 data: None,
1288 }),
1289 };
1290 call_reply::<_, _, _, Empty>(instance, &mock_env(), &response).unwrap();
1291 }
1292
1293 const CHANNEL_ID: &str = "channel-123";
1294 const ACCOUNT: &str = "account-456";
1295
1296 #[test]
1297 fn call_ibc_channel_open_and_connect_works() {
1298 let mut instance = mock_instance(IBC_REFLECT, &[]);
1299 setup(&mut instance, CHANNEL_ID, ACCOUNT);
1300 }
1301
1302 #[test]
1303 fn call_ibc_channel_close_works() {
1304 let mut instance = mock_instance(IBC_REFLECT, &[]);
1305 let account = instance.api().addr_make(ACCOUNT);
1306 setup(&mut instance, CHANNEL_ID, &account);
1307 let handshake_close =
1308 mock_ibc_channel_close_init(CHANNEL_ID, IbcOrder::Ordered, IBC_VERSION);
1309 call_ibc_channel_close::<_, _, _, Empty>(&mut instance, &mock_env(), &handshake_close)
1310 .unwrap()
1311 .unwrap();
1312 }
1313
1314 #[test]
1315 fn call_ibc_packet_ack_works() {
1316 let mut instance = mock_instance(IBC_REFLECT, &[]);
1317 setup(&mut instance, CHANNEL_ID, ACCOUNT);
1318 let ack = IbcAcknowledgement::new(br#"{}"#);
1319 let msg = mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, ack).unwrap();
1320 call_ibc_packet_ack::<_, _, _, Empty>(&mut instance, &mock_env(), &msg)
1321 .unwrap()
1322 .unwrap();
1323 }
1324
1325 #[test]
1326 fn call_ibc_packet_timeout_works() {
1327 let mut instance = mock_instance(IBC_REFLECT, &[]);
1328 setup(&mut instance, CHANNEL_ID, ACCOUNT);
1329 let msg = mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap();
1330 call_ibc_packet_timeout::<_, _, _, Empty>(&mut instance, &mock_env(), &msg)
1331 .unwrap()
1332 .unwrap();
1333 }
1334
1335 #[test]
1336 fn call_ibc_packet_receive_works() {
1337 let mut instance = mock_instance(IBC_REFLECT, &[]);
1338 setup(&mut instance, CHANNEL_ID, ACCOUNT);
1339 let who_am_i = br#"{"who_am_i":{}}"#;
1340 let msg = mock_ibc_packet_recv(CHANNEL_ID, who_am_i).unwrap();
1341 call_ibc_packet_receive::<_, _, _, Empty>(&mut instance, &mock_env(), &msg)
1342 .unwrap()
1343 .unwrap();
1344 }
1345
1346 #[test]
1347 fn call_ibc_source_callback_works() {
1348 let mut instance = mock_instance(IBC_CALLBACKS, &[]);
1349
1350 let creator = instance.api().addr_make("creator");
1352 let info = mock_info(&creator, &[]);
1353 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, br#"{}"#)
1354 .unwrap()
1355 .unwrap();
1356
1357 #[derive(serde::Serialize, serde::Deserialize)]
1359 struct CallbackStats {
1360 pub ibc_ack_callbacks: Vec<IbcPacketAckMsg>,
1361 pub ibc_timeout_callbacks: Vec<IbcPacketTimeoutMsg>,
1362 }
1363
1364 let ack = mock_ibc_packet_ack(CHANNEL_ID, br#"{}"#, IbcAcknowledgement::new(br#"{}"#))
1366 .unwrap();
1367 let msg = IbcSourceCallbackMsg::Acknowledgement(IbcAckCallbackMsg::new(
1368 ack.acknowledgement,
1369 ack.original_packet,
1370 ack.relayer,
1371 ));
1372 call_ibc_source_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg)
1373 .unwrap()
1374 .unwrap();
1375 let stats: CallbackStats = serde_json::from_slice(
1377 &call_query::<_, _, _>(&mut instance, &mock_env(), br#"{"callback_stats":{}}"#)
1378 .unwrap()
1379 .unwrap(),
1380 )
1381 .unwrap();
1382 assert_eq!(1, stats.ibc_ack_callbacks.len());
1383 assert_eq!(0, stats.ibc_timeout_callbacks.len());
1384
1385 let timeout = mock_ibc_packet_timeout(CHANNEL_ID, br#"{}"#).unwrap();
1387 let msg = IbcSourceCallbackMsg::Timeout(IbcTimeoutCallbackMsg::new(
1388 timeout.packet,
1389 timeout.relayer,
1390 ));
1391 call_ibc_source_callback::<_, _, _, Empty>(&mut instance, &mock_env(), &msg)
1392 .unwrap()
1393 .unwrap();
1394 let stats: CallbackStats = serde_json::from_slice(
1396 &call_query::<_, _, _>(&mut instance, &mock_env(), br#"{"callback_stats":{}}"#)
1397 .unwrap()
1398 .unwrap(),
1399 )
1400 .unwrap();
1401 assert_eq!(1, stats.ibc_ack_callbacks.len());
1402 assert_eq!(1, stats.ibc_timeout_callbacks.len());
1403 }
1404 }
1405
1406 #[cfg(feature = "ibc2")]
1407 mod ibc2 {
1408 use super::*;
1409 use cosmwasm_std::testing::{
1410 mock_ibc2_packet_ack, mock_ibc2_packet_recv, mock_ibc2_packet_send,
1411 mock_ibc2_packet_timeout,
1412 };
1413 static IBC2: &[u8] = include_bytes!("../testdata/ibc2.wasm");
1414
1415 #[derive(serde::Serialize)]
1416 pub struct IbcPayload {
1417 pub response_without_ack: bool,
1418 pub send_async_ack_for_prev_msg: bool,
1419 }
1420
1421 #[test]
1422 fn call_ibc2_packet_ack_works() {
1423 let mut instance = mock_instance(IBC2, &[]);
1425 let info = mock_info("creator", &[]);
1426 let instantiate_msg = br#"{}"#;
1427 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, instantiate_msg)
1428 .unwrap()
1429 .unwrap();
1430
1431 let ibc2_msg = IbcPayload {
1432 response_without_ack: false,
1433 send_async_ack_for_prev_msg: false,
1434 };
1435 let ibc2_ack = mock_ibc2_packet_ack(&ibc2_msg).unwrap();
1436 call_ibc2_packet_ack::<_, _, _, Empty>(&mut instance, &mock_env(), &ibc2_ack)
1437 .unwrap()
1438 .unwrap();
1439 }
1440
1441 #[test]
1442 fn call_ibc2_packet_receive_works() {
1443 let mut instance = mock_instance(IBC2, &[]);
1445 let info = mock_info("creator", &[]);
1446 let instantiate_msg = br#"{}"#;
1447 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, instantiate_msg)
1448 .unwrap()
1449 .unwrap();
1450
1451 let ibc2_msg = IbcPayload {
1452 response_without_ack: false,
1453 send_async_ack_for_prev_msg: false,
1454 };
1455 let ibc2_timeout = mock_ibc2_packet_recv(&ibc2_msg).unwrap();
1456 call_ibc2_packet_receive::<_, _, _, Empty>(&mut instance, &mock_env(), &ibc2_timeout)
1457 .unwrap()
1458 .unwrap();
1459 }
1460
1461 #[test]
1462 fn call_ibc2_packet_timeout_works() {
1463 let mut instance = mock_instance(IBC2, &[]);
1465 let info = mock_info("creator", &[]);
1466 let instantiate_msg = br#"{}"#;
1467 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, instantiate_msg)
1468 .unwrap()
1469 .unwrap();
1470
1471 let ibc2_msg = br#"SomeRandomMsg"#;
1472 let ibc2_msg = mock_ibc2_packet_timeout(ibc2_msg).unwrap();
1473 call_ibc2_packet_timeout::<_, _, _, Empty>(&mut instance, &mock_env(), &ibc2_msg)
1474 .unwrap()
1475 .unwrap();
1476 }
1477
1478 #[test]
1479 fn call_ibc2_packet_send_works() {
1480 let mut instance = mock_instance(IBC2, &[]);
1482 let info = mock_info("creator", &[]);
1483 let instantiate_msg = br#"{}"#;
1484 call_instantiate::<_, _, _, Empty>(&mut instance, &mock_env(), &info, instantiate_msg)
1485 .unwrap()
1486 .unwrap();
1487
1488 let ibc2_msg = IbcPayload {
1489 response_without_ack: false,
1490 send_async_ack_for_prev_msg: false,
1491 };
1492 let ibc2_sent = mock_ibc2_packet_send(&ibc2_msg).unwrap();
1493 call_ibc2_packet_send::<_, _, _, Empty>(&mut instance, &mock_env(), &ibc2_sent)
1494 .unwrap()
1495 .unwrap();
1496 }
1497 }
1498}