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_makefunction, - the
IntoAddr,IntoBech32andIntoBech32mtraits, - the
MockApi,MockApiBech32andMockApiBech32mstructs.
App
Calling
addr_makeonapp.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 and MockApiBech32m structs can be
used along with with_api method of AppBuilder.
If the address should be encoded in Bech32 format then use
MockApiBech32 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 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
🖝 Using
IntoAddrtrait
The most generic and future-proof way to generate a user address is by using
IntoAddr trait. Internally, this trait uses MockApi 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
🖝 Using
IntoBech32trait
When you want to stick to Bech32 format in tests, then always use
IntoBech32 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
🖝 Using
IntoBech32mtrait
In case you would need Bech32m format while testing your contracts, then use
IntoBech32m 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, MockApiBech32 and
MockApiBech32m 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
🖝 Using
MockApistruct
To generate an address with default prefix cosmwasm encoded in Bech32 format use method
addr_make on default instance of MockApi:
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
🖝 Using
MockApiBech32struct
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
🖝 Using
MockApiBech32mstruct
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 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()
);
});