1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//! # Implementation of address conversions and generators

use crate::error::AnyResult;
use crate::{MockApiBech32, MockApiBech32m};
use cosmwasm_std::testing::MockApi;
use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage};
use sha2::digest::Update;
use sha2::{Digest, Sha256};

const DEFAULT_PREFIX: &str = "cosmwasm";

/// Defines conversions to [Addr], this conversion is format agnostic
/// and should be aligned with the format generated by [MockApi].
///
/// [MockApi]: https://github.com/CosmWasm/cosmwasm/blob/9a239838baba50f4f47230da306f39a8bb4ea697/packages/std/src/testing/mock.rs#L251-L257
pub trait IntoAddr {
    /// Converts into [Addr].
    fn into_addr(self) -> Addr;

    /// Converts into [Addr] with custom prefix.
    fn into_addr_with_prefix(self, prefix: &'static str) -> Addr;
}

impl IntoAddr for &str {
    /// Converts [&str] into [Addr].
    fn into_addr(self) -> Addr {
        MockApi::default().addr_make(self)
    }

    /// Converts [&str] into [Addr] with custom prefix.
    fn into_addr_with_prefix(self, prefix: &'static str) -> Addr {
        MockApi::default().with_prefix(prefix).addr_make(self)
    }
}

/// Defines conversions to `Bech32` compatible addresses.
pub trait IntoBech32 {
    /// Converts into [Addr] containing a string compatible with `Bech32` format with default prefix.
    fn into_bech32(self) -> Addr;

    /// Converts into [Addr] containing a string compatible with `Bech32` format with custom prefix.
    fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr;
}

impl IntoBech32 for &str {
    /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with default prefix.
    fn into_bech32(self) -> Addr {
        MockApiBech32::new(DEFAULT_PREFIX).addr_make(self)
    }

    /// Converts [&str] into [Addr] containing a string compatible with `Bech32` format with custom prefix.
    fn into_bech32_with_prefix(self, prefix: &'static str) -> Addr {
        MockApiBech32::new(prefix).addr_make(self)
    }
}

/// Defines conversions to `Bech32m` compatible addresses.
pub trait IntoBech32m {
    /// Converts into [Addr] containing a string compatible with `Bech32m` format with default prefix.
    fn into_bech32m(self) -> Addr;
    /// Converts into [Addr] containing a string compatible with `Bech32m` format with custom prefix.
    fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr;
}

impl IntoBech32m for &str {
    /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with default prefix.
    fn into_bech32m(self) -> Addr {
        MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self)
    }

    /// Converts [&str] into [Addr] containing a string compatible with `Bech32m` format with custom prefix.
    fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr {
        MockApiBech32m::new(prefix).addr_make(self)
    }
}

/// Common address generator interface.
///
/// The default implementation of this trait generates fully predictable
/// addresses, no matter if [contract_address](AddressGenerator::contract_address)
/// or [predictable_contract_address](AddressGenerator::predictable_contract_address) is used,
/// but users should not make any assumptions about the value of the generated address.
pub trait AddressGenerator {
    /// Generates a _non-predictable_ contract address, just like the real-life chain
    /// returns contract address after its instantiation.
    /// Address generated by this function is returned as a result of processing
    /// `WasmMsg::Instantiate` message.
    ///
    /// The default implementation generates a contract address based
    /// on contract's code and instance identifier.
    ///
    /// # Example
    ///
    /// ```
    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
    /// # let api = MockApi::default();
    /// # let mut storage = MockStorage::default();
    /// struct MyAddressGenerator;
    ///
    /// impl AddressGenerator for MyAddressGenerator {}
    ///
    /// let my_address_generator = MyAddressGenerator{};
    ///
    /// let addr = my_address_generator.contract_address(&api, &mut storage, 100, 1).unwrap();
    /// assert!(addr.as_str().starts_with("cosmwasm1"));
    /// ```
    fn contract_address(
        &self,
        api: &dyn Api,
        _storage: &mut dyn Storage,
        code_id: u64,
        instance_id: u64,
    ) -> AnyResult<Addr> {
        let canonical_addr = instantiate_address(code_id, instance_id);
        Ok(api.addr_humanize(&canonical_addr)?)
    }

    /// Generates a _predictable_ contract address, just like the real-life chain
    /// returns contract address after its instantiation using `MsgInstantiateContract2` message.
    /// Address generated by this function is returned as a result of processing
    /// `WasmMsg::Instantiate2` message.
    ///
    /// The default implementation generates a contract address based on provided
    /// creator address and salt.
    ///
    /// # Example
    ///
    /// ```
    /// # use cosmwasm_std::{Api, Checksum};
    /// # use cosmwasm_std::testing::{MockApi, MockStorage};
    /// # use cw_multi_test::{AddressGenerator, SimpleAddressGenerator};
    /// # let api = MockApi::default();
    /// # let mut storage = MockStorage::default();
    /// struct MyAddressGenerator;
    ///
    /// impl AddressGenerator for MyAddressGenerator {}
    ///
    /// let my_address_generator = MyAddressGenerator{};
    ///
    /// let creator1 = api.addr_canonicalize(&api.addr_make("creator1").to_string()).unwrap();
    /// let creator2 = api.addr_canonicalize(&api.addr_make("creator2").to_string()).unwrap();
    /// let salt1 = [0xc0,0xff,0xee];
    /// let salt2 = [0xbe,0xef];
    /// let chs = Checksum::generate(&[1]);
    ///
    /// let addr11 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt1).unwrap();
    /// let addr12 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator1, &salt2).unwrap();
    /// let addr21 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt1).unwrap();
    /// let addr22 = my_address_generator.predictable_contract_address(&api, &mut storage, 1, 0, chs.as_slice(), &creator2, &salt2).unwrap();
    ///
    /// assert_ne!(addr11, addr12);
    /// assert_ne!(addr11, addr21);
    /// assert_ne!(addr11, addr22);
    /// assert_ne!(addr12, addr21);
    /// assert_ne!(addr12, addr22);
    /// assert_ne!(addr21, addr22);
    /// ```
    fn predictable_contract_address(
        &self,
        api: &dyn Api,
        _storage: &mut dyn Storage,
        _code_id: u64,
        _instance_id: u64,
        checksum: &[u8],
        creator: &CanonicalAddr,
        salt: &[u8],
    ) -> AnyResult<Addr> {
        let canonical_addr = instantiate2_address(checksum, creator, salt)?;
        Ok(api.addr_humanize(&canonical_addr)?)
    }
}

/// Returns non-predictable contract address.
///
/// Address is generated using the same algorithm as [`BuildContractAddressClassic`]
/// implementation in `wasmd`.
///
/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
fn instantiate_address(code_id: u64, instance_id: u64) -> CanonicalAddr {
    let mut key = Vec::<u8>::new();
    key.extend_from_slice(b"wasm\0");
    key.extend_from_slice(&code_id.to_be_bytes());
    key.extend_from_slice(&instance_id.to_be_bytes());
    let module = Sha256::digest("module".as_bytes());
    Sha256::new()
        .chain(module)
        .chain(key)
        .finalize()
        .to_vec()
        .into()
}

/// Default contract address generator used in [WasmKeeper](crate::WasmKeeper).
pub struct SimpleAddressGenerator;

impl AddressGenerator for SimpleAddressGenerator {}