cw_multi_test/
addresses.rs

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