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}