cw_multi_test/
wasm.rs

1use crate::addresses::{AddressGenerator, SimpleAddressGenerator};
2use crate::app::{CosmosRouter, RouterQuerier};
3use crate::checksums::{ChecksumGenerator, SimpleChecksumGenerator};
4use crate::contracts::Contract;
5use crate::error::*;
6use crate::executor::AppResponse;
7use crate::prefixed_storage::typed_prefixed_storage::{
8    StoragePrefix, TypedPrefixedStorage, TypedPrefixedStorageMut,
9};
10use crate::prefixed_storage::{PrefixedStorage, ReadonlyPrefixedStorage};
11use crate::transactions::transactional;
12use cosmwasm_std::testing::mock_wasmd_attr;
13#[cfg(feature = "stargate")]
14use cosmwasm_std::GovMsg;
15#[cfg(feature = "cosmwasm_2_2")]
16use cosmwasm_std::MigrateInfo;
17use cosmwasm_std::{
18    to_json_binary, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Checksum, Coin, ContractInfo,
19    ContractInfoResponse, CosmosMsg, CustomMsg, CustomQuery, Deps, DepsMut, Env, Event,
20    MessageInfo, MsgResponse, Order, Querier, QuerierWrapper, Record, Reply, ReplyOn, Response,
21    StdError, StdResult, Storage, SubMsg, SubMsgResponse, SubMsgResult, TransactionInfo, WasmMsg,
22    WasmQuery,
23};
24#[cfg(feature = "staking")]
25use cosmwasm_std::{DistributionMsg, StakingMsg};
26use cw_storage_plus::Map;
27use prost::Message;
28use schemars::JsonSchema;
29use serde::de::DeserializeOwned;
30use serde::{Deserialize, Serialize};
31use std::borrow::Borrow;
32use std::collections::BTreeMap;
33use std::fmt::Debug;
34
35/// Contract state kept in storage, separate from the contracts themselves (contract code).
36const CONTRACTS: Map<&Addr, ContractData> = Map::new("contracts");
37
38/// Contract [address namespace].
39///
40/// [address namespace]: https://github.com/CosmWasm/wasmd/blob/96e2b91144c9a371683555f3c696f882583cc6a2/x/wasm/types/events.go#L59
41const CONTRACT_ATTR: &str = "_contract_address";
42
43/// A structure representing a privileged message.
44#[derive(Clone, Debug, PartialEq, Eq, JsonSchema)]
45pub struct WasmSudo {
46    /// Address of a contract the privileged action will be sent to.
47    pub contract_addr: Addr,
48    /// Message representing privileged action to be executed by contract `sudo` entry-point.
49    pub message: Binary,
50}
51
52impl WasmSudo {
53    /// Creates a new privileged message for specified contract address and action to be executed.
54    pub fn new<T: Serialize>(contract_addr: &Addr, msg: &T) -> StdResult<WasmSudo> {
55        Ok(WasmSudo {
56            contract_addr: contract_addr.clone(),
57            message: to_json_binary(msg)?,
58        })
59    }
60}
61
62/// Contract data includes information about contract,
63/// equivalent of `ContractInfo` in `wasmd` interface.
64#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
65pub struct ContractData {
66    /// Identifier of stored contract code
67    pub code_id: u64,
68    /// Address of account who initially instantiated the contract
69    pub creator: Addr,
70    /// Optional address of account who can execute migrations
71    pub admin: Option<Addr>,
72    /// Metadata passed while contract instantiation
73    pub label: String,
74    /// Blockchain height in the moment of instantiating the contract
75    pub created: u64,
76}
77
78/// Contract code base data.
79struct CodeData {
80    /// Address of an account that initially stored the contract code.
81    creator: Addr,
82    /// Checksum of the contract's code base.
83    checksum: Checksum,
84    /// Identifier of the _source_ code of the contract stored in wasm keeper.
85    source_id: usize,
86}
87
88/// This trait implements the interface of the Wasm module.
89pub trait Wasm<ExecC, QueryC> {
90    /// Handles all `WasmMsg` messages.
91    fn execute(
92        &self,
93        api: &dyn Api,
94        storage: &mut dyn Storage,
95        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
96        block: &BlockInfo,
97        sender: Addr,
98        msg: WasmMsg,
99    ) -> StdResult<AppResponse>;
100
101    /// Handles all `WasmQuery` requests.
102    fn query(
103        &self,
104        api: &dyn Api,
105        storage: &dyn Storage,
106        querier: &dyn Querier,
107        block: &BlockInfo,
108        request: WasmQuery,
109    ) -> StdResult<Binary>;
110
111    /// Handles all sudo messages, this is an admin interface and can not be called via `CosmosMsg`.
112    fn sudo(
113        &self,
114        api: &dyn Api,
115        storage: &mut dyn Storage,
116        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
117        block: &BlockInfo,
118        msg: WasmSudo,
119    ) -> StdResult<AppResponse>;
120
121    /// Stores the contract's code and returns an identifier of the stored contract's code.
122    fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64;
123
124    /// Stores the contract's code under specified identifier,
125    /// returns the same code identifier when successful.
126    fn store_code_with_id(
127        &mut self,
128        creator: Addr,
129        code_id: u64,
130        code: Box<dyn Contract<ExecC, QueryC>>,
131    ) -> StdResult<u64>;
132
133    /// Duplicates the contract's code with specified identifier
134    /// and returns an identifier of the copy of the contract's code.
135    fn duplicate_code(&mut self, code_id: u64) -> StdResult<u64>;
136
137    /// Returns `ContractData` for the contract with specified address.
138    fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> StdResult<ContractData>;
139
140    /// Returns a raw state dump of all key-values held by a contract with specified address.
141    fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record>;
142
143    /// Returns the namespace of the contract storage.
144    fn contract_namespace(&self, contract: &Addr) -> Vec<u8> {
145        let mut name = b"contract_data/".to_vec();
146        name.extend_from_slice(contract.as_bytes());
147        name
148    }
149
150    /// Returns **read-only** (not mutable) contract storage.
151    fn contract_storage<'a>(
152        &self,
153        storage: &'a dyn Storage,
154        address: &Addr,
155    ) -> Box<dyn Storage + 'a> {
156        // We double-namespace this, once from global storage -> wasm_storage
157        // then from wasm_storage -> the contracts subspace
158        let namespace = self.contract_namespace(address);
159        let storage: TypedPrefixedStorage<'_, WasmKeeper<ExecC, QueryC>> =
160            WasmStorage::multilevel(storage, &namespace);
161        let prefixed_storage: ReadonlyPrefixedStorage = storage.into();
162        Box::new(prefixed_storage)
163    }
164
165    /// Returns **read-write** (mutable) contract storage.
166    fn contract_storage_mut<'a>(
167        &self,
168        storage: &'a mut dyn Storage,
169        address: &Addr,
170    ) -> Box<dyn Storage + 'a> {
171        // We double-namespace this, once from global storage -> wasm_storage
172        // then from wasm_storage -> the contracts subspace
173        let namespace = self.contract_namespace(address);
174        let storage: TypedPrefixedStorageMut<'_, WasmKeeper<ExecC, QueryC>> =
175            WasmStorageMut::multilevel(storage, &namespace);
176        let prefixed_storage: PrefixedStorage = storage.into();
177        Box::new(prefixed_storage)
178    }
179}
180
181/// A structure representing a default wasm keeper.
182pub struct WasmKeeper<ExecC, QueryC> {
183    /// Contract codes that stand for wasm code in real-life blockchain.
184    code_base: Vec<Box<dyn Contract<ExecC, QueryC>>>,
185    /// Code data with code base identifier and additional attributes.
186    code_data: BTreeMap<u64, CodeData>,
187    /// Contract's address generator.
188    address_generator: Box<dyn AddressGenerator>,
189    /// Contract's code checksum generator.
190    checksum_generator: Box<dyn ChecksumGenerator>,
191    /// Just markers to make type elision fork when using it as `Wasm` trait
192    _p: std::marker::PhantomData<QueryC>,
193}
194
195impl<ExecC, QueryC> StoragePrefix for WasmKeeper<ExecC, QueryC> {
196    const NAMESPACE: &'static [u8] = b"wasm";
197}
198type WasmStorage<'a, ExecC, QueryC> = TypedPrefixedStorage<'a, WasmKeeper<ExecC, QueryC>>;
199type WasmStorageMut<'a, ExecC, QueryC> = TypedPrefixedStorageMut<'a, WasmKeeper<ExecC, QueryC>>;
200
201impl<ExecC, QueryC> Default for WasmKeeper<ExecC, QueryC> {
202    /// Returns the default value for [WasmKeeper].
203    fn default() -> Self {
204        Self {
205            code_base: Vec::default(),
206            code_data: BTreeMap::default(),
207            address_generator: Box::new(SimpleAddressGenerator),
208            checksum_generator: Box::new(SimpleChecksumGenerator),
209            _p: std::marker::PhantomData,
210        }
211    }
212}
213
214impl<ExecC, QueryC> Wasm<ExecC, QueryC> for WasmKeeper<ExecC, QueryC>
215where
216    ExecC: CustomMsg + DeserializeOwned + 'static,
217    QueryC: CustomQuery + DeserializeOwned + 'static,
218{
219    fn execute(
220        &self,
221        api: &dyn Api,
222        storage: &mut dyn Storage,
223        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
224        block: &BlockInfo,
225        sender: Addr,
226        msg: WasmMsg,
227    ) -> StdResult<AppResponse> {
228        self.execute_wasm(api, storage, router, block, sender.clone(), msg.clone())
229            .map_err(|e| {
230                std_error!(
231                    "Error executing WasmMsg:\n  sender: {}\n  {:?}\n{}",
232                    sender,
233                    msg,
234                    e
235                )
236            })
237    }
238
239    fn query(
240        &self,
241        api: &dyn Api,
242        storage: &dyn Storage,
243        querier: &dyn Querier,
244        block: &BlockInfo,
245        request: WasmQuery,
246    ) -> StdResult<Binary> {
247        match request {
248            WasmQuery::Smart { contract_addr, msg } => {
249                let addr = api.addr_validate(&contract_addr)?;
250                self.query_smart(addr, api, storage, querier, block, msg.into())
251            }
252            WasmQuery::Raw { contract_addr, key } => {
253                let addr = api.addr_validate(&contract_addr)?;
254                Ok(self.query_raw(addr, storage, &key))
255            }
256            WasmQuery::ContractInfo { contract_addr } => {
257                let addr = api.addr_validate(&contract_addr)?;
258                let contract = self.contract_data(storage, &addr)?;
259                let res = ContractInfoResponse::new(
260                    contract.code_id,
261                    contract.creator,
262                    contract.admin,
263                    false,
264                    None,
265                    None,
266                );
267                to_json_binary(&res)
268            }
269            #[cfg(feature = "cosmwasm_1_2")]
270            WasmQuery::CodeInfo { code_id } => {
271                let code_data = self.code_data(code_id)?;
272                let res = cosmwasm_std::CodeInfoResponse::new(
273                    code_id,
274                    code_data.creator.clone(),
275                    code_data.checksum,
276                );
277                to_json_binary(&res)
278            }
279            _ => unimplemented!("{}", unsupported_wasm_query(request)),
280        }
281    }
282
283    fn sudo(
284        &self,
285        api: &dyn Api,
286        storage: &mut dyn Storage,
287        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
288        block: &BlockInfo,
289        msg: WasmSudo,
290    ) -> StdResult<AppResponse> {
291        let custom_event = Event::new("sudo").add_attribute(CONTRACT_ATTR, &msg.contract_addr);
292        let res = self.call_sudo(
293            msg.contract_addr.clone(),
294            api,
295            storage,
296            router,
297            block,
298            msg.message.to_vec(),
299        )?;
300        let (res, msgs) = self.build_app_response(&msg.contract_addr, custom_event, res);
301        self.process_response(api, router, storage, block, msg.contract_addr, res, msgs)
302    }
303
304    /// Stores the contract's code in the in-memory lookup table.
305    /// Returns an identifier of the stored contract code.
306    fn store_code(&mut self, creator: Addr, code: Box<dyn Contract<ExecC, QueryC>>) -> u64 {
307        let code_id = self
308            .next_code_id()
309            .unwrap_or_else(|| panic!("{}", no_more_code_id_available()));
310        self.save_code(code_id, creator, code)
311    }
312
313    /// Stores the contract's code in the in-memory lookup table.
314    /// Returns an identifier of the stored contract code.
315    fn store_code_with_id(
316        &mut self,
317        creator: Addr,
318        code_id: u64,
319        code: Box<dyn Contract<ExecC, QueryC>>,
320    ) -> StdResult<u64> {
321        // validate provided contract code identifier
322        if self.code_data.contains_key(&code_id) {
323            std_error_bail!(duplicated_code_id(code_id));
324        } else if code_id == 0 {
325            std_error_bail!(invalid_code_id());
326        }
327        Ok(self.save_code(code_id, creator, code))
328    }
329
330    /// Duplicates the contract's code with specified identifier.
331    /// Returns an identifier of the copy of the contract's code.
332    fn duplicate_code(&mut self, code_id: u64) -> StdResult<u64> {
333        let code_data = self.code_data(code_id)?;
334        let new_code_id = self
335            .next_code_id()
336            .ok_or_else(|| StdError::msg(no_more_code_id_available()))?;
337        self.code_data.insert(
338            new_code_id,
339            CodeData {
340                creator: code_data.creator.clone(),
341                checksum: code_data.checksum,
342                source_id: code_data.source_id,
343            },
344        );
345        Ok(new_code_id)
346    }
347
348    /// Returns `ContractData` for the contract with specified address.
349    fn contract_data(&self, storage: &dyn Storage, address: &Addr) -> StdResult<ContractData> {
350        let storage: TypedPrefixedStorage<'_, WasmKeeper<ExecC, QueryC>> =
351            WasmStorage::new(storage);
352        CONTRACTS.load(&storage, address)
353    }
354
355    /// Returns a raw state dump of all key-values held by a contract with specified address.
356    fn dump_wasm_raw(&self, storage: &dyn Storage, address: &Addr) -> Vec<Record> {
357        let storage = self.contract_storage(storage, address);
358        storage.range(None, None, Order::Ascending).collect()
359    }
360}
361
362impl<ExecC, QueryC> WasmKeeper<ExecC, QueryC>
363where
364    ExecC: CustomMsg + DeserializeOwned + 'static,
365    QueryC: CustomQuery + DeserializeOwned + 'static,
366{
367    /// Creates a wasm keeper with default settings.
368    ///
369    /// # Example
370    ///
371    /// ```
372    /// use cw_multi_test::{no_init, AppBuilder, WasmKeeper};
373    ///
374    /// // create wasm keeper
375    /// let wasm_keeper = WasmKeeper::new();
376    ///
377    /// // create and use the application with newly created wasm keeper
378    /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init);
379    /// ```
380    pub fn new() -> Self {
381        Self::default()
382    }
383
384    /// Populates an existing [WasmKeeper] with custom contract address generator.
385    ///
386    /// # Example
387    ///
388    /// ```
389    /// use cosmwasm_std::{Addr, Api, StdResult, Storage};
390    /// use cw_multi_test::{no_init, AddressGenerator, AppBuilder, WasmKeeper};
391    /// # use cosmwasm_std::testing::MockApi;
392    ///
393    /// struct CustomAddressGenerator;
394    ///
395    /// impl AddressGenerator for CustomAddressGenerator {
396    ///     fn contract_address(
397    ///         &self,
398    ///         api: &dyn Api,
399    ///         storage: &mut dyn Storage,
400    ///         code_id: u64,
401    ///         instance_id: u64,
402    ///     ) -> StdResult<Addr> {
403    ///         // here implement your address generation logic
404    /// #       Ok(MockApi::default().addr_make("test_address"))
405    ///     }
406    /// }
407    ///
408    /// // populate wasm with your custom address generator
409    /// let wasm_keeper = WasmKeeper::new().with_address_generator(CustomAddressGenerator);
410    ///
411    /// // create and use the application with customized wasm keeper
412    /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init);
413    /// ```
414    pub fn with_address_generator(
415        mut self,
416        address_generator: impl AddressGenerator + 'static,
417    ) -> Self {
418        self.address_generator = Box::new(address_generator);
419        self
420    }
421
422    /// Populates an existing [WasmKeeper] with custom checksum generator for the contract code.
423    ///
424    /// # Example
425    ///
426    /// ```
427    /// use cosmwasm_std::{Addr, Checksum};
428    /// use cw_multi_test::{no_init, AppBuilder, ChecksumGenerator, WasmKeeper};
429    ///
430    /// struct MyChecksumGenerator;
431    ///
432    /// impl ChecksumGenerator for MyChecksumGenerator {
433    ///     fn checksum(&self, creator: &Addr, code_id: u64) -> Checksum {
434    ///         // here implement your custom checksum generator
435    /// #       Checksum::from_hex("custom_checksum").unwrap()
436    ///     }
437    /// }
438    ///
439    /// // populate wasm keeper with your custom checksum generator
440    /// let wasm_keeper = WasmKeeper::new().with_checksum_generator(MyChecksumGenerator);
441    ///
442    /// // create and use the application with customized wasm keeper
443    /// let mut app = AppBuilder::default().with_wasm(wasm_keeper).build(no_init);
444    /// ```
445    pub fn with_checksum_generator(
446        mut self,
447        checksum_generator: impl ChecksumGenerator + 'static,
448    ) -> Self {
449        self.checksum_generator = Box::new(checksum_generator);
450        self
451    }
452
453    /// Returns a handler to code of the contract with specified code id.
454    pub fn contract_code(&self, code_id: u64) -> StdResult<&dyn Contract<ExecC, QueryC>> {
455        let code_data = self.code_data(code_id)?;
456        Ok(self.code_base[code_data.source_id].borrow())
457    }
458
459    /// Returns code data of the contract with specified code id.
460    fn code_data(&self, code_id: u64) -> StdResult<&CodeData> {
461        if code_id < 1 {
462            std_error_bail!(invalid_code_id());
463        }
464        self.code_data
465            .get(&code_id)
466            .ok_or_else(|| StdError::msg(unregistered_code_id(code_id)))
467    }
468
469    /// Validates all attributes.
470    ///
471    /// In `wasmd`, before version v0.45.0 empty attribute values were not allowed.
472    /// Since `wasmd` v0.45.0 empty attribute values are allowed,
473    /// so the value is not validated anymore.
474    fn verify_attributes(attributes: &[Attribute]) -> StdResult<()> {
475        for attr in attributes {
476            let key = attr.key.trim();
477            let val = attr.value.trim();
478            if key.is_empty() {
479                std_error_bail!(empty_attribute_key(val));
480            }
481            if key.starts_with('_') {
482                std_error_bail!(reserved_attribute_key(key));
483            }
484        }
485        Ok(())
486    }
487
488    fn verify_response<T>(response: Response<T>) -> StdResult<Response<T>>
489    where
490        T: CustomMsg,
491    {
492        Self::verify_attributes(&response.attributes)?;
493
494        for event in &response.events {
495            Self::verify_attributes(&event.attributes)?;
496            let ty = event.ty.trim();
497            if ty.len() < 2 {
498                std_error_bail!(event_type_too_short(ty));
499            }
500        }
501
502        Ok(response)
503    }
504
505    fn save_code(
506        &mut self,
507        code_id: u64,
508        creator: Addr,
509        code: Box<dyn Contract<ExecC, QueryC>>,
510    ) -> u64 {
511        // prepare the next identifier for the contract's code
512        let source_id = self.code_base.len();
513        // prepare the contract's Wasm blob checksum
514        let checksum = code
515            .checksum()
516            .unwrap_or(self.checksum_generator.checksum(&creator, code_id));
517        // store the 'source' code of the contract
518        self.code_base.push(code);
519        // store the additional code attributes like creator address and checksum
520        self.code_data.insert(
521            code_id,
522            CodeData {
523                creator,
524                checksum,
525                source_id,
526            },
527        );
528        code_id
529    }
530
531    /// Returns the next contract's code identifier.
532    fn next_code_id(&self) -> Option<u64> {
533        self.code_data.keys().last().unwrap_or(&0u64).checked_add(1)
534    }
535
536    /// Executes the contract's `query` entry-point.
537    pub fn query_smart(
538        &self,
539        address: Addr,
540        api: &dyn Api,
541        storage: &dyn Storage,
542        querier: &dyn Querier,
543        block: &BlockInfo,
544        msg: Vec<u8>,
545    ) -> StdResult<Binary> {
546        self.with_storage_readonly(
547            api,
548            storage,
549            querier,
550            block,
551            address,
552            |handler, deps, env| handler.query(deps, env, msg),
553        )
554    }
555
556    /// Returns the value stored under specified key in contracts storage.
557    pub fn query_raw(&self, address: Addr, storage: &dyn Storage, key: &[u8]) -> Binary {
558        let storage = self.contract_storage(storage, &address);
559        let data = storage.get(key).unwrap_or_default();
560        data.into()
561    }
562
563    fn send<T>(
564        &self,
565        api: &dyn Api,
566        storage: &mut dyn Storage,
567        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
568        block: &BlockInfo,
569        sender: T,
570        recipient: String,
571        amount: &[Coin],
572    ) -> StdResult<AppResponse>
573    where
574        T: Into<Addr>,
575    {
576        if !amount.is_empty() {
577            let msg: CosmosMsg<ExecC> = BankMsg::Send {
578                to_address: recipient,
579                amount: amount.to_vec(),
580            }
581            .into();
582            let res = router.execute(api, storage, block, sender.into(), msg)?;
583            Ok(res)
584        } else {
585            Ok(AppResponse::default())
586        }
587    }
588
589    /// unified logic for UpdateAdmin and ClearAdmin messages
590    fn update_admin(
591        &self,
592        api: &dyn Api,
593        storage: &mut dyn Storage,
594        sender: Addr,
595        contract_addr: &str,
596        new_admin: Option<String>,
597    ) -> StdResult<AppResponse> {
598        let contract_addr = api.addr_validate(contract_addr)?;
599        let admin = new_admin.map(|a| api.addr_validate(&a)).transpose()?;
600
601        // check admin status
602        let mut contract_data = self.contract_data(storage, &contract_addr)?;
603        if contract_data.admin != Some(sender) {
604            std_error_bail!(
605                "Only admin can update the contract admin: {:?}",
606                contract_data.admin
607            );
608        }
609        // update admin field
610        contract_data.admin = admin;
611        self.save_contract(storage, &contract_addr, &contract_data)?;
612
613        // No custom events or data here.
614        Ok(AppResponse::default())
615    }
616
617    // this returns the contract address as well, so we can properly resend the data
618    fn execute_wasm(
619        &self,
620        api: &dyn Api,
621        storage: &mut dyn Storage,
622        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
623        block: &BlockInfo,
624        sender: Addr,
625        msg: WasmMsg,
626    ) -> StdResult<AppResponse> {
627        match msg {
628            WasmMsg::Execute {
629                contract_addr,
630                msg,
631                funds,
632            } => {
633                let contract_addr = api.addr_validate(&contract_addr)?;
634                // first move the cash
635                self.send(
636                    api,
637                    storage,
638                    router,
639                    block,
640                    sender.clone(),
641                    contract_addr.clone().into(),
642                    &funds,
643                )?;
644
645                // then call the contract
646                let info = MessageInfo { sender, funds };
647                let response = self.call_execute(
648                    api,
649                    storage,
650                    contract_addr.clone(),
651                    router,
652                    block,
653                    info,
654                    msg.to_vec(),
655                )?;
656
657                let custom_event =
658                    Event::new("execute").add_attribute(CONTRACT_ATTR, &contract_addr);
659
660                let (sub_response, sub_messages) =
661                    self.build_app_response(&contract_addr, custom_event, response);
662
663                let mut app_response = self.process_response(
664                    api,
665                    router,
666                    storage,
667                    block,
668                    contract_addr,
669                    sub_response,
670                    sub_messages,
671                )?;
672                app_response.data = encode_response_data(app_response.data);
673                Ok(app_response)
674            }
675            WasmMsg::Instantiate {
676                admin,
677                code_id,
678                msg,
679                funds,
680                label,
681            } => self.process_wasm_msg_instantiate(
682                api, storage, router, block, sender, admin, code_id, msg, funds, label, None,
683            ),
684            #[cfg(feature = "cosmwasm_1_2")]
685            WasmMsg::Instantiate2 {
686                admin,
687                code_id,
688                msg,
689                funds,
690                label,
691                salt,
692            } => self.process_wasm_msg_instantiate(
693                api,
694                storage,
695                router,
696                block,
697                sender,
698                admin,
699                code_id,
700                msg,
701                funds,
702                label,
703                Some(salt),
704            ),
705            WasmMsg::Migrate {
706                contract_addr,
707                new_code_id,
708                msg,
709            } => {
710                let contract_addr = api.addr_validate(&contract_addr)?;
711                // Check admin status.
712                if new_code_id as usize > self.code_data.len() {
713                    std_error_bail!("Cannot migrate contract to unregistered code id");
714                }
715                let mut data = self.contract_data(storage, &contract_addr)?;
716                if data.admin != Some(sender.clone()) {
717                    std_error_bail!("Only admin can migrate contract: {:?}", data.admin);
718                }
719                // Save the current (old) code_id for later use.
720                #[cfg(feature = "cosmwasm_2_2")]
721                let old_migrate_version = Some(data.code_id);
722                //  Update the stored code_id.
723                data.code_id = new_code_id;
724                self.save_contract(storage, &contract_addr, &data)?;
725
726                // Then call migrate (the classic version without MigrateInfo).
727                #[cfg(not(feature = "cosmwasm_2_2"))]
728                let res = self.call_migrate(
729                    contract_addr.clone(),
730                    api,
731                    storage,
732                    router,
733                    block,
734                    msg.to_vec(),
735                )?;
736
737                // Then call migrate with MigrateInfo.
738                #[cfg(feature = "cosmwasm_2_2")]
739                let res = self.call_migrate(
740                    contract_addr.clone(),
741                    api,
742                    storage,
743                    router,
744                    block,
745                    msg.to_vec(),
746                    MigrateInfo {
747                        sender,
748                        old_migrate_version,
749                    },
750                )?;
751
752                let custom_event = Event::new("migrate")
753                    .add_attribute(CONTRACT_ATTR, &contract_addr)
754                    .add_attribute("code_id", new_code_id.to_string());
755                let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
756                let mut res =
757                    self.process_response(api, router, storage, block, contract_addr, res, msgs)?;
758                res.data = encode_response_data(res.data);
759                Ok(res)
760            }
761            WasmMsg::UpdateAdmin {
762                contract_addr,
763                admin,
764            } => self.update_admin(api, storage, sender, &contract_addr, Some(admin)),
765            WasmMsg::ClearAdmin { contract_addr } => {
766                self.update_admin(api, storage, sender, &contract_addr, None)
767            }
768            _ => unimplemented!("{}", unsupported_wasm_message(msg)),
769        }
770    }
771
772    /// Processes WasmMsg::Instantiate and WasmMsg::Instantiate2 messages.
773    fn process_wasm_msg_instantiate(
774        &self,
775        api: &dyn Api,
776        storage: &mut dyn Storage,
777        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
778        block: &BlockInfo,
779        sender: Addr,
780        admin: Option<String>,
781        code_id: u64,
782        msg: Binary,
783        funds: Vec<Coin>,
784        label: String,
785        salt: Option<Binary>,
786    ) -> StdResult<AppResponse> {
787        if label.is_empty() {
788            std_error_bail!("Label is required on all contracts");
789        }
790
791        let contract_addr = self.register_contract(
792            api,
793            storage,
794            code_id,
795            sender.clone(),
796            admin.map(Addr::unchecked),
797            label,
798            block.height,
799            salt,
800        )?;
801
802        // move the cash
803        self.send(
804            api,
805            storage,
806            router,
807            block,
808            sender.clone(),
809            contract_addr.clone().into(),
810            &funds,
811        )?;
812
813        // then call the contract
814        let info = MessageInfo { sender, funds };
815        let res = self.call_instantiate(
816            contract_addr.clone(),
817            api,
818            storage,
819            router,
820            block,
821            info,
822            msg.to_vec(),
823        )?;
824
825        let custom_event = Event::new("instantiate")
826            .add_attribute(CONTRACT_ATTR, &contract_addr)
827            .add_attribute("code_id", code_id.to_string());
828
829        let (res, msgs) = self.build_app_response(&contract_addr, custom_event, res);
830        let mut res = self.process_response(
831            api,
832            router,
833            storage,
834            block,
835            contract_addr.clone(),
836            res,
837            msgs,
838        )?;
839        res.data = Some(instantiate_response(res.data, &contract_addr));
840        Ok(res)
841    }
842
843    /// This will execute the given messages, making all changes to the local cache.
844    /// This *will* write some data to the cache if the message fails half-way through.
845    /// All sequential calls to RouterCache will be one atomic unit (all commit or all fail).
846    ///
847    /// For normal use cases, you can use Router::execute() or Router::execute_multi().
848    /// This is designed to be handled internally as part of larger process flows.
849    ///
850    /// The `data` on `AppResponse` is data returned from `reply` call, not from execution of
851    /// sub-message itself. In case if `reply` is not called, no `data` is set.
852    fn execute_submsg(
853        &self,
854        api: &dyn Api,
855        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
856        storage: &mut dyn Storage,
857        block: &BlockInfo,
858        contract: Addr,
859        msg: SubMsg<ExecC>,
860    ) -> StdResult<AppResponse> {
861        let SubMsg {
862            msg,
863            id,
864            reply_on,
865            payload,
866            ..
867        } = msg;
868        // Prepare the message type URL, will be needed when calling `reply` entrypoint.
869        let type_url = Self::response_type_url(&msg);
870
871        // Execute the submessage in cache
872        let sub_message_result = transactional(storage, |write_cache, _| {
873            router.execute(api, write_cache, block, contract.clone(), msg)
874        });
875
876        // call reply if meaningful
877        if let Ok(mut r) = sub_message_result {
878            if matches!(reply_on, ReplyOn::Always | ReplyOn::Success) {
879                let reply = Reply {
880                    id,
881                    payload,
882                    gas_used: 0,
883                    result: SubMsgResult::Ok(
884                        #[allow(deprecated)]
885                        SubMsgResponse {
886                            events: r.events.clone(),
887                            data: r.data.clone(),
888                            msg_responses: vec![MsgResponse {
889                                type_url,
890                                value: r.data.unwrap_or_default(),
891                            }],
892                        },
893                    ),
894                };
895                // do reply and combine it with the original response
896                let reply_res = self.reply(api, router, storage, block, contract, reply)?;
897                // override data
898                r.data = reply_res.data;
899                // append the events
900                r.events.extend_from_slice(&reply_res.events);
901            } else {
902                // reply is not called, no data should be returned
903                r.data = None;
904            }
905            Ok(r)
906        } else if let Err(e) = sub_message_result {
907            if matches!(reply_on, ReplyOn::Always | ReplyOn::Error) {
908                let reply = Reply {
909                    id,
910                    payload,
911                    gas_used: 0,
912                    result: SubMsgResult::Err(format!("{e:?}")),
913                };
914                self.reply(api, router, storage, block, contract, reply)
915            } else {
916                Err(e)
917            }
918        } else {
919            sub_message_result
920        }
921    }
922
923    fn reply(
924        &self,
925        api: &dyn Api,
926        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
927        storage: &mut dyn Storage,
928        block: &BlockInfo,
929        contract: Addr,
930        reply: Reply,
931    ) -> StdResult<AppResponse> {
932        let ok_attr = if reply.result.is_ok() {
933            "handle_success"
934        } else {
935            "handle_failure"
936        };
937        let custom_event = Event::new("reply")
938            .add_attribute(CONTRACT_ATTR, &contract)
939            .add_attribute("mode", ok_attr);
940
941        let res = self.call_reply(contract.clone(), api, storage, router, block, reply)?;
942        let (res, msgs) = self.build_app_response(&contract, custom_event, res);
943        self.process_response(api, router, storage, block, contract, res, msgs)
944    }
945
946    /// Captures all the events, data and sub messages from the contract call.
947    ///
948    /// This function does not handle the messages.
949    fn build_app_response(
950        &self,
951        contract: &Addr,
952        custom_event: Event, // entry-point specific custom event added by x/wasm
953        response: Response<ExecC>,
954    ) -> (AppResponse, Vec<SubMsg<ExecC>>) {
955        let Response {
956            messages,
957            attributes,
958            events,
959            data,
960            ..
961        } = response;
962
963        // always add custom event
964        let mut app_events = Vec::with_capacity(2 + events.len());
965        app_events.push(custom_event);
966
967        // we only emit the `wasm` event if some attributes are specified
968        if !attributes.is_empty() {
969            // turn attributes into event and place it first
970            let wasm_event = Event::new("wasm")
971                .add_attribute(CONTRACT_ATTR, contract)
972                .add_attributes(attributes);
973            app_events.push(wasm_event);
974        }
975
976        // These need to get `wasm-` prefix to match the wasmd semantics (custom wasm messages cannot
977        // fake system level event types, like transfer from the bank module)
978        let wasm_events = events.into_iter().map(|mut ev| {
979            ev.ty = format!("wasm-{}", ev.ty);
980            ev.attributes
981                .insert(0, mock_wasmd_attr(CONTRACT_ATTR, contract));
982            ev
983        });
984        app_events.extend(wasm_events);
985
986        let app_response = AppResponse {
987            events: app_events,
988            data,
989        };
990        (app_response, messages)
991    }
992
993    fn process_response(
994        &self,
995        api: &dyn Api,
996        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
997        storage: &mut dyn Storage,
998        block: &BlockInfo,
999        contract: Addr,
1000        response: AppResponse,
1001        sub_messages: Vec<SubMsg<ExecC>>,
1002    ) -> StdResult<AppResponse> {
1003        // Unpack the provided response.
1004        let AppResponse {
1005            mut events, data, ..
1006        } = response;
1007        // Recurse in all submessages.
1008        let data = sub_messages
1009            .into_iter()
1010            .try_fold(data, |data, sub_message| {
1011                // Execute the submessage.
1012                let sub_response = self.execute_submsg(
1013                    api,
1014                    router,
1015                    storage,
1016                    block,
1017                    contract.clone(),
1018                    sub_message,
1019                )?;
1020                // COLLECT and append all events from the processed submessage.
1021                events.extend_from_slice(&sub_response.events);
1022                // REPLACE the data with value from the processes submessage (if not empty).
1023                Ok::<_, StdError>(sub_response.data.or(data))
1024            })?;
1025        // Return the response with updated data, events and message responses taken from
1026        // all processed sub messages. Note that events and message responses are collected,
1027        // but the data is replaced with the data from the last processes submessage.
1028        Ok(AppResponse { events, data })
1029    }
1030
1031    /// Creates a contract address and empty storage instance.
1032    /// Returns the new contract address.
1033    ///
1034    /// You have to call init after this to set up the contract properly.
1035    /// These two steps are separated to have cleaner return values.
1036    pub fn register_contract(
1037        &self,
1038        api: &dyn Api,
1039        storage: &mut dyn Storage,
1040        code_id: u64,
1041        creator: Addr,
1042        admin: impl Into<Option<Addr>>,
1043        label: String,
1044        created: u64,
1045        salt: impl Into<Option<Binary>>,
1046    ) -> StdResult<Addr> {
1047        // check if the contract's code with specified code_id exists
1048        if code_id as usize > self.code_data.len() {
1049            std_error_bail!("Cannot init contract with unregistered code id");
1050        }
1051
1052        // generate a new contract address
1053        let instance_id = self.instance_count(storage) as u64;
1054        let addr = if let Some(salt_binary) = salt.into() {
1055            // generate predictable contract address when salt is provided
1056            let code_data = self.code_data(code_id)?;
1057            let canonical_addr = &api.addr_canonicalize(creator.as_ref())?;
1058            self.address_generator.predictable_contract_address(
1059                api,
1060                storage,
1061                code_id,
1062                instance_id,
1063                code_data.checksum.as_slice(),
1064                canonical_addr,
1065                salt_binary.as_slice(),
1066            )?
1067        } else {
1068            // generate non-predictable contract address
1069            self.address_generator
1070                .contract_address(api, storage, code_id, instance_id)?
1071        };
1072
1073        // contract with the same address must not already exist
1074        if self.contract_data(storage, &addr).is_ok() {
1075            std_error_bail!(duplicated_contract_address(addr));
1076        }
1077
1078        // prepare contract data and save new contract instance
1079        let info = ContractData {
1080            code_id,
1081            creator,
1082            admin: admin.into(),
1083            label,
1084            created,
1085        };
1086        self.save_contract(storage, &addr, &info)?;
1087        Ok(addr)
1088    }
1089
1090    /// Executes contract's `execute` entry-point.
1091    pub fn call_execute(
1092        &self,
1093        api: &dyn Api,
1094        storage: &mut dyn Storage,
1095        address: Addr,
1096        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1097        block: &BlockInfo,
1098        info: MessageInfo,
1099        msg: Vec<u8>,
1100    ) -> StdResult<Response<ExecC>> {
1101        Self::verify_response(self.with_storage(
1102            api,
1103            storage,
1104            router,
1105            block,
1106            address,
1107            |contract, deps, env| contract.execute(deps, env, info, msg),
1108        )?)
1109    }
1110
1111    /// Executes contract's `instantiate` entry-point.
1112    pub fn call_instantiate(
1113        &self,
1114        address: Addr,
1115        api: &dyn Api,
1116        storage: &mut dyn Storage,
1117        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1118        block: &BlockInfo,
1119        info: MessageInfo,
1120        msg: Vec<u8>,
1121    ) -> StdResult<Response<ExecC>> {
1122        Self::verify_response(self.with_storage(
1123            api,
1124            storage,
1125            router,
1126            block,
1127            address,
1128            |contract, deps, env| contract.instantiate(deps, env, info, msg),
1129        )?)
1130    }
1131
1132    /// Executes contract's `reply` entry-point.
1133    pub fn call_reply(
1134        &self,
1135        address: Addr,
1136        api: &dyn Api,
1137        storage: &mut dyn Storage,
1138        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1139        block: &BlockInfo,
1140        reply: Reply,
1141    ) -> StdResult<Response<ExecC>> {
1142        Self::verify_response(self.with_storage(
1143            api,
1144            storage,
1145            router,
1146            block,
1147            address,
1148            |contract, deps, env| contract.reply(deps, env, reply),
1149        )?)
1150    }
1151
1152    /// Executes contract's `sudo` entry-point.
1153    pub fn call_sudo(
1154        &self,
1155        address: Addr,
1156        api: &dyn Api,
1157        storage: &mut dyn Storage,
1158        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1159        block: &BlockInfo,
1160        msg: Vec<u8>,
1161    ) -> StdResult<Response<ExecC>> {
1162        Self::verify_response(self.with_storage(
1163            api,
1164            storage,
1165            router,
1166            block,
1167            address,
1168            |contract, deps, env| contract.sudo(deps, env, msg),
1169        )?)
1170    }
1171
1172    /// Executes contract's `migrate` entry-point.
1173    #[cfg(not(feature = "cosmwasm_2_2"))]
1174    pub fn call_migrate(
1175        &self,
1176        address: Addr,
1177        api: &dyn Api,
1178        storage: &mut dyn Storage,
1179        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1180        block: &BlockInfo,
1181        msg: Vec<u8>,
1182    ) -> StdResult<Response<ExecC>> {
1183        Self::verify_response(self.with_storage(
1184            api,
1185            storage,
1186            router,
1187            block,
1188            address,
1189            |contract, deps, env| contract.migrate(deps, env, msg),
1190        )?)
1191    }
1192
1193    /// Executes contract's `migrate` entry-point.
1194    #[cfg(feature = "cosmwasm_2_2")]
1195    pub fn call_migrate(
1196        &self,
1197        address: Addr,
1198        api: &dyn Api,
1199        storage: &mut dyn Storage,
1200        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1201        block: &BlockInfo,
1202        msg: Vec<u8>,
1203        info: MigrateInfo,
1204    ) -> StdResult<Response<ExecC>> {
1205        Self::verify_response(self.with_storage(
1206            api,
1207            storage,
1208            router,
1209            block,
1210            address,
1211            |contract, deps, env| contract.migrate(deps, env, msg, info),
1212        )?)
1213    }
1214
1215    fn get_env<T: Into<Addr>>(&self, address: T, block: &BlockInfo) -> Env {
1216        Env {
1217            block: block.clone(),
1218            contract: ContractInfo {
1219                address: address.into(),
1220            },
1221            transaction: Some(TransactionInfo::new(0, Binary::default())),
1222        }
1223    }
1224
1225    fn with_storage_readonly<F, T>(
1226        &self,
1227        api: &dyn Api,
1228        storage: &dyn Storage,
1229        querier: &dyn Querier,
1230        block: &BlockInfo,
1231        address: Addr,
1232        action: F,
1233    ) -> StdResult<T>
1234    where
1235        F: FnOnce(&dyn Contract<ExecC, QueryC>, Deps<QueryC>, Env) -> StdResult<T>,
1236    {
1237        let contract = self.contract_data(storage, &address)?;
1238        let handler = self.contract_code(contract.code_id)?;
1239        let storage = self.contract_storage(storage, &address);
1240        let env = self.get_env(address, block);
1241
1242        let deps = Deps {
1243            storage: storage.as_ref(),
1244            api,
1245            querier: QuerierWrapper::new(querier),
1246        };
1247        action(handler, deps, env)
1248    }
1249
1250    fn with_storage<F, T>(
1251        &self,
1252        api: &dyn Api,
1253        storage: &mut dyn Storage,
1254        router: &dyn CosmosRouter<ExecC = ExecC, QueryC = QueryC>,
1255        block: &BlockInfo,
1256        address: Addr,
1257        action: F,
1258    ) -> StdResult<T>
1259    where
1260        F: FnOnce(&dyn Contract<ExecC, QueryC>, DepsMut<QueryC>, Env) -> StdResult<T>,
1261        ExecC: DeserializeOwned,
1262    {
1263        let contract = self.contract_data(storage, &address)?;
1264        let handler = self.contract_code(contract.code_id)?;
1265
1266        // We don't actually need a transaction here, as it is already embedded in a transactional.
1267        // execute_submsg or App.execute_multi.
1268        // However, we need to get write and read access to the same storage in two different objects,
1269        // and this is the only way I know how to do so.
1270        transactional(storage, |write_cache, read_store| {
1271            let mut contract_storage = self.contract_storage_mut(write_cache, &address);
1272            let querier = RouterQuerier::new(router, api, read_store, block);
1273            let env = self.get_env(address, block);
1274
1275            let deps = DepsMut {
1276                storage: contract_storage.as_mut(),
1277                api,
1278                querier: QuerierWrapper::new(&querier),
1279            };
1280            action(handler, deps, env)
1281        })
1282    }
1283
1284    /// Saves contract data in a storage under specified address.
1285    pub fn save_contract(
1286        &self,
1287        storage: &mut dyn Storage,
1288        address: &Addr,
1289        contract: &ContractData,
1290    ) -> StdResult<()> {
1291        let mut storage: TypedPrefixedStorageMut<'_, WasmKeeper<ExecC, QueryC>> =
1292            WasmStorageMut::new(storage);
1293        CONTRACTS.save(&mut storage, address, contract)
1294    }
1295
1296    /// Returns the number of all contract instances.
1297    fn instance_count(&self, storage: &dyn Storage) -> usize {
1298        let storage: TypedPrefixedStorage<'_, WasmKeeper<ExecC, QueryC>> =
1299            WasmStorage::new(storage);
1300        CONTRACTS
1301            .range_raw(&storage, None, None, Order::Ascending)
1302            .count()
1303    }
1304
1305    /// Returns the response type for specified message.
1306    fn response_type_url(msg: &CosmosMsg<ExecC>) -> String {
1307        const UNKNOWN: &str = "/unknown";
1308        #[allow(clippy::collapsible_match)]
1309        match &msg {
1310            CosmosMsg::Bank(bank_msg) => match bank_msg {
1311                BankMsg::Send { .. } => "/cosmos.bank.v1beta1.MsgSendResponse",
1312                BankMsg::Burn { .. } => "/cosmos.bank.v1beta1.MsgBurnResponse",
1313                _ => UNKNOWN,
1314            },
1315            CosmosMsg::Custom(..) => UNKNOWN,
1316            #[cfg(feature = "staking")]
1317            CosmosMsg::Staking(staking_msg) => match staking_msg {
1318                StakingMsg::Delegate { .. } => "/cosmos.staking.v1beta1.MsgDelegateResponse",
1319                StakingMsg::Undelegate { .. } => "/cosmos.staking.v1beta1.MsgUndelegateResponse",
1320                StakingMsg::Redelegate { .. } => {
1321                    "/cosmos.staking.v1beta1.MsgBeginRedelegateResponse"
1322                }
1323                _ => UNKNOWN,
1324            },
1325            #[cfg(feature = "staking")]
1326            CosmosMsg::Distribution(distribution_msg) => match distribution_msg {
1327                #[cfg(feature = "cosmwasm_1_3")]
1328                DistributionMsg::FundCommunityPool { .. } => {
1329                    "/cosmos.distribution.v1beta1.MsgFundCommunityPoolResponse"
1330                }
1331                DistributionMsg::SetWithdrawAddress { .. } => {
1332                    "/cosmos.distribution.v1beta1.MsgSetWithdrawAddressResponse"
1333                }
1334                DistributionMsg::WithdrawDelegatorReward { .. } => {
1335                    "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorRewardResponse"
1336                }
1337                _ => UNKNOWN,
1338            },
1339            #[cfg(feature = "stargate")]
1340            #[allow(deprecated)]
1341            CosmosMsg::Stargate { .. } => UNKNOWN,
1342            #[cfg(feature = "cosmwasm_2_0")]
1343            CosmosMsg::Any(..) => UNKNOWN,
1344            #[cfg(feature = "stargate")]
1345            CosmosMsg::Ibc(..) => UNKNOWN,
1346            CosmosMsg::Wasm(wasm_msg) => match wasm_msg {
1347                WasmMsg::Instantiate { .. } => "/cosmwasm.wasm.v1.MsgInstantiateContractResponse",
1348                #[cfg(feature = "cosmwasm_1_2")]
1349                WasmMsg::Instantiate2 { .. } => "/cosmwasm.wasm.v1.MsgInstantiateContract2Response",
1350                WasmMsg::Execute { .. } => "/cosmwasm.wasm.v1.MsgExecuteContractResponse",
1351                WasmMsg::Migrate { .. } => "/cosmwasm.wasm.v1.MsgMigrateContractResponse",
1352                WasmMsg::UpdateAdmin { .. } => "/cosmwasm.wasm.v1.MsgUpdateAdminResponse",
1353                WasmMsg::ClearAdmin { .. } => "/cosmwasm.wasm.v1.MsgClearAdminResponse",
1354                _ => UNKNOWN,
1355            },
1356            #[cfg(feature = "stargate")]
1357            CosmosMsg::Gov(gov_msg) => match gov_msg {
1358                GovMsg::Vote { .. } => "/cosmos.gov.v1beta1.MsgVoteResponse",
1359                #[cfg(feature = "cosmwasm_1_2")]
1360                GovMsg::VoteWeighted { .. } => "/cosmos.gov.v1beta1.MsgVoteWeightedResponse",
1361                _ => UNKNOWN,
1362            },
1363            _ => UNKNOWN,
1364        }
1365        .to_string()
1366    }
1367}
1368
1369#[derive(Clone, PartialEq, Message)]
1370struct InstantiateResponse {
1371    #[prost(string, tag = "1")]
1372    pub address: String,
1373    #[prost(bytes, tag = "2")]
1374    pub data: Vec<u8>,
1375}
1376
1377fn instantiate_response(data: Option<Binary>, contact_address: &Addr) -> Binary {
1378    let data = data.unwrap_or_default().to_vec();
1379    let init_data = InstantiateResponse {
1380        address: contact_address.into(),
1381        data,
1382    };
1383    let mut new_data = Vec::<u8>::with_capacity(init_data.encoded_len());
1384    // the data must encode successfully
1385    init_data.encode(&mut new_data).unwrap();
1386    new_data.into()
1387}
1388
1389#[derive(Clone, PartialEq, Message)]
1390struct ExecuteResponse {
1391    #[prost(bytes, tag = "1")]
1392    pub data: Vec<u8>,
1393}
1394
1395/// Encodes the response data.
1396fn encode_response_data(data: Option<Binary>) -> Option<Binary> {
1397    data.map(|d| {
1398        let execute_response = ExecuteResponse { data: d.to_vec() };
1399        let mut encoded_data = Vec::<u8>::with_capacity(execute_response.encoded_len());
1400        execute_response.encode(&mut encoded_data).unwrap();
1401        encoded_data.into()
1402    })
1403}
1404
1405#[cfg(test)]
1406mod test {
1407    use super::*;
1408    use crate::app::Router;
1409    use crate::bank::BankKeeper;
1410    use crate::featured::staking::{DistributionKeeper, StakeKeeper};
1411    use crate::module::FailingModule;
1412    use crate::test_helpers::{caller, error, payout};
1413    use crate::transactions::StorageTransaction;
1414    use crate::{GovFailingModule, IbcFailingModule, StargateFailing};
1415    use cosmwasm_std::testing::{message_info, mock_env, MockApi, MockQuerier, MockStorage};
1416    #[cfg(feature = "cosmwasm_1_2")]
1417    use cosmwasm_std::CodeInfoResponse;
1418    use cosmwasm_std::{coin, from_json, to_json_vec, CanonicalAddr, CosmosMsg, Empty, HexBinary};
1419    use std::slice;
1420
1421    /// Type alias for default build `Router` to make its reference in typical scenario
1422    type BasicRouter<ExecC = Empty, QueryC = Empty> = Router<
1423        BankKeeper,
1424        FailingModule<ExecC, QueryC, Empty>,
1425        WasmKeeper<ExecC, QueryC>,
1426        StakeKeeper,
1427        DistributionKeeper,
1428        IbcFailingModule,
1429        GovFailingModule,
1430        StargateFailing,
1431    >;
1432
1433    fn wasm_keeper() -> WasmKeeper<Empty, Empty> {
1434        WasmKeeper::new()
1435    }
1436
1437    fn mock_router() -> BasicRouter {
1438        Router {
1439            wasm: WasmKeeper::new(),
1440            bank: BankKeeper::new(),
1441            custom: FailingModule::new(),
1442            staking: StakeKeeper::new(),
1443            distribution: DistributionKeeper::new(),
1444            ibc: IbcFailingModule::new(),
1445            gov: GovFailingModule::new(),
1446            stargate: StargateFailing,
1447        }
1448    }
1449
1450    #[test]
1451    fn register_contract() {
1452        let api = MockApi::default();
1453
1454        // prepare user addresses
1455        let creator_addr = api.addr_make("creator");
1456        let user_addr = api.addr_make("foobar");
1457        let admin_addr = api.addr_make("admin");
1458        let unregistered_addr = api.addr_make("unregistered");
1459
1460        let mut wasm_storage = MockStorage::new();
1461        let mut wasm_keeper = wasm_keeper();
1462        let block = mock_env().block;
1463        let code_id = wasm_keeper.store_code(creator_addr, error::contract(false));
1464
1465        transactional(&mut wasm_storage, |cache, _| {
1466            // cannot register contract with unregistered codeId
1467            wasm_keeper.register_contract(
1468                &api,
1469                cache,
1470                code_id + 1,
1471                user_addr.clone(),
1472                admin_addr.clone(),
1473                "label".to_owned(),
1474                1000,
1475                None,
1476            )
1477        })
1478        .unwrap_err();
1479
1480        let contract_addr = transactional(&mut wasm_storage, |cache, _| {
1481            // we can register a new instance of this code
1482            wasm_keeper.register_contract(
1483                &api,
1484                cache,
1485                code_id,
1486                user_addr.clone(),
1487                admin_addr.clone(),
1488                "label".to_owned(),
1489                1000,
1490                None,
1491            )
1492        })
1493        .unwrap();
1494
1495        // verify contract data are as expected
1496        let contract_data = wasm_keeper
1497            .contract_data(&wasm_storage, &contract_addr)
1498            .unwrap();
1499
1500        assert_eq!(
1501            contract_data,
1502            ContractData {
1503                code_id,
1504                creator: user_addr.clone(),
1505                admin: admin_addr.into(),
1506                label: "label".to_owned(),
1507                created: 1000,
1508            }
1509        );
1510
1511        let err = transactional(&mut wasm_storage, |cache, _| {
1512            // now, we call this contract and see the error message from the contract
1513            let info = message_info(&user_addr, &[]);
1514            wasm_keeper.call_instantiate(
1515                contract_addr.clone(),
1516                &api,
1517                cache,
1518                &mock_router(),
1519                &block,
1520                info,
1521                b"{}".to_vec(),
1522            )
1523        })
1524        .unwrap_err();
1525
1526        // StdError from contract_error auto-converted to string
1527        assert_eq!(
1528            "kind: Other, error: kind: Other, error: Init failed",
1529            err.to_string()
1530        );
1531
1532        let err = transactional(&mut wasm_storage, |cache, _| {
1533            // and the error for calling an unregistered contract
1534            let info = message_info(&user_addr, &[]);
1535            wasm_keeper.call_instantiate(
1536                unregistered_addr,
1537                &api,
1538                cache,
1539                &mock_router(),
1540                &block,
1541                info,
1542                b"{}".to_vec(),
1543            )
1544        })
1545        .unwrap_err();
1546
1547        // Default error message from router when not found
1548        assert!(err
1549            .to_string()
1550            .starts_with("kind: Other, error: type: cw_multi_test::wasm::ContractData; key:"));
1551    }
1552
1553    #[test]
1554    fn query_contract_info() {
1555        let api = MockApi::default();
1556
1557        // prepare user addresses
1558        let creator_addr = api.addr_make("creator");
1559        let admin_addr = api.addr_make("admin");
1560
1561        let mut wasm_storage = MockStorage::new();
1562        let mut wasm_keeper = wasm_keeper();
1563        let block = mock_env().block;
1564        let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract());
1565        assert_eq!(1, code_id);
1566
1567        let contract_addr = wasm_keeper
1568            .register_contract(
1569                &api,
1570                &mut wasm_storage,
1571                code_id,
1572                creator_addr.clone(),
1573                admin_addr.clone(),
1574                "label".to_owned(),
1575                1000,
1576                None,
1577            )
1578            .unwrap();
1579
1580        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
1581        let query = WasmQuery::ContractInfo {
1582            contract_addr: contract_addr.into(),
1583        };
1584
1585        let contract_info = wasm_keeper
1586            .query(&api, &wasm_storage, &querier, &block, query)
1587            .unwrap();
1588
1589        let actual: ContractInfoResponse = from_json(contract_info).unwrap();
1590        let expected =
1591            ContractInfoResponse::new(code_id, creator_addr, admin_addr.into(), false, None, None);
1592        assert_eq!(expected, actual);
1593    }
1594
1595    #[test]
1596    #[cfg(feature = "cosmwasm_1_2")]
1597    fn query_code_info() {
1598        let api = MockApi::default();
1599        let wasm_storage = MockStorage::new();
1600        let mut wasm_keeper = wasm_keeper();
1601        let block = mock_env().block;
1602        let creator_addr = api.addr_make("creator");
1603        let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract());
1604        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
1605        let query = WasmQuery::CodeInfo { code_id };
1606        let code_info = wasm_keeper
1607            .query(&api, &wasm_storage, &querier, &block, query)
1608            .unwrap();
1609        let actual: CodeInfoResponse = from_json(code_info).unwrap();
1610        assert_eq!(code_id, actual.code_id);
1611        assert_eq!(creator_addr.as_str(), actual.creator.as_str());
1612        assert_eq!(32, actual.checksum.as_slice().len());
1613    }
1614
1615    #[test]
1616    #[cfg(feature = "cosmwasm_1_2")]
1617    fn different_contracts_must_have_different_checksum() {
1618        let api = MockApi::default();
1619        let creator_addr = api.addr_make("creator");
1620        let wasm_storage = MockStorage::new();
1621        let mut wasm_keeper = wasm_keeper();
1622        let block = mock_env().block;
1623        let code_id_payout = wasm_keeper.store_code(creator_addr.clone(), payout::contract());
1624        let code_id_caller = wasm_keeper.store_code(creator_addr, caller::contract());
1625        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
1626        let query_payout = WasmQuery::CodeInfo {
1627            code_id: code_id_payout,
1628        };
1629        let query_caller = WasmQuery::CodeInfo {
1630            code_id: code_id_caller,
1631        };
1632        let code_info_payout = wasm_keeper
1633            .query(&api, &wasm_storage, &querier, &block, query_payout)
1634            .unwrap();
1635        let code_info_caller = wasm_keeper
1636            .query(&api, &wasm_storage, &querier, &block, query_caller)
1637            .unwrap();
1638        let info_payout: CodeInfoResponse = from_json(code_info_payout).unwrap();
1639        let info_caller: CodeInfoResponse = from_json(code_info_caller).unwrap();
1640        assert_eq!(code_id_payout, info_payout.code_id);
1641        assert_eq!(code_id_caller, info_caller.code_id);
1642        assert_ne!(info_caller.code_id, info_payout.code_id);
1643        assert_eq!(info_caller.creator, info_payout.creator);
1644        assert_ne!(info_caller.checksum, info_payout.checksum);
1645    }
1646
1647    #[test]
1648    #[cfg(feature = "cosmwasm_1_2")]
1649    fn querying_invalid_code_info_must_fail() {
1650        let api = MockApi::default();
1651        let wasm_storage = MockStorage::new();
1652        let wasm_keeper = wasm_keeper();
1653        let block = mock_env().block;
1654
1655        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
1656        let query = WasmQuery::CodeInfo { code_id: 100 };
1657
1658        wasm_keeper
1659            .query(&api, &wasm_storage, &querier, &block, query)
1660            .unwrap_err();
1661    }
1662
1663    #[test]
1664    fn can_dump_raw_wasm_state() {
1665        let api = MockApi::default();
1666
1667        // prepare user addresses
1668        let creator_addr = api.addr_make("creator");
1669        let admin_addr = api.addr_make("admin");
1670        let user_addr = api.addr_make("foobar");
1671
1672        let mut wasm_keeper = wasm_keeper();
1673        let block = mock_env().block;
1674        let code_id = wasm_keeper.store_code(creator_addr, payout::contract());
1675
1676        let mut wasm_storage = MockStorage::new();
1677
1678        let contract_addr = wasm_keeper
1679            .register_contract(
1680                &api,
1681                &mut wasm_storage,
1682                code_id,
1683                user_addr.clone(),
1684                admin_addr,
1685                "label".to_owned(),
1686                1000,
1687                None,
1688            )
1689            .unwrap();
1690
1691        // make a contract with state
1692        let payout = coin(1500, "mlg");
1693        let msg = payout::InstantiateMessage {
1694            payout: payout.clone(),
1695        };
1696        wasm_keeper
1697            .call_instantiate(
1698                contract_addr.clone(),
1699                &api,
1700                &mut wasm_storage,
1701                &mock_router(),
1702                &block,
1703                message_info(&user_addr, &[]),
1704                to_json_vec(&msg).unwrap(),
1705            )
1706            .unwrap();
1707
1708        // dump state
1709        let state = wasm_keeper.dump_wasm_raw(&wasm_storage, &contract_addr);
1710        assert_eq!(state.len(), 2);
1711        // check contents
1712        let (k, v) = &state[0];
1713        assert_eq!(k.as_slice(), b"count");
1714        let count: u32 = from_json(v).unwrap();
1715        assert_eq!(count, 1);
1716        let (k, v) = &state[1];
1717        assert_eq!(k.as_slice(), b"payout");
1718        let stored_pay: payout::InstantiateMessage = from_json(v).unwrap();
1719        assert_eq!(stored_pay.payout, payout);
1720    }
1721
1722    #[test]
1723    fn contract_send_coins() {
1724        let api = MockApi::default();
1725
1726        // prepare user addresses
1727        let creator_addr = api.addr_make("creator");
1728        let user_addr = api.addr_make("foobar");
1729
1730        let mut wasm_keeper = wasm_keeper();
1731        let block = mock_env().block;
1732        let code_id = wasm_keeper.store_code(creator_addr, payout::contract());
1733
1734        let mut wasm_storage = MockStorage::new();
1735        let mut cache = StorageTransaction::new(&wasm_storage);
1736
1737        let contract_addr = wasm_keeper
1738            .register_contract(
1739                &api,
1740                &mut cache,
1741                code_id,
1742                user_addr.clone(),
1743                None,
1744                "label".to_owned(),
1745                1000,
1746                None,
1747            )
1748            .unwrap();
1749
1750        let payout = coin(100, "TGD");
1751
1752        // init the contract
1753        let info = message_info(&user_addr, &[]);
1754        let init_msg = to_json_vec(&payout::InstantiateMessage {
1755            payout: payout.clone(),
1756        })
1757        .unwrap();
1758        let res = wasm_keeper
1759            .call_instantiate(
1760                contract_addr.clone(),
1761                &api,
1762                &mut cache,
1763                &mock_router(),
1764                &block,
1765                info,
1766                init_msg,
1767            )
1768            .unwrap();
1769        assert_eq!(0, res.messages.len());
1770
1771        // execute the contract
1772        let info = message_info(&user_addr, &[]);
1773        let res = wasm_keeper
1774            .call_execute(
1775                &api,
1776                &mut cache,
1777                contract_addr.clone(),
1778                &mock_router(),
1779                &block,
1780                info,
1781                b"{}".to_vec(),
1782            )
1783            .unwrap();
1784        assert_eq!(1, res.messages.len());
1785        match &res.messages[0].msg {
1786            CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => {
1787                assert_eq!(to_address.as_str(), user_addr.as_str());
1788                assert_eq!(amount.as_slice(), slice::from_ref(&payout));
1789            }
1790            m => panic!("Unexpected message {m:?}"),
1791        }
1792
1793        // and flush before query
1794        cache.prepare().commit(&mut wasm_storage);
1795
1796        // query the contract
1797        let query = to_json_vec(&payout::QueryMsg::Payout {}).unwrap();
1798        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
1799        let data = wasm_keeper
1800            .query_smart(contract_addr, &api, &wasm_storage, &querier, &block, query)
1801            .unwrap();
1802        let res: payout::InstantiateMessage = from_json(data).unwrap();
1803        assert_eq!(res.payout, payout);
1804    }
1805
1806    fn assert_payout(
1807        router: &WasmKeeper<Empty, Empty>,
1808        storage: &mut dyn Storage,
1809        contract_addr: &Addr,
1810        payout: &Coin,
1811    ) {
1812        let api = MockApi::default();
1813        let user_addr = api.addr_make("silly");
1814        let info = message_info(&user_addr, &[]);
1815        let res = router
1816            .call_execute(
1817                &api,
1818                storage,
1819                contract_addr.clone(),
1820                &mock_router(),
1821                &mock_env().block,
1822                info,
1823                b"{}".to_vec(),
1824            )
1825            .unwrap();
1826        assert_eq!(1, res.messages.len());
1827        match &res.messages[0].msg {
1828            CosmosMsg::Bank(BankMsg::Send { to_address, amount }) => {
1829                assert_eq!(to_address.as_str(), user_addr.as_str());
1830                assert_eq!(amount.as_slice(), slice::from_ref(payout));
1831            }
1832            m => panic!("Unexpected message {m:?}"),
1833        }
1834    }
1835
1836    fn assert_no_contract(storage: &dyn Storage, contract_addr: &Addr) {
1837        let contract = CONTRACTS.may_load(storage, contract_addr).unwrap();
1838        assert!(contract.is_none(), "{contract_addr:?}");
1839    }
1840
1841    #[test]
1842    fn multi_level_wasm_cache() {
1843        let api = MockApi::default();
1844
1845        // prepare user addresses
1846        let creator_addr = api.addr_make("creator");
1847        let user_addr = api.addr_make("foobar");
1848        let user_addr_1 = api.addr_make("johnny");
1849
1850        let mut wasm_keeper = wasm_keeper();
1851        let block = mock_env().block;
1852        let code_id = wasm_keeper.store_code(creator_addr, payout::contract());
1853
1854        let mut wasm_storage = MockStorage::new();
1855
1856        let payout1 = coin(100, "TGD");
1857
1858        // set contract 1 and commit (on router)
1859        let contract1 = transactional(&mut wasm_storage, |cache, _| {
1860            let contract = wasm_keeper
1861                .register_contract(
1862                    &api,
1863                    cache,
1864                    code_id,
1865                    user_addr.clone(),
1866                    None,
1867                    "".to_string(),
1868                    1000,
1869                    None,
1870                )
1871                .unwrap();
1872            let info = message_info(&user_addr, &[]);
1873            let init_msg = to_json_vec(&payout::InstantiateMessage {
1874                payout: payout1.clone(),
1875            })
1876            .unwrap();
1877            wasm_keeper
1878                .call_instantiate(
1879                    contract.clone(),
1880                    &api,
1881                    cache,
1882                    &mock_router(),
1883                    &block,
1884                    info,
1885                    init_msg,
1886                )
1887                .unwrap();
1888
1889            Ok(contract)
1890        })
1891        .unwrap();
1892
1893        let payout2 = coin(50, "BTC");
1894        let payout3 = coin(1234, "ATOM");
1895
1896        // create a new cache and check we can use contract 1
1897        let (contract2, contract3) = transactional(&mut wasm_storage, |cache, wasm_reader| {
1898            assert_payout(&wasm_keeper, cache, &contract1, &payout1);
1899
1900            // create contract 2 and use it
1901            let contract2 = wasm_keeper
1902                .register_contract(
1903                    &api,
1904                    cache,
1905                    code_id,
1906                    user_addr.clone(),
1907                    None,
1908                    "".to_owned(),
1909                    1000,
1910                    None,
1911                )
1912                .unwrap();
1913            let info = message_info(&user_addr, &[]);
1914            let init_msg = to_json_vec(&payout::InstantiateMessage {
1915                payout: payout2.clone(),
1916            })
1917            .unwrap();
1918            let _res = wasm_keeper
1919                .call_instantiate(
1920                    contract2.clone(),
1921                    &api,
1922                    cache,
1923                    &mock_router(),
1924                    &block,
1925                    info,
1926                    init_msg,
1927                )
1928                .unwrap();
1929            assert_payout(&wasm_keeper, cache, &contract2, &payout2);
1930
1931            // create a level2 cache and check we can use contract 1 and contract 2
1932            let contract3 = transactional(cache, |cache2, read| {
1933                assert_payout(&wasm_keeper, cache2, &contract1, &payout1);
1934                assert_payout(&wasm_keeper, cache2, &contract2, &payout2);
1935
1936                // create a contract on level 2
1937                let contract3 = wasm_keeper
1938                    .register_contract(
1939                        &api,
1940                        cache2,
1941                        code_id,
1942                        user_addr,
1943                        None,
1944                        "".to_owned(),
1945                        1000,
1946                        None,
1947                    )
1948                    .unwrap();
1949                let info = message_info(&user_addr_1, &[]);
1950                let init_msg = to_json_vec(&payout::InstantiateMessage {
1951                    payout: payout3.clone(),
1952                })
1953                .unwrap();
1954                let _res = wasm_keeper
1955                    .call_instantiate(
1956                        contract3.clone(),
1957                        &api,
1958                        cache2,
1959                        &mock_router(),
1960                        &block,
1961                        info,
1962                        init_msg,
1963                    )
1964                    .unwrap();
1965                assert_payout(&wasm_keeper, cache2, &contract3, &payout3);
1966
1967                // ensure first cache still doesn't see this contract
1968                assert_no_contract(read, &contract3);
1969                Ok(contract3)
1970            })
1971            .unwrap();
1972
1973            // after applying transaction, all contracts present on cache
1974            assert_payout(&wasm_keeper, cache, &contract1, &payout1);
1975            assert_payout(&wasm_keeper, cache, &contract2, &payout2);
1976            assert_payout(&wasm_keeper, cache, &contract3, &payout3);
1977
1978            // but not yet the root router
1979            assert_no_contract(wasm_reader, &contract1);
1980            assert_no_contract(wasm_reader, &contract2);
1981            assert_no_contract(wasm_reader, &contract3);
1982
1983            Ok((contract2, contract3))
1984        })
1985        .unwrap();
1986
1987        // ensure that it is now applied to the router
1988        assert_payout(&wasm_keeper, &mut wasm_storage, &contract1, &payout1);
1989        assert_payout(&wasm_keeper, &mut wasm_storage, &contract2, &payout2);
1990        assert_payout(&wasm_keeper, &mut wasm_storage, &contract3, &payout3);
1991    }
1992
1993    fn assert_admin(
1994        storage: &dyn Storage,
1995        wasm_keeper: &WasmKeeper<Empty, Empty>,
1996        contract_addr: &impl ToString,
1997        admin: Option<Addr>,
1998    ) {
1999        let api = MockApi::default();
2000        let querier: MockQuerier<Empty> = MockQuerier::new(&[]);
2001        // query
2002        let data = wasm_keeper
2003            .query(
2004                &api,
2005                storage,
2006                &querier,
2007                &mock_env().block,
2008                WasmQuery::ContractInfo {
2009                    contract_addr: contract_addr.to_string(),
2010                },
2011            )
2012            .unwrap();
2013        let res: ContractInfoResponse = from_json(data).unwrap();
2014        assert_eq!(res.admin, admin);
2015    }
2016
2017    #[test]
2018    fn update_clear_admin_works() {
2019        let api = MockApi::default();
2020        let mut wasm_keeper = wasm_keeper();
2021        let block = mock_env().block;
2022        let creator = api.addr_make("creator");
2023        let code_id = wasm_keeper.store_code(creator.clone(), caller::contract());
2024
2025        let mut wasm_storage = MockStorage::new();
2026
2027        let admin = api.addr_make("admin");
2028        let new_admin = api.addr_make("new_admin");
2029        let normal_user = api.addr_make("normal_user");
2030
2031        let contract_addr = wasm_keeper
2032            .register_contract(
2033                &api,
2034                &mut wasm_storage,
2035                code_id,
2036                creator,
2037                admin.clone(),
2038                "label".to_owned(),
2039                1000,
2040                None,
2041            )
2042            .unwrap();
2043
2044        // init the contract
2045        let info = message_info(&admin, &[]);
2046        let init_msg = to_json_vec(&Empty {}).unwrap();
2047        let res = wasm_keeper
2048            .call_instantiate(
2049                contract_addr.clone(),
2050                &api,
2051                &mut wasm_storage,
2052                &mock_router(),
2053                &block,
2054                info,
2055                init_msg,
2056            )
2057            .unwrap();
2058        assert_eq!(0, res.messages.len());
2059
2060        assert_admin(
2061            &wasm_storage,
2062            &wasm_keeper,
2063            &contract_addr,
2064            Some(admin.clone()),
2065        );
2066
2067        // non-admin should not be allowed to become admin on their own
2068        wasm_keeper
2069            .execute_wasm(
2070                &api,
2071                &mut wasm_storage,
2072                &mock_router(),
2073                &block,
2074                normal_user.clone(),
2075                WasmMsg::UpdateAdmin {
2076                    contract_addr: contract_addr.to_string(),
2077                    admin: normal_user.to_string(),
2078                },
2079            )
2080            .unwrap_err();
2081
2082        // should still be admin
2083        assert_admin(
2084            &wasm_storage,
2085            &wasm_keeper,
2086            &contract_addr,
2087            Some(admin.clone()),
2088        );
2089
2090        // admin should be allowed to transfer administration permissions
2091        let res = wasm_keeper
2092            .execute_wasm(
2093                &api,
2094                &mut wasm_storage,
2095                &mock_router(),
2096                &block,
2097                admin,
2098                WasmMsg::UpdateAdmin {
2099                    contract_addr: contract_addr.to_string(),
2100                    admin: new_admin.to_string(),
2101                },
2102            )
2103            .unwrap();
2104        assert_eq!(res.events.len(), 0);
2105
2106        // new_admin should now be admin
2107        assert_admin(
2108            &wasm_storage,
2109            &wasm_keeper,
2110            &contract_addr,
2111            Some(new_admin.clone()),
2112        );
2113
2114        // new_admin should now be able to clear to admin
2115        let res = wasm_keeper
2116            .execute_wasm(
2117                &api,
2118                &mut wasm_storage,
2119                &mock_router(),
2120                &block,
2121                new_admin,
2122                WasmMsg::ClearAdmin {
2123                    contract_addr: contract_addr.to_string(),
2124                },
2125            )
2126            .unwrap();
2127        assert_eq!(res.events.len(), 0);
2128
2129        // should have no admin now
2130        assert_admin(&wasm_storage, &wasm_keeper, &contract_addr, None);
2131    }
2132
2133    #[test]
2134    fn uses_simple_address_generator_by_default() {
2135        let api = MockApi::default();
2136        let mut wasm_keeper = wasm_keeper();
2137        let creator_addr = api.addr_make("creator");
2138        let code_id = wasm_keeper.store_code(creator_addr.clone(), payout::contract());
2139        assert_eq!(1, code_id);
2140
2141        let mut wasm_storage = MockStorage::new();
2142
2143        let admin = api.addr_make("admin");
2144        let contract_addr = wasm_keeper
2145            .register_contract(
2146                &api,
2147                &mut wasm_storage,
2148                code_id,
2149                creator_addr.clone(),
2150                admin.clone(),
2151                "label".to_owned(),
2152                1000,
2153                None,
2154            )
2155            .unwrap();
2156
2157        assert_eq!(
2158            contract_addr.as_str(),
2159            "cosmwasm1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsgn6fq2",
2160            "default address generator returned incorrect address"
2161        );
2162
2163        let salt = HexBinary::from_hex("c0ffee").unwrap();
2164
2165        let contract_addr = wasm_keeper
2166            .register_contract(
2167                &api,
2168                &mut wasm_storage,
2169                code_id,
2170                creator_addr.clone(),
2171                admin.clone(),
2172                "label".to_owned(),
2173                1000,
2174                Binary::from(salt.clone()),
2175            )
2176            .unwrap();
2177
2178        assert_eq!(
2179            contract_addr.as_str(),
2180            "cosmwasm1drhu6t78wacgm5qjzs4hvkv9fd9awa9henw7fh6vmzrhf7k2nkjsg3flns",
2181            "default address generator returned incorrect address"
2182        );
2183
2184        let code_id = wasm_keeper.store_code(creator_addr, payout::contract());
2185        assert_eq!(2, code_id);
2186
2187        let user_addr = api.addr_make("boobaz");
2188
2189        let contract_addr = wasm_keeper
2190            .register_contract(
2191                &api,
2192                &mut wasm_storage,
2193                code_id,
2194                user_addr,
2195                admin,
2196                "label".to_owned(),
2197                1000,
2198                Binary::from(salt),
2199            )
2200            .unwrap();
2201
2202        assert_eq!(
2203            contract_addr.as_str(),
2204            "cosmwasm13cfeertf2gny0rzp5jwqzst8crmfgvcd2lq5su0c9z66yxa45qdsdd0uxc",
2205            "default address generator returned incorrect address"
2206        );
2207    }
2208
2209    struct TestAddressGenerator {
2210        address: Addr,
2211        predictable_address: Addr,
2212    }
2213
2214    impl AddressGenerator for TestAddressGenerator {
2215        fn contract_address(
2216            &self,
2217            _api: &dyn Api,
2218            _storage: &mut dyn Storage,
2219            _code_id: u64,
2220            _instance_id: u64,
2221        ) -> StdResult<Addr> {
2222            Ok(self.address.clone())
2223        }
2224
2225        fn predictable_contract_address(
2226            &self,
2227            _api: &dyn Api,
2228            _storage: &mut dyn Storage,
2229            _code_id: u64,
2230            _instance_id: u64,
2231            _checksum: &[u8],
2232            _creator: &CanonicalAddr,
2233            _salt: &[u8],
2234        ) -> StdResult<Addr> {
2235            Ok(self.predictable_address.clone())
2236        }
2237    }
2238
2239    #[test]
2240    fn can_use_custom_address_generator() {
2241        let api = MockApi::default();
2242        let expected_addr = api.addr_make("address");
2243        let expected_predictable_addr = api.addr_make("predictable_address");
2244        let mut wasm_keeper: WasmKeeper<Empty, Empty> =
2245            WasmKeeper::new().with_address_generator(TestAddressGenerator {
2246                address: expected_addr.clone(),
2247                predictable_address: expected_predictable_addr.clone(),
2248            });
2249        let creator = api.addr_make("creator");
2250        let code_id = wasm_keeper.store_code(creator.clone(), payout::contract());
2251
2252        let mut wasm_storage = MockStorage::new();
2253
2254        let admin = api.addr_make("admin");
2255        let contract_addr = wasm_keeper
2256            .register_contract(
2257                &api,
2258                &mut wasm_storage,
2259                code_id,
2260                creator.clone(),
2261                admin.clone(),
2262                "label".to_owned(),
2263                1000,
2264                None,
2265            )
2266            .unwrap();
2267
2268        assert_eq!(
2269            contract_addr, expected_addr,
2270            "custom address generator returned incorrect address"
2271        );
2272
2273        let contract_addr = wasm_keeper
2274            .register_contract(
2275                &api,
2276                &mut wasm_storage,
2277                code_id,
2278                creator,
2279                admin,
2280                "label".to_owned(),
2281                1000,
2282                Binary::from(HexBinary::from_hex("23A74B8C").unwrap()),
2283            )
2284            .unwrap();
2285
2286        assert_eq!(
2287            contract_addr, expected_predictable_addr,
2288            "custom address generator returned incorrect address"
2289        );
2290    }
2291}