From 8bb74574fa1b3ea6aa19370b531b4674dbba8c89 Mon Sep 17 00:00:00 2001
From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com>
Date: Fri, 10 Oct 2025 11:15:36 +0200
Subject: [PATCH 1/4] MultiTest chapters.
---
docs/multi-test/addresses.md | 17 +
docs/multi-test/api.md | 72 +++
docs/multi-test/app-builder.md | 429 ++++++++++++++++
docs/multi-test/app.md | 79 +++
docs/multi-test/features.md | 83 ++++
.../getting-started/_category_.json | 8 +
.../getting-started/counter/_category_.json | 8 +
.../getting-started/counter/counter.md | 108 ++++
.../getting-started/counter/implementation.md | 468 ++++++++++++++++++
.../getting-started/introduction.mdx | 13 +
.../writing-tests/_category_.json | 8 +
.../writing-tests/writing-tests.md | 306 ++++++++++++
docs/multi-test/governance.md | 199 ++++++++
13 files changed, 1798 insertions(+)
create mode 100644 docs/multi-test/addresses.md
create mode 100644 docs/multi-test/api.md
create mode 100644 docs/multi-test/app-builder.md
create mode 100644 docs/multi-test/app.md
create mode 100644 docs/multi-test/features.md
create mode 100644 docs/multi-test/getting-started/_category_.json
create mode 100644 docs/multi-test/getting-started/counter/_category_.json
create mode 100644 docs/multi-test/getting-started/counter/counter.md
create mode 100644 docs/multi-test/getting-started/counter/implementation.md
create mode 100644 docs/multi-test/getting-started/introduction.mdx
create mode 100644 docs/multi-test/getting-started/writing-tests/_category_.json
create mode 100644 docs/multi-test/getting-started/writing-tests/writing-tests.md
create mode 100644 docs/multi-test/governance.md
diff --git a/docs/multi-test/addresses.md b/docs/multi-test/addresses.md
new file mode 100644
index 0000000..0d28dc0
--- /dev/null
+++ b/docs/multi-test/addresses.md
@@ -0,0 +1,17 @@
+---
+tags: ["multitest", "addresses"]
+---
+
+import { Cards } from "nextra/components";
+
+# Addresses
+
+The following chapters provide useful explanations of how addresses are managed in **`MultiTest`**.
+
+Click on any of the cards below to learn more about each address category.
+
+
+
+
+
+
diff --git a/docs/multi-test/api.md b/docs/multi-test/api.md
new file mode 100644
index 0000000..c34f268
--- /dev/null
+++ b/docs/multi-test/api.md
@@ -0,0 +1,72 @@
+---
+sidebar_position: 7
+---
+
+# Api
+
+**MultiTest** provides three implementations of the [Api][Api] trait:
+
+- [`cosmwasm_std::testing::MockApi`][MockApi],
+- [`cw_multi_test::MockApiBech32`][MockApiBech32],
+- [`cw_multi_test::MockApiBech32m`][MockApiBech32m].
+
+Additionally, [`MockApi`][MockApi], [`MockApiBech32`][MockApiBech32] and
+[`MockApiBech32m`][MockApiBech32m] implement `addr_make` method, allowing for
+convenient creation of user addresses in tests. You can find multiple examples of `addr_make`
+method usage in the [Addresses](addresses/user-address#app) chapter. Depending on your needs, you
+can use any implementation of the [Api][Api] trait in your tests by utilizing the
+[`AppBuilder::with_api`](app-builder#with_api) method to create a chain simulator.
+
+## `Api` trait
+
+The table below summarizes all methods of the [Api][Api] trait with short descriptions:
+
+| Methods of [Api] trait | Description |
+|------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
+| [`addr_canonicalize`][addr_canonicalize] | Converts a human-readable address into its canonical binary representation. |
+| [`addr_humanize`][addr_humanize] | Converts a canonical address into human-readable address. |
+| [`addr_validate`][addr_validate] | Checks if the human-readable address is valid. |
+| [`secp256k1_verify`][secp256k1_verify] | Verifies a message hash against a signature, with the public key of the signer, using the **secp256k1** elliptic curve digital signature algorithm. |
+| [`secp256k1_recover_pubkey`][secp256k1_recover_pubkey] | Recovers a public key from a message hash and a signature in compressed form, which can be used in `secp256k1_verify` directly. |
+| [`secp256r1_verify`][secp256r1_verify] | Verifies a message hash against a signature, with the public key of the signer, using the **secp256r1** elliptic curve digital signature algorithm. |
+| [`secp256r1_recover_pubkey`][secp256r1_recover_pubkey] | Recovers a public key from a message hash and a signature in compressed form, which can be used in `secp256r1_verify` directly. |
+| [`ed25519_verify`][ed25519_verify] | Verifies message against a signature, with the public key of the signer, using the **ed25519** elliptic curve digital signature algorithm. |
+| [`ed25519_batch_verify`][ed25519_batch_verify] | Performs batch **ed25519** signature verification. |
+| [`bls12_381_aggregate_g1`][bls12_381_aggregate_g1] | Adds up points (48 bytes each) of the G1 subgroup on the BLS12-381 curve. |
+| [`bls12_381_aggregate_g2`][bls12_381_aggregate_g2] | Adds up points (96 bytes each) of the G2 subgroup on the BLS12-381 curve. |
+| [`bls12_381_pairing_equality`][bls12_381_pairing_equality] | Checks the pairing equality of the BLS12-381 curve. |
+| [`bls12_381_hash_to_g1`][bls12_381_hash_to_g1] | Takes some arbitrary data and hashes it to a point (48 bytes long) on the G1 subgroup of the BLS12-381 curve. |
+| [`bls12_381_hash_to_g2`][bls12_381_hash_to_g2] | Takes some arbitrary data and hashes it to a point (96 bytes long) on the G2 subgroup of the BLS12-381 curve. |
+| [`debug`][debug] | Emits a debugging message. |
+
+## `Api` trait implementations
+
+A concise comparison of different [Api][Api] trait implementations is shown in the table below:
+
+| | MockApi | MockApiBech32 | MockApiBech32m |
+|-------------------------------------|:----------:|:-------------:|:--------------:|
+| Implements [Api][Api] trait | Yes | Yes | Yes |
+| Implements **`addr_make`** function | Yes | Yes | Yes |
+| Address format | Bech32 | Bech32 | Bech32m |
+| Default prefix (HRP) | `cosmwasm` | No | No |
+| Supports custom prefixes | Yes | Yes | Yes |
+
+[Api]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html
+[addr_canonicalize]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.addr_canonicalize
+[addr_humanize]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.addr_humanize
+[addr_validate]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.addr_validate
+[secp256k1_verify]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.secp256k1_verify
+[secp256k1_recover_pubkey]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.secp256k1_recover_pubkey
+[secp256r1_verify]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.secp256r1_verify
+[secp256r1_recover_pubkey]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.secp256r1_recover_pubkey
+[ed25519_verify]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.ed25519_verify
+[ed25519_batch_verify]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.ed25519_batch_verify
+[bls12_381_aggregate_g1]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.bls12_381_aggregate_g1
+[bls12_381_aggregate_g2]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.bls12_381_aggregate_g2
+[bls12_381_pairing_equality]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.bls12_381_pairing_equality
+[bls12_381_hash_to_g1]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.bls12_381_hash_to_g1
+[bls12_381_hash_to_g2]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#method.bls12_381_hash_to_g2
+[debug]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html#tymethod.debug
+[MockApi]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html
+[MockApiBech32]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32.html
+[MockApiBech32m]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32m.html
diff --git a/docs/multi-test/app-builder.md b/docs/multi-test/app-builder.md
new file mode 100644
index 0000000..de9489f
--- /dev/null
+++ b/docs/multi-test/app-builder.md
@@ -0,0 +1,429 @@
+---
+sidebar_position: 5
+---
+
+# `AppBuilder`
+
+[`AppBuilder`][AppBuilder] is an implementation of the [Builder Pattern] that provides a
+flexible and modular way to construct the [`App`](./app) blockchain simulator. It allows smart
+contract developers to configure various components of the blockchain simulator (e.g., Bank,
+Staking, Gov, IBC) individually through dedicated `with_*` methods. Each method modifies and returns
+a new instance of the builder, enabling method chaining for a fluent interface. The
+[`build`][build] method finalizes the construction process, ensuring that all components are
+correctly initialized and integrated.
+
+The following sections detail all builder functions, providing specific usage examples.
+
+## `default`
+
+The simplest way to create a chain using [`AppBuilder`][AppBuilder] is by calling the
+`default` method. Since [`AppBuilder`][AppBuilder] follows the principles of the
+builder pattern, you need to finalize the building process by calling the [`build`][build]
+method with a chain initialization callback function. When no specific chain initialization is
+required you can just use the provided [`no_init`](app#no_init) callback. In the following code
+example, the chain is created with default settings as described in
+[Features summary](features#features-summary).
+
+```rust showLineNumbers {3} copy /default/ /build/
+use cw_multi_test::{no_init, AppBuilder};
+
+let app = AppBuilder::default().build(no_init);
+
+let sender_addr = app.api().addr_make("sender");
+
+assert!(sender_addr.as_str().starts_with("cosmwasm1"));
+```
+
+## `new`
+
+The constructor `new` is an equivalent of the `default` method in
+[`AppBuilder`][AppBuilder]. The example below creates a chain with default settings as
+described in [Features summary](features#features-summary).
+
+```rust showLineNumbers {3} copy /new/ /build/
+use cw_multi_test::{no_init, AppBuilder};
+
+let app = AppBuilder::new().build(no_init);
+
+let sender_addr = app.api().addr_make("sender");
+
+assert!(sender_addr.as_str().starts_with("cosmwasm1"));
+```
+
+## `new_custom`
+
+(WIP)
+
+## `with_api`
+
+The default [`Api`][Api] trait implementation used in [`AppBuilder`][AppBuilder] is
+[`cosmwasm_std::testing::MockApi`][MockApi] provided by CosmWasm library. Besides other
+functionalities described in detail in the [API](./api) chapter, the [`MockApi`][MockApi]
+provides a function [`addr_make`][addr_make] for generating user addresses in **Bech32**
+format with the `cosmwasm` prefix. An example usage is shown below.
+
+```rust showLineNumbers copy {7} /api()/ /addr_make/ /cosmwasm/
+use cw_multi_test::{no_init, AppBuilder};
+
+// Create the chain with default Api implementation.
+let app = AppBuilder::default().build(no_init);
+
+// Create the address using default Api.
+let sender_addr = app.api().addr_make("sender");
+
+// Default Api generates Bech32 addresses with prefix 'cosmwasm'.
+assert_eq!(
+ "cosmwasm1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qlm3aqg",
+ sender_addr.as_str()
+);
+```
+
+If you need to test contracts on your own chain that uses a specific Bech32 prefixes, you can easily
+customize the default [`MockApi`][MockApi] behavior using the
+[`AppBuilder::with_api`][with_api] method. An example of using `osmo` prefix is shown in the
+following code snippet.
+
+```rust showLineNumbers copy {1,6} /with_api/ /osmo/
+use cosmwasm_std::testing::MockApi;
+use cw_multi_test::{no_init, AppBuilder};
+
+// Create the chain with customized default Api implementation.
+let app = AppBuilder::default()
+ .with_api(MockApi::default().with_prefix("osmo"))
+ .build(no_init);
+
+// Create the address using customized Api.
+let sender_addr = app.api().addr_make("sender");
+
+// This customized Api generates Bech32 addresses with prefix 'osmo'.
+assert_eq!(
+ "osmo1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qcrt3u2",
+ sender_addr.as_str()
+);
+```
+
+**`MultiTest`** provides two additional implementations of the [`Api`][Api] trait:
+[`MockApiBech32`][MockApiBech32] and [`MockApiBech32m`][MockApiBech32m]. You can use
+them in your tests by providing their instances to [`AppBuilder::with_api`][with_api] method.
+
+An example of using [`MockApiBech32`][MockApiBech32] with custom prefix:
+
+```rust showLineNumbers copy {1,6} /with_api/ /juno/
+use cw_multi_test::MockApiBech32;
+use cw_multi_test::{no_init, AppBuilder};
+
+// Create the chain with Bech32 Api implementation.
+let app = AppBuilder::default()
+ .with_api(MockApiBech32::new("juno"))
+ .build(no_init);
+
+// Create the address using Bech32 Api.
+let sender_addr = app.api().addr_make("sender");
+
+// This Api generates Bech32 addresses with prefix 'juno'.
+assert_eq!(
+ "juno1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qwm56ug",
+ sender_addr.as_str()
+);
+```
+
+An example of using [`MockApiBech32m`][MockApiBech32m] with custom prefix:
+
+```rust showLineNumbers copy {1,6} /with_api/ /juno/
+use cw_multi_test::MockApiBech32m;
+use cw_multi_test::{no_init, AppBuilder};
+
+// Create the chain with Bech32m Api implementation.
+let app = AppBuilder::default()
+ .with_api(MockApiBech32m::new("juno"))
+ .build(no_init);
+
+// Create the address using Bech32m Api.
+let sender_addr = app.api().addr_make("sender");
+
+// This Api generates Bech32m addresses with prefix 'juno'.
+assert_eq!(
+ "juno1pgm8hyk0pvphmlvfjc8wsvk4daluz5tgrw6pu5mfpemk74uxnx9qm8yke2",
+ sender_addr.as_str()
+);
+```
+
+:::tip
+
+ More details about the available [`Api`][Api] implementations are in the [API](api) chapter.
+ If needed, you can provide your own implementation of the [`Api`][Api] trait and
+ use it in your tests by utilizing the `with_api` method of the `AppBuilder`.
+
+:::
+
+## `with_bank`
+
+(WIP)
+
+## `with_block`
+
+While the default block configuration is sufficient for most test cases, you can initialize the
+chain with a custom [`BlockInfo`][BlockInfo] using the [`with_block`][with_block]
+method provided by [`AppBuilder`][AppBuilder].
+
+The following example demonstrates this use case in detail.
+
+```rust showLineNumbers copy {15} /with_block/
+use cosmwasm_std::{BlockInfo, Timestamp};
+use cw_multi_test::{no_init, AppBuilder};
+
+// create the chain builder
+let builder = AppBuilder::default();
+
+// prepare the custom block
+let block = BlockInfo {
+ height: 1,
+ time: Timestamp::from_seconds(1723627489),
+ chain_id: "starship-testnet".to_string(),
+};
+
+// build the chain initialized with the custom block
+let app = builder.with_block(block).build(no_init);
+
+// get the current block properties
+let block = app.block_info();
+
+// now the block height is 21
+assert_eq!(1, block.height);
+
+// now the block timestamp is Wed Aug 14 2024 09:24:49 GMT+0000
+assert_eq!(1723627489, block.time.seconds());
+
+// now the chain identifier is "starship-testnet"
+assert_eq!("starship-testnet", block.chain_id);
+```
+
+The [`AppBuilder`][AppBuilder] is initialized with default settings in line 5. A custom block
+is created in lines 8-12 and passed to the [`with_block`][with_block] method in line 15.
+Since this is the only customization in this example, the blockchain construction is finalized in
+the same line by calling the [`build`][build] method.
+
+The current block metadata is retrieved in line 18, followed by value checks:
+
+- line 21: the block height is now `1`,
+- line 24: the block time is set to the Unix timestamp `1723627489`, representing
+ `Wednesday, August 14, 2024, 09:24:49 GMT`,
+- line 27: the chain identifier is now `"starship-testnet"`.
+
+The [`with_block`][with_block] method of [`AppBuilder`][AppBuilder] can be combined
+with any other `with_*` methods to configure a custom starting block.
+
+## `with_custom`
+
+(WIP)
+
+## `with_distribution`
+
+(WIP)
+
+## `with_gov`
+
+The [`with_gov`][with_gov] function allows you to customize the governance module of your
+test blockchain environment. This function enables you to override the default governance module
+with a custom implementation that suits your specific testing needs. Currently, **`MultiTest`**
+provides two minimal implementations of the governance module that do not attempt to replicate real
+blockchain behavior: [`GovAcceptingModule`][GovAcceptingModule] and
+[`GovFailingModule`][GovFailingModule].
+
+To use a built-in governance module that accepts all messages, initialize the chain like shown below
+(line 4):
+
+```rust showLineNumbers copy {15} /with_gov/ /GovAcceptingModule/
+use cw_multi_test::{no_init, AppBuilder, GovAcceptingModule};
+
+let app = AppBuilder::default()
+ .with_gov(GovAcceptingModule::new())
+ .build(no_init);
+```
+
+When processing governance messages in your tests should always fail, initialize the chain like in
+the following code snippet (line 4):
+
+```rust showLineNumbers copy /with_gov/ /GovFailingModule/
+use cw_multi_test::{no_init, AppBuilder, GovFailingModule};
+
+let app = AppBuilder::default()
+ .with_gov(GovFailingModule::new())
+ .build(no_init);
+```
+
+:::tip
+
+Note that [`GovFailingModule`][GovFailingModule] is the default one in `App`.
+
+:::
+
+You can find more usage examples of the built-in governance modules in the [Governance](./governance) chapter.
+
+## `with_ibc`
+
+(WIP)
+
+## `with_staking`
+
+(WIP)
+
+## `with_stargate`
+
+(WIP)
+
+## `with_storage`
+
+By default, **`MultiTest`** uses [`MockStorage`][MockStorage], which is provided by the
+CosmWasm library. [`MockStorage`][MockStorage] is an in-memory storage that does not persist
+data beyond the test execution. Any values stored in it during testing are lost once the test
+completes.
+
+To use the default storage, simply initialize a chain with the default settings, as shown in the
+following code snippet. After initialization, [`App`][App] provides two methods to access the
+storage: [`storage`][storage] and [`storage_mut`][storage_mut]. The former is used for
+reading the storage, while the latter allows both reading and writing.
+
+```rust showLineNumbers {4} /storage_mut()/ /storage()/
+use cosmwasm_std::Storage;
+use cw_multi_test::{no_init, AppBuilder};
+
+let mut app = AppBuilder::default().build(no_init);
+
+let key = b"key";
+let value = b"value";
+
+app.storage_mut().set(key, value);
+
+assert_eq!(value, app.storage().get(key).unwrap().as_slice());
+```
+
+You can also explicitly provide a [`MockStorage`][MockStorage] instance to the
+[`with_storage`][with_storage] method of [`AppBuilder`][AppBuilder]. The example below
+achieves the same result as the previous one.
+
+```rust showLineNumbers {1,6} /storage_mut()/ /storage()/
+use cosmwasm_std::testing::MockStorage;
+use cosmwasm_std::Storage;
+use cw_multi_test::{no_init, AppBuilder};
+
+let mut app = AppBuilder::default()
+ .with_storage(MockStorage::new())
+ .build(no_init);
+
+let key = b"key";
+let value = b"value";
+
+app.storage_mut().set(key, value);
+
+assert_eq!(value, app.storage().get(key).unwrap().as_slice());
+```
+
+Initializing a chain with a [`MockStorage`][MockStorage] instance using the
+[`with_storage`][with_storage] method of [`AppBuilder`][AppBuilder] allows for
+sophisticated storage initialization before the chain starts. A simplified example is shown below.
+In lines 8-9 the storage is created and initialized, then passed to `with_storage` method in
+line 11. The initialization code in line 9 can of course be more complex in your test case.
+
+```rust showLineNumbers {8,9,11} /with_storage/
+use cosmwasm_std::testing::MockStorage;
+use cosmwasm_std::Storage;
+use cw_multi_test::{no_init, AppBuilder};
+
+let key = b"key";
+let value = b"value";
+
+let mut storage = MockStorage::new();
+storage.set(key, value);
+
+let app = AppBuilder::default().with_storage(storage).build(no_init);
+
+assert_eq!(value, app.storage().get(key).unwrap().as_slice());
+```
+
+It is worth noting that the same initialization can be implemented directly in a callback function
+passed to [`build`][build] method of [`AppBuilder`][AppBuilder] as shown in the
+following example:
+
+```rust showLineNumbers {11} /build/
+use cosmwasm_std::testing::MockStorage;
+use cosmwasm_std::Storage;
+use cw_multi_test::AppBuilder;
+
+let key = b"key";
+let value = b"value";
+
+let app = AppBuilder::default()
+ .with_storage(MockStorage::new())
+ .build(|router, api, storage| {
+ storage.set(key, value);
+ });
+
+assert_eq!(value, app.storage().get(key).unwrap().as_slice());
+```
+
+:::tip
+
+In the examples above, to keep the simple, we accessed the storage directly and focused on the chain
+initialization part involving the `with_storage` method of `AppBuilder`.
+Please note, that inside smart contract code, the storage used by the chain should be accessed through
+libraries like [StoragePlus](../storage-plus).
+
+:::
+
+You can find additional information about storage in the [Storage](./storage) chapter.
+
+## `with_wasm`
+
+(WIP)
+
+## `build`
+
+Since [`AppBuilder`][AppBuilder] follows the principles of the builder pattern, you must
+always finalize the chain-building process by calling the [`build`][build] method with an
+initialization callback function. If no specific chain initialization is required, you can use the
+provided [`no_init`](app#no_init) callback. Otherwise, you can initialize the chain using a custom
+callback function. An example of how to initialize a user's balance is shown below.
+
+```rust showLineNumbers copy /build/
+use cosmwasm_std::coin;
+use cw_multi_test::AppBuilder;
+
+let my_address = "me".into_addr();
+let my_funds = vec![coin(23, "ATOM"), coin(18, "FLOCK")];
+
+let app = AppBuilder::default().build(|router, api, storage| {
+ router
+ .bank
+ .init_balance(storage, &my_address, my_funds)
+ .unwrap();
+});
+
+assert_eq!(
+ "23ATOM",
+ app.wrap()
+ .query_balance(my_address, "ATOM")
+ .unwrap()
+ .to_string()
+);
+```
+
+[Api]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Api.html
+[App]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html
+[AppBuilder]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html
+[build]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.build
+[Builder Pattern]: https://en.wikipedia.org/wiki/Builder_pattern
+[BlockInfo]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.BlockInfo.html
+[GovAcceptingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovAcceptingModule.html
+[GovFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html
+[MockApi]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html
+[MockApiBech32]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32.html
+[MockApiBech32m]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32m.html
+[with_api]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_api
+[with_block]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_block
+[with_gov]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_gov
+[with_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_storage
+[addr_make]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html#method.addr_make
+[MockStorage]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockStorage.html
+[storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.storage
+[storage_mut]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.storage_mut
diff --git a/docs/multi-test/app.md b/docs/multi-test/app.md
new file mode 100644
index 0000000..2c074b5
--- /dev/null
+++ b/docs/multi-test/app.md
@@ -0,0 +1,79 @@
+---
+sidebar_position: 4
+---
+
+
+# `App`
+
+The [`App`][App] structure represents the blockchain simulator. Creating [`App`][App]
+mimics the startup of a real-life blockchain within tests that utilize **MultiTest**.
+
+## `default`
+
+The most straightforward way to create an [`App`][App] is by using the `default` method,
+
+```rust showLineNumbers
+use cw_multi_test::App;
+
+let app = App::default();
+```
+
+which is an equivalent of calling the `new` constructor with an empty initialization callback [`no_init`][no_init].
+
+```rust showLineNumbers
+use cw_multi_test::{no_init, App};
+
+let app = App::new(no_init);
+```
+
+In both cases, the newly created [`App`][App] object simulates a blockchain with the default
+settings as summarized in the chapter [Features summary](features#features-summary).
+
+## `new`
+
+Using the [`App::new`][new] constructor enables additional initialization of the blockchain
+at startup, prior to executing any tests. Initialization is done inside the callback function passed
+as an argument to the `new` constructor (lines 7-13 in the code snippet shown below).
+
+Initialization callback function takes three arguments:
+
+- **router** - provides access to other modules of the blockchain,
+- **api** - provides access to CosmWasm API,
+- **storage** - provides access to the blockchain's storage.
+
+An example of funds initialization inside the custom callback function is shown below:
+
+```rust showLineNumbers {7-13}
+use cosmwasm_std::coin;
+use cw_multi_test::App;
+
+let me = "me";
+let my_funds = vec![coin(20, "OSMO")];
+
+let app = App::new(|router, api, storage| {
+ let my_address = api.addr_make(me);
+ router
+ .bank
+ .init_balance(storage, &my_address, my_funds)
+ .unwrap();
+});
+
+let my_coins = app
+ .wrap()
+ .query_all_balances(app.api().addr_make(me))
+ .unwrap();
+
+assert_eq!(1, my_coins.len());
+assert_eq!("20OSMO", my_coins[0].to_string());
+```
+
+## `no_init`
+
+The [`no_init`][no_init] function serves as an empty chain initialization callback,
+offering a convenient option when no specific chain initialization is required.
+Usually used when calling [`App::new`][new] or [`AppBuilder::build`][build] methods.
+
+[App]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html
+[new]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.new
+[build]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.build
+[no_init]: https://docs.rs/cw-multi-test/latest/cw_multi_test/fn.no_init.html
diff --git a/docs/multi-test/features.md b/docs/multi-test/features.md
new file mode 100644
index 0000000..88d0069
--- /dev/null
+++ b/docs/multi-test/features.md
@@ -0,0 +1,83 @@
+---
+sidebar_position: 2
+---
+
+# Features
+
+## Features summary
+
+All **MultiTest** features are listed in the table below.
+
+The **Default implementation** column indicates whether the feature has a default
+implementation in **MultiTest** that simulates the functionality of the real blockchain as closely
+as possible. In cases where **MultiTest** does not have a default implementation for the feature,
+you can provide your own, using `AppBuilder`'s function listed in **AppBuilder constructor**
+column. Names of **MultiTest** feature flags required to enable specific functionality are shown
+in the column **Feature flag**.
+
+| Feature | Default
implementation | Feature
flag | AppBuilder
constructor | Functionality |
+|----------------|---------------------------------------------------|:----------------:|------------------------------------------------------|----------------------------------------------------|
+| [Blocks] | [`mock_env().block`][mock_env_block] | | [`with_block`](app-builder#with_block) | Operations on blocks. |
+| [Api] | [`MockApi`][MockApi] | | [`with_api`](app-builder#with_api) | Access to CosmWasm API. |
+| [Storage] | [`MockStorage`][MockStorage] | | [`with_storage`](app-builder#with_storage) | Access to storage. |
+| [Bank] | [`BankKeeper`][BankKeeper] | | [`with_bank`](app-builder#with_bank) | Interactions with **Bank** module. |
+| [Staking] | [`StakeKeeper`][StakeKeeper] | `staking` | [`with_staking`](app-builder#with_staking) | Interactions with **Staking** module. |
+| [Distribution] | [`DistributionKeeper`][DistributionKeeper] | `staking` | [`with_distribution`](app-builder#with_distribution) | Interactions with **Distribution** module. |
+| [Governance] | [`GovFailingModule`][GovFailingModule] | | [`with_gov`](app-builder#with_gov) | Interactions with **Governance** module. |
+| [Stargate] | [`StargateFailing`][StargateFailing] | `stargate` | [`with_stargate`](app-builder#with_stargate) | Operations using `Stargate` and/or `Any` messages. |
+| [Wasm] | [`WasmKeeper`][WasmKeeper] | | [`with_wasm`](app-builder#with_wasm) | Interactions with **Wasm** module. |
+| [Custom] | [`FailingModule`][FailingModule] | | [`new_custom`](app-builder#new_custom) | Operations using custom module. |
+| [IBC] | [`IbcFailingModule`][IbcFailingModule] | `stargate` | [`with_ibc`](app-builder#with_ibc) | Inter-blockchain communication operations. |
+
+## Feature flags summary
+
+The following table summarizes feature flags supported by **MultiTest**.
+
+| Feature flag | Description |
+|----------------|-------------------------------------------------------------------------------------------------------------------------------------|
+| `backtrace` | Enables `backtrace` feature in _**anyhow**_ dependency. |
+| `staking` | Enables `staking` feature in _**cosmwasm-std**_ dependency and enables staking/distribution functionality in **MultiTest** library. |
+| `stargate` | Enables `stargate` feature in _**cosmwasm-std**_ dependency and enables stargate/IBC functionality in **MultiTest** library. |
+| `cosmwasm_1_1` | Enables `cosmwasm_1_1` feature in _**cosmwasm-std**_ dependency. |
+| `cosmwasm_1_2` | Enables `cosmwasm_1_2` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_1_1` feature in **MultiTest** library. |
+| `cosmwasm_1_3` | Enables `cosmwasm_1_3` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_1_2` feature in **MultiTest** library. |
+| `cosmwasm_1_4` | Enables `cosmwasm_1_4` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_1_3` feature in **MultiTest** library. |
+| `cosmwasm_2_0` | Enables `cosmwasm_2_0` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_1_4` feature in **MultiTest** library. |
+| `cosmwasm_2_1` | Enables `cosmwasm_2_1` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_2_0` feature in **MultiTest** library. |
+| `cosmwasm_2_2` | Enables `cosmwasm_2_2` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_2_1` feature in **MultiTest** library. |
+| `cosmwasm_3_0` | Enables `cosmwasm_3_0` feature in _**cosmwasm-std**_ dependency and additionally `cosmwasm_2_2` feature in **MultiTest** library. |
+
+## Starting point
+
+Usually, a good starting point when using **MultiTest** is the following dependency configuration in the **Cargo.toml** file:
+
+```toml title="Cargo.toml"
+[dependencies]
+cosmwasm-std = "3"
+
+[dev-dependencies]
+cw-multi-test = { version = "3", features = ["staking", "stargate", "cosmwasm_3_0"] }
+```
+
+[Blocks]: ./introduction.md
+[Api]: ./introduction.md
+[Storage]: ./introduction.md
+[Bank]: ./introduction.md
+[Staking]: ./introduction.md
+[Distribution]: ./introduction.md
+[Governance]: ./introduction.md
+[Stargate]: ./introduction.md
+[Wasm]: ./introduction.md
+[Custom]: ./introduction.md
+[IBC]: ./introduction.md
+[mock_env_block]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/fn.mock_env.html
+[MockApi]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html
+[MockStorage]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockStorage.html
+[BankKeeper]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.BankKeeper.html
+[StakeKeeper]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StakeKeeper.html
+[DistributionKeeper]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.DistributionKeeper.html
+[GovFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html
+[StargateFailing]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.StargateFailing.html
+[WasmKeeper]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.WasmKeeper.html
+[FailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.FailingModule.html
+[IbcFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.IbcFailingModule.html
diff --git a/docs/multi-test/getting-started/_category_.json b/docs/multi-test/getting-started/_category_.json
new file mode 100644
index 0000000..8aa5499
--- /dev/null
+++ b/docs/multi-test/getting-started/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Getting started",
+ "position": 3,
+ "link": {
+ "type": "doc",
+ "id": "introduction"
+ }
+}
diff --git a/docs/multi-test/getting-started/counter/_category_.json b/docs/multi-test/getting-started/counter/_category_.json
new file mode 100644
index 0000000..1d399e3
--- /dev/null
+++ b/docs/multi-test/getting-started/counter/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Counter",
+ "position": 1,
+ "link": {
+ "type": "doc",
+ "id": "counter"
+ }
+}
diff --git a/docs/multi-test/getting-started/counter/counter.md b/docs/multi-test/getting-started/counter/counter.md
new file mode 100644
index 0000000..69634ac
--- /dev/null
+++ b/docs/multi-test/getting-started/counter/counter.md
@@ -0,0 +1,108 @@
+# Counter
+
+The following sections describe how to create an example smart contract,
+which manages a **counter** that can be `initialized`, `incremented`, `decremented`, and `queried`.
+Later on, you will be [writing tests](writing-tests.mdx) for this smart contract using **MultiTest**.
+
+:::info
+
+**Counter** smart contract is a simplified version of the contract created from the
+[cw-template](https://github.com/CosmWasm/cw-template).
+Check [Setting up the contract](../../../core/installation#setting-up-the-contract) for more details.
+
+:::
+
+## Specification
+
+The example smart contract is a simple **counter** that allows users to initialize the counter,
+perform operations such as incrementing, decrementing, setting a specific value, and querying the
+current counter value. The primary purpose of this contract is to maintain and manipulate a counter
+value on the blockchain. This functionality can be utilized in various scenarios where a count or
+tally needs to be tracked, such as counting votes, tracking the number of actions performed,
+or maintaining a score in a game or competition.
+
+**Features:**
+
+- The counter can be initialized with a value of zero or any non-negative integer between 0 and 255.
+- Users can increment, decrement, or set the counter to a new value within the range of 0 to 255.
+- Boundary conditions are checked, preventing the counter from going below 0 or beyond 255.
+- Users can query the current value of the counter at any time.
+- The counter's value is persisted and limited to 8-bit unsigned integers [0..255].
+
+## Creating the counter project
+
+Smart contracts written in Rust are developed as Rust libraries, so let's first create a Rust
+library named **counter**.
+
+Change the working directory to your home directory:
+
+```shell
+cd ~
+```
+
+Create a dedicated directory to store your example smart contract:
+
+```shell
+mkdir my-contracts
+```
+
+Change the working directory to `my-contracts`:
+
+```shell
+cd my-contracts
+```
+
+Create a new Rust library named **counter**:
+
+```shell
+cargo init --lib counter
+```
+
+Change the working directory to `counter`:
+
+```shell
+cd counter
+```
+
+Newly created library contains the **Cargo.toml** file and **lib.rs** file in `src` directory,
+so the expected structure of the `counter` directory is:
+
+```text title="counter directory"
+.
+├── Cargo.toml
+└── src
+ └── lib.rs
+```
+
+By convention, the source code of the smart contract is placed in a file named **contract.rs**, and
+the messages processed by this contract are usually placed in file named **msg.rs**. Both files
+should be stored in `src` directory.
+
+Let's create an empty **contract.rs** file...
+
+```shell
+touch src/contract.rs
+```
+
+...and empty **msg.rs** file:
+
+```shell
+touch src/msg.rs
+```
+
+The final structure of the smart contract project placed in the `counter` directory should look like this:
+
+```text title="counter directory"
+.
+├── Cargo.toml
+└── src
+ ├── contract.rs
+ ├── lib.rs
+ └── msg.rs
+```
+
+## Filling the content
+
+In the previous section you have created a project structure for **counter** smart contract,
+but the source files are still empty. In the following chapter, we provide an example
+[**implementation**](./implementation.md) of the **counter** smart contract.
diff --git a/docs/multi-test/getting-started/counter/implementation.md b/docs/multi-test/getting-started/counter/implementation.md
new file mode 100644
index 0000000..f818176
--- /dev/null
+++ b/docs/multi-test/getting-started/counter/implementation.md
@@ -0,0 +1,468 @@
+---
+title: Implementation
+sidebar_position: 1
+---
+
+# Counter implementation
+
+The following code snippets present the content of [Cargo.toml](#cargotoml), [lib.rs](#librs),
+[msg.rs](#msgrs), and [contract.rs](#contractrs) files, respectively.
+You can just copy and paste the provided content to previously created empty files, temporarily
+skipping the detailed explanations. However, if you're curious about what happens inside each file,
+feel free to check the detailed explanations provided for each code snippet.
+
+## Cargo.toml
+
+```toml title="Cargo.toml" showLineNumbers
+[package]
+name = "counter"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[features]
+# use library feature to disable all instantiate/execute/query exports
+library = []
+
+[dependencies]
+cosmwasm-schema = "2"
+cosmwasm-std = { version = "2", features = ["cosmwasm_2_2"] }
+cw-storage-plus = "2"
+schemars = "0.8"
+serde = "1.0"
+
+[dev-dependencies]
+cw-multi-test = { version = "2", features = ["cosmwasm_2_2"] }
+```
+
+`Cargo.toml` file is a configuration file for a Rust project, in our case for a smart contract
+written in Rust. Here's a detailed explanation of each section and what it's doing.
+
+### \[package\] section
+
+```toml title="Cargo.toml" showLineNumbers
+[package]
+name = "counter"
+version = "0.1.0"
+edition = "2021"
+```
+
+- **`[package]`** section provides metadata about the Rust crate (smart contract library in our
+ case).
+- **`name = "counter"`** specifies the name of the crate, it's named **counter** like our smart
+ contract.
+- **`version = "0.1.0"`** indicates the current version of the package and the counter smart
+ contract.
+- **`edition = "2021"`** specifies the Rust edition being used; editions in Rust are sets of
+ language and compiler improvements, with 2021 being one of the latest editions at the time,
+ providing the latest features and enhancements.
+
+### \[lib\] section
+
+```toml title="Cargo.toml" showLineNumbers=8
+[lib]
+crate-type = ["cdylib", "rlib"]
+```
+
+- **`[lib]`** section specifies settings for building the library.
+- **`crate-type`** enumerates types of libraries to be produced during compiling.
+- **`"cdylib"`** specifies that the package will be compiled as a C-compatible dynamic library;
+ which is required for smart contracts to run on the CosmWasm runtime.
+- **`"rlib"`** specifies a Rust library file that can be used as a dependency for other Rust
+ projects, in our case for other smart contracts.
+
+### \[features\] section
+
+```toml title="Cargo.toml" showLineNumbers=11
+[features]
+# use library feature to disable all instantiate/execute/query exports
+library = []
+```
+
+- **`[features]`** section defines optional features for the Rust package.
+- **`library = []`** defines a feature named **library**, which when set, disables exporting smart
+ contract entry-points. Exporting entry points is necessary for interacting with the smart contract
+ on the blockchain. However, when the contract is used as a dependency by other contracts,
+ exporting these entry-points should be disabled to prevent unintended function name clashes.
+
+### \[dependencies\] section
+
+```toml title="Cargo.toml" showLineNumbers=15
+[dependencies]
+cosmwasm-schema = "2"
+cosmwasm-std = { version = "2", features = ["cosmwasm_2_2"] }
+cw-storage-plus = "2"
+schemars = "0.8"
+serde = "1.0"
+```
+
+- **`[dependencies]`** section lists the libraries that the package depends on.
+- **`cosmwasm-schema`** is used for generating JSON schemas from Rust data structures, which is
+ useful for documentation and ensuring compatibility of messages and queries.
+- **`cosmwasm-std`** is the standard library for CosmWasm contracts, providing common types and
+ utilities needed for interacting with the CosmWasm runtime.
+- **`cw-storage-plus`** is a library that provides advanced storage abstractions and utilities on
+ top of the basic storage capabilities in CosmWasm, making it easier to manage state within contracts.
+- **`schemars`** is a library for generating JSON schemas, which complements `cosmwasm-schema` by
+ providing additional features for schema generation.
+- **`serde`** is a widely used serialization library in Rust, allowing easy conversion of Rust data
+ structures to and from formats like JSON, which is crucial for data interchange in smart contracts.
+
+### \[dev-dependencies\] section
+
+```toml title="Cargo.toml" showLineNumbers=22
+[dev-dependencies]
+cw-multi-test = { version = "2", features = ["cosmwasm_2_2"] }
+```
+
+- **`[dev-dependencies]`** section lists dependencies that are only needed for development and
+ testing.
+- **`cw-multi-test`** is a name of **`MultiTest`** library, and should **ALWAYS** be placed in
+ **[dev-dependencies]** section.
+
+Overall, this `Cargo.toml` file configures a Rust project for a CosmWasm-based smart contract. It
+sets up the basic package details, specifies how the contract should be compiled, defines
+dependencies for core functionality and testing, and includes features to enable or disable certain
+parts of the contract code. This setup ensures the contract can be developed, tested, and deployed
+effectively on the blockchain within the CosmWasm ecosystem.
+
+## lib.rs
+
+```rust title="lib.rs" showLineNumbers
+pub mod contract;
+pub mod msg;
+```
+
+The `lib.rs` file in a Rust project serves as the main entry point for defining the structure of a
+library. In the context of our example **counter** smart contract, the `lib.rs` file is defining and
+organizing the modules that make up the contract. Recall the **counter** project file structure:
+
+```text {4,6} title="counter directory content"
+.
+├── Cargo.toml
+└── src
+ ├── contract.rs
+ ├── lib.rs
+ └── msg.rs
+```
+
+There are two modules in the project: `contract.rs` and `msg.rs`. That's why in the `lib.rs` file
+there are two declarations:
+
+- `pub mod contract;`
This line declares a public module named **contract**; tells Rust
+ to include the code from a file named `contract.rs` located in the same directory and makes the
+ module publicly accessible (`pub` keyword), which means that other modules or external code can
+ access the entry-points of our smart contract.
+- `pub mod msg;`
This line declares a public module named **msg**; includes the code
+ from a file named `msg.rs` and also makes this module public which allows other parts of the code
+ (especially our **counter** smart contract) to access the messages defined here.
+
+Overall, this `lib.rs` file is setting up the main structure of the smart contract by defining its
+key components as separate modules. This organization helps in keeping the code clean, modular, and
+maintainable by separating the core contract logic (`contract.rs`) from the message and query
+definitions (`msg.rs`). This modular approach makes the smart contract easier to understand, extend,
+and test.
+
+## msg.rs
+
+The **msg** module in file `msg.rs` typically defines the messages and queries that the smart
+contract accepts and responds to. Messages are usually structured as Rust enums or structs and
+define the input and output interfaces of the contract. In our example this includes messages shown
+below.
+
+```rust title="msg.rs" showLineNumbers
+use cosmwasm_schema::{cw_serde, QueryResponses};
+
+#[cw_serde]
+pub enum CounterInitMsg {
+ Zero,
+ Set(u8),
+}
+
+#[cw_serde]
+pub enum CounterExecMsg {
+ Inc,
+ Dec,
+ Set(u8),
+}
+
+#[cw_serde]
+#[derive(QueryResponses)]
+pub enum CounterQueryMsg {
+ #[returns(CounterResponse)]
+ Value,
+}
+
+#[cw_serde]
+pub struct CounterResponse {
+ pub value: u8,
+}
+```
+
+Let's take a detailed look at the implementation of these messages.
+
+### Imports
+
+```rust title="msg.rs" showLineNumbers
+use cosmwasm_schema::cw_serde;
+```
+
+Required imports, like `cw_serde` annotation.
+
+### Instantiation message
+
+This message is passed to `instantiate` entry-point.
+
+```rust title="msg.rs" showLineNumbers=3
+#[cw_serde]
+pub enum CounterInitMsg {
+ Zero,
+ Set(u8),
+}
+```
+
+`CounterInitMsg` enumeration is used to initialize the contract.
+`CounterInitMsg::Zero` variant initializes the counter with the zero value,
+and `CounterInitMsg::Set` variant initializes the counter with an arbitrary value in range 0 to 255.
+This message is passed to `instantiate` entry-point of the counter smart contract.
+
+### Execution message
+
+This message is passed to `execute` entry-point.
+
+```rust title="msg.rs" showLineNumbers=9
+#[cw_serde]
+pub enum CounterExecMsg {
+ Inc,
+ Dec,
+ Set(u8),
+}
+```
+
+`CounterExecMsg` enumeration is used to perform various actions within the contract,
+especially incrementing (the `CounterExecMsg::Inc` variant), decrementing (the `CounterExecMsg::Dec` variant)
+and setting an arbitrary counter value (the `CounterExecMsg::Set` variant).
+This message is passed to `execute` entry-point of the counter smart contract.
+
+### Query message
+
+This message is passed to `query` entry-point.
+
+```rust title="msg.rs" showLineNumbers=16
+#[cw_serde]
+#[derive(QueryResponses)]
+pub enum CounterQueryMsg {
+ #[returns(CounterResponse)]
+ Value,
+}
+```
+
+`CounterQueryMsg` enumeration, with its single variant `CounterQueryMsg::Value` is used to query
+the state of the contract, in our case to retrieve the current counter value. This message is passed
+to `query` entry-point of the counter smart contract. The `#[derive(QueryResponses)]` annotation informs
+the schema generator about the type of the value returned by the query.
+
+### Response message
+
+This message is returned from `query` entry-point and passed to the user.
+
+```rust title="msg.rs" showLineNumbers=21
+#[cw_serde]
+pub struct CounterResponse {
+ pub value: u8,
+}
+```
+
+`CounterResponse` struct with a single field `value`, used to pass the responses (results) from the queries.
+
+Overall, the `msg.rs` file is basically setting up the contract’s _social skills_, defining how it
+interacts with the outside world by initializing, executing actions, and answering questions. Each
+message type is a different way of communicating with the counter, making it an easy-going,
+versatile smart contract, ready for action.
+
+## contract.rs
+
+Typically, in a smart contract project, the **contract** module (placed in the `contract.rs` file)
+contains the core logic of the contract, including functions (entry-points) for instantiation,
+execution, querying and migrating. This is where the main functionality of the smart contract is
+implemented. And this is also the case for our **counter** smart contract. The full source code is
+shown below.
+
+```rust title="contract.rs" showLineNumbers
+#[cfg(not(feature = "library"))]
+use cosmwasm_std::entry_point;
+
+use crate::msg::{CounterExecMsg, CounterInitMsg, CounterQueryMsg, CounterResponse};
+use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError};
+use cw_storage_plus::Item;
+
+const COUNTER: Item = Item::new("value");
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn instantiate(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterInitMsg,
+) -> Result {
+ COUNTER.save(
+ deps.storage,
+ &match msg {
+ CounterInitMsg::Zero => 0,
+ CounterInitMsg::Set(new_value) => new_value,
+ },
+ )?;
+ Ok(Response::default())
+}
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn execute(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterExecMsg,
+) -> Result {
+ COUNTER.update::<_, StdError>(deps.storage, |old_value| {
+ Ok(match msg {
+ CounterExecMsg::Inc => old_value.saturating_add(1),
+ CounterExecMsg::Dec => old_value.saturating_sub(1),
+ CounterExecMsg::Set(new_value) => new_value,
+ })
+ })?;
+ Ok(Response::default())
+}
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn query(deps: Deps, _env: Env, msg: CounterQueryMsg) -> Result {
+ match msg {
+ CounterQueryMsg::Value => Ok(to_json_binary(&CounterResponse {
+ value: COUNTER.may_load(deps.storage)?.unwrap(),
+ })?),
+ }
+}
+```
+
+Let's take a detailed look at this implementation.
+
+### Conditional imports
+
+```rust title="contract.rs" showLineNumbers=1
+#[cfg(not(feature = "library"))]
+use cosmwasm_std::entry_point;
+```
+
+The import shown above is used for conditional compilation in CosmWasm smart contracts. It ensures
+that the `entry_point` annotation is only included when the contract is being compiled as a
+standalone WASM binary, not as a library. The `entry_point` annotation is essential for defining the
+main functions of the smart contract, such as instantiate, execute, and query, which are responsible
+for interacting with the contract. If you're using this smart contract in another project, this
+configuration ensures that unnecessary code isn't included when compiling it as a library.
+
+### Imports
+
+```rust title="contract.rs" showLineNumbers=4
+use crate::msg::{CounterExecMsg, CounterInitMsg, CounterQueryMsg, CounterResponse};
+use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError};
+use cw_storage_plus::Item;
+```
+
+These are additional imports required to compile the contract. The first `use` statement
+imports message structures for handling execution, initialization, and queries related to a
+counter-based smart contract. The second `use` imports essential tools and types from the
+CosmWasm standard library, required for interacting with the blockchain environment, converting
+data, and accessing dependencies. The third `use` brings in the `Item` type, which is
+needed for storing single values in the contract’s persistent storage.
+
+### Storage variable definition
+
+```rust title="contract.rs" showLineNumbers=8
+const COUNTER: Item = Item::new("value");
+```
+
+`COUNTER` is a storage variable (although declared as `const`) for a counter,
+represented as an 8-bit unsigned integer. The `"value"` string is the key used to store and
+retrieve the counter value in the contract's persistent storage. This is used for tracking a counter
+value that can be incremented, decremented, queried, or reset by the smart contract. More details
+about the [Item](../../../storage-plus/containers/item.md) type can be found in
+[cw-storage-plus](../../../storage-plus) documentation.
+
+### _instantiate_ entrypoint
+
+The `instantiate` function (entry-point) is called during the instantiation of the smart
+contract. Depending on the value of the message passed in `msg` argument, the counter will be
+initialized with zero or with the value provided in `CounterInitMsg::Set` variant. Using the
+`COUNTER` variable, the initial value is saved in the contract's persistent storage for
+future use.
+
+```rust title="contract.rs" showLineNumbers=10
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn instantiate(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterInitMsg,
+) -> Result {
+ COUNTER.save(
+ deps.storage,
+ &match msg {
+ CounterInitMsg::Zero => 0,
+ CounterInitMsg::Set(new_value) => new_value,
+ },
+ )?;
+ Ok(Response::default())
+}
+```
+
+### _execute_ entrypoint
+
+The `execute` function (entry-point) is called whenever the user wants to interact with the
+contract, especially when the value of the counter should be incremented, decremented or reset.
+Depending on the `msg` value passed as an argument, the "old value" of the counter will be
+incremented by one for `CounterExecMsg::Inc` variant, decremented by one for
+`CounterExecMsg::Dec` variant, or replaced with the new value for
+`CounterExecMsg::Set` variant. The new value will be saved in the contract's persistent
+storage by calling `update` function of the `COUNTER` variable.
+
+```rust title="contract.rs" showLineNumbers=27
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn execute(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterExecMsg,
+) -> Result {
+ COUNTER.update::<_, StdError>(deps.storage, |old_value| {
+ Ok(match msg {
+ CounterExecMsg::Inc => old_value.saturating_add(1),
+ CounterExecMsg::Dec => old_value.saturating_sub(1),
+ CounterExecMsg::Set(new_value) => new_value,
+ })
+ })?;
+ Ok(Response::default())
+}
+```
+
+### _query_ entrypoint
+
+The `query` function (entry-point) is called whenever the user asks the counter smart
+contract for the current value. The counter value is retrieved from the contract's persistent
+storage, wrapped with `CounterResponse` type and returned to the user.
+
+```rust title="contract.rs" showLineNumbers=44
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn query(deps: Deps, _env: Env, msg: CounterQueryMsg) -> Result {
+ match msg {
+ CounterQueryMsg::Value => Ok(to_json_binary(&CounterResponse {
+ value: COUNTER.may_load(deps.storage)?.unwrap(),
+ })?),
+ }
+}
+```
+
+## What next?
+
+Having the **counter** smart contract prepared, you can begin writing tests using **MultiTest**!
diff --git a/docs/multi-test/getting-started/introduction.mdx b/docs/multi-test/getting-started/introduction.mdx
new file mode 100644
index 0000000..d1901de
--- /dev/null
+++ b/docs/multi-test/getting-started/introduction.mdx
@@ -0,0 +1,13 @@
+# Getting started
+
+This unit is designed to help you quickly become familiar with the fundamental aspects of testing
+smart contracts using **MultiTest**. It provides a practical example and best practices to ensure
+a smooth start with using **MultiTest** for testing smart contracts.
+In the following chapters, you will be:
+
+- designing an example [**counter**](./counter) smart contract,
+- [**writing tests**](./counter) for the counter smart contract.
+
+The example **counter** smart contract and all test cases are provided in two versions: one using
+pure CosmWasm libraries and the other using the Sylvia framework. The functionality of the
+**counter** smart contract is the same in both versions.
diff --git a/docs/multi-test/getting-started/writing-tests/_category_.json b/docs/multi-test/getting-started/writing-tests/_category_.json
new file mode 100644
index 0000000..7d6b28f
--- /dev/null
+++ b/docs/multi-test/getting-started/writing-tests/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Writing tests",
+ "position": 2,
+ "link": {
+ "type": "doc",
+ "id": "writing-tests"
+ }
+}
diff --git a/docs/multi-test/getting-started/writing-tests/writing-tests.md b/docs/multi-test/getting-started/writing-tests/writing-tests.md
new file mode 100644
index 0000000..be7e320
--- /dev/null
+++ b/docs/multi-test/getting-started/writing-tests/writing-tests.md
@@ -0,0 +1,306 @@
+# Writing tests
+
+Having the **counter** smart contract set up, let's first check if the project compiles:
+
+```shell
+cargo build
+```
+
+```text title="output"
+ [32;1mUpdating[0m crates.io index
+ [32;1mLocking[0m 112 packages to latest compatible versions
+ ⋮
+[32;1mCompiling[0m cosmwasm-crypto v2.1.3
+[32;1mCompiling[0m cosmwasm-std v2.1.3
+[32;1mCompiling[0m cw-storage-plus v2.0.0
+[32;1mCompiling[0m counter v0.1.0 (/home/user/my-contracts/counter)
+ [32;1mFinished[0m `dev` profile [unoptimized + debuginfo] target(s) in 3.27s
+```
+
+If the output is similar to the one shown above, it looks like the **counter** smart contract has
+been built successfully.
+
+It is a very good habit to run [Rust linter](https://doc.rust-lang.org/clippy) after each code
+change, so let's run it before we move forward.
+
+```shell
+cargo clippy
+```
+
+```text title="output"
+ ⋮
+[32;1mChecking[0m cosmwasm-crypto v2.1.3
+[32;1mChecking[0m cosmwasm-std v2.1.3
+[32;1mChecking[0m cw-storage-plus v2.0.0
+[32;1mChecking[0m counter v0.1.0 (/home/user/mt-test-examples/mte-counter)
+[32;1mFinished[0m `dev` profile [unoptimized + debuginfo] target(s) in 17.28s
+```
+
+Luckily, `clippy` reports no issues for the **counter** smart contract.
+
+## Preparing the directory structure for tests
+
+Before we start writing tests, we need to set up the directories and files for the test cases. The
+final directory and file structure are shown below.
+
+```ansi showLineNumbers {7-11} filename="counter (directory)"
+[34;1m.[0m
+├── Cargo.toml
+├── [34;1msrc[0m
+│ ├── contract.rs
+│ ├── lib.rs
+│ └── msg.rs
+└── [34;1mtests[0m
+ ├── mod.rs
+ └── [34;1mmultitest[0m
+ ├── mod.rs
+ └── test_counter.rs
+```
+
+:::tip
+
+There are several configurations possible for placing tests in Rust. For the purpose of this example,
+we have chosen to place all test cases outside **`src`** directory, in a new directory named **`tests`**.
+
+:::
+
+:::tip
+
+Note, that both directories **`src`** and **`tests`** are placed at the root of the project (in the `counter` directory).
+
+:::
+
+Let's begin by creating the `tests` directory:
+
+```shell copy filename="TERMINAL"
+mkdir tests
+```
+
+Then create an empty `mod.rs` file inside the `tests` directory:
+
+```shell copy filename="TERMINAL"
+touch tests/mod.rs
+```
+
+Now, copy and paste the following content to `tests/mod.rs` file:
+
+```rust copy filename="tests/mod.rs"
+mod multitest;
+```
+
+By convention, we place all **`MultiTest`** test cases under the `multitest` directory, so let's
+create it:
+
+```shell copy filename="TERMINAL"
+mkdir tests/multitest
+```
+
+Inside the `tests/multitest` directory we should also create an empty file named `mod.rs`:
+
+```shell copy filename="TERMINAL"
+touch tests/multitest/mod.rs
+```
+
+And populate it with the following content (just copy and paste it):
+
+```rust copy filename="tests/multitest/mod.rs"
+mod test_counter;
+```
+
+Finally, inside the `tests/multitest` directory, we create a file named `test_counter.rs`:
+
+```shell copy filename="TERMINAL"
+touch tests/multitest/test_counter.rs
+```
+
+For now, we will leave this file empty, but later, we will place all our test cases there.
+
+Now that the directory structure for tests is ready, it's time to run all tests.
+
+## Running all tests for counter
+
+Once the directories and files are set up for tests, let's execute them:
+
+```shell copy filename="TERMINAL"
+cargo test
+```
+
+The expected output should be similar to the one shown below:
+
+```ansi {6,12,16} showLineNumbers filename="OUTPUT"
+ [32;1mFinished[0m `test` profile [unoptimized + debuginfo] target(s) in 17.96s
+ [32;1mRunning[0m unittests src/lib.rs (target/debug/deps/counter-f350df45a1cd1c74)
+
+running 0 tests
+
+test result: [32mok[0m[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
+ [32;1mRunning[0m tests/mod.rs (target/debug/deps/mod-54761c1d31e6d0fe)
+
+running 0 tests
+
+test result: [32mok[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
+ [32;1mDoc-tests[0m counter
+
+running 0 tests
+
+test result: [32mok[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+```
+
+Rust testing framework searches for several types of tests in the project, counts all test cases and
+executes them. In our example - while we haven't written any single test yet - there is nothing to
+execute. The reported number of executed tests is **0** for unit tests (line 2), **0** for
+integration tests (line 12) and **0** for documentation tests (line 16).
+
+Similarly, to execute all tests using [cargo-nextest](https://nexte.st), type:
+
+```shell copy filename="TERMINAL"
+cargo nextest run
+```
+
+The expected output is:
+
+```ansi {4} showLineNumbers filename="OUTPUT"
+ [32;1mFinished[0m `test` profile [unoptimized + debuginfo] target(s) in 0.06s
+ [32;1mStarting[0m 0 tests across 2 binaries (run ID: 3e0cbabb-3ef9-4b2f-98a8-d375bc510845, nextest profile: default)
+------------
+ [32;1mSummary[0m [ 0.000s] 0 tests run: 0 [32;1mpassed[0m, 0 [33;1mskipped[0m
+```
+
+[cargo-nextest](https://nexte.st) reports in a user-friendly manner that there were no tests to run (**line 4**).
+
+Now, you have almost everything you need to start testing the **counter** smart contract. What’s left is to prepare
+the tools for measuring code coverage, which is a handy way to track progress in writing tests.
+
+## Preparing the code coverage script
+
+Typing the entire command for Tarpaulin every time you want to measure current code coverage can be
+quite tedious, so let's prepare a short script to automate this task.
+
+Create an empty file named `coverage.sh` in the `counter` directory:
+
+```shell copy filename="TERMINAL"
+touch coverage.sh
+```
+
+Populate it with the following content:
+
+```shell copy filename="coverage.sh"
+#!/usr/bin/env bash
+
+# generate coverage report
+cargo tarpaulin --force-clean --out Html --engine llvm --output-dir "$(pwd)/target/coverage-report"
+
+# display link to coverage report
+echo "Report: file://$(pwd)/target/coverage-report/tarpaulin-report.html"
+```
+
+Finally, make this file executable:
+
+```shell filename="TERMINAL"
+chmod +x coverage.sh
+```
+
+The complete file structure of the **counter** smart contract project, with the code coverage script
+should now look like this:
+
+```shell filename="TERMINAL"
+tree
+```
+
+```ansi {3} filename="counter (directory)"
+[34;1m.[0m
+├── Cargo.toml
+├── [32;1mcoverage.sh[0m
+├── [34;1msrc[0m
+│ ├── contract.rs
+│ ├── lib.rs
+│ └── msg.rs
+└── [34;1mtests[0m
+ ├── mod.rs
+ └── [34;1mmultitest[0m
+ ├── mod.rs
+ └── test_counter.rs
+```
+
+## Measuring code coverage
+
+With the code coverage script at hand, measuring code coverage is now as simple as typing:
+
+```shell copy filename="TERMINAL"
+./coverage.sh
+```
+
+The result should be similar to this (only the last few lines are shown):
+
+```ansi filename="OUTPUT"
+⋮
+|| Tested/Total Lines:
+|| src/contract.rs: 0/18
+||
+0.00% coverage, 0/18 lines covered
+Report: file:///home/user/counter/target/coverage-report/tarpaulin-report.html
+```
+
+Additionally, Tarpaulin generates a coverage report in HTML format, that can be viewed directly in a browser.
+As expected, the current code coverage for the **counter** smart contract is **0.00%** since we haven't written
+any tests yet. Follow the next chapters, and make the code coverage report shine green.
+
+```rust title="Code coverage report" showLineNumbers {11-25,28-42,45-51}
+#[cfg(not(feature = "library"))]
+use cosmwasm_std::entry_point;
+
+use crate::msg::{CounterExecMsg, CounterInitMsg, CounterQueryMsg, CounterResponse};
+use cosmwasm_std::{to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError};
+use cw_storage_plus::Item;
+
+const COUNTER: Item = Item::new("value");
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn instantiate(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterInitMsg,
+) -> Result {
+ COUNTER.save(
+ deps.storage,
+ &match msg {
+ CounterInitMsg::Zero => 0,
+ CounterInitMsg::Set(new_value) => new_value,
+ },
+ )?;
+ Ok(Response::default())
+}
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn execute(
+ deps: DepsMut,
+ _env: Env,
+ _info: MessageInfo,
+ msg: CounterExecMsg,
+) -> Result {
+ COUNTER.update::<_, StdError>(deps.storage, |old_value| {
+ Ok(match msg {
+ CounterExecMsg::Inc => old_value.saturating_add(1),
+ CounterExecMsg::Dec => old_value.saturating_sub(1),
+ CounterExecMsg::Set(new_value) => new_value,
+ })
+ })?;
+ Ok(Response::default())
+}
+
+#[cfg_attr(not(feature = "library"), entry_point)]
+pub fn query(deps: Deps, _env: Env, msg: CounterQueryMsg) -> Result {
+ match msg {
+ CounterQueryMsg::Value => Ok(to_json_binary(&CounterResponse {
+ value: COUNTER.may_load(deps.storage)?.unwrap(),
+ })?),
+ }
+}
+```
+
+## Writing tests for smart contracts
+
+Now it is time to start implementing tests for the **counter** smart contract.
diff --git a/docs/multi-test/governance.md b/docs/multi-test/governance.md
new file mode 100644
index 0000000..eff09ca
--- /dev/null
+++ b/docs/multi-test/governance.md
@@ -0,0 +1,199 @@
+---
+sidebar_position: 13
+---
+
+# Governance
+
+**`MultiTest`** provides two minimal implementations of the governance module that **do not**
+replicate the real blockchain behavior: [`GovAcceptingModule`][GovAcceptingModule] and
+[`GovFailingModule`][GovFailingModule]. The default chain configuration is using
+[`GovFailingModule`][GovFailingModule].
+
+The following sections provide examples of how to initialize a specific governance module and how to
+execute governance messages in tests.
+
+## Default governance module
+
+Currently, in **`MultiTest`**, the default governance module is
+[`GovFailingModule`][GovFailingModule], and no additional configuration is required to use
+it.
+
+### `GovMsg::Vote`
+
+```rust showLineNumbers {5,20} copy /GovMsg::Vote/
+use cosmwasm_std::{GovMsg, VoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, IntoAddr};
+
+// Build the application with default (always failing) governance module.
+let mut app = AppBuilder::default().build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for vote.
+let vote_msg = GovMsg::Vote {
+ proposal_id: 1,
+ option: VoteOption::Yes,
+};
+
+// Execute vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();
+
+// Always an error is returned.
+assert!(response.to_string().starts_with("Unexpected exec msg Vote"));
+```
+
+### `GovMsg::VoteWeighted`
+
+```rust showLineNumbers {5,23} copy /GovMsg::VoteWeighted/
+use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, IntoAddr};
+
+// Build the application with default (always failing) governance module.
+let mut app = AppBuilder::default().build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for weighted vote.
+let vote_msg = GovMsg::VoteWeighted {
+ proposal_id: 1,
+ options: vec![WeightedVoteOption {
+ option: VoteOption::Yes,
+ weight: Decimal::new(Uint128::new(12)),
+ }],
+};
+
+// Execute weighted vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();
+
+// Always an error is returned.
+assert!(response.to_string().starts_with("Unexpected exec msg VoteWeighted"));
+```
+
+## Failing governance module
+
+Executing governance messages using [`GovFailingModule`][GovFailingModule] always returns an
+error.
+
+### `GovMsg::Vote`
+
+```rust showLineNumbers {6,22} copy /GovMsg::Vote/
+use cosmwasm_std::{GovMsg, VoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, GovFailingModule, IntoAddr};
+
+// Build the application with always failing governance module.
+let mut app = AppBuilder::default()
+ .with_gov(GovFailingModule::new())
+ .build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for vote.
+let vote_msg = GovMsg::Vote {
+ proposal_id: 1,
+ option: VoteOption::Yes,
+};
+
+// Execute vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();
+
+// Always an error is returned.
+assert!(response.to_string().starts_with("Unexpected exec msg Vote"));
+```
+
+### `GovMsg::VoteWeighted`
+
+```rust showLineNumbers {6,25} copy /GovMsg::VoteWeighted/
+use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, GovFailingModule, IntoAddr};
+
+// Build the application with always failing governance module.
+let mut app = AppBuilder::default()
+ .with_gov(GovFailingModule::new())
+ .build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for weighted vote.
+let vote_msg = GovMsg::VoteWeighted {
+ proposal_id: 1,
+ options: vec![WeightedVoteOption {
+ option: VoteOption::Yes,
+ weight: Decimal::new(Uint128::new(12)),
+ }],
+};
+
+// Execute weighted vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap_err();
+
+// Always an error is returned.
+assert!(response.to_string().starts_with("Unexpected exec msg VoteWeighted"));
+```
+
+## Accepting governance module
+
+Executing governance messages using [`GovAcceptingModule`][GovAcceptingModule] always
+succeeds, but the returned data is empty.
+
+### `GovMsg::Vote`
+
+```rust showLineNumbers {6,22} copy /GovMsg::Vote/
+use cosmwasm_std::{GovMsg, VoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, GovAcceptingModule, IntoAddr};
+
+// Build the application with always failing governance module.
+let mut app = AppBuilder::default()
+ .with_gov(GovAcceptingModule::new())
+ .build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for vote.
+let vote_msg = GovMsg::Vote {
+ proposal_id: 1,
+ option: VoteOption::Yes,
+};
+
+// Execute vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap();
+
+// Always empty data is returned.
+assert_eq!(None, response.data);
+```
+
+### `GovMsg::VoteWeighted`
+
+```rust showLineNumbers {6,25} copy /GovMsg::VoteWeighted/
+use cosmwasm_std::{Decimal, GovMsg, Uint128, VoteOption, WeightedVoteOption};
+use cw_multi_test::{no_init, AppBuilder, Executor, GovAcceptingModule, IntoAddr};
+
+// Build the application with always failing governance module.
+let mut app = AppBuilder::default()
+ .with_gov(GovAcceptingModule::new())
+ .build(no_init);
+
+// Prepare sender address.
+let sender_addr = "sender".into_addr();
+
+// Prepare message for weighted vote.
+let vote_msg = GovMsg::VoteWeighted {
+ proposal_id: 1,
+ options: vec![WeightedVoteOption {
+ option: VoteOption::Yes,
+ weight: Decimal::new(Uint128::new(12)),
+ }],
+};
+
+// Execute weighted vote governance message.
+let response = app.execute(sender_addr, vote_msg.into()).unwrap();
+
+// Always empty data is returned.
+assert_eq!(None, response.data);
+```
+
+[GovAcceptingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovAcceptingModule.html
+[GovFailingModule]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.GovFailingModule.html
From bc800ad3529428d4c28b33edfc126eb477c135da Mon Sep 17 00:00:00 2001
From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com>
Date: Fri, 10 Oct 2025 11:37:59 +0200
Subject: [PATCH 2/4] Added more content.
---
docs/multi-test/addresses.md | 17 -
docs/multi-test/addresses/_category_.json | 8 +
docs/multi-test/addresses/addresses.md | 7 +
docs/multi-test/addresses/contract-address.md | 7 +
docs/multi-test/addresses/user-address.md | 407 ++++++++++++++++++
.../multi-test/addresses/validator-address.md | 7 +
docs/multi-test/app-builder.md | 2 +-
.../getting-started/counter/_category_.json | 2 +-
.../getting-started/counter/implementation.md | 2 +-
.../counter/{counter.md => introduction.md} | 2 +-
.../{introduction.mdx => introduction.md} | 4 +-
.../writing-tests/_category_.json | 2 +-
.../{writing-tests.md => introduction.md} | 0
docs/multi-test/storage.md | 218 ++++++++++
14 files changed, 661 insertions(+), 24 deletions(-)
delete mode 100644 docs/multi-test/addresses.md
create mode 100644 docs/multi-test/addresses/_category_.json
create mode 100644 docs/multi-test/addresses/addresses.md
create mode 100644 docs/multi-test/addresses/contract-address.md
create mode 100644 docs/multi-test/addresses/user-address.md
create mode 100644 docs/multi-test/addresses/validator-address.md
rename docs/multi-test/getting-started/counter/{counter.md => introduction.md} (96%)
rename docs/multi-test/getting-started/{introduction.mdx => introduction.md} (77%)
rename docs/multi-test/getting-started/writing-tests/{writing-tests.md => introduction.md} (100%)
create mode 100644 docs/multi-test/storage.md
diff --git a/docs/multi-test/addresses.md b/docs/multi-test/addresses.md
deleted file mode 100644
index 0d28dc0..0000000
--- a/docs/multi-test/addresses.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-tags: ["multitest", "addresses"]
----
-
-import { Cards } from "nextra/components";
-
-# Addresses
-
-The following chapters provide useful explanations of how addresses are managed in **`MultiTest`**.
-
-Click on any of the cards below to learn more about each address category.
-
-
-
-
-
-
diff --git a/docs/multi-test/addresses/_category_.json b/docs/multi-test/addresses/_category_.json
new file mode 100644
index 0000000..8e460ab
--- /dev/null
+++ b/docs/multi-test/addresses/_category_.json
@@ -0,0 +1,8 @@
+{
+ "label": "Addresses",
+ "position": 8,
+ "link": {
+ "type": "doc",
+ "id": "addresses"
+ }
+}
diff --git a/docs/multi-test/addresses/addresses.md b/docs/multi-test/addresses/addresses.md
new file mode 100644
index 0000000..839ae9f
--- /dev/null
+++ b/docs/multi-test/addresses/addresses.md
@@ -0,0 +1,7 @@
+# Addresses
+
+The following chapters provide useful explanations of how addresses are managed in **MultiTest**:
+
+- [User address](./user-address.md)
+- [Contract address](./contract-address.md)
+- [Validator address](./validator-address.md)
diff --git a/docs/multi-test/addresses/contract-address.md b/docs/multi-test/addresses/contract-address.md
new file mode 100644
index 0000000..b02e70b
--- /dev/null
+++ b/docs/multi-test/addresses/contract-address.md
@@ -0,0 +1,7 @@
+---
+sidebar_position: 2
+---
+
+# Contract address
+
+(WIP)
diff --git a/docs/multi-test/addresses/user-address.md b/docs/multi-test/addresses/user-address.md
new file mode 100644
index 0000000..d029701
--- /dev/null
+++ b/docs/multi-test/addresses/user-address.md
@@ -0,0 +1,407 @@
+---
+sidebar_position: 1
+---
+
+# 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):
+
+```rust showLineNumbers {3,5} copy /addr_make/
+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:
+
+```rust showLineNumbers {3,5} copy /addr_make/
+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`][MockApiBech32] and [`MockApiBech32m`][MockApiBech32m] structs can be
+used along with `with_api` method of `AppBuilder`.
+
+If the address should be encoded in **Bech32** format then use
+[`MockApiBech32`][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:
+
+```rust showLineNumbers {4,7} copy /addr_make/ /MockApiBech32::new/
+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`][MockApiBech32m] to configure the `AppBuilder`:
+
+```rust showLineNumbers {4,7} copy /addr_make/ /MockApiBech32m::new/
+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**:
+
+```rust showLineNumbers {4,7} copy /addr_make/ /MockApiBech32m::new/
+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`][IntoAddr] trait
+
+The most generic and future-proof way to generate a user address is by using
+[`IntoAddr`][IntoAddr] trait. Internally, this trait uses [`MockApi`][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:
+
+```rust showLineNumbers {3} copy /into_addr/
+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:
+
+```rust showLineNumbers {3} copy /into_addr_with_prefix/
+use cw_multi_test::IntoAddr;
+
+let addr = "owner".into_addr_with_prefix("nebula");
+
+assert_eq!(
+ "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
+ addr.as_str()
+);
+```
+
+## IntoBech32
+
+> 🖝 Using [`IntoBech32`][IntoBech32] trait
+
+When you want to stick to **Bech32** format in tests, then always use
+[`IntoBech32`][IntoBech32] trait. To generate an address with the default prefix
+**cosmwasm**, just call `into_bech32` method on any string like in line 3:
+
+```rust showLineNumbers {3} copy /into_bech32/
+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:
+
+```rust showLineNumbers {3} copy /into_bech32_with_prefix/
+use cw_multi_test::IntoBech32;
+
+let addr = "owner".into_bech32_with_prefix("nebula");
+
+assert_eq!(
+ "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
+ addr.as_str()
+)
+```
+
+## IntoBech32m
+
+> 🖝 Using [`IntoBech32m`][IntoBech32m] trait
+
+In case you would need **Bech32m** format while testing your contracts, then use
+[`IntoBech32m`][IntoBech32m] trait. An address with the default prefix **cosmwasm** can be
+generated by calling `into_bech32m` method on any string (line 3):
+
+```rust showLineNumbers {3} copy /into_bech32m/
+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:
+
+```rust showLineNumbers {3} copy /into_bech32m_with_prefix/
+use cw_multi_test::IntoBech32m;
+
+let addr = "owner".into_bech32m_with_prefix("nebula");
+
+assert_eq!(
+ "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsevs0fr",
+ addr.as_str()
+);
+```
+
+:::tip
+
+All the methods of generating user addresses described above are built on the functionality
+provided by the [`MockApi`][MockApi], [`MockApiBech32`][MockApiBech32] and
+[`MockApiBech32m`][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 [`MockApi`][MockApi] struct
+
+To generate an address with default prefix **cosmwasm** encoded in **Bech32** format use method
+`addr_make` on default instance of [`MockApi`][MockApi]:
+
+```rust showLineNumbers {3} copy /addr_make/
+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:
+
+```rust showLineNumbers {3} copy /with_prefix/ /addr_make/
+use cosmwasm_std::testing::MockApi;
+
+let addr = MockApi::default().with_prefix("nebula").addr_make("owner");
+
+assert_eq!(
+ "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
+ addr.as_str()
+);
+```
+
+## MockApiBech32
+
+> 🖝 Using [`MockApiBech32`][MockApiBech32] struct
+
+**cosmwasm** prefix and **Bech32** encoding:
+
+```rust showLineNumbers {3} copy /MockApiBech32::new/ /addr_make/
+use cw_multi_test::MockApiBech32;
+
+let addr = MockApiBech32::new("cosmwasm").addr_make("owner");
+
+assert_eq!(
+ "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqs2g053y",
+ addr.as_str()
+);
+```
+
+Custom prefix and **Bech32** encoding:
+
+```rust showLineNumbers {3} copy /MockApiBech32::new/ /addr_make/
+use cw_multi_test::MockApiBech32;
+
+let addr = MockApiBech32::new("nebula").addr_make("owner");
+
+assert_eq!(
+ "nebula1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsvsqrvp",
+ addr.as_str()
+);
+```
+
+## MockApiBech32m
+
+> 🖝 Using [`MockApiBech32m`][MockApiBech32m] struct
+
+**cosmwasm** prefix and **Bech32m** encoding:
+
+```rust showLineNumbers {3} copy /MockApiBech32m::new/ /addr_make/
+use cw_multi_test::MockApiBech32m;
+
+let addr = MockApiBech32m::new("cosmwasm").addr_make("owner");
+
+assert_eq!(
+ "cosmwasm1fsgzj6t7udv8zhf6zj32mkqhcjcpv52yph5qsdcl0qt94jgdckqsl5lc5x",
+ addr.as_str()
+);
+```
+
+Custom prefix and **Bech32m** encoding:
+
+```rust showLineNumbers {3} copy /MockApiBech32m::new/ /addr_make/
+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:
+
+```rust {4} showLineNumbers copy /addr_make/ / api,/
+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:
+
+```rust {6} showLineNumbers copy /addr_make/ / api,/
+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:
+
+```rust {6} showLineNumbers copy /addr_make/ / api,/
+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:
+
+```rust {6} showLineNumbers copy /addr_make/ / api,/
+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()
+ );
+ });
+```
+
+[MockApi]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockApi.html
+[MockApiBech32]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32.html
+[MockApiBech32m]: https://docs.rs/cw-multi-test/latest/cw_multi_test/type.MockApiBech32m.html
+[IntoAddr]: https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.IntoAddr.html
+[IntoBech32]: https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.IntoBech32.html
+[IntoBech32m]: https://docs.rs/cw-multi-test/latest/cw_multi_test/trait.IntoBech32m.html
diff --git a/docs/multi-test/addresses/validator-address.md b/docs/multi-test/addresses/validator-address.md
new file mode 100644
index 0000000..027dc1d
--- /dev/null
+++ b/docs/multi-test/addresses/validator-address.md
@@ -0,0 +1,7 @@
+---
+sidebar_position: 3
+---
+
+# Validator address
+
+(WIP)
diff --git a/docs/multi-test/app-builder.md b/docs/multi-test/app-builder.md
index de9489f..589960b 100644
--- a/docs/multi-test/app-builder.md
+++ b/docs/multi-test/app-builder.md
@@ -367,7 +367,7 @@ assert_eq!(value, app.storage().get(key).unwrap().as_slice());
In the examples above, to keep the simple, we accessed the storage directly and focused on the chain
initialization part involving the `with_storage` method of `AppBuilder`.
Please note, that inside smart contract code, the storage used by the chain should be accessed through
-libraries like [StoragePlus](../storage-plus).
+libraries like [StoragePlus](../storage-plus/introduction.md).
:::
diff --git a/docs/multi-test/getting-started/counter/_category_.json b/docs/multi-test/getting-started/counter/_category_.json
index 1d399e3..069dd37 100644
--- a/docs/multi-test/getting-started/counter/_category_.json
+++ b/docs/multi-test/getting-started/counter/_category_.json
@@ -3,6 +3,6 @@
"position": 1,
"link": {
"type": "doc",
- "id": "counter"
+ "id": "introduction"
}
}
diff --git a/docs/multi-test/getting-started/counter/implementation.md b/docs/multi-test/getting-started/counter/implementation.md
index f818176..ac2ec00 100644
--- a/docs/multi-test/getting-started/counter/implementation.md
+++ b/docs/multi-test/getting-started/counter/implementation.md
@@ -388,7 +388,7 @@ represented as an 8-bit unsigned integer. The `"value"` string is the key used t
retrieve the counter value in the contract's persistent storage. This is used for tracking a counter
value that can be incremented, decremented, queried, or reset by the smart contract. More details
about the [Item](../../../storage-plus/containers/item.md) type can be found in
-[cw-storage-plus](../../../storage-plus) documentation.
+[StoragePlus](../../../storage-plus/introduction.md) documentation.
### _instantiate_ entrypoint
diff --git a/docs/multi-test/getting-started/counter/counter.md b/docs/multi-test/getting-started/counter/introduction.md
similarity index 96%
rename from docs/multi-test/getting-started/counter/counter.md
rename to docs/multi-test/getting-started/counter/introduction.md
index 69634ac..4249a90 100644
--- a/docs/multi-test/getting-started/counter/counter.md
+++ b/docs/multi-test/getting-started/counter/introduction.md
@@ -2,7 +2,7 @@
The following sections describe how to create an example smart contract,
which manages a **counter** that can be `initialized`, `incremented`, `decremented`, and `queried`.
-Later on, you will be [writing tests](writing-tests.mdx) for this smart contract using **MultiTest**.
+Later on, you will be [writing tests](../writing-tests/introduction.md) for this smart contract using **MultiTest**.
:::info
diff --git a/docs/multi-test/getting-started/introduction.mdx b/docs/multi-test/getting-started/introduction.md
similarity index 77%
rename from docs/multi-test/getting-started/introduction.mdx
rename to docs/multi-test/getting-started/introduction.md
index d1901de..f1d942f 100644
--- a/docs/multi-test/getting-started/introduction.mdx
+++ b/docs/multi-test/getting-started/introduction.md
@@ -5,8 +5,8 @@ smart contracts using **MultiTest**. It provides a practical example and best pr
a smooth start with using **MultiTest** for testing smart contracts.
In the following chapters, you will be:
-- designing an example [**counter**](./counter) smart contract,
-- [**writing tests**](./counter) for the counter smart contract.
+- designing an example [**counter**](./counter/introduction.md) smart contract,
+- [**writing tests**](./writing-tests/introduction.md) for the counter smart contract.
The example **counter** smart contract and all test cases are provided in two versions: one using
pure CosmWasm libraries and the other using the Sylvia framework. The functionality of the
diff --git a/docs/multi-test/getting-started/writing-tests/_category_.json b/docs/multi-test/getting-started/writing-tests/_category_.json
index 7d6b28f..632d160 100644
--- a/docs/multi-test/getting-started/writing-tests/_category_.json
+++ b/docs/multi-test/getting-started/writing-tests/_category_.json
@@ -3,6 +3,6 @@
"position": 2,
"link": {
"type": "doc",
- "id": "writing-tests"
+ "id": "introduction"
}
}
diff --git a/docs/multi-test/getting-started/writing-tests/writing-tests.md b/docs/multi-test/getting-started/writing-tests/introduction.md
similarity index 100%
rename from docs/multi-test/getting-started/writing-tests/writing-tests.md
rename to docs/multi-test/getting-started/writing-tests/introduction.md
diff --git a/docs/multi-test/storage.md b/docs/multi-test/storage.md
new file mode 100644
index 0000000..29eb681
--- /dev/null
+++ b/docs/multi-test/storage.md
@@ -0,0 +1,218 @@
+---
+sidebar_position: 9
+---
+
+# Storage
+
+## Default storage
+
+By default, **`MultiTest`** relies on [`MockStorage`][MockStorage], a storage implementation
+provided by the CosmWasm library. [`MockStorage`][MockStorage] operates entirely in memory,
+meaning that any data written during testing is discarded once the test completes. Since it does not
+persist any data beyond the test execution, each test is executed in isolation without retaining any
+previous state. To use a default storage in your tests, just create the chain with default settings,
+as shown below.
+
+```rust showLineNumbers
+// initialize your chain this way:
+let app = App::default();
+
+// or this way:
+let app = AppBuilder::default().build(no_init);
+```
+
+The [`App`][App] provides several methods to access and manipulate the storage, all of which
+are covered in the [Accessing storage in tests](#accessing-storage-in-tests) section.
+
+## Custom storage
+
+If the default storage does not fully meet your testing requirements, you can provide a custom
+storage by implementing the [Storage] trait. Only the `get`, `set`,`remove` and
+`range` methods are required, as the trait already provides a basic implementation for
+`range_keys` and `range_values` methods. The table below summarizes all these methods.
+
+| Methods of [Storage] trait | Description |
+|--------------------------------|---------------------------------------------------------------------------|
+| [`get`][get] | Returns a value associated with a specified key. |
+| [`set`][set] | Sets a new value for a specified key. |
+| [`remove`][remove] | Removes an entry with a specified key. |
+| [`range`][range] | Iterates over a set of **key/value** pairs, either forwards or backwards. |
+| [`range_keys`][range_keys] | Iterates over a set of **keys**, either forwards or backwards. |
+| [`range_values`][range_values] | Iterates over a set of **values**, either forwards or backwards. |
+
+For inspiration on implementing custom storage, you can refer to [MemoryStorage] in the CosmWasm
+library. The following code stub could be a good starting point.
+
+```rust showLineNumbers copy
+#[derive(Default)]
+struct CustomStorage(/* use your persistent type here */);
+
+impl Storage for CustomStorage {
+ fn get(&self, key: &[u8]) -> Option> {
+ // return a value associated with the specified key
+ }
+
+ fn set(&mut self, key: &[u8], value: &[u8]) {
+ // associate value with specified key and persist them
+ }
+
+ fn remove(&mut self, key: &[u8]) {
+ // remove an entry with specified key from storage
+ }
+
+ fn range<'a>(&'a self, start: Option<&[u8]>, end: Option<&[u8]>, order: Order) -> Box + 'a> {
+ // return an iterator over key/value pairs
+ }
+}
+```
+
+## Initializing storage
+
+To initialize the default storage or use a custom storage implementation in tests, use the
+[`AppBuilder::with_storage`][with_storage] method when building the chain. For more details,
+see the [AppBuilder/with_storage](app-builder#with_storage) chapter.
+
+## Accessing storage from smart contracts
+
+Smart contracts should access the storage used by the chain through libraries like [StoragePlus](../storage-plus/introduction.md).
+
+## Accessing storage in tests
+
+[App] provides several methods to access and manipulate storage in tests, and the table below
+summarizes them all.
+
+| Methods of [App] | Access | Purpose |
+|--------------------------------------------------------------------------|:------:|----------------------------------------------------------------------------------------------|
+| [`storage`][app_storage] | R | Read the value associated with any key. |
+| [`storage_mut`][app_storage_mut] | R/W | Read or write the value associated with any key. |
+| [`contract_storage`][app_contract_storage] | R | Read the value associated with any key but only for specified the contract address. |
+| [`contract_storage_mut`][app_contract_storage_mut] | R/W | Read or write the value associated with any key but only for specified the contract address. |
+| [`prefixed_storage`][app_prefixed_storage] | R | Read the value associated with any key having a single prefix. |
+| [`prefixed_storage_mut`][app_prefixed_storage_mut] | R/W | Read or write the value associated with any key having a single prefix. |
+| [`prefixed_multilevel_storage`][app_prefixed_multilevel_storage] | R | Read the value associated with any key having multiple prefixes. |
+| [`prefixed_multilevel_storage_mut`][app_prefixed_multilevel_storage_mut] | R/W | Read or write the value associated with any key having a multiple prefixes. |
+
+- `R` - read-only
+- `R/W` - read/write
+
+### `storage`
+
+Using methods [`storage`][app_storage] and [`storage_mut`][app_storage_mut] you can
+access any value associated with a key, as long as you know the key (with or without a prefix). The
+following example firstly assigns value to a key in line 9, and then reads the value from storage in
+line 13. The key can be any binary.
+
+```rust showLineNumbers copy /storage_mut/ /storage/
+use cosmwasm_std::Storage;
+use cw_multi_test::App;
+
+let mut app = App::default();
+
+let key = b"key";
+let value = b"value";
+
+app.storage_mut().set(key, value);
+
+assert_eq!(
+ Some(value.to_vec()),
+ app.storage().get(key)
+);
+```
+
+### `contract_storage`
+
+If you know the address of a contract, you can access all keys and values stored by that contract
+using the [`contract_storage`][app_contract_storage] and
+[`contract_storage_mut`][app_contract_storage_mut] methods. The following example assigns a
+value to a key in a similar way to how the contract would (line 11) and then reads this value on
+line 15. These methods are giving easy and simple access to the storage of any contract.
+
+```rust showLineNumbers copy /contract_storage_mut/ /contract_storage/
+use cw_multi_test::App;
+use cw_multi_test::IntoAddr;
+
+let mut app = App::default();
+
+let key = b"key";
+let value = b"value";
+
+let contract_addr = "contract".into_addr();
+
+app.contract_storage_mut(&contract_addr).set(key, value);
+
+assert_eq!(
+ Some(value.to_vec()),
+ app.contract_storage(&contract_addr).get(key)
+);
+```
+
+### `prefixed_storage`
+
+Methods [`prefixed_storage`][app_prefixed_storage] and
+[`prefixed_storage_mut`][app_prefixed_storage_mut] simplify access to keys having the same
+single prefix. In the example below, the common prefix (namespace) is the bank. Value is set in line
+10 and then retrieved in line 14.
+
+```rust showLineNumbers copy /prefixed_storage_mut/ /prefixed_storage/
+use cw_multi_test::App;
+
+let mut app = App::default();
+
+let key = b"key";
+let value = b"value";
+
+let namespace = b"bank";
+
+app.prefixed_storage_mut(namespace).set(key, value);
+
+assert_eq!(
+ Some(value.to_vec()),
+ app.prefixed_storage(namespace).get(key)
+);
+```
+
+### `prefixed_multilevel_storage`
+
+If there is a need to access keys having multiple namespaces (multilevel prefixes), then methods
+[`prefixed_multilevel_storage`][app_prefixed_multilevel_storage] and
+[`prefixed_multilevel_storage_mut`][app_prefixed_multilevel_storage_mut] should be used. The
+following example sets a value for a key having two levels of prefixes (line 10) and then the same
+value is read in line 14.
+
+```rust showLineNumbers copy /prefixed_multilevel_storage_mut/ /prefixed_multilevel_storage/
+use cw_multi_test::App;
+
+let mut app = App::default();
+
+let key = b"key";
+let value = b"value";
+
+let namespaces = &[b"my-module".as_slice(), b"my-bank".as_slice()];
+
+app.prefixed_multilevel_storage_mut(namespaces).set(key, value);
+
+assert_eq!(
+ Some(value.to_vec()),
+ app.prefixed_multilevel_storage(namespaces).get(key)
+);
+```
+
+[MockStorage]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/testing/struct.MockStorage.html
+[MemoryStorage]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.MemoryStorage.html
+[Storage]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html
+[App]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html
+[get]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#tymethod.get
+[set]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#tymethod.set
+[remove]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#tymethod.remove
+[range]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#method.range
+[range_keys]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#method.range_keys
+[range_values]: https://docs.rs/cosmwasm-std/latest/cosmwasm_std/trait.Storage.html#method.range_values
+[with_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.AppBuilder.html#method.with_storage
+[app_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.storage
+[app_storage_mut]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.storage_mut
+[app_contract_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.contract_storage
+[app_contract_storage_mut]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.contract_storage_mut
+[app_prefixed_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.prefixed_storage
+[app_prefixed_storage_mut]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.prefixed_storage_mut
+[app_prefixed_multilevel_storage]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.prefixed_multilevel_storage
+[app_prefixed_multilevel_storage_mut]: https://docs.rs/cw-multi-test/latest/cw_multi_test/struct.App.html#method.prefixed_multilevel_storage_mut
From d3717bb335086f82b189e7c8d0b9e02395cd7c8e Mon Sep 17 00:00:00 2001
From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com>
Date: Fri, 10 Oct 2025 11:46:37 +0200
Subject: [PATCH 3/4] Updates.
---
src/css/custom.css | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/css/custom.css b/src/css/custom.css
index 28ed869..054faf7 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -8,7 +8,7 @@
--ifm-color-primary-lightest: #c9baff;
--ifm-code-font-size: 95%;
- --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
+ --docusaurus-highlighted-code-line-bg: rgba(229, 240, 252, 1);
--ifm-footer-background-color: transparent;
.footer {
@@ -25,7 +25,7 @@
--ifm-color-primary-lighter: #c0aeff;
--ifm-color-primary-lightest: #ebe6ff;
- --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
+ --docusaurus-highlighted-code-line-bg: rgba(229, 240, 252, 0.1);
--ifm-footer-background-color: transparent;
.footer {
From b208c15e382a9072dc4f72fb93b4ab01a067369c Mon Sep 17 00:00:00 2001
From: Dariusz Depta <141360751+DariuszDepta@users.noreply.github.com>
Date: Fri, 10 Oct 2025 12:19:54 +0200
Subject: [PATCH 4/4] Added coverage hightlighting, removed ascii control
chcracters.
---
.../writing-tests/introduction.md | 147 +++++++++---------
docusaurus.config.ts | 17 ++
src/css/custom.css | 8 +
3 files changed, 101 insertions(+), 71 deletions(-)
diff --git a/docs/multi-test/getting-started/writing-tests/introduction.md b/docs/multi-test/getting-started/writing-tests/introduction.md
index be7e320..27c285f 100644
--- a/docs/multi-test/getting-started/writing-tests/introduction.md
+++ b/docs/multi-test/getting-started/writing-tests/introduction.md
@@ -7,14 +7,14 @@ cargo build
```
```text title="output"
- [32;1mUpdating[0m crates.io index
- [32;1mLocking[0m 112 packages to latest compatible versions
- ⋮
-[32;1mCompiling[0m cosmwasm-crypto v2.1.3
-[32;1mCompiling[0m cosmwasm-std v2.1.3
-[32;1mCompiling[0m cw-storage-plus v2.0.0
-[32;1mCompiling[0m counter v0.1.0 (/home/user/my-contracts/counter)
- [32;1mFinished[0m `dev` profile [unoptimized + debuginfo] target(s) in 3.27s
+ Updating crates.io index
+ Locking 112 packages to latest compatible versions
+ ⋮
+Compiling cosmwasm-crypto v2.1.3
+Compiling cosmwasm-std v2.1.3
+Compiling cw-storage-plus v2.0.0
+Compiling counter v0.1.0 (/home/user/my-contracts/counter)
+ Finished `dev` profile [unoptimized + debuginfo] target(s) in 3.27s
```
If the output is similar to the one shown above, it looks like the **counter** smart contract has
@@ -28,12 +28,12 @@ cargo clippy
```
```text title="output"
- ⋮
-[32;1mChecking[0m cosmwasm-crypto v2.1.3
-[32;1mChecking[0m cosmwasm-std v2.1.3
-[32;1mChecking[0m cw-storage-plus v2.0.0
-[32;1mChecking[0m counter v0.1.0 (/home/user/mt-test-examples/mte-counter)
-[32;1mFinished[0m `dev` profile [unoptimized + debuginfo] target(s) in 17.28s
+ ⋮
+Checking cosmwasm-crypto v2.1.3
+Checking cosmwasm-std v2.1.3
+Checking cw-storage-plus v2.0.0
+Checking counter v0.1.0 (/home/user/mt-test-examples/mte-counter)
+Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.28s
```
Luckily, `clippy` reports no issues for the **counter** smart contract.
@@ -43,18 +43,18 @@ Luckily, `clippy` reports no issues for the **counter** smart contract.
Before we start writing tests, we need to set up the directories and files for the test cases. The
final directory and file structure are shown below.
-```ansi showLineNumbers {7-11} filename="counter (directory)"
-[34;1m.[0m
-├── Cargo.toml
-├── [34;1msrc[0m
-│ ├── contract.rs
-│ ├── lib.rs
-│ └── msg.rs
-└── [34;1mtests[0m
- ├── mod.rs
- └── [34;1mmultitest[0m
- ├── mod.rs
- └── test_counter.rs
+```text title="counter directory" showLineNumbers {7-11}
+.
+├── Cargo.toml
+├── src
+│ ├── contract.rs
+│ ├── lib.rs
+│ └── msg.rs
+└── tests
+ ├── mod.rs
+ └── multitest
+ ├── mod.rs
+ └── test_counter.rs
```
:::tip
@@ -72,44 +72,44 @@ Note, that both directories **`src`** and **`tests`** are placed at the root of
Let's begin by creating the `tests` directory:
-```shell copy filename="TERMINAL"
+```shell
mkdir tests
```
Then create an empty `mod.rs` file inside the `tests` directory:
-```shell copy filename="TERMINAL"
+```shell
touch tests/mod.rs
```
Now, copy and paste the following content to `tests/mod.rs` file:
-```rust copy filename="tests/mod.rs"
+```rust title="tests/mod.rs"
mod multitest;
```
-By convention, we place all **`MultiTest`** test cases under the `multitest` directory, so let's
+By convention, we place all **MultiTest** test cases under the `multitest` directory, so let's
create it:
-```shell copy filename="TERMINAL"
+```shell
mkdir tests/multitest
```
Inside the `tests/multitest` directory we should also create an empty file named `mod.rs`:
-```shell copy filename="TERMINAL"
+```shell
touch tests/multitest/mod.rs
```
And populate it with the following content (just copy and paste it):
-```rust copy filename="tests/multitest/mod.rs"
+```rust title="tests/multitest/mod.rs"
mod test_counter;
```
Finally, inside the `tests/multitest` directory, we create a file named `test_counter.rs`:
-```shell copy filename="TERMINAL"
+```shell
touch tests/multitest/test_counter.rs
```
@@ -121,37 +121,37 @@ Now that the directory structure for tests is ready, it's time to run all tests.
Once the directories and files are set up for tests, let's execute them:
-```shell copy filename="TERMINAL"
+```shell
cargo test
```
The expected output should be similar to the one shown below:
-```ansi {6,12,16} showLineNumbers filename="OUTPUT"
- [32;1mFinished[0m `test` profile [unoptimized + debuginfo] target(s) in 17.96s
- [32;1mRunning[0m unittests src/lib.rs (target/debug/deps/counter-f350df45a1cd1c74)
+```text title="output" showLineNumbers {6,12,16}
+ Finished `test` profile [unoptimized + debuginfo] target(s) in 17.96s
+ Running unittests src/lib.rs (target/debug/deps/counter-f350df45a1cd1c74)
running 0 tests
-test result: [32mok[0m[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
- [32;1mRunning[0m tests/mod.rs (target/debug/deps/mod-54761c1d31e6d0fe)
+ Running tests/mod.rs (target/debug/deps/mod-54761c1d31e6d0fe)
running 0 tests
-test result: [32mok[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
- [32;1mDoc-tests[0m counter
+ Doc-tests counter
running 0 tests
-test result: [32mok[0m. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
Rust testing framework searches for several types of tests in the project, counts all test cases and
executes them. In our example - while we haven't written any single test yet - there is nothing to
-execute. The reported number of executed tests is **0** for unit tests (line 2), **0** for
-integration tests (line 12) and **0** for documentation tests (line 16).
+execute. The reported number of executed tests is **0** for unit tests (**line 6**), **0** for
+integration tests (**line 12**) and **0** for documentation tests (**line 16**).
Similarly, to execute all tests using [cargo-nextest](https://nexte.st), type:
@@ -162,10 +162,10 @@ cargo nextest run
The expected output is:
```ansi {4} showLineNumbers filename="OUTPUT"
- [32;1mFinished[0m `test` profile [unoptimized + debuginfo] target(s) in 0.06s
- [32;1mStarting[0m 0 tests across 2 binaries (run ID: 3e0cbabb-3ef9-4b2f-98a8-d375bc510845, nextest profile: default)
+ Finished `test` profile [unoptimized + debuginfo] target(s) in 0.06s
+ Starting 0 tests across 2 binaries (run ID: 3e0cbabb-3ef9-4b2f-98a8-d375bc510845, nextest profile: default)
------------
- [32;1mSummary[0m [ 0.000s] 0 tests run: 0 [32;1mpassed[0m, 0 [33;1mskipped[0m
+ Summary [ 0.000s] 0 tests run: 0 passed, 0 skipped
```
[cargo-nextest](https://nexte.st) reports in a user-friendly manner that there were no tests to run (**line 4**).
@@ -180,13 +180,13 @@ quite tedious, so let's prepare a short script to automate this task.
Create an empty file named `coverage.sh` in the `counter` directory:
-```shell copy filename="TERMINAL"
+```shell
touch coverage.sh
```
Populate it with the following content:
-```shell copy filename="coverage.sh"
+```bash title="coverage.sh"
#!/usr/bin/env bash
# generate coverage report
@@ -198,43 +198,42 @@ echo "Report: file://$(pwd)/target/coverage-report/tarpaulin-report.html"
Finally, make this file executable:
-```shell filename="TERMINAL"
+```shell
chmod +x coverage.sh
```
The complete file structure of the **counter** smart contract project, with the code coverage script
should now look like this:
-```shell filename="TERMINAL"
-tree
-```
-
-```ansi {3} filename="counter (directory)"
-[34;1m.[0m
-├── Cargo.toml
-├── [32;1mcoverage.sh[0m
-├── [34;1msrc[0m
-│ ├── contract.rs
-│ ├── lib.rs
-│ └── msg.rs
-└── [34;1mtests[0m
- ├── mod.rs
- └── [34;1mmultitest[0m
- ├── mod.rs
- └── test_counter.rs
+```text title="counter directory"
+.
+├── Cargo.toml
+//highlight-next-line
+├── coverage.sh
+├── src
+│ ├── contract.rs
+│ ├── lib.rs
+│ └── msg.rs
+//highlight-next-line
+└── tests
+ ├── mod.rs
+//highlight-next-line
+ └── multitest
+ ├── mod.rs
+ └── test_counter.rs
```
## Measuring code coverage
With the code coverage script at hand, measuring code coverage is now as simple as typing:
-```shell copy filename="TERMINAL"
+```shell
./coverage.sh
```
The result should be similar to this (only the last few lines are shown):
-```ansi filename="OUTPUT"
+```text title="output"
⋮
|| Tested/Total Lines:
|| src/contract.rs: 0/18
@@ -247,7 +246,7 @@ Additionally, Tarpaulin generates a coverage report in HTML format, that can be
As expected, the current code coverage for the **counter** smart contract is **0.00%** since we haven't written
any tests yet. Follow the next chapters, and make the code coverage report shine green.
-```rust title="Code coverage report" showLineNumbers {11-25,28-42,45-51}
+```text title="Code coverage report" showLineNumbers
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
@@ -258,6 +257,7 @@ use cw_storage_plus::Item;
const COUNTER: Item = Item::new("value");
#[cfg_attr(not(feature = "library"), entry_point)]
+//no-coverage-start
pub fn instantiate(
deps: DepsMut,
_env: Env,
@@ -273,8 +273,10 @@ pub fn instantiate(
)?;
Ok(Response::default())
}
+//no-coverage-end
#[cfg_attr(not(feature = "library"), entry_point)]
+//no-coverage-start
pub fn execute(
deps: DepsMut,
_env: Env,
@@ -290,8 +292,10 @@ pub fn execute(
})?;
Ok(Response::default())
}
+//no-coverage-end
#[cfg_attr(not(feature = "library"), entry_point)]
+//no-coverage-start
pub fn query(deps: Deps, _env: Env, msg: CounterQueryMsg) -> Result {
match msg {
CounterQueryMsg::Value => Ok(to_json_binary(&CounterResponse {
@@ -299,6 +303,7 @@ pub fn query(deps: Deps, _env: Env, msg: CounterQueryMsg) -> Result