cw_multi_test/
addresses.rs

1//! # Implementation of address conversions and generators
2
3use crate::{MockApiBech32, MockApiBech32m};
4use cosmwasm_std::testing::MockApi;
5use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, StdResult, Storage};
6use sha2::digest::Update;
7use sha2::{Digest, Sha256};
8
9const DEFAULT_PREFIX: &str = "cosmwasm";
10
11/// Defines conversions to [Addr], this conversion is format agnostic
12/// and should be aligned with the format generated by [MockApi].
13///
14/// [MockApi]: https://github.com/CosmWasm/cosmwasm/blob/9a239838baba50f4f47230da306f39a8bb4ea697/packages/std/src/testing/mock.rs#L251-L257
15pub trait IntoAddr {
16    /// Converts into [Addr].
17    fn into_addr(self) -> Addr;
18
19    /// Converts into [Addr] with custom prefix.
20    fn into_addr_with_prefix(self, prefix: &'static str) -> Addr;
21}
22
23impl IntoAddr for &str {
24    /// Converts [&str] into [Addr].
25    fn into_addr(self) -> Addr {
26        MockApi::default().addr_make(self)
27    }
28
29    /// Converts [&str] into [Addr] with custom prefix.
30    fn into_addr_with_prefix(self, prefix: &'static str) -> Addr {
31        MockApi::default().with_prefix(prefix).addr_make(self)
32    }
33}
34
35/// Defines conversions to `Bech32` compatible addresses.
36pub trait IntoBech32 {
37    /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix.
38    fn into_bech32(self) -> Addr;
39
40    /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix.
41    fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr;
42}
43
44impl IntoBech32 for &str {
45    /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with default prefix.
46    fn into_bech32(self) -> Addr {
47        MockApiBech32::new(DEFAULT_PREFIX).addr_make(self)
48    }
49
50    /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with custom prefix.
51    fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr {
52        MockApiBech32::new(prefix).addr_make(self)
53    }
54}
55
56/// Defines conversions to `Bech32m` compatible addresses.
57pub trait IntoBech32m {
58    /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix.
59    fn into_bech32m(self) -> Addr;
60    /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix.
61    fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr;
62}
63
64impl IntoBech32m for &str {
65    /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with default prefix.
66    fn into_bech32m(self) -> Addr {
67        MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self)
68    }
69
70    /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with custom prefix.
71    fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr {
72        MockApiBech32m::new(prefix).addr_make(self)
73    }
74}
75
76/// Common address generator interface.
77///
78/// The default implementation of this trait generates fully predictable
79/// addresses, no matter if [contract_address](AddressGenerator::contract_address)
80/// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used,
81/// but users should not make any assumptions about the value of the generated address.
82pub trait AddressGenerator {
83    /// Generates a _non-predictable_ contract address, just like the real-life chain
84    /// returns contract address after its instantiation.
85    /// Address generated by this function is returned as a result of processing
86    /// `WasmMsg::Instantiate` message.
87    ///
88    /// The default implementation generates a contract address based
89    /// on contract's code and instance identifier.
90    ///
91    /// # Example
92    ///
93    /// ```
94    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
95    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
96    /// # let api = MockApi::default();
97    /// # let mut storage = MockStorage::default();
98    /// struct MyAddressGenerator;
99    ///
100    /// impl AddressGenerator for MyAddressGenerator {}
101    ///
102    /// let my_address_generator = MyAddressGenerator{};
103    ///
104    /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap();
105    /// assert!(addr.as_str().starts_with("cosmwasm1"));
106    /// ```
107    fn contract_address(
108        &self,
109        api: &dyn Api,
110        _storage: &mut dyn Storage,
111        code_id: u64,
112        instance_id: u64,
113    ) -> StdResult<Addr> {
114        let canonical_addr = instantiate_address(code_id, instance_id);
115        api.addr_humanize(&canonical_addr)
116    }
117
118    /// Generates a _predictable_ contract address, just like the real-life chain
119    /// returns contract address after its instantiation using `MsgInstantiateContract2` message.
120    /// Address generated by this function is returned as a result of processing
121    /// `WasmMsg::Instantiate2` message.
122    ///
123    /// The default implementation generates a contract address based on provided
124    /// creator address and salt.
125    ///
126    /// # Example
127    ///
128    /// ```
129    /// # use cosmwasm_std::{Api, Checksum};
130    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
131    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
132    /// # let api = MockApi::default();
133    /// # let mut storage = MockStorage::default();
134    /// struct MyAddressGenerator;
135    ///
136    /// impl AddressGenerator for MyAddressGenerator {}
137    ///
138    /// let my_address_generator = MyAddressGenerator{};
139    ///
140    /// let creator1 = api.addr_canonicalize(&api.addr_make("creator1").to_string()).unwrap();
141    /// let creator2 = api.addr_canonicalize(&api.addr_make("creator2").to_string()).unwrap();
142    /// let salt1 = [0xc0,0xff,0xee];
143    /// let salt2 = [0xbe,0xef];
144    /// let chs = Checksum::generate(&[1]);
145    ///
146    /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt1).unwrap();
147    /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt2).unwrap();
148    /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt1).unwrap();
149    /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt2).unwrap();
150    ///
151    /// assert_ne!(addr11, addr12);
152    /// assert_ne!(addr11, addr21);
153    /// assert_ne!(addr11, addr22);
154    /// assert_ne!(addr12, addr21);
155    /// assert_ne!(addr12, addr22);
156    /// assert_ne!(addr21, addr22);
157    /// ```
158    fn predictable_contract_address(
159        &self,
160        api: &dyn Api,
161        _storage: &mut dyn Storage,
162        _code_id: u64,
163        _instance_id: u64,
164        checksum: &[u8],
165        creator: &CanonicalAddr,
166        salt: &[u8],
167    ) -> StdResult<Addr> {
168        let canonical_addr = instantiate2_address(checksum, creator, salt)?;
169        api.addr_humanize(&canonical_addr)
170    }
171}
172
173/// Returns non-predictable contract address.
174///
175/// Address is generated using the same algorithm as [`BuildContractAddressClassic`]
176/// implementation in `wasmd`.
177///
178/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
179fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr {
180    let mut key = Vec::<u8>::new();
181    key.extend_from_slice(b"wasm\0");
182    key.extend_from_slice(&code_id.to_be_bytes());
183    key.extend_from_slice(&instance_id.to_be_bytes());
184    let module = Sha256::digest("module".as_bytes());
185    Sha256::new()
186        .chain(module)
187        .chain(key)
188        .finalize()
189        .to_vec()
190        .into()
191}
192
193/// Default contract address generator used in [WasmKeeper](crate::WasmKeeper).
194pub struct SimpleAddressGenerator;
195
196impl AddressGenerator for SimpleAddressGenerator {}