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
andIntoBech32m
traits, - the
MockApi
,MockApiBech32
andMockApiBech32m
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
Using IntoAddr
(opens in a new tab) trait
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
Using IntoBech32
(opens in a new tab) trait
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
Using IntoBech32m
(opens in a new tab) trait
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
Using MockApi
(opens in a new tab) struct
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
Using MockApiBech32
(opens in a new tab) struct
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 MockApiBech32m
(opens in a new tab) struct
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()
);
});