User address

User address

In the real-life blockchain based on Cosmos-SDK, user addresses are derived from the public key of the user in the following manner:

  • the public key of the user (in raw bytes) is first hashed using SHA-256,
  • then the resulting SHA-256 hash is hashed again using RIPEMD-160; this step reduces the hash to 20 bytes, which is the standard length of addresses in Cosmos-SDK),
  • finally the resulting RIPEMD-160 hash is then encoded using Bech32 format; a human-readable prefix (HRP) specific to the blockchain is prepended.

In MultiTest, user addresses are indeed derived from a user-provided string, such as an alias (e.g., alice, creator, etc.) and not from an actual public/private key pair, which simplifies address creation for testing purposes in two steps:

  • the alias or any provided string is first hashed using SHA-256,
  • and then the 32-byte hash is encoded using Bech32 format; a human-readable prefix (HRP) specific to the blockchain is prepended.

The following examples demonstrate (in several ways) how to generate a Bech32 addresses (optionally with custom prefix) using these common approaches:

  • the addr_make function,
  • the IntoAddr, IntoBech32 and IntoBech32m traits,
  • the MockApi, MockApiBech32 and MockApiBech32m structs.

App

🖝

Calling addr_make on app.api()

Having the chain simulator App already created, you can just call addr_make function, providing any string as an argument, like shown below in line 5. The address returned by this function is by default encoded in Bech32 format and has a default prefix cosmwasm. Notice, that the App is created with default settings (line 3):

use cw_multi_test::App;
 
let app = App::default();
 
let addr = app.api().addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
);

Exactly the same address will be generated when the App is created using the default settings in AppBuilder, like shown below in lines 3 and 5:

use cw_multi_test::AppBuilder;
 
let app = AppBuilder::default().build(no_init);
 
let addr = app.api().addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
);

The next two code snippets demonstrate how to customize the App using AppBuilder to generate addresses with the custom prefix, just like in your blockchain. For this purpose, the MockApiBech32 (opens in a new tab) and MockApiBech32m (opens in a new tab) structs can be used along with with_api method of AppBuilder.

If the address should be encoded in Bech32 format then use MockApiBech32 (opens in a new tab) to configure the AppBuilder like shown in line 4, and then call the addr_make function (line 7) exactly the same way as in the previous examples:

use cw_multi_test::{no_init, AppBuilder, MockApiBech32};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32::new("nebula"))
    .build(no_init);
 
let addr = app.api().addr_make("owner");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
    addr.as_str()
);

When Bech32m is the required address encoding, then just use MockApiBech32m (opens in a new tab) to configure the AppBuilder:

use cw_multi_test::{no_init, AppBuilder, MockApiBech32m};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32m::new("nebula"))
    .build(no_init);
 
let addr = app.api().addr_make("owner");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsevs0fr",
    addr.as_str()
);

The last example demonstrates how to generate addresses encoded in Bech32m format with the default human-readable prefix cosmwasm:

use cw_multi_test::{no_init, AppBuilder, MockApiBech32m};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32m::new("cosmwasm"))
    .build(no_init);
 
let addr = app.api().addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsl5lc5x",
    addr.as_str()
);

IntoAddr

The most generic and future-proof way to generate a user address is by using IntoAddr (opens in a new tab) trait. Internally, this trait uses MockApi (opens in a new tab) struct which currently generates addresses encoded in Bech32 format with the default prefix cosmwasm. Should the format or prefix change in the future, this trait will generate addresses adjusted to these changes. To convert any string to the address, just call into_addr method on it, like shown in line 3:

use cw_multi_test::IntoAddr;
 
let addr = "owner".into_addr();
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
)

Similarly, when you need an address with the prefix to be the same as in your blockchain, then call into_addr_with_prefix method on any string, like in line 3 shown below:

use cw_multi_test::IntoAddr;
 
let addr = "owner".into_addr_with_prefix("nebula");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
    addr.as_str()
);

IntoBech32

When you want to stick to Bech32 format in tests, then always use IntoBech32 (opens in a new tab) trait. To generate an address with the default prefix cosmwasm, just call into_bech32 method on any string like in line 3:

use cw_multi_test::IntoBech32;
 
let addr = "owner".into_bech32();
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
);

Custom prefix can be used by calling into_bech32_with_prefix method on the string:

use cw_multi_test::IntoBech32;
 
let addr = "owner".into_bech32_with_prefix("nebula");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
    addr.as_str()
)

IntoBech32m

In case you would need Bech32m format while testing your contracts, then use IntoBech32m (opens in a new tab) trait. An address with the default prefix cosmwasm can be generated by calling into_bech32m method on any string (line 3):

use cw_multi_test::IntoBech32m;
 
let addr = "owner".into_bech32m();
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsl5lc5x",
    addr.as_str()
);

Similarly, the custom prefix can be provided to method into_bech32m_with_prefix called on string:

use cw_multi_test::IntoBech32m;
 
let addr = "owner".into_bech32m_with_prefix("nebula");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsevs0fr",
    addr.as_str()
);
💡

All the methods of generating user addresses described above are built on the functionality provided by the MockApi (opens in a new tab), MockApiBech32 (opens in a new tab) and MockApiBech32m (opens in a new tab) structs. In certain scenarios, you might find it useful to use these structs directly - for instance, when creating utility functions for tests or custom testing frameworks. Examples of their usage are provided below.

MockApi

To generate an address with default prefix cosmwasm encoded in Bech32 format use method addr_make on default instance of MockApi (opens in a new tab):

use cosmwasm_std::testing::MockApi;
 
let addr = MockApi::default().addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
);

The with_prefix method applies a custom prefix and Bech32 encoding to generated address:

use cosmwasm_std::testing::MockApi;
 
let addr = MockApi::default().with_prefix("nebula").addr_make("owner");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
    addr.as_str()
);

MockApiBech32

cosmwasm prefix and Bech32 encoding:

use cw_multi_test::MockApiBech32;
 
let addr = MockApiBech32::new("cosmwasm").addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
    addr.as_str()
);

Custom prefix and Bech32 encoding:

use cw_multi_test::MockApiBech32;
 
let addr = MockApiBech32::new("nebula").addr_make("owner");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
    addr.as_str()
);

MockApiBech32m

cosmwasm prefix and Bech32m encoding:

use cw_multi_test::MockApiBech32m;
 
let addr = MockApiBech32m::new("cosmwasm").addr_make("owner");
 
assert_eq!(
    "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsl5lc5x",
    addr.as_str()
);

Custom prefix and Bech32m encoding:

use cw_multi_test::MockApiBech32m;
 
let addr = MockApiBech32m::new("nebula").addr_make("owner");
 
assert_eq!(
    "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsevs0fr",
    addr.as_str()
);

Initialization callback

During blockchain initialization, a common use case is supplying user accounts with tokens before running tests. In these scenarios, user addresses can be generated directly within the initialization callback function, passed as an argument to the App::new or AppBuilder::build methods. Examples of such usage are provided below and are self-explanatory.

Default cosmwasm prefix with Bech32 encoding:

use cw_multi_test::App;
 
let app = App::new(|router, api, storage| {
    let addr = api.addr_make("owner");
    assert_eq!(
        "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
        addr.as_str()
    );
});

Custom prefix prefix with Bech32 encoding:

use cw_multi_test::{AppBuilder, MockApiBech32};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32::new("nebula"))
    .build(|router, api, storage| {
        let addr = api.addr_make("owner");
        assert_eq!(
            "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
            addr.as_str()
        );
    });

Custom prefix with Bech32m encoding:

use cw_multi_test::{AppBuilder, MockApiBech32m};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32m::new("nebula"))
    .build(|router, api, storage| {
        let addr = api.addr_make("owner");
        assert_eq!(
            "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsevs0fr",
            addr.as_str()
        );
    });

cosmwasm prefix with Bech32m encoding:

use cw_multi_test::{AppBuilder, MockApiBech32m};
 
let app = AppBuilder::default()
    .with_api(MockApiBech32m::new("cosmwasm"))
    .build(|router, api, storage| {
        let addr = api.addr_make("owner");
        assert_eq!(
            "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsl5lc5x",
            addr.as_str()
        );
    });