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
use crate::error::AnyResult;
use crate::AddressGenerator;
use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, Storage};
use sha2::digest::Update;
use sha2::{Digest, Sha256};

/// Address generator that mimics the original `wasmd` behavior.
///
/// [MockAddressGenerator] implements [AddressGenerator] trait in terms of
/// [`contract_address`](AddressGenerator::contract_address) and
/// [`predictable_contract_address`](AddressGenerator::predictable_contract_address) functions:
/// - `contract_address` generates non-predictable addresses for contracts,
///   using the same algorithm as `wasmd`, see: [`BuildContractAddressClassic`] for details.
/// - `predictable_contract_address` generates predictable addresses for contracts using
///   [`instantiate2_address`] function defined in `cosmwasm-std`.
///
/// [`BuildContractAddressClassic`]:https://github.com/CosmWasm/wasmd/blob/3b6512c9f154995188ead84ab3bd9e034b49a0f3/x/wasm/keeper/addresses.go#L35-L41
/// [`instantiate2_address`]:https://github.com/CosmWasm/cosmwasm/blob/8a652d7cd8071f71139deca6be8194ed4a278b2c/packages/std/src/addresses.rs#L309-L318
#[derive(Default)]
pub struct MockAddressGenerator;

impl AddressGenerator for MockAddressGenerator {
    /// Generates a _non-predictable_ contract address, like `wasmd` does it in real-life chain.
    ///
    /// Note that addresses generated by `wasmd` may change and users **should not**
    /// rely on this value in any extend.
    ///
    /// Returns the contract address after its instantiation.
    /// Address generated by this function is returned as a result
    /// of processing `WasmMsg::Instantiate` message.
    ///
    /// **NOTES**
    /// > 👉 The canonical address generated by this function is humanized using the
    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
    /// > The following example uses Bech32 format for humanizing canonical addresses.
    ///
    /// > 👉 Do NOT use this function **directly** to generate a contract address,
    /// > pass this address generator to `WasmKeeper`:
    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
    ///
    /// # Example
    ///
    /// ```
    /// # use cosmwasm_std::testing::MockStorage;
    /// # use cw_multi_test::AddressGenerator;
    /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
    /// // use `Api` that implements Bech32 format
    /// let api = MockApiBech32::new("juno");
    /// // prepare mock storage
    /// let mut storage = MockStorage::default();
    /// // initialize the address generator
    /// let address_generator = MockAddressGenerator::default();
    /// // generate the address
    /// let addr = address_generator.contract_address(&api, &mut storage, 1, 1).unwrap();
    ///
    /// assert_eq!(addr.to_string(),
    ///            "juno14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9skjuwg8");
    /// ```
    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(Addr::unchecked(api.addr_humanize(&canonical_addr)?))
    }

    /// Generates a _predictable_ contract address, like `wasmd` does it in real-life chain.
    ///
    /// Returns a contract address after its instantiation.
    /// Address generated by this function is returned as a result
    /// of processing `WasmMsg::Instantiate2` message.
    ///
    /// **NOTES**
    /// > 👉 The canonical address generated by this function is humanized using the
    /// > `Api::addr_humanize` function, so the resulting value depends on used `Api` implementation.
    /// > The following example uses Bech32 format for humanizing canonical addresses.
    ///
    /// > 👉 Do NOT use this function **directly** to generate a contract address,
    /// > pass this address generator to WasmKeeper:
    /// > `WasmKeeper::new().with_address_generator(MockAddressGenerator::default());`
    ///
    /// # Example
    ///
    /// ```
    /// # use cosmwasm_std::Api;
    /// # use cosmwasm_std::testing::MockStorage;
    /// # use cw_multi_test::AddressGenerator;
    /// # use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
    /// // use `Api` that implements Bech32 format
    /// let api = MockApiBech32::new("juno");
    /// // prepare mock storage
    /// let mut storage = MockStorage::default();
    /// // initialize the address generator
    /// let address_generator = MockAddressGenerator::default();
    /// // checksum of the contract code base
    /// let checksum = [0, 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];
    /// // creator address
    /// let creator = api.addr_canonicalize(api.addr_make("creator").as_str()).unwrap();
    /// // salt
    /// let salt = [10,11,12];
    /// // generate the address
    /// let addr = address_generator
    ///     .predictable_contract_address(&api, &mut storage, 1, 1, &checksum, &creator, &salt)
    ///     .unwrap();
    ///
    /// assert_eq!(addr.to_string(),
    ///            "juno1sv3gjp85m3xxluxreruards8ruxk5ykys8qfljwrdj5tv8kqxuhsmlfyud");
    /// ```
    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(Addr::unchecked(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()
}