clone_cw_multi_test/
app_builder.rs

1//! Implementation of the builder for [App].
2
3use crate::wasm_emulation::channel::RemoteChannel;
4use crate::{
5    App, Bank, BankKeeper, Distribution, DistributionKeeper, FailingModule, Gov, GovFailingModule,
6    Ibc, IbcFailingModule, Module, Router, StakeKeeper, Staking, Wasm, WasmKeeper,
7};
8use anyhow::Result as AnyResult;
9use cosmwasm_std::testing::{mock_env, MockApi, MockStorage};
10use cosmwasm_std::{Api, BlockInfo, CustomMsg, CustomQuery, Empty, Storage};
11use serde::de::DeserializeOwned;
12use std::fmt::Debug;
13
14/// This is essential to create a custom app with custom module.
15///
16/// # Example
17///
18/// ```
19/// # use cosmwasm_std::Empty;
20/// # use cw_multi_test::{BasicAppBuilder, FailingModule, Module};
21/// # type MyHandler = FailingModule<Empty, Empty, Empty>;
22/// # type MyExecC = Empty;
23/// # type MyQueryC = Empty;
24///
25/// let mut app = BasicAppBuilder::<MyExecC, MyQueryC>::new_custom()
26///                   .with_custom(MyHandler::default())
27///                   .build(|_, _, _| {});
28/// ```
29pub type BasicAppBuilder<ExecC, QueryC> = AppBuilder<
30    BankKeeper,
31    MockApi,
32    MockStorage,
33    FailingModule<ExecC, QueryC, Empty>,
34    WasmKeeper<ExecC, QueryC>,
35    StakeKeeper,
36    DistributionKeeper,
37    IbcFailingModule,
38    GovFailingModule,
39>;
40
41/// Utility to build [App] in stages.
42/// When particular properties are not explicitly set, then default values are used.
43pub struct AppBuilder<Bank, Api, Storage, Custom, Wasm, Staking, Distr, Ibc, Gov> {
44    api: Api,
45    block: BlockInfo,
46    storage: Storage,
47    bank: Bank,
48    wasm: Wasm,
49    custom: Custom,
50    staking: Staking,
51    distribution: Distr,
52    ibc: Ibc,
53    gov: Gov,
54    remote: Option<RemoteChannel>,
55}
56
57impl Default
58    for AppBuilder<
59        BankKeeper,
60        MockApi,
61        MockStorage,
62        FailingModule<Empty, Empty, Empty>,
63        WasmKeeper<Empty, Empty>,
64        StakeKeeper,
65        DistributionKeeper,
66        IbcFailingModule,
67        GovFailingModule,
68    >
69{
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75impl
76    AppBuilder<
77        BankKeeper,
78        MockApi,
79        MockStorage,
80        FailingModule<Empty, Empty, Empty>,
81        WasmKeeper<Empty, Empty>,
82        StakeKeeper,
83        DistributionKeeper,
84        IbcFailingModule,
85        GovFailingModule,
86    >
87{
88    /// Creates builder with default components working with empty exec and query messages.
89    pub fn new() -> Self {
90        AppBuilder {
91            api: MockApi::default(),
92            block: mock_env().block,
93            storage: MockStorage::new(),
94            bank: BankKeeper::new(),
95            wasm: WasmKeeper::new(),
96            custom: FailingModule::new("custom"),
97            staking: StakeKeeper::new(),
98            distribution: DistributionKeeper::new(),
99            ibc: IbcFailingModule::new("ibc"),
100            gov: GovFailingModule::new("gov"),
101            remote: None,
102        }
103    }
104}
105
106impl<ExecC, QueryC>
107    AppBuilder<
108        BankKeeper,
109        MockApi,
110        MockStorage,
111        FailingModule<ExecC, QueryC, Empty>,
112        WasmKeeper<ExecC, QueryC>,
113        StakeKeeper,
114        DistributionKeeper,
115        IbcFailingModule,
116        GovFailingModule,
117    >
118where
119    ExecC: CustomMsg + DeserializeOwned + 'static,
120    QueryC: Debug + CustomQuery + DeserializeOwned + 'static,
121{
122    /// Creates builder with default components designed to work with custom exec and query
123    /// messages.
124    pub fn new_custom() -> Self {
125        AppBuilder {
126            api: MockApi::default(),
127            block: mock_env().block,
128            storage: MockStorage::new(),
129            bank: BankKeeper::new(),
130            wasm: WasmKeeper::new(),
131            custom: FailingModule::new("custom"),
132            staking: StakeKeeper::new(),
133            distribution: DistributionKeeper::new(),
134            ibc: IbcFailingModule::new("ibc"),
135            gov: GovFailingModule::new("gov"),
136            remote: None,
137        }
138    }
139}
140
141impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
142    AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
143where
144    CustomT: Module,
145    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
146    CustomT::QueryT: CustomQuery,
147{
148    /// Overwrites the default wasm executor.
149    ///
150    /// At this point it is needed that new wasm implements some `Wasm` trait, but it doesn't need
151    /// to be bound to Bank or Custom yet - as those may change. The cross-components validation is
152    /// done on final building.
153    pub fn with_wasm<NewWasm: Wasm<CustomT::ExecT, CustomT::QueryT>>(
154        self,
155        wasm: NewWasm,
156    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, NewWasm, StakingT, DistrT, IbcT, GovT> {
157        let AppBuilder {
158            bank,
159            api,
160            storage,
161            custom,
162            block,
163            staking,
164            distribution,
165            ibc,
166            gov,
167            remote,
168            ..
169        } = self;
170
171        AppBuilder {
172            api,
173            block,
174            storage,
175            bank,
176            wasm,
177            custom,
178            staking,
179            distribution,
180            ibc,
181            gov,
182            remote,
183        }
184    }
185
186    /// Overwrites the default bank interface.
187    pub fn with_bank<NewBank: Bank>(
188        self,
189        bank: NewBank,
190    ) -> AppBuilder<NewBank, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
191        let AppBuilder {
192            wasm,
193            api,
194            storage,
195            custom,
196            block,
197            staking,
198            distribution,
199            ibc,
200            gov,
201            remote,
202            ..
203        } = self;
204
205        AppBuilder {
206            api,
207            block,
208            storage,
209            bank,
210            wasm,
211            custom,
212            staking,
213            distribution,
214            ibc,
215            gov,
216            remote,
217        }
218    }
219
220    /// Overwrites the default api interface.
221    pub fn with_api<NewApi: Api>(
222        self,
223        api: NewApi,
224    ) -> AppBuilder<BankT, NewApi, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
225        let AppBuilder {
226            wasm,
227            bank,
228            storage,
229            custom,
230            block,
231            staking,
232            distribution,
233            ibc,
234            gov,
235            remote,
236            ..
237        } = self;
238
239        AppBuilder {
240            api,
241            block,
242            storage,
243            bank,
244            wasm,
245            custom,
246            staking,
247            distribution,
248            ibc,
249            gov,
250            remote,
251        }
252    }
253
254    /// Overwrites the default storage interface.
255    pub fn with_storage<NewStorage: Storage>(
256        self,
257        storage: NewStorage,
258    ) -> AppBuilder<BankT, ApiT, NewStorage, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
259        let AppBuilder {
260            wasm,
261            api,
262            bank,
263            custom,
264            block,
265            staking,
266            distribution,
267            ibc,
268            gov,
269            remote,
270            ..
271        } = self;
272
273        AppBuilder {
274            api,
275            block,
276            storage,
277            bank,
278            wasm,
279            custom,
280            staking,
281            distribution,
282            ibc,
283            gov,
284            remote,
285        }
286    }
287
288    /// Overwrites the default custom messages handler.
289    ///
290    /// At this point it is needed that new custom implements some `Module` trait, but it doesn't need
291    /// to be bound to ExecC or QueryC yet - as those may change. The cross-components validation is
292    /// done on final building.
293    pub fn with_custom<NewCustom: Module>(
294        self,
295        custom: NewCustom,
296    ) -> AppBuilder<BankT, ApiT, StorageT, NewCustom, WasmT, StakingT, DistrT, IbcT, GovT> {
297        let AppBuilder {
298            wasm,
299            bank,
300            api,
301            storage,
302            block,
303            staking,
304            distribution,
305            ibc,
306            gov,
307            remote,
308            ..
309        } = self;
310
311        AppBuilder {
312            api,
313            block,
314            storage,
315            bank,
316            wasm,
317            custom,
318            staking,
319            distribution,
320            ibc,
321            gov,
322            remote,
323        }
324    }
325
326    /// Overwrites the default staking interface.
327    pub fn with_staking<NewStaking: Staking>(
328        self,
329        staking: NewStaking,
330    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, NewStaking, DistrT, IbcT, GovT> {
331        let AppBuilder {
332            wasm,
333            api,
334            storage,
335            custom,
336            block,
337            bank,
338            distribution,
339            ibc,
340            gov,
341            remote,
342            ..
343        } = self;
344
345        AppBuilder {
346            api,
347            block,
348            storage,
349            bank,
350            wasm,
351            custom,
352            staking,
353            distribution,
354            ibc,
355            gov,
356            remote,
357        }
358    }
359
360    /// Overwrites the default distribution interface.
361    pub fn with_distribution<NewDistribution: Distribution>(
362        self,
363        distribution: NewDistribution,
364    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, NewDistribution, IbcT, GovT>
365    {
366        let AppBuilder {
367            wasm,
368            api,
369            storage,
370            custom,
371            block,
372            staking,
373            bank,
374            ibc,
375            gov,
376            remote,
377            ..
378        } = self;
379
380        AppBuilder {
381            api,
382            block,
383            storage,
384            bank,
385            wasm,
386            custom,
387            staking,
388            distribution,
389            ibc,
390            gov,
391            remote,
392        }
393    }
394
395    /// Overwrites the default ibc interface.
396    ///
397    /// If you wish to simply ignore/drop all returned IBC Messages,
398    /// you can use the `IbcAcceptingModule` type:
399    /// ```text
400    /// builder.with_ibc(IbcAcceptingModule::new())
401    /// ```
402    pub fn with_ibc<NewIbc: Ibc>(
403        self,
404        ibc: NewIbc,
405    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, NewIbc, GovT> {
406        let AppBuilder {
407            wasm,
408            api,
409            storage,
410            custom,
411            block,
412            staking,
413            bank,
414            distribution,
415            gov,
416            remote,
417            ..
418        } = self;
419
420        AppBuilder {
421            api,
422            block,
423            storage,
424            bank,
425            wasm,
426            custom,
427            staking,
428            distribution,
429            ibc,
430            gov,
431            remote,
432        }
433    }
434
435    /// Overwrites the default gov interface.
436    pub fn with_gov<NewGov: Gov>(
437        self,
438        gov: NewGov,
439    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, NewGov> {
440        let AppBuilder {
441            wasm,
442            api,
443            storage,
444            custom,
445            block,
446            staking,
447            bank,
448            distribution,
449            ibc,
450            remote,
451            ..
452        } = self;
453
454        AppBuilder {
455            api,
456            block,
457            storage,
458            bank,
459            wasm,
460            custom,
461            staking,
462            distribution,
463            ibc,
464            gov,
465            remote,
466        }
467    }
468
469    /// Sets the chain of the app
470    pub fn with_remote(
471        self,
472        remote: RemoteChannel,
473    ) -> AppBuilder<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
474        let AppBuilder {
475            wasm,
476            api,
477            storage,
478            custom,
479            block,
480            staking,
481            bank,
482            distribution,
483            ibc,
484            gov,
485            ..
486        } = self;
487
488        AppBuilder {
489            api,
490            block,
491            storage,
492            bank,
493            wasm,
494            custom,
495            staking,
496            distribution,
497            ibc,
498            remote: Some(remote),
499            gov,
500        }
501    }
502
503    /// Overwrites the initial block.
504    pub fn with_block(mut self, block: BlockInfo) -> Self {
505        self.block = block;
506        self
507    }
508
509    #[allow(clippy::type_complexity)]
510    /// Builds final `App`. At this point all components type have to be properly related to each
511    /// other. If there are some generics related compilation errors, make sure that all components
512    /// are properly relating to each other.
513    pub fn build<F>(
514        self,
515        init_fn: F,
516    ) -> AnyResult<App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>>
517    where
518        BankT: Bank,
519        ApiT: Api,
520        StorageT: Storage,
521        CustomT: Module,
522        WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
523        StakingT: Staking,
524        DistrT: Distribution,
525        IbcT: Ibc,
526        GovT: Gov,
527        F: FnOnce(
528            &mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
529            &dyn Api,
530            &mut dyn Storage,
531        ),
532    {
533        let router = Router {
534            wasm: self.wasm,
535            bank: self.bank,
536            custom: self.custom,
537            staking: self.staking,
538            distribution: self.distribution,
539            ibc: self.ibc,
540            gov: self.gov,
541        };
542
543        let mut app = App {
544            router,
545            api: self.api,
546            block: self.block,
547            storage: self.storage,
548            remote: self.remote.ok_or(anyhow::anyhow!(
549                "Remote has to be defined to use clone-testing"
550            ))?,
551        };
552        app.init_modules(init_fn);
553        Ok(app)
554    }
555}