Skip to main content

clone_cw_multi_test/
app.rs

1use crate::wasm_emulation::api::RealApi;
2use crate::wasm_emulation::channel::RemoteChannel;
3use crate::wasm_emulation::input::QuerierStorage;
4use cosmwasm_std::CustomMsg;
5use cw_storage_plus::Item;
6
7use crate::bank::{Bank, BankKeeper, BankSudo};
8use crate::error::{bail, AnyResult};
9use crate::executor::{AppResponse, Executor};
10use crate::gov::Gov;
11use crate::ibc::Ibc;
12use crate::module::{FailingModule, Module};
13use crate::staking::{Distribution, DistributionKeeper, StakeKeeper, Staking, StakingSudo};
14use crate::transactions::transactional;
15use crate::wasm::{ContractData, Wasm, WasmKeeper, WasmSudo};
16use crate::{AppBuilder, Contract, GovFailingModule, IbcFailingModule};
17use cosmwasm_std::testing::{MockApi, MockStorage};
18use cosmwasm_std::{
19    from_json, to_json_binary, Addr, Api, Binary, BlockInfo, ContractResult, CosmosMsg,
20    CustomQuery, Empty, Querier, QuerierResult, QuerierWrapper, QueryRequest, Record, Storage,
21    SystemError, SystemResult,
22};
23use schemars::JsonSchema;
24use serde::{de::DeserializeOwned, Serialize};
25use std::fmt::Debug;
26use std::marker::PhantomData;
27
28const ADDRESSES: Item<Vec<Addr>> = Item::new("addresses");
29
30pub fn next_block(block: &mut BlockInfo) {
31    block.time = block.time.plus_seconds(5);
32    block.height += 1;
33}
34
35/// Type alias for default build `App` to make its storing simpler in typical scenario
36pub type BasicApp<ExecC = Empty, QueryC = Empty> = App<
37    BankKeeper,
38    MockApi,
39    MockStorage,
40    FailingModule<ExecC, QueryC, Empty>,
41    WasmKeeper<ExecC, QueryC>,
42    StakeKeeper,
43    DistributionKeeper,
44    IbcFailingModule,
45    GovFailingModule,
46>;
47
48/// Router is a persisted state. You can query this.
49/// Execution generally happens on the RouterCache, which then can be atomically committed or rolled back.
50/// We offer .execute() as a wrapper around cache, execute, commit/rollback process.
51#[derive(Clone)]
52pub struct App<
53    Bank = BankKeeper,
54    Api = MockApi,
55    Storage = MockStorage,
56    Custom = FailingModule<Empty, Empty, Empty>,
57    Wasm = WasmKeeper<Empty, Empty>,
58    Staking = StakeKeeper,
59    Distr = DistributionKeeper,
60    Ibc = IbcFailingModule,
61    Gov = GovFailingModule,
62> {
63    pub(crate) router: Router<Bank, Custom, Wasm, Staking, Distr, Ibc, Gov>,
64    pub(crate) api: Api,
65    pub(crate) storage: Storage,
66    pub(crate) block: BlockInfo,
67    pub(crate) remote: RemoteChannel,
68}
69
70impl BasicApp {
71    /// Creates new default `App` implementation working with Empty custom messages.
72    pub fn new<F>(remote: RemoteChannel, init_fn: F) -> AnyResult<Self>
73    where
74        F: FnOnce(
75            &mut Router<
76                BankKeeper,
77                FailingModule<Empty, Empty, Empty>,
78                WasmKeeper<Empty, Empty>,
79                StakeKeeper,
80                DistributionKeeper,
81                IbcFailingModule,
82                GovFailingModule,
83            >,
84            &dyn Api,
85            &mut dyn Storage,
86        ),
87    {
88        AppBuilder::new().with_remote(remote).build(init_fn)
89    }
90}
91
92/// Creates new default `App` implementation working with customized exec and query messages.
93/// Outside of `App` implementation to make type elision better.
94pub fn custom_app<ExecC, QueryC, F>(
95    remote: RemoteChannel,
96    init_fn: F,
97) -> AnyResult<BasicApp<ExecC, QueryC>>
98where
99    ExecC: CustomMsg + DeserializeOwned + 'static,
100    QueryC: Debug + CustomQuery + DeserializeOwned + 'static,
101    F: FnOnce(
102        &mut Router<
103            BankKeeper,
104            FailingModule<ExecC, QueryC, Empty>,
105            WasmKeeper<ExecC, QueryC>,
106            StakeKeeper,
107            DistributionKeeper,
108            IbcFailingModule,
109            GovFailingModule,
110        >,
111        &dyn Api,
112        &mut dyn Storage,
113    ),
114{
115    AppBuilder::new_custom().with_remote(remote).build(init_fn)
116}
117
118impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Querier
119    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
120where
121    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
122    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
123    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
124    BankT: Bank,
125    ApiT: Api,
126    StorageT: Storage,
127    CustomT: Module,
128    StakingT: Staking,
129    DistrT: Distribution,
130    IbcT: Ibc,
131    GovT: Gov,
132{
133    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
134        self.router
135            .querier(&self.api, &self.storage, &self.block)
136            .raw_query(bin_request)
137    }
138}
139
140impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> Executor<CustomT::ExecT>
141    for App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
142where
143    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
144    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
145    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
146    BankT: Bank,
147    ApiT: Api,
148    StorageT: Storage,
149    CustomT: Module,
150    StakingT: Staking,
151    DistrT: Distribution,
152    IbcT: Ibc,
153    GovT: Gov,
154{
155    fn execute(&mut self, sender: Addr, msg: CosmosMsg<CustomT::ExecT>) -> AnyResult<AppResponse> {
156        let mut all = self.execute_multi(sender, vec![msg])?;
157        let res = all.pop().unwrap();
158        Ok(res)
159    }
160}
161
162impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
163    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
164where
165    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
166    BankT: Bank,
167    ApiT: Api,
168    StorageT: Storage,
169    CustomT: Module,
170    StakingT: Staking,
171    DistrT: Distribution,
172    IbcT: Ibc,
173    GovT: Gov,
174    CustomT::QueryT: CustomQuery,
175{
176    /// Returns a shared reference to application's router.
177    pub fn router(&self) -> &Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> {
178        &self.router
179    }
180
181    /// Returns a shared reference to application's api.
182    pub fn api(&self) -> &ApiT {
183        &self.api
184    }
185
186    /// Returns a shared reference to application's storage.
187    pub fn storage(&self) -> &StorageT {
188        &self.storage
189    }
190
191    /// Returns a mutable reference to application's storage.
192    pub fn storage_mut(&mut self) -> &mut StorageT {
193        &mut self.storage
194    }
195
196    pub fn init_modules<F, T>(&mut self, init_fn: F) -> T
197    where
198        F: FnOnce(
199            &mut Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
200            &dyn Api,
201            &mut dyn Storage,
202        ) -> T,
203    {
204        init_fn(&mut self.router, &self.api, &mut self.storage)
205    }
206
207    pub fn read_module<F, T>(&self, query_fn: F) -> T
208    where
209        F: FnOnce(
210            &Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>,
211            &dyn Api,
212            &dyn Storage,
213        ) -> T,
214    {
215        query_fn(&self.router, &self.api, &self.storage)
216    }
217}
218
219// Helper functions to call some custom WasmKeeper logic.
220// They show how we can easily add such calls to other custom keepers (CustomT, StakingT, etc)
221impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
222    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
223where
224    BankT: Bank,
225    ApiT: Api,
226    StorageT: Storage,
227    CustomT: Module,
228    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
229    StakingT: Staking,
230    DistrT: Distribution,
231    IbcT: Ibc,
232    GovT: Gov,
233    CustomT::ExecT: CustomMsg + DeserializeOwned + 'static,
234    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
235{
236    /// Registers contract code (like uploading wasm bytecode on a chain),
237    /// so it can later be used to instantiate a contract.
238    /// Only for wasm codes
239    pub fn store_wasm_code(&mut self, code: Vec<u8>) -> u64 {
240        self.init_modules(|router, _, _| {
241            router
242                .wasm
243                .store_wasm_code(Addr::unchecked("code-creator"), code)
244        })
245    }
246
247    /// Registers contract code (like uploading wasm bytecode on a chain),
248    /// so it can later be used to instantiate a contract.
249    pub fn store_code(&mut self, code: Box<dyn Contract<CustomT::ExecT, CustomT::QueryT>>) -> u64 {
250        self.init_modules(|router, _, _| {
251            router
252                .wasm
253                .store_code(Addr::unchecked("code-creator"), code)
254        })
255    }
256
257    /// Registers contract code (like [store_code](Self::store_code)),
258    /// but takes the address of the code creator as an additional argument.
259    pub fn store_wasm_code_with_creator(&mut self, creator: Addr, code: Vec<u8>) -> u64 {
260        self.init_modules(|router, _, _| router.wasm.store_wasm_code(creator, code))
261    }
262
263    /// Registers contract code (like [store_code](Self::store_code)),
264    /// but takes the address of the code creator as an additional argument.
265    pub fn store_code_with_creator(
266        &mut self,
267        creator: Addr,
268        code: Box<dyn Contract<CustomT::ExecT, CustomT::QueryT>>,
269    ) -> u64 {
270        self.init_modules(|router, _, _| router.wasm.store_code(creator, code))
271    }
272
273    /// Returns `ContractData` for the contract with specified address.
274    pub fn contract_data(&self, address: &Addr) -> AnyResult<ContractData> {
275        self.read_module(|router, _, storage| router.wasm.contract_data(storage, address))
276    }
277
278    /// Returns a raw state dump of all key-values held by a contract with specified address.
279    pub fn dump_wasm_raw(&self, address: &Addr) -> Vec<Record> {
280        self.read_module(|router, _, storage| router.wasm.dump_wasm_raw(storage, address))
281    }
282}
283
284impl<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
285    App<BankT, ApiT, StorageT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
286where
287    CustomT::ExecT: Debug + PartialEq + Clone + JsonSchema + DeserializeOwned + 'static,
288    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
289    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
290    BankT: Bank,
291    ApiT: Api,
292    StorageT: Storage,
293    CustomT: Module,
294    StakingT: Staking,
295    DistrT: Distribution,
296    IbcT: Ibc,
297    GovT: Gov,
298{
299    pub fn set_block(&mut self, block: BlockInfo) {
300        self.router
301            .staking
302            .process_queue(&self.api, &mut self.storage, &self.router, &self.block)
303            .unwrap();
304        self.block = block;
305    }
306
307    // this let's use use "next block" steps that add eg. one height and 5 seconds
308    pub fn update_block<F: Fn(&mut BlockInfo)>(&mut self, action: F) {
309        self.router
310            .staking
311            .process_queue(&self.api, &mut self.storage, &self.router, &self.block)
312            .unwrap();
313        action(&mut self.block);
314    }
315
316    /// Returns a copy of the current block_info
317    pub fn block_info(&self) -> BlockInfo {
318        self.block.clone()
319    }
320
321    /// Returns a new account address
322    pub fn next_address(&mut self) -> Addr {
323        let Self {
324            storage, remote, ..
325        } = self;
326
327        let mut addresses = ADDRESSES.may_load(storage).unwrap().unwrap_or_default();
328
329        let new_address =
330            RealApi::new(&remote.pub_address_prefix.clone()).next_address(addresses.len());
331        addresses.push(new_address.clone());
332        ADDRESSES.save(storage, &addresses).unwrap();
333
334        new_address
335    }
336
337    /// Simple helper so we get access to all the QuerierWrapper helpers,
338    /// eg. wrap().query_wasm_smart, query_all_balances, ...
339    pub fn wrap(&self) -> QuerierWrapper<CustomT::QueryT> {
340        QuerierWrapper::new(self)
341    }
342
343    pub fn get_querier_storage(&self) -> AnyResult<QuerierStorage> {
344        // We get the wasm storage for all wasm contract to make sure we dispatch everything (with the mock Querier)
345        let wasm = self.router.wasm.query_all(&self.storage)?;
346        let bank = self.router.bank.query_all(&self.storage)?;
347        Ok(QuerierStorage { wasm, bank })
348    }
349
350    /// Runs multiple CosmosMsg in one atomic operation.
351    /// This will create a cache before the execution, so no state changes are persisted if any of them
352    /// return an error. But all writes are persisted on success.
353    pub fn execute_multi(
354        &mut self,
355        sender: Addr,
356        msgs: Vec<CosmosMsg<CustomT::ExecT>>,
357    ) -> AnyResult<Vec<AppResponse>> {
358        // we need to do some caching of storage here, once in the entry point:
359        // meaning, wrap current state, all writes go to a cache, only when execute
360        // returns a success do we flush it (otherwise drop it)
361
362        let Self {
363            block,
364            router,
365            api,
366            storage,
367            ..
368        } = self;
369
370        transactional(&mut *storage, |write_cache, _| {
371            msgs.into_iter()
372                .map(|msg| router.execute(&*api, write_cache, block, sender.clone(), msg))
373                .collect()
374        })
375    }
376
377    /// Call a smart contract in "sudo" mode.
378    /// This will create a cache before the execution, so no state changes are persisted if this
379    /// returns an error, but all are persisted on success.
380    pub fn wasm_sudo<T: Serialize, U: Into<Addr>>(
381        &mut self,
382        contract_addr: U,
383        msg: &T,
384    ) -> AnyResult<AppResponse> {
385        let msg = to_json_binary(msg)?;
386
387        let Self {
388            block,
389            router,
390            api,
391            storage,
392            ..
393        } = self;
394
395        transactional(&mut *storage, |write_cache, _| {
396            router
397                .wasm
398                .sudo(&*api, contract_addr.into(), write_cache, router, block, msg)
399        })
400    }
401
402    /// Runs arbitrary SudoMsg.
403    /// This will create a cache before the execution, so no state changes are persisted if this
404    /// returns an error, but all are persisted on success.
405    pub fn sudo(&mut self, msg: SudoMsg) -> AnyResult<AppResponse> {
406        // we need to do some caching of storage here, once in the entry point:
407        // meaning, wrap current state, all writes go to a cache, only when execute
408        // returns a success do we flush it (otherwise drop it)
409        let Self {
410            block,
411            router,
412            api,
413            storage,
414            ..
415        } = self;
416
417        transactional(&mut *storage, |write_cache, _| {
418            router.sudo(&*api, write_cache, block, msg)
419        })
420    }
421}
422
423#[derive(Clone)]
424pub struct Router<Bank, Custom, Wasm, Staking, Distr, Ibc, Gov> {
425    // this can remain crate-only as all special functions are wired up to app currently
426    // we need to figure out another format for wasm, as some like sudo need to be called after init
427    pub(crate) wasm: Wasm,
428    // these must be pub so we can initialize them (super user) on build
429    pub bank: Bank,
430    pub custom: Custom,
431    pub staking: Staking,
432    pub distribution: Distr,
433    pub ibc: Ibc,
434    pub gov: Gov,
435}
436
437impl<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
438    Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
439where
440    CustomT::ExecT: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
441    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
442    CustomT: Module,
443    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
444    BankT: Bank,
445    StakingT: Staking,
446    DistrT: Distribution,
447    IbcT: Ibc,
448    GovT: Gov,
449{
450    pub fn querier<'a>(
451        &'a self,
452        api: &'a dyn Api,
453        storage: &'a dyn Storage,
454        block_info: &'a BlockInfo,
455    ) -> RouterQuerier<'a, CustomT::ExecT, CustomT::QueryT> {
456        RouterQuerier {
457            router: self,
458            api,
459            storage,
460            block_info,
461        }
462    }
463}
464
465/// We use it to allow calling into modules from another module in sudo mode.
466/// Things like gov proposals belong here.
467pub enum SudoMsg {
468    Bank(BankSudo),
469    Custom(Empty),
470    Staking(StakingSudo),
471    Wasm(WasmSudo),
472}
473
474impl From<WasmSudo> for SudoMsg {
475    fn from(wasm: WasmSudo) -> Self {
476        SudoMsg::Wasm(wasm)
477    }
478}
479
480impl From<BankSudo> for SudoMsg {
481    fn from(bank: BankSudo) -> Self {
482        SudoMsg::Bank(bank)
483    }
484}
485
486impl From<StakingSudo> for SudoMsg {
487    fn from(staking: StakingSudo) -> Self {
488        SudoMsg::Staking(staking)
489    }
490}
491
492pub trait CosmosRouter {
493    type ExecC;
494    type QueryC: CustomQuery;
495
496    fn execute(
497        &self,
498        api: &dyn Api,
499        storage: &mut dyn Storage,
500        block: &BlockInfo,
501        sender: Addr,
502        msg: CosmosMsg<Self::ExecC>,
503    ) -> AnyResult<AppResponse>;
504
505    fn query(
506        &self,
507        api: &dyn Api,
508        storage: &dyn Storage,
509        block: &BlockInfo,
510        request: QueryRequest<Self::QueryC>,
511    ) -> AnyResult<Binary>;
512
513    fn sudo(
514        &self,
515        api: &dyn Api,
516        storage: &mut dyn Storage,
517        block: &BlockInfo,
518        msg: SudoMsg,
519    ) -> AnyResult<AppResponse>;
520
521    fn get_querier_storage(&self, storage: &dyn Storage) -> AnyResult<QuerierStorage>;
522}
523
524impl<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT> CosmosRouter
525    for Router<BankT, CustomT, WasmT, StakingT, DistrT, IbcT, GovT>
526where
527    CustomT::ExecT: Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static,
528    CustomT::QueryT: CustomQuery + DeserializeOwned + 'static,
529    CustomT: Module,
530    WasmT: Wasm<CustomT::ExecT, CustomT::QueryT>,
531    BankT: Bank,
532    StakingT: Staking,
533    DistrT: Distribution,
534    IbcT: Ibc,
535    GovT: Gov,
536{
537    type ExecC = CustomT::ExecT;
538    type QueryC = CustomT::QueryT;
539
540    fn execute(
541        &self,
542        api: &dyn Api,
543        storage: &mut dyn Storage,
544        block: &BlockInfo,
545        sender: Addr,
546        msg: CosmosMsg<Self::ExecC>,
547    ) -> AnyResult<AppResponse> {
548        match msg {
549            CosmosMsg::Wasm(msg) => self.wasm.execute(api, storage, self, block, sender, msg),
550            CosmosMsg::Bank(msg) => self.bank.execute(api, storage, self, block, sender, msg),
551            CosmosMsg::Custom(msg) => self.custom.execute(api, storage, self, block, sender, msg),
552            CosmosMsg::Staking(msg) => self.staking.execute(api, storage, self, block, sender, msg),
553            CosmosMsg::Distribution(msg) => self
554                .distribution
555                .execute(api, storage, self, block, sender, msg),
556            CosmosMsg::Ibc(msg) => self.ibc.execute(api, storage, self, block, sender, msg),
557            CosmosMsg::Gov(msg) => self.gov.execute(api, storage, self, block, sender, msg),
558            _ => bail!("Cannot execute {:?}", msg),
559        }
560    }
561
562    /// this is used by `RouterQuerier` to actual implement the `Querier` interface.
563    /// you most likely want to use `router.querier(storage, block).wrap()` to get a
564    /// QuerierWrapper to interact with
565    fn query(
566        &self,
567        api: &dyn Api,
568        storage: &dyn Storage,
569        block: &BlockInfo,
570        request: QueryRequest<Self::QueryC>,
571    ) -> AnyResult<Binary> {
572        let querier = self.querier(api, storage, block);
573        match request {
574            QueryRequest::Wasm(req) => self.wasm.query(api, storage, self, &querier, block, req),
575            QueryRequest::Bank(req) => self.bank.query(api, storage, &querier, block, req),
576            QueryRequest::Custom(req) => self.custom.query(api, storage, &querier, block, req),
577            QueryRequest::Staking(req) => self.staking.query(api, storage, &querier, block, req),
578            QueryRequest::Ibc(req) => self.ibc.query(api, storage, &querier, block, req),
579            _ => unimplemented!(),
580        }
581    }
582
583    fn sudo(
584        &self,
585        api: &dyn Api,
586        storage: &mut dyn Storage,
587        block: &BlockInfo,
588        msg: SudoMsg,
589    ) -> AnyResult<AppResponse> {
590        match msg {
591            SudoMsg::Wasm(msg) => {
592                self.wasm
593                    .sudo(api, msg.contract_addr, storage, self, block, msg.msg)
594            }
595            SudoMsg::Bank(msg) => self.bank.sudo(api, storage, self, block, msg),
596            SudoMsg::Staking(msg) => self.staking.sudo(api, storage, self, block, msg),
597            SudoMsg::Custom(_) => unimplemented!(),
598        }
599    }
600
601    fn get_querier_storage(&self, storage: &dyn Storage) -> AnyResult<QuerierStorage> {
602        // We get the wasm storage for all wasm contract to make sure we dispatch everything (with the mock Querier)
603        let wasm = self.wasm.query_all(storage)?;
604        let bank = self.bank.query_all(storage)?;
605        Ok(QuerierStorage { wasm, bank })
606    }
607}
608
609pub struct MockRouter<ExecC, QueryC>(PhantomData<(ExecC, QueryC)>);
610
611impl Default for MockRouter<Empty, Empty> {
612    fn default() -> Self {
613        Self::new()
614    }
615}
616
617impl<ExecC, QueryC> MockRouter<ExecC, QueryC> {
618    pub fn new() -> Self
619    where
620        QueryC: CustomQuery,
621    {
622        MockRouter(PhantomData)
623    }
624}
625
626impl<ExecC, QueryC> CosmosRouter for MockRouter<ExecC, QueryC>
627where
628    QueryC: CustomQuery,
629{
630    type ExecC = ExecC;
631    type QueryC = QueryC;
632
633    fn execute(
634        &self,
635        _api: &dyn Api,
636        _storage: &mut dyn Storage,
637        _block: &BlockInfo,
638        _sender: Addr,
639        _msg: CosmosMsg<Self::ExecC>,
640    ) -> AnyResult<AppResponse> {
641        panic!("Cannot execute MockRouters");
642    }
643
644    fn query(
645        &self,
646        _api: &dyn Api,
647        _storage: &dyn Storage,
648        _block: &BlockInfo,
649        _request: QueryRequest<Self::QueryC>,
650    ) -> AnyResult<Binary> {
651        panic!("Cannot query MockRouters");
652    }
653
654    fn sudo(
655        &self,
656        _api: &dyn Api,
657        _storage: &mut dyn Storage,
658        _block: &BlockInfo,
659        _msg: SudoMsg,
660    ) -> AnyResult<AppResponse> {
661        panic!("Cannot sudo MockRouters");
662    }
663
664    fn get_querier_storage(&self, _storage: &dyn Storage) -> AnyResult<QuerierStorage> {
665        Ok(QuerierStorage::default())
666    }
667}
668
669pub struct RouterQuerier<'a, ExecC, QueryC> {
670    router: &'a dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
671    api: &'a dyn Api,
672    storage: &'a dyn Storage,
673    block_info: &'a BlockInfo,
674}
675
676impl<'a, ExecC, QueryC> RouterQuerier<'a, ExecC, QueryC> {
677    pub fn new(
678        router: &'a dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
679        api: &'a dyn Api,
680        storage: &'a dyn Storage,
681        block_info: &'a BlockInfo,
682    ) -> Self {
683        Self {
684            router,
685            api,
686            storage,
687            block_info,
688        }
689    }
690}
691
692impl<'a, ExecC, QueryC> Querier for RouterQuerier<'a, ExecC, QueryC>
693where
694    ExecC: Clone + Debug + PartialEq + JsonSchema + DeserializeOwned + 'static,
695    QueryC: CustomQuery + DeserializeOwned + 'static,
696{
697    fn raw_query(&self, bin_request: &[u8]) -> QuerierResult {
698        let request: QueryRequest<QueryC> = match from_json(bin_request) {
699            Ok(v) => v,
700            Err(e) => {
701                return SystemResult::Err(SystemError::InvalidRequest {
702                    error: format!("Parsing query request: {}", e),
703                    request: bin_request.into(),
704                })
705            }
706        };
707        let contract_result: ContractResult<Binary> = self
708            .router
709            .query(self.api, self.storage, self.block_info, request)
710            .into();
711        SystemResult::Ok(contract_result)
712    }
713}