apollo_cw_multi_test/
addresses.rs

1//! # Implementation of address conversions and generators
2
3use anyhow::Result as AnyResult;
4use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, HexBinary, Storage};
5use sha2::digest::Update;
6use sha2::{Digest, Sha256};
7
8/// Common address generator interface.
9///
10/// The default implementation of this trait generates fully predictable
11/// addresses, no matter if [contract_address](AddressGenerator::contract_address)
12/// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used,
13/// but users should not make any assumptions about the value of the generated address.
14pub trait AddressGenerator {
15    /// Generates a _non-predictable_ contract address, just like the real-life chain
16    /// returns contract address after its instantiation.
17    /// Address generated by this function is returned as a result of processing
18    /// `WasmMsg::Instantiate` message.
19    ///
20    /// The default implementation generates a contract address based
21    /// on contract's instance identifier only.
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
27    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
28    /// # let api = MockApi::default();
29    /// # let mut storage = MockStorage::default();
30    /// struct MyAddressGenerator;
31    ///
32    /// impl AddressGenerator for MyAddressGenerator {}
33    ///
34    /// let my_address_generator = MyAddressGenerator{};
35    ///
36    /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 0).unwrap();
37    /// assert_eq!(addr.as_str(), "contract0");
38    ///
39    /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap();
40    /// assert_eq!(addr.as_str(), "contract1");
41    ///
42    /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 5).unwrap();
43    /// assert_eq!(addr.as_str(), "contract5");
44    ///
45    /// let addr = my_address_generator.contract_address(&api, &mut storage, 200, 6).unwrap();
46    /// assert_eq!(addr.as_str(), "contract6");
47    /// ```
48    fn contract_address(
49        &self,
50        _api: &dyn Api,
51        _storage: &mut dyn Storage,
52        _code_id: u64,
53        instance_id: u64,
54    ) -> AnyResult<Addr> {
55        Ok(Addr::unchecked(format!("contract{instance_id}")))
56    }
57
58    /// Generates a _predictable_ contract address, just like the real-life chain
59    /// returns contract address after its instantiation using `MsgInstantiateContract2` message.
60    /// Address generated by this function is returned as a result of processing
61    /// `WasmMsg::Instantiate2` message.
62    ///
63    /// The default implementation generates a contract address based on provided
64    /// creator address and salt.
65    ///
66    /// # Example
67    ///
68    /// ```
69    /// # use cosmwasm_std::Api;
70    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
71    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
72    /// # let api = MockApi::default();
73    /// # let mut storage = MockStorage::default();
74    /// struct MyAddressGenerator;
75    ///
76    /// impl AddressGenerator for MyAddressGenerator {}
77    ///
78    /// let my_address_generator = MyAddressGenerator{};
79    ///
80    /// let creator1 = api.addr_canonicalize("creator1").unwrap();
81    /// let creator2 = api.addr_canonicalize("creator2").unwrap();
82    /// let salt1 = [0xc0,0xff,0xee];
83    /// let salt2 = [0xbe,0xef];
84    ///
85    /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt1).unwrap();
86    /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator1, &salt2).unwrap();
87    /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt1).unwrap();
88    /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, &[1], &creator2, &salt2).unwrap();
89    ///
90    /// assert_ne!(addr11, addr12);
91    /// assert_ne!(addr11, addr21);
92    /// assert_ne!(addr11, addr22);
93    /// assert_ne!(addr12, addr21);
94    /// assert_ne!(addr12, addr22);
95    /// assert_ne!(addr21, addr22);
96    /// ```
97    fn predictable_contract_address(
98        &self,
99        _api: &dyn Api,
100        _storage: &mut dyn Storage,
101        _code_id: u64,
102        _instance_id: u64,
103        _checksum: &[u8],
104        creator: &CanonicalAddr,
105        salt: &[u8],
106    ) -> AnyResult<Addr> {
107        Ok(Addr::unchecked(format!(
108            "contract{creator}{}",
109            HexBinary::from(salt).to_hex()
110        )))
111    }
112}
113
114/// Default contract address generator used in [WasmKeeper](crate::WasmKeeper).
115pub struct SimpleAddressGenerator;
116
117impl AddressGenerator for SimpleAddressGenerator {}
118
119/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/wasmd) behavior.
120///
121/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of
122/// [`contract_address`](AddressGenerator::contract_address) and
123/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions:
124/// - `contract_address` generates non-predictable addresses for contracts,
125///   using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details.
126/// - `predictable_contract_address` generates predictable addresses for contracts using
127///   [`instantiate2_address`] function defined in `cosmwasm-std`.
128///
129/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
130/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318
131#[derive(Default)]
132pub struct MockAddressGenerator;
133
134impl AddressGenerator for MockAddressGenerator {
135    /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain.
136    ///
137    /// Note that addresses generated by `wasmd` may change and users **should not**
138    /// rely on this value in any extend.
139    ///
140    /// Returns the contract address after its instantiation.
141    /// Address generated by this function is returned as a result
142    /// of processing `WasmMsg::Instantiate` message.
143    ///
144    /// **NOTES**
145    /// > 👉 The canonical address generated by this function is humanized using the
146    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
147    /// > The following example uses Bech32 format for humanizing canonical addresses.
148    ///
149    /// > 👉 Do NOT use this function **directly** to generate a contract address,
150    /// > pass this address generator to `WasmKeeper`:
151    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
152    ///
153    /// # Example
154    ///
155    /// ```
156    /// # use cosmwasm_std::testing::MockStorage;
157    /// # use cw_multi_test::AddressGenerator;
158    /// # use cw_multi_test::{MockAddressGenerator, MockApiBech32};
159    /// // use `Api` that implements Bech32 format
160    /// let api = MockApiBech32::new("juno");
161    /// // prepare mock storage
162    /// let mut storage = MockStorage::default();
163    /// // initialize the address generator
164    /// let address_generator = MockAddressGenerator::default();
165    /// // generate the address
166    /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap();
167    ///
168    /// assert_eq!(addr.to_string(),
169    ///            "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8");
170    /// ```
171    fn contract_address(
172        &self,
173        api: &dyn Api,
174        _storage: &mut dyn Storage,
175        code_id: u64,
176        instance_id: u64,
177    ) -> AnyResult<Addr> {
178        let canonical_addr = instantiate_address(code_id, instance_id);
179        Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?))
180    }
181
182    /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain.
183    ///
184    /// Returns a contract address after its instantiation.
185    /// Address generated by this function is returned as a result
186    /// of processing `WasmMsg::Instantiate2` message.
187    ///
188    /// **NOTES**
189    /// > 👉 The canonical address generated by this function is humanized using the
190    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
191    /// > The following example uses Bech32 format for humanizing canonical addresses.
192    ///
193    /// > 👉 Do NOT use this function **directly** to generate a contract address,
194    /// > pass this address generator to WasmKeeper:
195    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
196    ///
197    /// # Example
198    ///
199    /// ```
200    /// # use cosmwasm_std::Api;
201    /// # use cosmwasm_std::testing::MockStorage;
202    /// # use cw_multi_test::AddressGenerator;
203    /// # use cw_multi_test::{MockAddressGenerator, MockApiBech32};
204    /// // use `Api` that implements Bech32 format
205    /// let api = MockApiBech32::new("juno");
206    /// // prepare mock storage
207    /// let mut storage = MockStorage::default();
208    /// // initialize the address generator
209    /// let address_generator = MockAddressGenerator::default();
210    /// // checksum of the contract code base
211    /// let checksum = [0, 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,
212    ///                 11,12,13,14,15,16,17,18,19,20,21,
213    ///                 22,23,24,25,26,27,28,29,30,31];
214    /// // creator address
215    /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap();
216    /// // salt
217    /// let salt = [10,11,12];
218    /// // generate the address
219    /// let addr = address_generator
220    ///     .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt)
221    ///     .unwrap();
222    ///
223    /// assert_eq!(addr.to_string(),
224    ///            "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud");
225    /// ```
226    fn predictable_contract_address(
227        &self,
228        api: &dyn Api,
229        _storage: &mut dyn Storage,
230        _code_id: u64,
231        _instance_id: u64,
232        checksum: &[u8],
233
234        creator: &CanonicalAddr,
235        salt: &[u8],
236    ) -> AnyResult<Addr> {
237        let canonical_addr = instantiate2_address(checksum, creator, salt)?;
238        Ok(Addr::unchecked(api.addr_humanize(&canonical_addr)?))
239    }
240}
241
242/// Returns non-predictable contract address.
243///
244/// Address is generated using the same algorithm as [`BuildContractAddressClassic`]
245/// implementation in `wasmd`.
246///
247/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
248fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr {
249    let mut key = Vec::<u8>::new();
250    key.extend_from_slice(b"wasm\0");
251    key.extend_from_slice(&code_id.to_be_bytes());
252    key.extend_from_slice(&instance_id.to_be_bytes());
253    let module = Sha256::digest("module".as_bytes());
254    Sha256::new()
255        .chain(module)
256        .chain(key)
257        .finalize()
258        .to_vec()
259        .into()
260}