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