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 {}