abstract_cw_multi_test/
contracts.rs

1//! # Implementation of the contract trait and contract wrapper
2
3use crate::error::{anyhow, bail, AnyError, AnyResult};
4use cosmwasm_std::{
5    from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env,
6    IbcSourceCallbackMsg, MessageInfo, QuerierWrapper, Reply, Response, SubMsg,
7};
8use cosmwasm_std::{
9    IbcBasicResponse, IbcChannelCloseMsg, IbcChannelConnectMsg, IbcChannelOpenMsg,
10    IbcChannelOpenResponse, IbcPacketAckMsg, IbcPacketReceiveMsg, IbcPacketTimeoutMsg,
11    IbcReceiveResponse,
12};
13use ibc::{IbcClosure, IbcFn};
14use serde::de::DeserializeOwned;
15use std::fmt::{Debug, Display};
16use std::ops::Deref;
17
18/// This trait serves as a primary interface for interacting with contracts.
19#[rustfmt::skip]
20pub trait Contract<C, Q = Empty>
21where
22    C: CustomMsg,
23    Q: CustomQuery,
24{
25    /// Evaluates contract's `execute` entry-point.
26    fn execute(&self, deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: Vec<u8>) -> AnyResult<Response<C>>;
27
28    /// Evaluates contract's `instantiate` entry-point.
29    fn instantiate(&self, deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: Vec<u8>) -> AnyResult<Response<C>>;
30
31    /// Evaluates contract's `query` entry-point.
32    fn query(&self, deps: Deps<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Binary>;
33
34    /// Evaluates contract's `sudo` entry-point.
35    fn sudo(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Response<C>>;
36
37    /// Evaluates contract's `reply` entry-point.
38    fn reply(&self, deps: DepsMut<Q>, env: Env, msg: Reply) -> AnyResult<Response<C>>;
39
40    /// Evaluates contract's `migrate` entry-point.
41    fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Response<C>>;
42
43    /// Returns the provided checksum of the contract's Wasm blob.
44    fn checksum(&self) -> Option<Checksum> {
45        None
46    }
47
48    /// Executes the contract ibc_channel_open endpoint
49    #[allow(unused)]
50    fn ibc_channel_open(
51        &self,
52        deps: DepsMut<Q>,
53        env: Env,
54        msg: IbcChannelOpenMsg,
55    ) -> AnyResult<IbcChannelOpenResponse> {
56        bail!("No Ibc capabilities on this contract")
57    }
58
59    /// Executes the contract ibc_channel_connect endpoint
60    #[allow(unused)]
61    fn ibc_channel_connect(
62        &self,
63        deps: DepsMut<Q>,
64        env: Env,
65        msg: IbcChannelConnectMsg,
66    ) -> AnyResult<IbcBasicResponse<C>> {
67        bail!("No Ibc capabilities on this contract")
68    }
69
70    /// Executes the contract ibc_channel_close endpoint
71    #[allow(unused)]
72    fn ibc_channel_close(
73        &self,
74        deps: DepsMut<Q>,
75        env: Env,
76        msg: IbcChannelCloseMsg,
77    ) -> AnyResult<IbcBasicResponse<C>> {
78        bail!("No Ibc capabilities on this contract")
79    }
80
81    /// Executes the contract ibc_packet_receive endpoint
82    #[allow(unused)]
83    fn ibc_packet_receive(
84        &self,
85        deps: DepsMut<Q>,
86        env: Env,
87        msg: IbcPacketReceiveMsg,
88    ) -> AnyResult<IbcReceiveResponse<C>> {
89        bail!("No Ibc capabilities on this contract")
90    }
91
92    /// Executes the contract ibc_packet_acknowledge endpoint
93    #[allow(unused)]
94    fn ibc_packet_acknowledge(
95        &self,
96        deps: DepsMut<Q>,
97        env: Env,
98        msg: IbcPacketAckMsg,
99    ) -> AnyResult<IbcBasicResponse<C>> {
100        bail!("No Ibc capabilities on this contract")
101    }
102
103    /// Executes the contract ibc_packet_timeout endpoint
104    #[allow(unused)]
105    fn ibc_packet_timeout(
106        &self,
107        deps: DepsMut<Q>,
108        env: Env,
109        msg: IbcPacketTimeoutMsg,
110    ) -> AnyResult<IbcBasicResponse<C>> {
111        bail!("No Ibc capabilities on this contract")
112    }
113    
114    /// Executes the contract ibc_source_callback endpoint
115    #[allow(unused)]
116    fn ibc_source_callback(
117        &self,
118        deps: DepsMut<Q>,
119        env: Env,
120        msg: IbcSourceCallbackMsg,
121    ) -> AnyResult<IbcBasicResponse<C>> {
122        bail!("No Ibc source callback on this contract")
123    }
124
125
126}
127
128#[rustfmt::skip]
129mod closures {
130    use super::*;
131
132    // function types
133    pub type ContractFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: T) -> Result<Response<C>, E>;
134    pub type PermissionedFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: T) -> Result<Response<C>, E>;
135    pub type ReplyFn<C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: Reply) -> Result<Response<C>, E>;
136    pub type QueryFn<T, E, Q> = fn(deps: Deps<Q>, env: Env, msg: T) -> Result<Binary, E>;
137
138    // closure types
139    pub type ContractClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, MessageInfo, T) -> Result<Response<C>, E>>;
140    pub type PermissionedClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, T) -> Result<Response<C>, E>>;
141    pub type ReplyClosure<C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, Reply) -> Result<Response<C>, E>>;
142    pub type QueryClosure<T, E, Q> = Box<dyn Fn(Deps<Q>, Env, T) -> Result<Binary, E>>;
143
144    pub mod ibc{
145        use super::*;
146        pub type IbcFn<T, R, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: T) -> Result<R, E>;
147
148        pub type IbcClosure<T, R, E, Q> = Box<dyn Fn(DepsMut<Q>,Env, T) -> Result<R, E>>;
149    }
150}
151
152use closures::*;
153
154/// This structure wraps the [Contract] trait implementor
155/// and provides generic access to the contract's entry-points.
156///
157/// List of generic types used in [ContractWrapper]:
158/// - **T1** type of message passed to [execute] entry-point.
159/// - **T2** type of message passed to [instantiate] entry-point.
160/// - **T3** type of message passed to [query] entry-point.
161/// - **T4** type of message passed to [sudo] entry-point.
162/// - instead of **~~T5~~**, always the `Reply` type is used in [reply] entry-point.
163/// - **T6** type of message passed to [migrate] entry-point.
164/// - **E1** type of error returned from [execute] entry-point.
165/// - **E2** type of error returned from [instantiate] entry-point.
166/// - **E3** type of error returned from [query] entry-point.
167/// - **E4** type of error returned from [sudo] entry-point.
168/// - **E5** type of error returned from [reply] entry-point.
169/// - **E6** type of error returned from [migrate] entry-point.
170/// - **C** type of custom message returned from all entry-points except [query].
171/// - **Q** type of custom query in `Querier` passed as 'Deps' or 'DepsMut' to all entry-points.
172///
173/// The following table summarizes the purpose of all generic types used in [ContractWrapper].
174/// ```text
175/// ┌─────────────────────┬────────────────────────┬─────────────────────┬─────────┬─────────┬───────┬───────┐
176/// │      Contract       │    Contract            │                     │         │         │       │       │
177/// │    entry-point      │    wrapper             │    Closure type     │ Message │ Message │ Error │ Query │
178/// │                     │    member              │                     │   IN    │   OUT   │  OUT  │       │
179/// ╞═════════════════════╪════════════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡
180/// │          (1)        │                        │                     │         │         │       │       │
181/// ╞═════════════════════╪════════════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡
182/// │ execute             │ execute_fn             │ ContractClosure     │   T1    │    C    │  E1   │   Q   │
183/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
184/// │ instantiate         │ instantiate_fn         │ ContractClosure     │   T2    │    C    │  E2   │   Q   │
185/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
186/// │ query               │ query_fn               │ QueryClosure        │   T3    │ Binary  │  E3   │   Q   │
187/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
188/// │ sudo                │ sudo_fn                │ PermissionedClosure │   T4    │    C    │  E4   │   Q   │
189/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
190/// │ reply               │ reply_fn               │ ReplyClosure        │  Reply  │    C    │  E5   │   Q   │
191/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
192/// │ migrate             │ migrate_fn             │ PermissionedClosure │   T6    │    C    │  E6   │   Q   │
193/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
194/// │ ibc_channel_open    │ ibc_channel_open_fn    │ IbcClosure          │   --    │    C    │  E7   │   Q   │
195/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
196/// │ ibc_channel_connect │ ibc_channel_connect_fn │ IbcClosure          │   --    │    C    │  E8   │   Q   │
197/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
198/// │ ibc_channel_close   │ ibc_channel_close_fn   │ IbcClosure          │   --    │    C    │  E9   │   Q   │
199/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
200/// │ ibc_packet_receive  │ ibc_packet_receive_fn  │ IbcClosure          │   --    │    C    │  E10  │   Q   │
201/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
202/// │ ibc_packet_ack      │ ibc_packet_ack_fn      │ IbcClosure          │   --    │    C    │  E11  │   Q   │
203/// ├─────────────────────┼────────────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
204/// │ ibc_packet_timeout  │ ibc_packet_timeout_fn  │ IbcClosure          │   --    │    C    │  E12  │   Q   │
205/// └─────────────────────┴────────────────────────┴─────────────────────┴─────────┴─────────┴───────┴───────┘
206/// ```
207/// The general schema depicting which generic type is used in entry points is shown below.
208/// Entry point, when called, is provided minimum two arguments: custom query of type **Q**
209/// (inside `Deps` or `DepsMut`) and input message of type **T1**, **T2**, **T3**, **T4**,
210/// **Reply** or **T6**. As a result, entry point returns custom output message of type
211/// Response<**C**> or **Binary** and an error of type **E1**, **E2**, **E3**, **E4**, **E5**
212/// or **E6**.
213///
214/// ```text
215///    entry_point(query, .., message_in) -> Result<message_out, error>
216///                  ┬           ┬                      ┬          ┬
217///             Q >──┘           │                      │          └──> E1,E2,E3,E4,E5,E6
218///    T1,T2,T3,T4,Reply,T6 >────┘                      └─────────────> C,Binary
219/// ```
220/// Generic type **C** defines a custom message that is specific for the **whole blockchain**.
221/// Similarly, the generic type **Q** defines a custom query that is also specific
222/// to the **whole blockchain**. Other generic types are specific to the implemented contract.
223/// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**,
224/// but each contract may use different type for other generic types.
225/// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`.
226///
227/// [execute]: Contract::execute
228/// [instantiate]: Contract::instantiate
229/// [query]: Contract::query
230/// [sudo]: Contract::sudo
231/// [reply]: Contract::reply
232/// [migrate]: Contract::migrate
233pub struct ContractWrapper<
234    T1,
235    T2,
236    T3,
237    E1,
238    E2,
239    E3,
240    C = Empty,
241    Q = Empty,
242    T4 = Empty,
243    E4 = AnyError,
244    E5 = AnyError,
245    T6 = Empty,
246    E6 = AnyError,
247    E7 = AnyError,
248    E8 = AnyError,
249    E9 = AnyError,
250    E10 = AnyError,
251    E11 = AnyError,
252    E12 = AnyError,
253    E13 = AnyError,
254> where
255    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
256    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
257    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
258    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
259    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
260    E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point.
261    E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point.
262    E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point.
263    E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point.
264    E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point.
265    E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point.
266    E7: Display + Debug + Send + Sync, // Type of error returned from `channel_open` entry-point.
267    E8: Display + Debug + Send + Sync, // Type of error returned from `channel_connect` entry-point.
268    E9: Display + Debug + Send + Sync, // Type of error returned from `channel_close` entry-point.
269    E10: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_receive` entry-point.
270    E11: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_ack` entry-point.
271    E12: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_timeout` entry-point.
272    E13: Display + Debug + Send + Sync, // Type of error returned from `ibc_source_callback` entry-point.
273    C: CustomMsg, // Type of custom message returned from all entry-points except `query`.
274    Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
275{
276    execute_fn: ContractClosure<T1, C, E1, Q>,
277    instantiate_fn: ContractClosure<T2, C, E2, Q>,
278    query_fn: QueryClosure<T3, E3, Q>,
279    sudo_fn: Option<PermissionedClosure<T4, C, E4, Q>>,
280    reply_fn: Option<ReplyClosure<C, E5, Q>>,
281    migrate_fn: Option<PermissionedClosure<T6, C, E6, Q>>,
282    checksum: Option<Checksum>,
283
284    channel_open_fn: Option<IbcClosure<IbcChannelOpenMsg, IbcChannelOpenResponse, E7, Q>>,
285    channel_connect_fn: Option<IbcClosure<IbcChannelConnectMsg, IbcBasicResponse<C>, E8, Q>>,
286    channel_close_fn: Option<IbcClosure<IbcChannelCloseMsg, IbcBasicResponse<C>, E9, Q>>,
287
288    ibc_packet_receive_fn: Option<IbcClosure<IbcPacketReceiveMsg, IbcReceiveResponse<C>, E10, Q>>,
289    ibc_packet_ack_fn: Option<IbcClosure<IbcPacketAckMsg, IbcBasicResponse<C>, E11, Q>>,
290    ibc_packet_timeout_fn: Option<IbcClosure<IbcPacketTimeoutMsg, IbcBasicResponse<C>, E12, Q>>,
291
292    ibc_source_callback: Option<IbcClosure<IbcSourceCallbackMsg, IbcBasicResponse<C>, E13, Q>>,
293}
294
295impl<T1, T2, T3, E1, E2, E3, C, Q> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q>
296where
297    T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point.
298    T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point.
299    T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point.
300    E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point.
301    E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point.
302    E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point.
303    C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`.
304    Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
305{
306    /// Creates a new contract wrapper with default settings.
307    pub fn new(
308        execute_fn: ContractFn<T1, C, E1, Q>,
309        instantiate_fn: ContractFn<T2, C, E2, Q>,
310        query_fn: QueryFn<T3, E3, Q>,
311    ) -> Self {
312        Self {
313            execute_fn: Box::new(execute_fn),
314            instantiate_fn: Box::new(instantiate_fn),
315            query_fn: Box::new(query_fn),
316            sudo_fn: None,
317            reply_fn: None,
318            migrate_fn: None,
319            checksum: None,
320
321            channel_open_fn: None,
322            channel_connect_fn: None,
323            channel_close_fn: None,
324
325            ibc_packet_receive_fn: None,
326            ibc_packet_ack_fn: None,
327            ibc_packet_timeout_fn: None,
328
329            ibc_source_callback: None,
330        }
331    }
332
333    /// This will take a contract that returns `Response<Empty>` and will _upgrade_ it
334    /// to `Response<C>` if needed, to be compatible with a chain-specific extension.
335    pub fn new_with_empty(
336        execute_fn: ContractFn<T1, Empty, E1, Empty>,
337        instantiate_fn: ContractFn<T2, Empty, E2, Empty>,
338        query_fn: QueryFn<T3, E3, Empty>,
339    ) -> Self {
340        Self {
341            execute_fn: customize_contract_fn(execute_fn),
342            instantiate_fn: customize_contract_fn(instantiate_fn),
343            query_fn: customize_query_fn(query_fn),
344            sudo_fn: None,
345            reply_fn: None,
346            migrate_fn: None,
347            checksum: None,
348
349            channel_open_fn: None,
350            channel_connect_fn: None,
351            channel_close_fn: None,
352
353            ibc_packet_receive_fn: None,
354            ibc_packet_ack_fn: None,
355            ibc_packet_timeout_fn: None,
356
357            ibc_source_callback: None,
358        }
359    }
360}
361
362#[allow(clippy::type_complexity)]
363impl<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6, E7, E8, E9, E10, E11, E12, E13>
364    ContractWrapper<
365        T1,
366        T2,
367        T3,
368        E1,
369        E2,
370        E3,
371        C,
372        Q,
373        T4,
374        E4,
375        E5,
376        T6,
377        E6,
378        E7,
379        E8,
380        E9,
381        E10,
382        E11,
383        E12,
384        E13,
385    >
386where
387    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
388    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
389    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
390    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
391    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
392    E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point.
393    E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point.
394    E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point.
395    E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point.
396    E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point.
397    E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point.
398    E7: Display + Debug + Send + Sync, // Type of error returned from `channel_open` entry-point.
399    E8: Display + Debug + Send + Sync, // Type of error returned from `channel_connect` entry-point.
400    E9: Display + Debug + Send + Sync, // Type of error returned from `channel_close` entry-point.
401    E10: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_receive` entry-point.
402    E11: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_ack` entry-point.
403    E12: Display + Debug + Send + Sync, // Type of error returned from `ibc_packet_timeout` entry-point.
404    E13: Display + Debug + Send + Sync, // Type of error returned from `ibc_source_callback` entry-point.
405    C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`.
406    Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
407{
408    /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type.
409    pub fn with_sudo<T4A, E4A>(
410        self,
411        sudo_fn: PermissionedFn<T4A, C, E4A, Q>,
412    ) -> ContractWrapper<
413        T1,
414        T2,
415        T3,
416        E1,
417        E2,
418        E3,
419        C,
420        Q,
421        T4A,
422        E4A,
423        E5,
424        T6,
425        E6,
426        E7,
427        E8,
428        E9,
429        E10,
430        E11,
431        E12,
432        E13,
433    >
434    where
435        T4A: DeserializeOwned + 'static,
436        E4A: Display + Debug + Send + Sync + 'static,
437    {
438        ContractWrapper {
439            execute_fn: self.execute_fn,
440            instantiate_fn: self.instantiate_fn,
441            query_fn: self.query_fn,
442            sudo_fn: Some(Box::new(sudo_fn)),
443            reply_fn: self.reply_fn,
444            migrate_fn: self.migrate_fn,
445            checksum: None,
446
447            channel_open_fn: self.channel_open_fn,
448            channel_connect_fn: self.channel_connect_fn,
449            channel_close_fn: self.channel_close_fn,
450
451            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
452            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
453            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
454
455            ibc_source_callback: self.ibc_source_callback,
456        }
457    }
458
459    /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message.
460    pub fn with_sudo_empty<T4A, E4A>(
461        self,
462        sudo_fn: PermissionedFn<T4A, Empty, E4A, Empty>,
463    ) -> ContractWrapper<
464        T1,
465        T2,
466        T3,
467        E1,
468        E2,
469        E3,
470        C,
471        Q,
472        T4A,
473        E4A,
474        E5,
475        T6,
476        E6,
477        E7,
478        E8,
479        E9,
480        E10,
481        E11,
482        E12,
483        E13,
484    >
485    where
486        T4A: DeserializeOwned + 'static,
487        E4A: Display + Debug + Send + Sync + 'static,
488    {
489        ContractWrapper {
490            execute_fn: self.execute_fn,
491            instantiate_fn: self.instantiate_fn,
492            query_fn: self.query_fn,
493            sudo_fn: Some(customize_permissioned_fn(sudo_fn)),
494            reply_fn: self.reply_fn,
495            migrate_fn: self.migrate_fn,
496            checksum: None,
497
498            channel_open_fn: self.channel_open_fn,
499            channel_connect_fn: self.channel_connect_fn,
500            channel_close_fn: self.channel_close_fn,
501
502            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
503            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
504            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
505
506            ibc_source_callback: self.ibc_source_callback,
507        }
508    }
509
510    /// Populates [ContractWrapper] with contract's `reply` entry-point and custom message type.
511    pub fn with_reply<E5A>(
512        self,
513        reply_fn: ReplyFn<C, E5A, Q>,
514    ) -> ContractWrapper<
515        T1,
516        T2,
517        T3,
518        E1,
519        E2,
520        E3,
521        C,
522        Q,
523        T4,
524        E4,
525        E5A,
526        T6,
527        E6,
528        E7,
529        E8,
530        E9,
531        E10,
532        E11,
533        E12,
534        E13,
535    >
536    where
537        E5A: Display + Debug + Send + Sync + 'static,
538    {
539        ContractWrapper {
540            execute_fn: self.execute_fn,
541            instantiate_fn: self.instantiate_fn,
542            query_fn: self.query_fn,
543            sudo_fn: self.sudo_fn,
544            reply_fn: Some(Box::new(reply_fn)),
545            migrate_fn: self.migrate_fn,
546            checksum: None,
547
548            channel_open_fn: self.channel_open_fn,
549            channel_connect_fn: self.channel_connect_fn,
550            channel_close_fn: self.channel_close_fn,
551
552            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
553            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
554            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
555
556            ibc_source_callback: self.ibc_source_callback,
557        }
558    }
559
560    /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message.
561    pub fn with_reply_empty<E5A>(
562        self,
563        reply_fn: ReplyFn<Empty, E5A, Empty>,
564    ) -> ContractWrapper<
565        T1,
566        T2,
567        T3,
568        E1,
569        E2,
570        E3,
571        C,
572        Q,
573        T4,
574        E4,
575        E5A,
576        T6,
577        E6,
578        E7,
579        E8,
580        E9,
581        E10,
582        E11,
583        E12,
584        E13,
585    >
586    where
587        E5A: Display + Debug + Send + Sync + 'static,
588    {
589        ContractWrapper {
590            execute_fn: self.execute_fn,
591            instantiate_fn: self.instantiate_fn,
592            query_fn: self.query_fn,
593            sudo_fn: self.sudo_fn,
594            reply_fn: Some(customize_permissioned_fn(reply_fn)),
595            migrate_fn: self.migrate_fn,
596            checksum: None,
597
598            channel_open_fn: self.channel_open_fn,
599            channel_connect_fn: self.channel_connect_fn,
600            channel_close_fn: self.channel_close_fn,
601
602            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
603            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
604            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
605
606            ibc_source_callback: self.ibc_source_callback,
607        }
608    }
609
610    /// Populates [ContractWrapper] with contract's `migrate` entry-point and custom message type.
611    pub fn with_migrate<T6A, E6A>(
612        self,
613        migrate_fn: PermissionedFn<T6A, C, E6A, Q>,
614    ) -> ContractWrapper<
615        T1,
616        T2,
617        T3,
618        E1,
619        E2,
620        E3,
621        C,
622        Q,
623        T4,
624        E4,
625        E5,
626        T6A,
627        E6A,
628        E7,
629        E8,
630        E9,
631        E10,
632        E11,
633        E12,
634        E13,
635    >
636    where
637        T6A: DeserializeOwned + 'static,
638        E6A: Display + Debug + Send + Sync + 'static,
639    {
640        ContractWrapper {
641            execute_fn: self.execute_fn,
642            instantiate_fn: self.instantiate_fn,
643            query_fn: self.query_fn,
644            sudo_fn: self.sudo_fn,
645            reply_fn: self.reply_fn,
646            migrate_fn: Some(Box::new(migrate_fn)),
647            checksum: None,
648
649            channel_open_fn: self.channel_open_fn,
650            channel_connect_fn: self.channel_connect_fn,
651            channel_close_fn: self.channel_close_fn,
652
653            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
654            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
655            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
656
657            ibc_source_callback: self.ibc_source_callback,
658        }
659    }
660
661    /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message.
662    pub fn with_migrate_empty<T6A, E6A>(
663        self,
664        migrate_fn: PermissionedFn<T6A, Empty, E6A, Empty>,
665    ) -> ContractWrapper<
666        T1,
667        T2,
668        T3,
669        E1,
670        E2,
671        E3,
672        C,
673        Q,
674        T4,
675        E4,
676        E5,
677        T6A,
678        E6A,
679        E7,
680        E8,
681        E9,
682        E10,
683        E11,
684        E12,
685        E13,
686    >
687    where
688        T6A: DeserializeOwned + 'static,
689        E6A: Display + Debug + Send + Sync + 'static,
690    {
691        ContractWrapper {
692            execute_fn: self.execute_fn,
693            instantiate_fn: self.instantiate_fn,
694            query_fn: self.query_fn,
695            sudo_fn: self.sudo_fn,
696            reply_fn: self.reply_fn,
697            migrate_fn: Some(customize_permissioned_fn(migrate_fn)),
698            checksum: None,
699
700            channel_open_fn: self.channel_open_fn,
701            channel_connect_fn: self.channel_connect_fn,
702            channel_close_fn: self.channel_close_fn,
703
704            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
705            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
706            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
707
708            ibc_source_callback: self.ibc_source_callback,
709        }
710    }
711
712    /// Populates [ContractWrapper] with the provided checksum of the contract's Wasm blob.
713    pub fn with_checksum(mut self, checksum: Checksum) -> Self {
714        self.checksum = Some(checksum);
715        self
716    }
717
718    /// Adding IBC endpoint capabilities
719    pub fn with_ibc<E7A, E8A, E9A, E10A, E11A, E12A>(
720        self,
721        channel_open_fn: IbcFn<IbcChannelOpenMsg, IbcChannelOpenResponse, E7A, Q>,
722        channel_connect_fn: IbcFn<IbcChannelConnectMsg, IbcBasicResponse<C>, E8A, Q>,
723        channel_close_fn: IbcFn<IbcChannelCloseMsg, IbcBasicResponse<C>, E9A, Q>,
724
725        ibc_packet_receive_fn: IbcFn<IbcPacketReceiveMsg, IbcReceiveResponse<C>, E10A, Q>,
726        ibc_packet_ack_fn: IbcFn<IbcPacketAckMsg, IbcBasicResponse<C>, E11A, Q>,
727        ibc_packet_timeout_fn: IbcFn<IbcPacketTimeoutMsg, IbcBasicResponse<C>, E12A, Q>,
728    ) -> ContractWrapper<
729        T1,
730        T2,
731        T3,
732        E1,
733        E2,
734        E3,
735        C,
736        Q,
737        T4,
738        E4,
739        E5,
740        T6,
741        E6,
742        E7A,
743        E8A,
744        E9A,
745        E10A,
746        E11A,
747        E12A,
748        E13,
749    >
750    where
751        E7A: Display + Debug + Send + Sync + 'static,
752        E8A: Display + Debug + Send + Sync + 'static,
753        E9A: Display + Debug + Send + Sync + 'static,
754        E10A: Display + Debug + Send + Sync + 'static,
755        E11A: Display + Debug + Send + Sync + 'static,
756        E12A: Display + Debug + Send + Sync + 'static,
757    {
758        ContractWrapper {
759            execute_fn: self.execute_fn,
760            instantiate_fn: self.instantiate_fn,
761            query_fn: self.query_fn,
762            sudo_fn: self.sudo_fn,
763            reply_fn: self.reply_fn,
764            migrate_fn: self.migrate_fn,
765            checksum: None,
766
767            channel_open_fn: Some(Box::new(channel_open_fn)),
768            channel_connect_fn: Some(Box::new(channel_connect_fn)),
769            channel_close_fn: Some(Box::new(channel_close_fn)),
770
771            ibc_packet_receive_fn: Some(Box::new(ibc_packet_receive_fn)),
772            ibc_packet_ack_fn: Some(Box::new(ibc_packet_ack_fn)),
773            ibc_packet_timeout_fn: Some(Box::new(ibc_packet_timeout_fn)),
774
775            ibc_source_callback: self.ibc_source_callback,
776        }
777    }
778    /// Adding IBC endpoint capabilities
779    pub fn with_ibc_source_callback<E13A>(
780        self,
781        ibc_source_callback: IbcFn<IbcSourceCallbackMsg, IbcBasicResponse<C>, E13A, Q>,
782    ) -> ContractWrapper<
783        T1,
784        T2,
785        T3,
786        E1,
787        E2,
788        E3,
789        C,
790        Q,
791        T4,
792        E4,
793        E5,
794        T6,
795        E6,
796        E7,
797        E8,
798        E9,
799        E10,
800        E11,
801        E12,
802        E13A,
803    >
804    where
805        E13A: Display + Debug + Send + Sync + 'static,
806    {
807        ContractWrapper {
808            execute_fn: self.execute_fn,
809            instantiate_fn: self.instantiate_fn,
810            query_fn: self.query_fn,
811            sudo_fn: self.sudo_fn,
812            reply_fn: self.reply_fn,
813            migrate_fn: self.migrate_fn,
814            checksum: None,
815
816            channel_open_fn: self.channel_open_fn,
817            channel_connect_fn: self.channel_connect_fn,
818            channel_close_fn: self.channel_close_fn,
819
820            ibc_packet_receive_fn: self.ibc_packet_receive_fn,
821            ibc_packet_ack_fn: self.ibc_packet_ack_fn,
822            ibc_packet_timeout_fn: self.ibc_packet_timeout_fn,
823
824            ibc_source_callback: Some(Box::new(ibc_source_callback)),
825        }
826    }
827}
828
829fn customize_contract_fn<T, C, E, Q>(
830    raw_fn: ContractFn<T, Empty, E, Empty>,
831) -> ContractClosure<T, C, E, Q>
832where
833    T: DeserializeOwned + 'static,
834    E: Display + Debug + Send + Sync + 'static,
835    C: CustomMsg,
836    Q: CustomQuery + DeserializeOwned,
837{
838    Box::new(
839        move |mut deps: DepsMut<Q>,
840              env: Env,
841              info: MessageInfo,
842              msg: T|
843              -> Result<Response<C>, E> {
844            let deps = decustomize_deps_mut(&mut deps);
845            raw_fn(deps, env, info, msg).map(customize_response::<C>)
846        },
847    )
848}
849
850fn customize_query_fn<T, E, Q>(raw_fn: QueryFn<T, E, Empty>) -> QueryClosure<T, E, Q>
851where
852    T: DeserializeOwned + 'static,
853    E: Display + Debug + Send + Sync + 'static,
854    Q: CustomQuery + DeserializeOwned,
855{
856    Box::new(
857        move |deps: Deps<Q>, env: Env, msg: T| -> Result<Binary, E> {
858            let deps = decustomize_deps(&deps);
859            raw_fn(deps, env, msg)
860        },
861    )
862}
863
864fn customize_permissioned_fn<T, C, E, Q>(
865    raw_fn: PermissionedFn<T, Empty, E, Empty>,
866) -> PermissionedClosure<T, C, E, Q>
867where
868    T: DeserializeOwned + 'static,
869    E: Display + Debug + Send + Sync + 'static,
870    C: CustomMsg,
871    Q: CustomQuery + DeserializeOwned,
872{
873    Box::new(
874        move |mut deps: DepsMut<Q>, env: Env, msg: T| -> Result<Response<C>, E> {
875            let deps = decustomize_deps_mut(&mut deps);
876            raw_fn(deps, env, msg).map(customize_response::<C>)
877        },
878    )
879}
880
881fn decustomize_deps_mut<'a, Q>(deps: &'a mut DepsMut<Q>) -> DepsMut<'a, Empty>
882where
883    Q: CustomQuery + DeserializeOwned,
884{
885    DepsMut {
886        storage: deps.storage,
887        api: deps.api,
888        querier: QuerierWrapper::new(deps.querier.deref()),
889    }
890}
891
892fn decustomize_deps<'a, Q>(deps: &'a Deps<'a, Q>) -> Deps<'a, Empty>
893where
894    Q: CustomQuery + DeserializeOwned,
895{
896    Deps {
897        storage: deps.storage,
898        api: deps.api,
899        querier: QuerierWrapper::new(deps.querier.deref()),
900    }
901}
902
903fn customize_response<C>(resp: Response<Empty>) -> Response<C>
904where
905    C: CustomMsg,
906{
907    let mut customized_resp = Response::<C>::new()
908        .add_submessages(resp.messages.into_iter().map(customize_msg::<C>))
909        .add_events(resp.events)
910        .add_attributes(resp.attributes);
911    customized_resp.data = resp.data;
912    customized_resp
913}
914
915fn customize_msg<C>(msg: SubMsg<Empty>) -> SubMsg<C>
916where
917    C: CustomMsg,
918{
919    SubMsg {
920        id: msg.id,
921        payload: msg.payload,
922        msg: match msg.msg {
923            CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm),
924            CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank),
925            #[cfg(feature = "staking")]
926            CosmosMsg::Staking(staking) => CosmosMsg::Staking(staking),
927            #[cfg(feature = "staking")]
928            CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution),
929            CosmosMsg::Custom(_) => unreachable!(),
930            #[cfg(feature = "stargate")]
931            CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc),
932            #[cfg(feature = "cosmwasm_2_0")]
933            CosmosMsg::Any(any) => CosmosMsg::Any(any),
934            other => panic!("unknown message variant {:?}", other),
935        },
936        gas_limit: msg.gas_limit,
937        reply_on: msg.reply_on,
938    }
939}
940
941impl<T1, T2, T3, E1, E2, E3, C, T4, E4, E5, T6, E6, E7, E8, E9, E10, E11, E12, E13, Q>
942    Contract<C, Q>
943    for ContractWrapper<
944        T1,
945        T2,
946        T3,
947        E1,
948        E2,
949        E3,
950        C,
951        Q,
952        T4,
953        E4,
954        E5,
955        T6,
956        E6,
957        E7,
958        E8,
959        E9,
960        E10,
961        E11,
962        E12,
963        E13,
964    >
965where
966    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
967    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
968    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
969    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
970    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
971    E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point.
972    E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point.
973    E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point.
974    E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point.
975    E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point.
976    E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point.
977    E7: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_open` entry-point.
978    E8: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_connect` entry-point.
979    E9: Display + Debug + Send + Sync + 'static, // Type of error returned from `channel_close` entry-point.
980    E10: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_receive` entry-point.
981    E11: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_ack` entry-point.
982    E12: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_packet_timeout` entry-point.
983    E13: Display + Debug + Send + Sync + 'static, // Type of error returned from `ibc_source_callback` entry-point.
984    C: CustomMsg, // Type of custom message returned from all entry-points except `query`.
985    Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
986{
987    /// Calls [execute] on wrapped [Contract] trait implementor.
988    ///
989    /// [execute]: Contract::execute
990    fn execute(
991        &self,
992        deps: DepsMut<Q>,
993        env: Env,
994        info: MessageInfo,
995        msg: Vec<u8>,
996    ) -> AnyResult<Response<C>> {
997        let msg: T1 = from_json(msg)?;
998        (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| anyhow!(err))
999    }
1000
1001    /// Calls [instantiate] on wrapped [Contract] trait implementor.
1002    ///
1003    /// [instantiate]: Contract::instantiate
1004    fn instantiate(
1005        &self,
1006        deps: DepsMut<Q>,
1007        env: Env,
1008        info: MessageInfo,
1009        msg: Vec<u8>,
1010    ) -> AnyResult<Response<C>> {
1011        let msg: T2 = from_json(msg)?;
1012        (self.instantiate_fn)(deps, env, info, msg).map_err(|err: E2| anyhow!(err))
1013    }
1014
1015    /// Calls [query] on wrapped [Contract] trait implementor.
1016    ///
1017    /// [query]: Contract::query
1018    fn query(&self, deps: Deps<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Binary> {
1019        let msg: T3 = from_json(msg)?;
1020        (self.query_fn)(deps, env, msg).map_err(|err: E3| anyhow!(err))
1021    }
1022
1023    /// Calls [sudo] on wrapped [Contract] trait implementor.
1024    /// Returns an error when the contract does not implement [sudo].
1025    ///
1026    /// [sudo]: Contract::sudo
1027    fn sudo(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Response<C>> {
1028        let msg: T4 = from_json(msg)?;
1029        match &self.sudo_fn {
1030            Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| anyhow!(err)),
1031            None => bail!("sudo is not implemented for contract"),
1032        }
1033    }
1034
1035    /// Calls [reply] on wrapped [Contract] trait implementor.
1036    /// Returns an error when the contract does not implement [reply].
1037    ///
1038    /// [reply]: Contract::reply
1039    fn reply(&self, deps: DepsMut<Q>, env: Env, reply_data: Reply) -> AnyResult<Response<C>> {
1040        let msg: Reply = reply_data;
1041        match &self.reply_fn {
1042            Some(reply) => reply(deps, env, msg).map_err(|err: E5| anyhow!(err)),
1043            None => bail!("reply is not implemented for contract"),
1044        }
1045    }
1046
1047    /// Calls [migrate] on wrapped [Contract] trait implementor.
1048    /// Returns an error when the contract does not implement [migrate].
1049    ///
1050    /// [migrate]: Contract::migrate
1051    fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> AnyResult<Response<C>> {
1052        let msg: T6 = from_json(msg)?;
1053        match &self.migrate_fn {
1054            Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| anyhow!(err)),
1055            None => bail!("migrate is not implemented for contract"),
1056        }
1057    }
1058
1059    /// Returns the provided checksum of the contract's Wasm blob.
1060    fn checksum(&self) -> Option<Checksum> {
1061        self.checksum
1062    }
1063
1064    fn ibc_channel_open(
1065        &self,
1066        deps: DepsMut<Q>,
1067        env: Env,
1068        msg: IbcChannelOpenMsg,
1069    ) -> AnyResult<IbcChannelOpenResponse> {
1070        match &self.channel_open_fn {
1071            Some(channel_open) => channel_open(deps, env, msg).map_err(|err| anyhow!(err)),
1072            None => bail!("channel open not implemented for contract"),
1073        }
1074    }
1075    fn ibc_channel_connect(
1076        &self,
1077        deps: DepsMut<Q>,
1078        env: Env,
1079        msg: IbcChannelConnectMsg,
1080    ) -> AnyResult<IbcBasicResponse<C>> {
1081        match &self.channel_connect_fn {
1082            Some(channel_connect) => channel_connect(deps, env, msg).map_err(|err| anyhow!(err)),
1083            None => bail!("channel connect not implemented for contract"),
1084        }
1085    }
1086    fn ibc_channel_close(
1087        &self,
1088        deps: DepsMut<Q>,
1089        env: Env,
1090        msg: IbcChannelCloseMsg,
1091    ) -> AnyResult<IbcBasicResponse<C>> {
1092        match &self.channel_close_fn {
1093            Some(channel_close) => channel_close(deps, env, msg).map_err(|err| anyhow!(err)),
1094            None => bail!("channel close not implemented for contract"),
1095        }
1096    }
1097
1098    fn ibc_packet_receive(
1099        &self,
1100        deps: DepsMut<Q>,
1101        env: Env,
1102        msg: IbcPacketReceiveMsg,
1103    ) -> AnyResult<IbcReceiveResponse<C>> {
1104        match &self.ibc_packet_receive_fn {
1105            Some(packet_receive) => packet_receive(deps, env, msg).map_err(|err| anyhow!(err)),
1106            None => bail!("packet receive not implemented for contract"),
1107        }
1108    }
1109    fn ibc_packet_acknowledge(
1110        &self,
1111        deps: DepsMut<Q>,
1112        env: Env,
1113        msg: IbcPacketAckMsg,
1114    ) -> AnyResult<IbcBasicResponse<C>> {
1115        match &self.ibc_packet_ack_fn {
1116            Some(packet_ack) => packet_ack(deps, env, msg).map_err(|err| anyhow!(err)),
1117            None => bail!("packet ack not implemented for contract"),
1118        }
1119    }
1120    fn ibc_packet_timeout(
1121        &self,
1122        deps: DepsMut<Q>,
1123        env: Env,
1124        msg: IbcPacketTimeoutMsg,
1125    ) -> AnyResult<IbcBasicResponse<C>> {
1126        match &self.ibc_packet_timeout_fn {
1127            Some(packet_timeout) => packet_timeout(deps, env, msg).map_err(|err| anyhow!(err)),
1128            None => bail!("packet timeout not implemented for contract"),
1129        }
1130    }
1131
1132    fn ibc_source_callback(
1133        &self,
1134        deps: DepsMut<Q>,
1135        env: Env,
1136        msg: IbcSourceCallbackMsg,
1137    ) -> AnyResult<IbcBasicResponse<C>> {
1138        match &self.ibc_source_callback {
1139            Some(ibc_source_callback) => {
1140                ibc_source_callback(deps, env, msg).map_err(|err| anyhow!(err))
1141            }
1142            None => bail!("ibc source callback not implemented for contract"),
1143        }
1144    }
1145}