clone_cw_multi_test/addons/addresses/
mock.rs

1use crate::error::AnyResult;
2use crate::AddressGenerator;
3use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage};
4use sha2::digest::Update;
5use sha2::{Digest, Sha256};
6
7/// Address generator that mimics the original `wasmd` behavior.
8///
9/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of
10/// [`contract_address`](AddressGenerator::contract_address) and
11/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions:
12/// - `contract_address` generates non-predictable addresses for contracts,
13///   using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details.
14/// - `predictable_contract_address` generates predictable addresses for contracts using
15///   [`instantiate2_address`] function defined in `cosmwasm-std`.
16///
17/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
18/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318
19#[derive(Default)]
20pub struct MockAddressGenerator;
21
22impl AddressGenerator for MockAddressGenerator {
23    /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain.
24    ///
25    /// Note that addresses generated by `wasmd` may change and users **should not**
26    /// rely on this value in any extend.
27    ///
28    /// Returns the contract address after its instantiation.
29    /// Address generated by this function is returned as a result
30    /// of processing `WasmMsg::Instantiate` message.
31    ///
32    /// **NOTES**
33    /// > 👉 The canonical address generated by this function is humanized using the
34    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
35    /// > The following example uses Bech32 format for humanizing canonical addresses.
36    ///
37    /// > 👉 Do NOT use this function **directly** to generate a contract address,
38    /// > pass this address generator to `WasmKeeper`:
39    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
40    ///
41    /// # Example
42    ///
43    /// ```
44    /// # use cosmwasm_std::testing::MockStorage;
45    /// # use cw_multi_test::AddressGenerator;
46    /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
47    /// // use `Api` that implements Bech32 format
48    /// let api = MockApiBech32::new("juno");
49    /// // prepare mock storage
50    /// let mut storage = MockStorage::default();
51    /// // initialize the address generator
52    /// let address_generator = MockAddressGenerator::default();
53    /// // generate the address
54    /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap();
55    ///
56    /// assert_eq!(addr.to_string(),
57    ///            "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8");
58    /// ```
59    fn contract_address(
60        &self,
61        api: &dyn Api,
62        _storage: &mut dyn Storage,
63        code_id: u64,
64        instance_id: u64,
65    ) -> AnyResult<Addr> {
66        let canonical_addr = instantiate_address(code_id, instance_id);
67        Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?))
68    }
69
70    /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain.
71    ///
72    /// Returns a contract address after its instantiation.
73    /// Address generated by this function is returned as a result
74    /// of processing `WasmMsg::Instantiate2` message.
75    ///
76    /// **NOTES**
77    /// > 👉 The canonical address generated by this function is humanized using the
78    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
79    /// > The following example uses Bech32 format for humanizing canonical addresses.
80    ///
81    /// > 👉 Do NOT use this function **directly** to generate a contract address,
82    /// > pass this address generator to WasmKeeper:
83    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
84    ///
85    /// # Example
86    ///
87    /// ```
88    /// # use cosmwasm_std::Api;
89    /// # use cosmwasm_std::testing::MockStorage;
90    /// # use cw_multi_test::AddressGenerator;
91    /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
92    /// // use `Api` that implements Bech32 format
93    /// let api = MockApiBech32::new("juno");
94    /// // prepare mock storage
95    /// let mut storage = MockStorage::default();
96    /// // initialize the address generator
97    /// let address_generator = MockAddressGenerator::default();
98    /// // checksum of the contract code base
99    /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,
100    ///                 11,12,13,14,15,16,17,18,19,20,21,
101    ///                 22,23,24,25,26,27,28,29,30,31];
102    /// // creator address
103    /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap();
104    /// // salt
105    /// let salt = [10,11,12];
106    /// // generate the address
107    /// let addr = address_generator
108    ///     .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt)
109    ///     .unwrap();
110    ///
111    /// assert_eq!(addr.to_string(),
112    ///            "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud");
113    /// ```
114    fn predictable_contract_address(
115        &self,
116        api: &dyn Api,
117        _storage: &mut dyn Storage,
118        _code_id: u64,
119        _instance_id: u64,
120        checksum: &[u8],
121
122        creator: &CanonicalAddr,
123        salt: &[u8],
124    ) -> AnyResult<Addr> {
125        let canonical_addr = instantiate2_address(checksum, creator, salt)?;
126        Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?))
127    }
128}
129
130/// Returns non-predictable contract address.
131///
132/// Address is generated using the same algorithm as [`BuildContractAddressClassic`]
133/// implementation in `wasmd`.
134///
135/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
136fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr {
137    let mut key = Vec::<u8>::new();
138    key.extend_from_slice(b"wasm\0");
139    key.extend_from_slice(&code_id.to_be_bytes());
140    key.extend_from_slice(&instance_id.to_be_bytes());
141    let module = Sha256::digest("module".as_bytes());
142    Sha256::new()
143        .chain(module)
144        .chain(key)
145        .finalize()
146        .to_vec()
147        .into()
148}