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