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()
}