cw_multi_test/
contracts.rs

1//! # Implementation of the contract trait and contract wrapper
2
3use crate::error::{std_error, std_error_bail};
4#[cfg(feature = "cosmwasm_2_2")]
5use cosmwasm_std::MigrateInfo;
6use cosmwasm_std::{
7    from_json, Binary, Checksum, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Empty, Env,
8    MessageInfo, QuerierWrapper, Reply, Response, StdError, StdResult, SubMsg,
9};
10use serde::de::DeserializeOwned;
11use std::fmt::{Debug, Display};
12use std::ops::Deref;
13
14/// This trait serves as a primary interface for interacting with smart contracts.
15#[rustfmt::skip]
16pub trait Contract<C, Q = Empty>
17where
18    C: CustomMsg,
19    Q: CustomQuery,
20{
21    /// Evaluates contract's `instantiate` entry-point.
22    fn instantiate(&self, deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: Vec<u8>) -> StdResult<Response<C>>;
23
24    /// Evaluates contract's `execute` entry-point.
25    fn execute(&self, deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: Vec<u8>) -> StdResult<Response<C>>;
26
27    /// Evaluates contract's `query` entry-point.
28    fn query(&self, deps: Deps<Q>, env: Env, msg: Vec<u8>) -> StdResult<Binary>;
29
30    /// Evaluates contract's `reply` entry-point.
31    fn reply(&self, deps: DepsMut<Q>, env: Env, msg: Reply) -> StdResult<Response<C>>;
32
33    /// Evaluates contract's `sudo` entry-point.
34    fn sudo(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> StdResult<Response<C>>;
35
36    /// Evaluates contract's `migrate` entry-point.
37    #[cfg(not(feature = "cosmwasm_2_2"))]
38    fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> StdResult<Response<C>>;
39
40    /// Evaluates contract's `migrate` entry-point.
41    #[cfg(feature = "cosmwasm_2_2")]
42    fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>, info: MigrateInfo) -> StdResult<Response<C>>;
43
44    /// Returns the provided checksum of the contract's Wasm blob.
45    fn checksum(&self) -> Option<Checksum> {
46        None
47    }
48}
49
50#[rustfmt::skip]
51mod closures {
52    use super::*;
53
54    // function types
55    pub type InstantiateFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: T) -> Result<Response<C>, E>;
56    pub type ExecuteFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, info: MessageInfo, msg: T) -> Result<Response<C>, E>;
57    pub type QueryFn<T, E, Q> = fn(deps: Deps<Q>, env: Env, msg: T) -> Result<Binary, E>;
58    pub type ReplyFn<C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: Reply) -> Result<Response<C>, E>;
59    pub type SudoFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: T) -> Result<Response<C>, E>;
60    #[cfg(not(feature = "cosmwasm_2_2"))]
61    pub type MigrateFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: T) -> Result<Response<C>, E>;
62    #[cfg(feature = "cosmwasm_2_2")]
63    pub type MigrateFn<T, C, E, Q> = fn(deps: DepsMut<Q>, env: Env, msg: T, info: MigrateInfo) -> Result<Response<C>, E>;
64
65    // closure types
66    pub type InstantiateClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, MessageInfo, T) -> Result<Response<C>, E>>;
67    pub type ExecuteClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, MessageInfo, T) -> Result<Response<C>, E>>;
68    pub type QueryClosure<T, E, Q> = Box<dyn Fn(Deps<Q>, Env, T) -> Result<Binary, E>>;
69    pub type ReplyClosure<C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, Reply) -> Result<Response<C>, E>>;
70    pub type SudoClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, T) -> Result<Response<C>, E>>;
71    #[cfg(not(feature = "cosmwasm_2_2"))]
72    pub type MigrateClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, T) -> Result<Response<C>, E>>;
73    #[cfg(feature = "cosmwasm_2_2")]
74    pub type MigrateClosure<T, C, E, Q> = Box<dyn Fn(DepsMut<Q>, Env, T, MigrateInfo) -> Result<Response<C>, E>>;
75}
76
77use closures::*;
78
79/// This structure wraps the [Contract] trait implementor
80/// and provides generic access to the contract's entry-points.
81///
82/// List of generic types used in [ContractWrapper]:
83/// - **T1** type of message passed to [execute] entry-point.
84/// - **T2** type of message passed to [instantiate] entry-point.
85/// - **T3** type of message passed to [query] entry-point.
86/// - **T4** type of message passed to [sudo] entry-point.
87/// - instead of **~~T5~~**, always the `Reply` type is used in [reply] entry-point.
88/// - **T6** type of message passed to [migrate] entry-point.
89/// - **E1** type of error returned from [execute] entry-point.
90/// - **E2** type of error returned from [instantiate] entry-point.
91/// - **E3** type of error returned from [query] entry-point.
92/// - **E4** type of error returned from [sudo] entry-point.
93/// - **E5** type of error returned from [reply] entry-point.
94/// - **E6** type of error returned from [migrate] entry-point.
95/// - **C** type of custom message returned from all entry-points except [query].
96/// - **Q** type of custom query in `Querier` passed as 'Deps' or 'DepsMut' to all entry-points.
97///
98/// The following table summarizes the purpose of all generic types used in [ContractWrapper].
99/// ```text
100/// ┌─────────────┬────────────────┬─────────────────────┬─────────┬─────────┬───────┬───────┐
101/// │  Contract   │    Contract    │                     │         │         │       │       │
102/// │ entry-point │    wrapper     │    Closure type     │ Message │ Message │ Error │ Query │
103/// │             │    member      │                     │   IN    │   OUT   │  OUT  │       │
104/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡
105/// │     (1)     │                │                     │         │         │       │       │
106/// ╞═════════════╪════════════════╪═════════════════════╪═════════╪═════════╪═══════╪═══════╡
107/// │ execute     │ execute_fn     │ ContractClosure     │   T1    │    C    │  E1   │   Q   │
108/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
109/// │ instantiate │ instantiate_fn │ ContractClosure     │   T2    │    C    │  E2   │   Q   │
110/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
111/// │ query       │ query_fn       │ QueryClosure        │   T3    │ Binary  │  E3   │   Q   │
112/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
113/// │ sudo        │ sudo_fn        │ PermissionedClosure │   T4    │    C    │  E4   │   Q   │
114/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
115/// │ reply       │ reply_fn       │ ReplyClosure        │  Reply  │    C    │  E5   │   Q   │
116/// ├─────────────┼────────────────┼─────────────────────┼─────────┼─────────┼───────┼───────┤
117/// │ migrate     │ migrate_fn     │ PermissionedClosure │   T6    │    C    │  E6   │   Q   │
118/// └─────────────┴────────────────┴─────────────────────┴─────────┴─────────┴───────┴───────┘
119/// ```
120/// The general schema depicting which generic type is used in entry points is shown below.
121/// Entry point, when called, is provided minimum two arguments: custom query of type **Q**
122/// (inside `Deps` or `DepsMut`) and input message of type **T1**, **T2**, **T3**, **T4**,
123/// **Reply** or **T6**. As a result, entry point returns custom output message of type
124/// Response<**C**> or **Binary** and an error of type **E1**, **E2**, **E3**, **E4**, **E5**
125/// or **E6**.
126///
127/// ```text
128///    entry_point(query, .., message_in) -> Result<message_out, error>
129///                  ┬           ┬                      ┬          ┬
130///             Q >──┘           │                      │          └──> E1,E2,E3,E4,E5,E6
131///    T1,T2,T3,T4,Reply,T6 >────┘                      └─────────────> C,Binary
132/// ```
133/// Generic type **C** defines a custom message that is specific for the **whole blockchain**.
134/// Similarly, the generic type **Q** defines a custom query that is also specific
135/// to the **whole blockchain**. Other generic types are specific to the implemented contract.
136/// So all smart contracts used in the same blockchain will have the same types for **C** and **Q**,
137/// but each contract may use different type for other generic types.
138/// It means that e.g. **T1** in smart contract `A` may differ from **T1** in smart contract `B`.
139///
140/// [execute]: Contract::execute
141/// [instantiate]: Contract::instantiate
142/// [query]: Contract::query
143/// [sudo]: Contract::sudo
144/// [reply]: Contract::reply
145/// [migrate]: Contract::migrate
146pub struct ContractWrapper<
147    T1,
148    T2,
149    T3,
150    E1,
151    E2,
152    E3,
153    C = Empty,
154    Q = Empty,
155    T4 = Empty,
156    E4 = StdError,
157    E5 = StdError,
158    T6 = Empty,
159    E6 = StdError,
160> where
161    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
162    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
163    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
164    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
165    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
166    E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point.
167    E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point.
168    E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point.
169    E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point.
170    E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point.
171    E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point.
172    C: CustomMsg,         // Type of custom message returned from all entry-points except `query`.
173    Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
174{
175    execute_fn: ExecuteClosure<T1, C, E1, Q>,
176    instantiate_fn: InstantiateClosure<T2, C, E2, Q>,
177    query_fn: QueryClosure<T3, E3, Q>,
178    reply_fn: Option<ReplyClosure<C, E5, Q>>,
179    sudo_fn: Option<SudoClosure<T4, C, E4, Q>>,
180    migrate_fn: Option<MigrateClosure<T6, C, E6, Q>>,
181    checksum: Option<Checksum>,
182}
183
184impl<T1, T2, T3, E1, E2, E3, C, Q> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q>
185where
186    T1: DeserializeOwned + 'static, // Type of message passed to `execute` entry-point.
187    T2: DeserializeOwned + 'static, // Type of message passed to `instantiate` entry-point.
188    T3: DeserializeOwned + 'static, // Type of message passed to `query` entry-point.
189    E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point.
190    E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point.
191    E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point.
192    C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`.
193    Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
194{
195    /// Creates a new contract wrapper with default settings.
196    pub fn new(
197        execute_fn: ExecuteFn<T1, C, E1, Q>,
198        instantiate_fn: InstantiateFn<T2, C, E2, Q>,
199        query_fn: QueryFn<T3, E3, Q>,
200    ) -> Self {
201        Self {
202            execute_fn: Box::new(execute_fn),
203            instantiate_fn: Box::new(instantiate_fn),
204            query_fn: Box::new(query_fn),
205            reply_fn: None,
206            sudo_fn: None,
207            migrate_fn: None,
208            checksum: None,
209        }
210    }
211
212    /// This will take a contract that returns `Response<Empty>` and will _upgrade_ it
213    /// to `Response<C>` if needed, to be compatible with a chain-specific extension.
214    pub fn new_with_empty(
215        execute_fn: ExecuteFn<T1, Empty, E1, Empty>,
216        instantiate_fn: InstantiateFn<T2, Empty, E2, Empty>,
217        query_fn: QueryFn<T3, E3, Empty>,
218    ) -> Self {
219        Self {
220            execute_fn: customize_execute_fn(execute_fn),
221            instantiate_fn: customize_instantiate_fn(instantiate_fn),
222            query_fn: customize_query_fn(query_fn),
223            reply_fn: None,
224            sudo_fn: None,
225            migrate_fn: None,
226            checksum: None,
227        }
228    }
229}
230
231#[allow(clippy::type_complexity)]
232impl<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
233    ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
234where
235    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
236    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
237    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
238    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
239    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
240    E1: Display + Debug + Send + Sync, // Type of error returned from `execute` entry-point.
241    E2: Display + Debug + Send + Sync, // Type of error returned from `instantiate` entry-point.
242    E3: Display + Debug + Send + Sync, // Type of error returned from `query` entry-point.
243    E4: Display + Debug + Send + Sync, // Type of error returned from `sudo` entry-point.
244    E5: Display + Debug + Send + Sync, // Type of error returned from `reply` entry-point.
245    E6: Display + Debug + Send + Sync, // Type of error returned from `migrate` entry-point.
246    C: CustomMsg + 'static, // Type of custom message returned from all entry-points except `query`.
247    Q: CustomQuery + DeserializeOwned + 'static, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
248{
249    /// Populates [ContractWrapper] with contract's `sudo` entry-point and custom message type.
250    pub fn with_sudo<T4A, E4A>(
251        self,
252        sudo_fn: SudoFn<T4A, C, E4A, Q>,
253    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4A, E4A, E5, T6, E6>
254    where
255        T4A: DeserializeOwned + 'static,
256        E4A: Display + Debug + Send + Sync + 'static,
257    {
258        ContractWrapper {
259            execute_fn: self.execute_fn,
260            instantiate_fn: self.instantiate_fn,
261            query_fn: self.query_fn,
262            reply_fn: self.reply_fn,
263            sudo_fn: Some(Box::new(sudo_fn)),
264            migrate_fn: self.migrate_fn,
265            checksum: None,
266        }
267    }
268
269    /// Populates [ContractWrapper] with contract's `sudo` entry-point and `Empty` as a custom message.
270    pub fn with_sudo_empty<T4A, E4A>(
271        self,
272        sudo_fn: SudoFn<T4A, Empty, E4A, Empty>,
273    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4A, E4A, E5, T6, E6>
274    where
275        T4A: DeserializeOwned + 'static,
276        E4A: Display + Debug + Send + Sync + 'static,
277    {
278        ContractWrapper {
279            execute_fn: self.execute_fn,
280            instantiate_fn: self.instantiate_fn,
281            query_fn: self.query_fn,
282            reply_fn: self.reply_fn,
283            sudo_fn: Some(customize_sudo_fn(sudo_fn)),
284            migrate_fn: self.migrate_fn,
285            checksum: None,
286        }
287    }
288
289    /// Populates [ContractWrapper] with contract's `reply` entry-point and custom message type.
290    pub fn with_reply<E5A>(
291        self,
292        reply_fn: ReplyFn<C, E5A, Q>,
293    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5A, T6, E6>
294    where
295        E5A: Display + Debug + Send + Sync + 'static,
296    {
297        ContractWrapper {
298            execute_fn: self.execute_fn,
299            instantiate_fn: self.instantiate_fn,
300            query_fn: self.query_fn,
301            reply_fn: Some(Box::new(reply_fn)),
302            sudo_fn: self.sudo_fn,
303            migrate_fn: self.migrate_fn,
304            checksum: None,
305        }
306    }
307
308    /// Populates [ContractWrapper] with contract's `reply` entry-point and `Empty` as a custom message.
309    pub fn with_reply_empty<E5A>(
310        self,
311        reply_fn: ReplyFn<Empty, E5A, Empty>,
312    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5A, T6, E6>
313    where
314        E5A: Display + Debug + Send + Sync + 'static,
315    {
316        ContractWrapper {
317            execute_fn: self.execute_fn,
318            instantiate_fn: self.instantiate_fn,
319            query_fn: self.query_fn,
320            reply_fn: Some(customize_reply_fn(reply_fn)),
321            sudo_fn: self.sudo_fn,
322            migrate_fn: self.migrate_fn,
323            checksum: None,
324        }
325    }
326
327    /// Populates [ContractWrapper] with contract's `migrate` entry-point and custom message type.
328    pub fn with_migrate<T6A, E6A>(
329        self,
330        migrate_fn: MigrateFn<T6A, C, E6A, Q>,
331    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6A, E6A>
332    where
333        T6A: DeserializeOwned + 'static,
334        E6A: Display + Debug + Send + Sync + 'static,
335    {
336        ContractWrapper {
337            execute_fn: self.execute_fn,
338            instantiate_fn: self.instantiate_fn,
339            query_fn: self.query_fn,
340            reply_fn: self.reply_fn,
341            sudo_fn: self.sudo_fn,
342            migrate_fn: Some(Box::new(migrate_fn)),
343            checksum: None,
344        }
345    }
346
347    /// Populates [ContractWrapper] with contract's `migrate` entry-point and `Empty` as a custom message.
348    pub fn with_migrate_empty<T6A, E6A>(
349        self,
350        migrate_fn: MigrateFn<T6A, Empty, E6A, Empty>,
351    ) -> ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6A, E6A>
352    where
353        T6A: DeserializeOwned + 'static,
354        E6A: Display + Debug + Send + Sync + 'static,
355    {
356        ContractWrapper {
357            execute_fn: self.execute_fn,
358            instantiate_fn: self.instantiate_fn,
359            query_fn: self.query_fn,
360            reply_fn: self.reply_fn,
361            sudo_fn: self.sudo_fn,
362            migrate_fn: Some(customize_migrate_fn(migrate_fn)),
363            checksum: None,
364        }
365    }
366
367    /// Populates [ContractWrapper] with the provided checksum of the contract's Wasm blob.
368    pub fn with_checksum(mut self, checksum: Checksum) -> Self {
369        self.checksum = Some(checksum);
370        self
371    }
372}
373
374fn customize_instantiate_fn<T, C, E, Q>(
375    raw_fn: InstantiateFn<T, Empty, E, Empty>,
376) -> InstantiateClosure<T, C, E, Q>
377where
378    T: DeserializeOwned + 'static,
379    E: Display + Debug + Send + Sync + 'static,
380    C: CustomMsg,
381    Q: CustomQuery + DeserializeOwned,
382{
383    Box::new(
384        move |mut deps: DepsMut<Q>,
385              env: Env,
386              info: MessageInfo,
387              msg: T|
388              -> Result<Response<C>, E> {
389            let deps = decustomize_deps_mut(&mut deps);
390            raw_fn(deps, env, info, msg).map(customize_response::<C>)
391        },
392    )
393}
394
395fn customize_execute_fn<T, C, E, Q>(
396    raw_fn: ExecuteFn<T, Empty, E, Empty>,
397) -> ExecuteClosure<T, C, E, Q>
398where
399    T: DeserializeOwned + 'static,
400    E: Display + Debug + Send + Sync + 'static,
401    C: CustomMsg,
402    Q: CustomQuery + DeserializeOwned,
403{
404    Box::new(
405        move |mut deps: DepsMut<Q>,
406              env: Env,
407              info: MessageInfo,
408              msg: T|
409              -> Result<Response<C>, E> {
410            let deps = decustomize_deps_mut(&mut deps);
411            raw_fn(deps, env, info, msg).map(customize_response::<C>)
412        },
413    )
414}
415
416fn customize_query_fn<T, E, Q>(raw_fn: QueryFn<T, E, Empty>) -> QueryClosure<T, E, Q>
417where
418    T: DeserializeOwned + 'static,
419    E: Display + Debug + Send + Sync + 'static,
420    Q: CustomQuery + DeserializeOwned,
421{
422    Box::new(
423        move |deps: Deps<Q>, env: Env, msg: T| -> Result<Binary, E> {
424            let deps = decustomize_deps(&deps);
425            raw_fn(deps, env, msg)
426        },
427    )
428}
429
430fn customize_reply_fn<C, E, Q>(raw_fn: ReplyFn<Empty, E, Empty>) -> ReplyClosure<C, E, Q>
431where
432    E: Display + Debug + Send + Sync + 'static,
433    C: CustomMsg,
434    Q: CustomQuery + DeserializeOwned,
435{
436    Box::new(
437        move |mut deps: DepsMut<Q>, env: Env, msg: Reply| -> Result<Response<C>, E> {
438            let deps = decustomize_deps_mut(&mut deps);
439            raw_fn(deps, env, msg).map(customize_response::<C>)
440        },
441    )
442}
443
444fn customize_sudo_fn<T, C, E, Q>(raw_fn: SudoFn<T, Empty, E, Empty>) -> SudoClosure<T, C, E, Q>
445where
446    T: DeserializeOwned + 'static,
447    E: Display + Debug + Send + Sync + 'static,
448    C: CustomMsg,
449    Q: CustomQuery + DeserializeOwned,
450{
451    Box::new(
452        move |mut deps: DepsMut<Q>, env: Env, msg: T| -> Result<Response<C>, E> {
453            let deps = decustomize_deps_mut(&mut deps);
454            raw_fn(deps, env, msg).map(customize_response::<C>)
455        },
456    )
457}
458
459fn customize_migrate_fn<T, C, E, Q>(
460    raw_fn: MigrateFn<T, Empty, E, Empty>,
461) -> MigrateClosure<T, C, E, Q>
462where
463    T: DeserializeOwned + 'static,
464    E: Display + Debug + Send + Sync + 'static,
465    C: CustomMsg,
466    Q: CustomQuery + DeserializeOwned,
467{
468    Box::new(
469        #[cfg(not(feature = "cosmwasm_2_2"))]
470        move |mut deps: DepsMut<Q>, env: Env, msg: T| -> Result<Response<C>, E> {
471            let deps = decustomize_deps_mut(&mut deps);
472            raw_fn(deps, env, msg).map(customize_response::<C>)
473        },
474        #[cfg(feature = "cosmwasm_2_2")]
475        move |mut deps: DepsMut<Q>, env: Env, msg: T, inf: MigrateInfo| -> Result<Response<C>, E> {
476            let deps = decustomize_deps_mut(&mut deps);
477            raw_fn(deps, env, msg, inf).map(customize_response::<C>)
478        },
479    )
480}
481
482fn decustomize_deps_mut<'a, Q>(deps: &'a mut DepsMut<Q>) -> DepsMut<'a, Empty>
483where
484    Q: CustomQuery + DeserializeOwned,
485{
486    DepsMut {
487        storage: deps.storage,
488        api: deps.api,
489        querier: QuerierWrapper::new(deps.querier.deref()),
490    }
491}
492
493fn decustomize_deps<'a, Q>(deps: &'a Deps<'a, Q>) -> Deps<'a, Empty>
494where
495    Q: CustomQuery + DeserializeOwned,
496{
497    Deps {
498        storage: deps.storage,
499        api: deps.api,
500        querier: QuerierWrapper::new(deps.querier.deref()),
501    }
502}
503
504fn customize_response<C>(resp: Response<Empty>) -> Response<C>
505where
506    C: CustomMsg,
507{
508    let mut customized_resp = Response::<C>::new()
509        .add_submessages(resp.messages.into_iter().map(customize_msg::<C>))
510        .add_events(resp.events)
511        .add_attributes(resp.attributes);
512    customized_resp.data = resp.data;
513    customized_resp
514}
515
516fn customize_msg<C>(msg: SubMsg<Empty>) -> SubMsg<C>
517where
518    C: CustomMsg,
519{
520    SubMsg {
521        id: msg.id,
522        payload: msg.payload,
523        msg: match msg.msg {
524            CosmosMsg::Wasm(wasm) => CosmosMsg::Wasm(wasm),
525            CosmosMsg::Bank(bank) => CosmosMsg::Bank(bank),
526            #[cfg(feature = "staking")]
527            CosmosMsg::Staking(staking) => CosmosMsg::Staking(staking),
528            #[cfg(feature = "staking")]
529            CosmosMsg::Distribution(distribution) => CosmosMsg::Distribution(distribution),
530            CosmosMsg::Custom(_) => unreachable!(),
531            #[cfg(feature = "stargate")]
532            CosmosMsg::Ibc(ibc) => CosmosMsg::Ibc(ibc),
533            #[cfg(feature = "cosmwasm_2_0")]
534            CosmosMsg::Any(any) => CosmosMsg::Any(any),
535            other => panic!("unknown message variant {other:?}"),
536        },
537        gas_limit: msg.gas_limit,
538        reply_on: msg.reply_on,
539    }
540}
541
542impl<T1, T2, T3, E1, E2, E3, C, T4, E4, E5, T6, E6, Q> Contract<C, Q>
543    for ContractWrapper<T1, T2, T3, E1, E2, E3, C, Q, T4, E4, E5, T6, E6>
544where
545    T1: DeserializeOwned, // Type of message passed to `execute` entry-point.
546    T2: DeserializeOwned, // Type of message passed to `instantiate` entry-point.
547    T3: DeserializeOwned, // Type of message passed to `query` entry-point.
548    T4: DeserializeOwned, // Type of message passed to `sudo` entry-point.
549    T6: DeserializeOwned, // Type of message passed to `migrate` entry-point.
550    E1: Display + Debug + Send + Sync + 'static, // Type of error returned from `execute` entry-point.
551    E2: Display + Debug + Send + Sync + 'static, // Type of error returned from `instantiate` entry-point.
552    E3: Display + Debug + Send + Sync + 'static, // Type of error returned from `query` entry-point.
553    E4: Display + Debug + Send + Sync + 'static, // Type of error returned from `sudo` entry-point.
554    E5: Display + Debug + Send + Sync + 'static, // Type of error returned from `reply` entry-point.
555    E6: Display + Debug + Send + Sync + 'static, // Type of error returned from `migrate` entry-point.
556    C: CustomMsg, // Type of custom message returned from all entry-points except `query`.
557    Q: CustomQuery + DeserializeOwned, // Type of custom query in querier passed as deps/deps_mut to all entry-points.
558{
559    /// Calls [instantiate] on wrapped [Contract] trait implementor.
560    ///
561    /// [instantiate]: Contract::instantiate
562    fn instantiate(
563        &self,
564        deps: DepsMut<Q>,
565        env: Env,
566        info: MessageInfo,
567        msg: Vec<u8>,
568    ) -> StdResult<Response<C>> {
569        let msg: T2 = from_json(msg)?;
570        (self.instantiate_fn)(deps, env, info, msg)
571            .map_err(|err: E2| StdError::msg(format!("{err}")))
572    }
573
574    /// Calls [execute] on wrapped [Contract] trait implementor.
575    ///
576    /// [execute]: Contract::execute
577    fn execute(
578        &self,
579        deps: DepsMut<Q>,
580        env: Env,
581        info: MessageInfo,
582        msg: Vec<u8>,
583    ) -> StdResult<Response<C>> {
584        let msg: T1 = from_json(msg)?;
585        (self.execute_fn)(deps, env, info, msg).map_err(|err: E1| std_error!(err))
586    }
587
588    /// Calls [query] on wrapped [Contract] trait implementor.
589    ///
590    /// [query]: Contract::query
591    fn query(&self, deps: Deps<Q>, env: Env, msg: Vec<u8>) -> StdResult<Binary> {
592        let msg: T3 = from_json(msg)?;
593        (self.query_fn)(deps, env, msg).map_err(|err: E3| std_error!(err))
594    }
595
596    /// Calls [reply] on wrapped [Contract] trait implementor.
597    /// Returns an error when the contract does not implement [reply].
598    ///
599    /// [reply]: Contract::reply
600    fn reply(&self, deps: DepsMut<Q>, env: Env, msg: Reply) -> StdResult<Response<C>> {
601        match &self.reply_fn {
602            Some(reply) => reply(deps, env, msg).map_err(|err: E5| std_error!(err)),
603            None => std_error_bail!("reply is not implemented for contract"),
604        }
605    }
606
607    /// Calls [sudo] on wrapped [Contract] trait implementor.
608    /// Returns an error when the contract does not implement [sudo].
609    ///
610    /// [sudo]: Contract::sudo
611    fn sudo(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> StdResult<Response<C>> {
612        let msg: T4 = from_json(msg)?;
613        match &self.sudo_fn {
614            Some(sudo) => sudo(deps, env, msg).map_err(|err: E4| std_error!(err)),
615            None => std_error_bail!("sudo is not implemented for contract"),
616        }
617    }
618
619    /// Calls [migrate] on wrapped [Contract] trait implementor.
620    /// Returns an error when the contract does not implement [migrate].
621    ///
622    /// [migrate]: Contract::migrate
623    #[cfg(not(feature = "cosmwasm_2_2"))]
624    fn migrate(&self, deps: DepsMut<Q>, env: Env, msg: Vec<u8>) -> StdResult<Response<C>> {
625        let msg: T6 = from_json(msg)?;
626        match &self.migrate_fn {
627            Some(migrate) => migrate(deps, env, msg).map_err(|err: E6| std_error!(err)),
628            None => std_error_bail!("migrate is not implemented for contract"),
629        }
630    }
631
632    /// Calls [migrate] on wrapped [Contract] trait implementor.
633    /// Returns an error when the contract does not implement [migrate].
634    ///
635    /// [migrate]: Contract::migrate
636    #[cfg(feature = "cosmwasm_2_2")]
637    fn migrate(
638        &self,
639        deps: DepsMut<Q>,
640        env: Env,
641        msg: Vec<u8>,
642        info: MigrateInfo,
643    ) -> StdResult<Response<C>> {
644        let msg: T6 = from_json(msg)?;
645        match &self.migrate_fn {
646            Some(migrate) => migrate(deps, env, msg, info).map_err(|err: E6| std_error!(err)),
647            None => std_error_bail!("migrate is not implemented for contract"),
648        }
649    }
650
651    /// Returns the provided checksum of the contract's Wasm blob.
652    fn checksum(&self) -> Option<Checksum> {
653        self.checksum
654    }
655}