Repository: CosmWasm/cw-multi-test
Pull request #138 (2024-03-08 14:30:30)

Added IntoAddr trait
Added `IntoAddr` trait and refactored addresses.


Patch:
diff --git a/src/addons/addresses/mock.rs b/src/addons/addresses/mock.rs
deleted file mode 100644
index ab166f9..0000000
--- a/src/addons/addresses/mock.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-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 [wasmd](https://github.com/CosmWasm/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()
-}
diff --git a/src/addons/addresses/mod.rs b/src/addons/addresses/mod.rs
deleted file mode 100644
index 9afc1d5..0000000
--- a/src/addons/addresses/mod.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-pub mod mock;
diff --git a/src/addons/api/b32.rs b/src/addons/api/b32.rs
deleted file mode 100644
index 0837567..0000000
--- a/src/addons/api/b32.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use crate::addons::api::MockApiBech;
-use bech32::Bech32;
-use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError};
-
-/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format
-/// for humanizing canonical addresses.
-///
-/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
-pub struct MockApiBech32(MockApiBech<Bech32>);
-
-impl MockApiBech32 {
-    /// Returns `Api` implementation that uses specified prefix
-    /// to generate addresses in `Bech32` format.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("juno");
-    /// let addr = api.addr_make("creator");
-    /// assert_eq!(addr.as_str(),
-    ///            "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp");
-    /// ```
-    pub fn new(prefix: &'static str) -> Self {
-        Self(MockApiBech::new(prefix))
-    }
-}
-
-impl Api for MockApiBech32 {
-    /// Takes a human-readable address in `Bech32` format and checks if it is valid.
-    ///
-    /// If the validation succeeds, an `Addr` containing the same string as the input is returned.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("juno");
-    /// let addr = api.addr_make("creator");
-    /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(),
-    ///            addr.as_str());
-    /// ```
-    fn addr_validate(&self, input: &str) -> StdResult<Addr> {
-        self.0.addr_humanize(&self.addr_canonicalize(input)?)
-    }
-
-    /// Takes a human-readable address in `Bech32` format and returns
-    /// a canonical binary representation of it.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("juno");
-    /// let addr = api.addr_make("creator");
-    /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(),
-    ///            "BC6BFD848EBD7819C9A82BF124D65E7F739D08E002601E23BB906AACD40A3D81");
-    /// ```
-    fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
-        self.0.addr_canonicalize(input)
-    }
-
-    /// Takes a canonical address and returns a human-readable address in `Bech32` format.
-    ///
-    /// This is the inverse operation of [`addr_canonicalize`].
-    ///
-    /// [`addr_canonicalize`]: MockApiBech32::addr_canonicalize
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("juno");
-    /// let addr = api.addr_make("creator");
-    /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap();
-    /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(),
-    ///            addr.as_str());
-    /// ```
-    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
-        self.0.addr_humanize(canonical)
-    }
-
-    fn secp256k1_verify(
-        &self,
-        message_hash: &[u8],
-        signature: &[u8],
-        public_key: &[u8],
-    ) -> Result<bool, VerificationError> {
-        self.0.secp256k1_verify(message_hash, signature, public_key)
-    }
-
-    fn secp256k1_recover_pubkey(
-        &self,
-        message_hash: &[u8],
-        signature: &[u8],
-        recovery_param: u8,
-    ) -> Result<Vec<u8>, RecoverPubkeyError> {
-        self.0
-            .secp256k1_recover_pubkey(message_hash, signature, recovery_param)
-    }
-
-    fn ed25519_verify(
-        &self,
-        message: &[u8],
-        signature: &[u8],
-        public_key: &[u8],
-    ) -> Result<bool, VerificationError> {
-        self.0.ed25519_verify(message, signature, public_key)
-    }
-
-    fn ed25519_batch_verify(
-        &self,
-        messages: &[&[u8]],
-        signatures: &[&[u8]],
-        public_keys: &[&[u8]],
-    ) -> Result<bool, VerificationError> {
-        self.0
-            .ed25519_batch_verify(messages, signatures, public_keys)
-    }
-
-    fn debug(&self, message: &str) {
-        self.0.debug(message)
-    }
-}
-
-impl MockApiBech32 {
-    /// Returns an address in `Bech32` format, built from provided input string.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("juno");
-    /// let addr = api.addr_make("creator");
-    /// assert_eq!(addr.as_str(),
-    ///            "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp");
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// This function panics when generating a valid address in **Bech32**
-    /// format is not possible, especially when prefix is too long or empty.
-    pub fn addr_make(&self, input: &str) -> Addr {
-        self.0.addr_make(input)
-    }
-}
diff --git a/src/addons/api/b32m.rs b/src/addons/api/b32m.rs
deleted file mode 100644
index 2c91477..0000000
--- a/src/addons/api/b32m.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-use crate::addons::api::MockApiBech;
-use bech32::Bech32m;
-use cosmwasm_std::{Addr, Api, CanonicalAddr, RecoverPubkeyError, StdResult, VerificationError};
-
-/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format
-/// for humanizing canonical addresses.
-///
-/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
-pub struct MockApiBech32m(MockApiBech<Bech32m>);
-
-impl MockApiBech32m {
-    /// Returns `Api` implementation that uses specified prefix
-    /// to generate addresses in `Bech32m` format.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cw_multi_test::addons::MockApiBech32m;
-    ///
-    /// let api = MockApiBech32m::new("osmo");
-    /// let addr = api.addr_make("sender");
-    /// assert_eq!(addr.as_str(),
-    ///            "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg");
-    /// ```
-    pub fn new(prefix: &'static str) -> Self {
-        Self(MockApiBech::new(prefix))
-    }
-}
-
-impl Api for MockApiBech32m {
-    /// Takes a human-readable address in `Bech32m` format and checks if it is valid.
-    ///
-    /// If the validation succeeds, an `Addr` containing the same string as the input is returned.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32m;
-    ///
-    /// let api = MockApiBech32m::new("osmo");
-    /// let addr = api.addr_make("sender");
-    /// assert_eq!(api.addr_validate(addr.as_str()).unwrap().as_str(),
-    ///            addr.as_str());
-    /// ```
-    fn addr_validate(&self, input: &str) -> StdResult<Addr> {
-        self.0.addr_humanize(&self.addr_canonicalize(input)?)
-    }
-
-    /// Takes a human-readable address in `Bech32m` format and returns
-    /// a canonical binary representation of it.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32;
-    ///
-    /// let api = MockApiBech32::new("osmo");
-    /// let addr = api.addr_make("sender");
-    /// assert_eq!(api.addr_canonicalize(addr.as_str()).unwrap().to_string(),
-    ///            "0A367B92CF0B037DFD89960EE832D56F7FC151681BB41E53690E776F5786998A");
-    /// ```
-    fn addr_canonicalize(&self, input: &str) -> StdResult<CanonicalAddr> {
-        self.0.addr_canonicalize(input)
-    }
-
-    /// Takes a canonical address and returns a human-readable address in `Bech32m` format.
-    ///
-    /// This is the inverse operation of [`addr_canonicalize`].
-    ///
-    /// [`addr_canonicalize`]: MockApiBech32m::addr_canonicalize
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cosmwasm_std::Api;
-    /// use cw_multi_test::addons::MockApiBech32m;
-    ///
-    /// let api = MockApiBech32m::new("osmo");
-    /// let addr = api.addr_make("sender");
-    /// let canonical_addr = api.addr_canonicalize(addr.as_str()).unwrap();
-    /// assert_eq!(api.addr_humanize(&canonical_addr).unwrap().as_str(),
-    ///            addr.as_str());
-    /// ```
-    fn addr_humanize(&self, canonical: &CanonicalAddr) -> StdResult<Addr> {
-        self.0.addr_humanize(canonical)
-    }
-
-    fn secp256k1_verify(
-        &self,
-        message_hash: &[u8],
-        signature: &[u8],
-        public_key: &[u8],
-    ) -> Result<bool, VerificationError> {
-        self.0.secp256k1_verify(message_hash, signature, public_key)
-    }
-
-    fn secp256k1_recover_pubkey(
-        &self,
-        message_hash: &[u8],
-        signature: &[u8],
-        recovery_param: u8,
-    ) -> Result<Vec<u8>, RecoverPubkeyError> {
-        self.0
-            .secp256k1_recover_pubkey(message_hash, signature, recovery_param)
-    }
-
-    fn ed25519_verify(
-        &self,
-        message: &[u8],
-        signature: &[u8],
-        public_key: &[u8],
-    ) -> Result<bool, VerificationError> {
-        self.0.ed25519_verify(message, signature, public_key)
-    }
-
-    fn ed25519_batch_verify(
-        &self,
-        messages: &[&[u8]],
-        signatures: &[&[u8]],
-        public_keys: &[&[u8]],
-    ) -> Result<bool, VerificationError> {
-        self.0
-            .ed25519_batch_verify(messages, signatures, public_keys)
-    }
-
-    fn debug(&self, message: &str) {
-        self.0.debug(message)
-    }
-}
-
-impl MockApiBech32m {
-    /// Returns an address in `Bech32m` format, built from provided input string.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// use cw_multi_test::addons::MockApiBech32m;
-    ///
-    /// let api = MockApiBech32m::new("osmo");
-    /// let addr = api.addr_make("sender");
-    /// assert_eq!(addr.as_str(),
-    ///            "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qdlmaeg");
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// This function panics when generating a valid address in **Bech32**
-    /// format is not possible, especially when prefix is too long or empty.
-    pub fn addr_make(&self, input: &str) -> Addr {
-        self.0.addr_make(input)
-    }
-}
diff --git a/src/addons/mod.rs b/src/addons/mod.rs
deleted file mode 100644
index 648c9b5..0000000
--- a/src/addons/mod.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//! # Additional testing tools (extensions)
-//!
-//! **CosmWasm MultiTest** addons provide additional tools for testing smart contracts,
-//! simulating complex blockchain scenarios that developers might encounter.
-//! They enhance the CosmWasm environment, enabling more advanced and nuanced testing.
-
-mod addresses;
-mod api;
-
-pub use addresses::mock::MockAddressGenerator;
-pub use api::b32::MockApiBech32;
-pub use api::b32m::MockApiBech32m;
diff --git a/src/addresses.rs b/src/addresses.rs
index 4b6c4f9..b934abf 100644
--- a/src/addresses.rs
+++ b/src/addresses.rs
@@ -1,7 +1,71 @@
 //! # Implementation of address generators
 
 use crate::error::AnyResult;
-use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary, Storage};
+use crate::{MockApiBech32, MockApiBech32m};
+use cosmwasm_std::{instantiate2_address, Addr, Api, CanonicalAddr, HexBinary, 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 {
+    fn into_addr(self) -> Addr {
+        MockApiBech32::new(DEFAULT_PREFIX).addr_make(self)
+    }
+
+    fn into_addr_with_prefix(self, prefix: &'static str) -> Addr {
+        MockApiBech32::new(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 {
+    fn into_bech32(self) -> Addr {
+        MockApiBech32::new(DEFAULT_PREFIX).addr_make(self)
+    }
+
+    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 {
+    fn into_bech32m(self) -> Addr {
+        MockApiBech32m::new(DEFAULT_PREFIX).addr_make(self)
+    }
+
+    fn into_bech32m_with_prefix(self, prefix: &'static str) -> Addr {
+        MockApiBech32m::new(prefix).addr_make(self)
+    }
+}
 
 /// Common address generator interface.
 ///
@@ -113,3 +177,146 @@ pub trait AddressGenerator {
 pub struct SimpleAddressGenerator;
 
 impl AddressGenerator for SimpleAddressGenerator {}
+
+/// Address generator that mimics the [wasmd](https://github.com/CosmWasm/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::{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::{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()
+}
diff --git a/src/addons/api/mod.rs b/src/api.rs
similarity index 80%
rename from src/addons/api/mod.rs
rename to src/api.rs
index 1e16c5a..c09d007 100644
--- a/src/addons/api/mod.rs
+++ b/src/api.rs
@@ -1,15 +1,12 @@
 use bech32::primitives::decode::CheckedHrpstring;
-use bech32::{encode, Hrp};
+use bech32::{encode, Bech32, Bech32m, Hrp};
 use cosmwasm_std::testing::MockApi;
 use cosmwasm_std::{
     Addr, Api, CanonicalAddr, RecoverPubkeyError, StdError, StdResult, VerificationError,
 };
 use sha2::{Digest, Sha256};
 
-pub mod b32;
-pub mod b32m;
-
-struct MockApiBech<T> {
+pub struct MockApiBech<T> {
     api: MockApi,
     prefix: &'static str,
     _phantom_data: std::marker::PhantomData<T>,
@@ -100,14 +97,23 @@ impl<T: bech32::Checksum> MockApiBech<T> {
     /// # Panics
     ///
     /// This function panics when generating a valid address in `Bech32` or `Bech32m`
-    /// format is not possible, especially when prefix is too long or empty.
+    /// format is not possible, especially when the prefix is too long or empty.
     pub fn addr_make(&self, input: &str) -> Addr {
         match Hrp::parse(self.prefix) {
-            Ok(hrp) => match encode::<T>(hrp, Sha256::digest(input).as_slice()) {
-                Ok(address) => Addr::unchecked(address),
-                Err(reason) => panic!("Generating address failed with reason: {}", reason),
-            },
+            Ok(hrp) => Addr::unchecked(encode::<T>(hrp, Sha256::digest(input).as_slice()).unwrap()),
             Err(reason) => panic!("Generating address failed with reason: {}", reason),
         }
     }
 }
+
+/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32] format
+/// for humanizing canonical addresses.
+///
+/// [Bech32]: https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki
+pub type MockApiBech32 = MockApiBech<Bech32>;
+
+/// Implementation of the `cosmwasm_std::Api` trait that uses [Bech32m] format
+/// for humanizing canonical addresses.
+///
+/// [Bech32m]: https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki
+pub type MockApiBech32m = MockApiBech<Bech32m>;
diff --git a/src/lib.rs b/src/lib.rs
index 9a6becd..c88382a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -124,8 +124,8 @@
 #![deny(rustdoc::broken_intra_doc_links)]
 #![deny(rustdoc::missing_crate_level_docs)]
 
-pub mod addons;
 mod addresses;
+mod api;
 mod app;
 mod app_builder;
 mod bank;
@@ -145,7 +145,11 @@ mod tests;
 mod transactions;
 mod wasm;
 
-pub use crate::addresses::{AddressGenerator, SimpleAddressGenerator};
+pub use crate::addresses::{
+    AddressGenerator, IntoAddr, IntoBech32, IntoBech32m, MockAddressGenerator,
+    SimpleAddressGenerator,
+};
+pub use crate::api::{MockApiBech32, MockApiBech32m};
 pub use crate::app::{
     custom_app, next_block, no_init, App, BasicApp, CosmosRouter, Router, SudoMsg,
 };


Test patch:
diff --git a/tests/mod.rs b/tests/mod.rs
index d14c147..f537060 100644
--- a/tests/mod.rs
+++ b/tests/mod.rs
@@ -3,7 +3,7 @@
 use cw_storage_plus::Item;
 use serde::{Deserialize, Serialize};
 
-mod test_addons;
+mod test_api;
 mod test_app;
 mod test_app_builder;
 mod test_module;
diff --git a/tests/test_addons/mod.rs b/tests/test_addons/mod.rs
deleted file mode 100644
index 0ce9c88..0000000
--- a/tests/test_addons/mod.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-mod test_api;
diff --git a/tests/test_addons/test_api/mod.rs b/tests/test_api/mod.rs
similarity index 99%
rename from tests/test_addons/test_api/mod.rs
rename to tests/test_api/mod.rs
index d049acc..e50ddd4 100644
--- a/tests/test_addons/test_api/mod.rs
+++ b/tests/test_api/mod.rs
@@ -1,6 +1,7 @@
 use cosmwasm_std::Api;
 use hex_literal::hex;
 
+mod test_addr;
 mod test_bech32;
 mod test_bech32m;
 
diff --git a/tests/test_api/test_addr.rs b/tests/test_api/test_addr.rs
new file mode 100644
index 0000000..015f338
--- /dev/null
+++ b/tests/test_api/test_addr.rs
@@ -0,0 +1,21 @@
+use cosmwasm_std::testing::MockApi;
+use cw_multi_test::IntoAddr;
+
+#[test]
+fn conversion_with_default_prefix_should_work() {
+    assert_eq!(
+        MockApi::default().addr_make("creator").as_str(),
+        "creator".into_addr().as_str(),
+    );
+}
+
+#[test]
+fn conversion_with_custom_prefix_should_work() {
+    assert_eq!(
+        MockApi::default()
+            .with_prefix("juno")
+            .addr_make("sender")
+            .as_str(),
+        "sender".into_addr_with_prefix("juno").as_str(),
+    );
+}
diff --git a/tests/test_addons/test_api/test_bech32.rs b/tests/test_api/test_bech32.rs
similarity index 55%
rename from tests/test_addons/test_api/test_bech32.rs
rename to tests/test_api/test_bech32.rs
index 6844848..35e8623 100644
--- a/tests/test_addons/test_api/test_bech32.rs
+++ b/tests/test_api/test_bech32.rs
@@ -1,22 +1,36 @@
 use super::*;
 use cosmwasm_std::CanonicalAddr;
-use cw_multi_test::addons::{MockApiBech32, MockApiBech32m};
+use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m};
 
-const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp";
+const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsksmtyp";
+const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqs8s7vcp";
 
 #[test]
 fn new_api_bech32_should_work() {
     assert_eq!(
         MockApiBech32::new("juno").addr_make("creator").as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     );
+    assert_eq!(
+        "creator".into_bech32_with_prefix("juno").as_str(),
+        ADDR_JUNO
+    );
+    assert_eq!("creator".into_bech32().as_str(), ADDR_DEFAULT);
 }
 
 #[test]
 fn api_bech32_should_differ_from_bech32m() {
     assert_ne!(
-        MockApiBech32::new("juno").addr_make("creator").as_str(),
-        MockApiBech32m::new("juno").addr_make("creator").as_str(),
+        MockApiBech32::new("juno").addr_make("sender").as_str(),
+        MockApiBech32m::new("juno").addr_make("sender").as_str(),
+    );
+    assert_ne!(
+        "sender".into_bech32_with_prefix("juno").as_str(),
+        "sender".into_bech32m_with_prefix("juno").as_str()
+    );
+    assert_ne!(
+        "sender".into_bech32().as_str(),
+        "sender".into_bech32m().as_str()
     );
 }
 
@@ -24,10 +38,10 @@ fn api_bech32_should_differ_from_bech32m() {
 fn address_validate_should_work() {
     assert_eq!(
         MockApiBech32::new("juno")
-            .addr_validate(HUMAN_ADDRESS)
+            .addr_validate(ADDR_JUNO)
             .unwrap()
             .as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     )
 }
 
@@ -56,20 +70,35 @@ fn address_validate_invalid_variant() {
 fn address_canonicalize_humanize_should_work() {
     let api = MockApiBech32::new("juno");
     assert_eq!(
-        api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap())
+        api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap())
             .unwrap()
             .as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     );
 }
 
 #[test]
 fn address_humanize_prefix_too_long() {
-    MockApiBech32::new(
-        "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_",
-    )
-    .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5]))
-    .unwrap_err();
+    assert_eq!(
+        "Generic error: hrp is too long, found 85 characters, must be <= 126",
+        MockApiBech32::new(
+            "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_",
+        )
+        .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5]))
+        .unwrap_err()
+        .to_string()
+    );
+}
+
+#[test]
+fn address_humanize_canonical_too_long() {
+    assert_eq!(
+        "Generic error: Invalid canonical address",
+        MockApiBech32::new("juno")
+            .addr_humanize(&CanonicalAddr::from([1; 1024]))
+            .unwrap_err()
+            .to_string()
+    );
 }
 
 #[test]
diff --git a/tests/test_addons/test_api/test_bech32m.rs b/tests/test_api/test_bech32m.rs
similarity index 59%
rename from tests/test_addons/test_api/test_bech32m.rs
rename to tests/test_api/test_bech32m.rs
index ffb1d48..61af017 100644
--- a/tests/test_addons/test_api/test_bech32m.rs
+++ b/tests/test_api/test_bech32m.rs
@@ -1,15 +1,21 @@
 use super::*;
 use cosmwasm_std::CanonicalAddr;
-use cw_multi_test::addons::{MockApiBech32, MockApiBech32m};
+use cw_multi_test::{IntoBech32, IntoBech32m, MockApiBech32, MockApiBech32m};
 
-const HUMAN_ADDRESS: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr";
+const ADDR_JUNO: &str = "juno1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsrvt8pr";
+const ADDR_DEFAULT: &str = "cosmwasm1h34lmpywh4upnjdg90cjf4j70aee6z8qqfspugamjp42e4q28kqsjvwqar";
 
 #[test]
 fn new_api_bech32m_should_work() {
     assert_eq!(
         MockApiBech32m::new("juno").addr_make("creator").as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     );
+    assert_eq!(
+        "creator".into_bech32m_with_prefix("juno").as_str(),
+        ADDR_JUNO
+    );
+    assert_eq!("creator".into_bech32m().as_str(), ADDR_DEFAULT);
 }
 
 #[test]
@@ -18,16 +24,24 @@ fn api_bech32m_should_differ_from_bech32() {
         MockApiBech32m::new("juno").addr_make("sender").as_str(),
         MockApiBech32::new("juno").addr_make("sender").as_str()
     );
+    assert_ne!(
+        "sender".into_bech32m_with_prefix("juno").as_str(),
+        "sender".into_bech32_with_prefix("juno").as_str()
+    );
+    assert_ne!(
+        "sender".into_bech32m().as_str(),
+        "sender".into_bech32().as_str()
+    );
 }
 
 #[test]
 fn address_validate_should_work() {
     assert_eq!(
         MockApiBech32m::new("juno")
-            .addr_validate(HUMAN_ADDRESS)
+            .addr_validate(ADDR_JUNO)
             .unwrap()
             .as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     )
 }
 
@@ -56,20 +70,35 @@ fn address_validate_invalid_variant() {
 fn address_canonicalize_humanize_should_work() {
     let api = MockApiBech32m::new("juno");
     assert_eq!(
-        api.addr_humanize(&api.addr_canonicalize(HUMAN_ADDRESS).unwrap())
+        api.addr_humanize(&api.addr_canonicalize(ADDR_JUNO).unwrap())
             .unwrap()
             .as_str(),
-        HUMAN_ADDRESS
+        ADDR_JUNO
     );
 }
 
 #[test]
 fn address_humanize_prefix_too_long() {
-    MockApiBech32m::new(
-        "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_",
-    )
-    .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5]))
-    .unwrap_err();
+    assert_eq!(
+        "Generic error: hrp is too long, found 85 characters, must be <= 126",
+        MockApiBech32m::new(
+            "juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_juno_",
+        )
+        .addr_humanize(&CanonicalAddr::from([1, 2, 3, 4, 5]))
+        .unwrap_err()
+        .to_string()
+    );
+}
+
+#[test]
+fn address_humanize_canonical_too_long() {
+    assert_eq!(
+        "Generic error: Invalid canonical address",
+        MockApiBech32m::new("juno")
+            .addr_humanize(&CanonicalAddr::from([1; 1024]))
+            .unwrap_err()
+            .to_string()
+    );
 }
 
 #[test]
diff --git a/tests/test_app/test_instantiate2.rs b/tests/test_app/test_instantiate2.rs
index cec92ad..8f82667 100644
--- a/tests/test_app/test_instantiate2.rs
+++ b/tests/test_app/test_instantiate2.rs
@@ -2,8 +2,8 @@
 
 use crate::test_contracts::counter;
 use cosmwasm_std::{instantiate2_address, to_json_binary, Api, Empty, WasmMsg};
-use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
 use cw_multi_test::{no_init, AppBuilder, Executor, WasmKeeper};
+use cw_multi_test::{MockAddressGenerator, MockApiBech32};
 use cw_utils::parse_instantiate_response_data;
 
 #[test]
diff --git a/tests/test_app/test_store_code_with_creator.rs b/tests/test_app/test_store_code_with_creator.rs
index 9cdc590..5f70a1e 100644
--- a/tests/test_app/test_store_code_with_creator.rs
+++ b/tests/test_app/test_store_code_with_creator.rs
@@ -1,8 +1,8 @@
 #![cfg(feature = "cosmwasm_1_2")]
 
 use crate::test_contracts::counter;
-use cw_multi_test::addons::{MockApiBech32, MockApiBech32m};
 use cw_multi_test::{no_init, AppBuilder};
+use cw_multi_test::{MockApiBech32, MockApiBech32m};
 
 #[test]
 fn store_code_with_custom_creator_address_should_work() {
diff --git a/tests/test_app_builder/test_with_api.rs b/tests/test_app_builder/test_with_api.rs
index c96184d..a61861c 100644
--- a/tests/test_app_builder/test_with_api.rs
+++ b/tests/test_app_builder/test_with_api.rs
@@ -1,5 +1,5 @@
 use cosmwasm_std::{Addr, Api, CanonicalAddr, HexBinary};
-use cw_multi_test::addons::MockApiBech32;
+use cw_multi_test::MockApiBech32;
 use cw_multi_test::{no_init, AppBuilder};
 
 #[test]
diff --git a/tests/test_wasm/test_with_addr_gen.rs b/tests/test_wasm/test_with_addr_gen.rs
index 619f2e5..ddabf3d 100644
--- a/tests/test_wasm/test_with_addr_gen.rs
+++ b/tests/test_wasm/test_with_addr_gen.rs
@@ -1,8 +1,8 @@
 use cosmwasm_std::{Addr, Api, Empty, Storage};
 
-use cw_multi_test::addons::{MockAddressGenerator, MockApiBech32};
 use cw_multi_test::error::AnyResult;
 use cw_multi_test::{no_init, AddressGenerator, AppBuilder, Executor, WasmKeeper};
+use cw_multi_test::{MockAddressGenerator, MockApiBech32};
 
 use crate::test_contracts;