You are on page 1of 102

24/06/2023, 20:53 CosmWasm book

Introduction
This book is a guide for creating CosmWasm smart contracts. It will lead you step by step,
and explain relevant topics from the easiest to the trickier ones.

The idea of the book is not only to tell you about smart contracts API but also to show you
how to do it in a clean and maintainable way. We will show you patterns that CosmWasm
creators established and encouraged you to use.

Prerequirements
This book explores CosmWasm smart contracts. It is not a Rust tutorial, and it assumes basic
Rust knowledge. As you will probably learn it alongside this book, I strongly recommend
grasping the language itself first. You can find great resources to start with Rust on Learn
Rust page.

CosmWasm API documentation


This is the guide-like documentation. If you are looking for the API documentation, you may
be interested in checking one of the following:

cosmwasm-std
cw-storage-plus
cw-multi-test
cw-utils
sylvia framework

Contributing to the book


This book is maintained on Github and auto deployed from there. Please create an issue or
pull request if you find any mistakes, bugs, or ambiguities.

https://book.cosmwasm.com/print.html 1/102
24/06/2023, 20:53 CosmWasm book

Setting up the environment


To work with CosmWasm smart contract, you will need rust installed on your machine. If you
don't have one, you can find installation instructions on the Rust website.

I assume you are working with a stable Rust channel in this book.

Additionally, you will need the Wasm rust compiler backend installed to build Wasm
binaries. To install it, run:

rustup target add wasm32-unknown-unknown

Optionally if you want to try out your contracts on a testnet, you will need a wasmd binary.
We would focus on testing contracts with Rust unit testing utility throughout the book, so it
is not required to follow. However, seeing the product working in a real-world environment
may be nice.

To install wasmd , first install the golang. Then clone the wasmd and install it:

$ git clone git@github.com:CosmWasm/wasmd.git


$ cd ./wasmd
$ make install

Also, to be able to upload Rust Wasm Contracts into the blockchain, you will need to install
docker. To minimize your contract sizes, it will be required to run CosmWasm Rust
Optimizer; without that, more complex contracts might exceed a size limit.

cosmwasm-check utility
An additional helpful tool for building smart contracts is the cosmwasm-check utility. It allows
you to check if the wasm binary is a proper smart contract ready to upload into the
blockchain. You can install it using cargo:

$ cargo install cosmwasm-check

If the installation succeeds, you should be able to execute the utility from your command
line.

$ cosmwasm-check --version
Contract checking 1.2.3

https://book.cosmwasm.com/print.html 2/102
24/06/2023, 20:53 CosmWasm book

Verifying the installation


To guarantee you are ready to build your smart contracts, you need to make sure you can
build examples. Checkout the cw-plus repository and run the testing command in its folder:

$ git clone git@github.com:CosmWasm/cw-plus.git


$ cd ./cw-plus
cw-plus $ cargo test

You should see that everything in the repository gets compiled, and all tests pass.

cw-plus is a great place to find example contracts - look for them in contracts directory.
The repository is maintained by CosmWasm creators, so contracts in there should follow
good practices.

To verify the cosmwasm-check utility, first, you need to build a smart contract. Go to some
contract directory, for example, contracts/cw1-whitelist , and call cargo wasm :

cw-plus $ cd contracts/cw1-whitelist
cw-plus/contracts/cw1-whitelist $ cargo wasm

You should be able to find your output binary in the target/wasm32-unknown-


unknown/release/ of the root repo directory - not in the contract directory itself! Now you
can check if contract validation passes:

cw-plus/contracts/cw1-whitelist $ cosmwasm-check ../../target/wasm32-unknown-


unknown/release/cw1_whitelist.wasm
Available capabilities: {"iterator", "cosmwasm_1_1", "cosmwasm_1_2", "stargate",
"staking"}

../../target/wasm32-unknown-unknown/release/cw1_whitelist.wasm: pass

All contracts (1) passed checks!

https://book.cosmwasm.com/print.html 3/102
24/06/2023, 20:53 CosmWasm book

Quick start with wasmd


In the past, we suggested playing with contracts on the malaga testnet using wasmd . Now
malaga is no longer operative, and the best way to test the contract in the real environment
is to use one of the big CosmWasm chains testnets - Osmosis, Juno, Terra, or other ones.
Here is the recommended introduction on how to start with the Osmosis testnet.

https://book.cosmwasm.com/print.html 4/102
24/06/2023, 20:53 CosmWasm book

Basics
In this chapter, we will go through creating basic smart contracts step by step. I will try to
explain the core ideas behind CosmWasm and the typical contract structure.

https://book.cosmwasm.com/print.html 5/102
24/06/2023, 20:53 CosmWasm book

Create a Rust project


As smart contracts are Rust library crates, we will start with creating one:

$ cargo new --lib ./empty-contract

You created a simple Rust library, but it is not yet ready to be a smart contract. The first
thing to do is to update the Cargo.toml file:

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }

As you can see, I added a crate-type field for the library section. Generating the cdylib is
required to create a proper web assembly binary. The downside of this is that such a library
cannot be used as a dependency for other Rust crates - for now, it is not needed, but later
we will show how to approach reusing contracts as dependencies.

Additionally, there is one core dependency for smart contracts: the cosmwasm-std . This
crate is a standard library for smart contracts. It provides essential utilities for
communication with the outside world and a couple of helper functions and types. Every
smart contract we will build will use this dependency.

https://book.cosmwasm.com/print.html 6/102
24/06/2023, 20:53 CosmWasm book

Entry points
Typical Rust application starts with the fn main() function called by the operating system.
Smart contracts are not significantly different. When the message is sent to the contract, a
function called "entry point" is called. Unlike native applications, which have only a single
main entry point, smart contracts have a couple corresponding to different message types:
instantiate , execute , query , sudo , migrate and more.

To start, we will go with three basic entry points:

instantiate which is called once per smart contract lifetime - you can think about it
as a constructor or initializer of a contract.
execute for handling messages which are able to modify contract state - they are used
to perform some actual actions.
query for handling messages requesting some information from a contract; unlike
execute , they can never affect any contract state, and are used just like database
queries.

Go to your src/lib.rs file, and start with an instantiate entry point:

use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response,
StdResult,
};

#[entry_point]
pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: Empty,
) -> StdResult<Response> {
Ok(Response::new())
}

In fact, instantiate is the only entry point required for a smart contract to be valid. It is not
very useful in this form, but it is a start. Let's take a closer look at the entry point structure.

First, we start with importing couple of types just for more consistent usage. Then we define
our entry point. The instantiate takes four arguments:

deps: DepsMut is a utility type for communicating with the outer world - it allows
querying and updating the contract state, querying other contracts state, and gives
access to an Api object with a couple of helper functions for dealing with CW
addresses.
env: Env is an object representing the blockchains state when executing the message
- the chain height and id, current timestamp, and the called contract address.

https://book.cosmwasm.com/print.html 7/102
24/06/2023, 20:53 CosmWasm book

info: MessageInfo contains metainformation about the message which triggered an


execution - an address that sends the message, and chain native tokens sent with the
message.
msg: Empty is the message triggering execution itself - for now, it is Empty type that
represents {} JSON, but the type of this argument can be anything that is
deserializable, and we will pass more complex types here in the future.

If you are new to the blockchain, those arguments may not have much sense to you, but
while progressing with this guide, I will explain their usage one by one.

Notice an essential attribute decorating our entry point #[entry_point] . Its purpose is to
wrap the whole entry point to the form Wasm runtime understands. The proper Wasm entry
points can use only basic types supported natively by Wasm specification, and Rust
structures and enums are not in this set. Working with such entry points would be rather
overcomplicated, so CosmWasm creators delivered the entry_point macro. It creates the
raw Wasm entry point, calling the decorated function internally and doing all the magic
required to build our high-level Rust arguments from arguments passed by Wasm runtime.

The next thing to look at is the return type. I used StdResult<Response> for this simple
example, which is an alias for Result<Response, StdError> . The return entry point type
would always be a Result type, with some error type implementing ToString trait and a
well-defined type for success case. For most entry points, an "Ok" case would be the
Response type that allows fitting the contract into our actor model, which we will discuss
very soon.

The body of the entry point is as simple as it could be - it always succeeds with a trivial
empty response.

https://book.cosmwasm.com/print.html 8/102
24/06/2023, 20:53 CosmWasm book

Building the contract


Now it is time to build our contract. We can use a traditional cargo build pipeline for local
testing purposes: cargo build for compiling it and cargo test for running all tests (which
we don't have yet, but we will work on that soon).

However, we need to create a wasm binary to upload the contract to blockchain. We can do
it by passing an additional argument to the build command:

$ cargo build --target wasm32-unknown-unknown --release

The --target argument tells cargo to perform cross-compilation for a given target instead
of building a native binary for an OS it is running on - in this case, wasm32-unknown-unknown ,
which is a fancy name for Wasm target.

Additionally, I passed the --release argument to the command - it is not required, but in
most cases, debug information is not very useful while running on-chain. It is crucial to
reduce the uploaded binary size for gas cost minimization. It is worth knowing that there is a
CosmWasm Rust Optimizer tool that takes care of building even smaller binaries. For
production, all the contracts should be compiled using this tool, but for learning purposes, it
is not an essential thing to do.

Aliasing build command


Now I can see you are disappointed in building your contracts with some overcomplicated
command instead of simple cargo build . Hopefully, it is not the case. The common
practice is to alias the building command to make it as simple as building a native app.

Let's create the .cargo/config file in your contract project directory with the following
content:

[alias]
wasm = "build --target wasm32-unknown-unknown --release"
wasm-debug = "build --target wasm32-unknown-unknown"

Now, building your Wasm binary is as easy as executing cargo wasm . We also added the
additional wasm-debug command for rare cases when we want to build the wasm binary,
including debug information.

https://book.cosmwasm.com/print.html 9/102
24/06/2023, 20:53 CosmWasm book

Checking contract validity


When the contract is built, the last step is to ensure it is a valid CosmWasm contract is to call
cosmwasm-check on it:

$ cargo wasm
...
$ cosmwasm-check ./target/wasm32-unknown-unknown/release/contract.wasm
Available capabilities: {"cosmwasm_1_1", "staking", "stargate", "iterator",
"cosmwasm_1_2"}

./target/wasm32-unknown-unknown/release/contract.wasm: pass

https://book.cosmwasm.com/print.html 10/102
24/06/2023, 20:53 CosmWasm book

Creating a query
We have already created a simple contract reacting to an empty instantiate message.
Unfortunately, it is not very useful. Let's make it a bit reactive.

First, we need to add serde crate to our dependencies. It would help us with the
serialization and deserialization of query messages. Update the Cargo.toml :

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }

[dev-dependencies]
cw-multi-test = "0.13.4"

Now go to your src/lib.rs file, and add a new query entry point:

use cosmwasm_std::{
entry_point, to_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo,
Response, StdResult,
};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct QueryResp {
message: String,
}

#[entry_point]
pub fn query(_deps: Deps, _env: Env, _msg: Empty) -> StdResult<Binary> {
let resp = QueryResp {
message: "Hello World".to_owned(),
};

to_binary(&resp)
}

Note that I omitted the previously created instantiate endpoint for simplicity - not to
overload you with code, I will always only show lines that changed in the code.

We first need a structure we will return from our query. We always want to return
something which is serializable. We are just deriving the Serialize and Deserialize traits
from serde crate.
https://book.cosmwasm.com/print.html 11/102
24/06/2023, 20:53 CosmWasm book

Then we need to implement our entry point. It is very similar to the instantiate one. The
first significant difference is a type of deps argument. For instantiate , it was a DepMut ,
but here we went with a Deps object. That is because the query can never alter the smart
contract's internal state. It can only read the state. It comes with some consequences - for
example, it is impossible to implement caching for future queries (as it would require some
data cache to write to).

The other difference is the lack of the info argument. The reason here is that the entry
point which performs actions (like instantiation or execution) can differ how an action is
performed based on the message metadata - for example, they can limit who can perform
an action (and do so by checking the message sender ). It is not a case for queries. Queries
are supposed just purely to return some transformed contract state. It can be calculated
based on some chain metadata (so the state can "automatically" change after some time),
but not on message info.

Note that our entry point still has the same Empty type for its msg argument - it means that
the query message we would send to the contract is still an empty JSON: {}

The last thing that changed is the return type. Instead of returning the Response type on the
success case, we return an arbitrary serializable object. This is because queries are not using
a typical actor model message flow - they cannot trigger any actions nor communicate with
other contracts in ways different than querying them (which is handled by the deps
argument). The query always returns plain data, which should be presented directly to the
querier.

Now take a look at the implementation. Nothing complicated happens there - we create an
object we want to return and encode it to the Binary type using the to_binary function.

Improving the message


We have a query, but there is a problem with the query message. It is always an empty JSON.
It is terrible - if we would like to add another query in the future, it would be difficult to have
any reasonable distinction between query variants.

In practice, we address this by using a non-empty query message type. Improve our
contract:

https://book.cosmwasm.com/print.html 12/102
24/06/2023, 20:53 CosmWasm book

#[derive(Serialize, Deserialize)]
pub enum QueryMsg {
Greet {},
}

#[entry_point]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
use QueryMsg::*;

match msg {
Greet {} => {
let resp = QueryResp {
message: "Hello World".to_owned(),
};

to_binary(&resp)
}
}
}

Now we introduced a proper message type for the query message. It is an enum, and by
default, it would serialize to a JSON with a single field - the name of the field will be an enum
variant (in our case - always "greet" - at least for now), and the value of this field would be an
object assigned to this enum variant.

Note that our enum has no type assigned to the only Greet variant. Typically in Rust, we
create such variants without additional {} after the variant name. Here the curly braces
have a purpose - without them, the variant would serialize to just a string type - so instead of
{ "greet": {} } , the JSON representation of this variant would be "greet" . This behavior
brings inconsistency in the message schema. It is, generally, a good habit to always add the
{} to serde serializable empty enum variants - for better JSON representation.

But now, we can still improve the code further. Right now, the query function has two
responsibilities. The first is obvious - handling the query itself. It was the first assumption,
and it is still there. But there is a new thing happening there - the query message
dispatching. It may not be obvious, as there is a single variant, but the query function is an
excellent way to become a massive unreadable match statement. To make the code more
SOLID, we will refactor it and take out handling the greet message to a separate function.

https://book.cosmwasm.com/print.html 13/102
24/06/2023, 20:53 CosmWasm book

#[derive(Serialize, Deserialize)]
pub struct GreetResp {
message: String,
}

#[entry_point]
pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
use QueryMsg::*;

match msg {
Greet {} => to_binary(&query::greet()?),
}
}

mod query {
use super::*;

pub fn greet() -> StdResult<GreetResp> {


let resp = GreetResp {
message: "Hello World".to_owned(),
};

Ok(resp)
}
}

Now it looks much better. Note there are a couple of additional improvements. I renamed
the query-response type GreetResp as I may have different responses for different queries.
I want the name to relate only to the variant, not the whole message.

Next is enclosing my new function in the module query . It makes it easier to avoid name
collisions - I can have the same variant for queries and execution messages in the future,
and their handlers would lie in separate namespaces.

A questionable decision may be returning StdResult instead of GreetResp from greet


function, as it would never return an error. It is a matter of style, but I prefer consistency
over the message handler, and the majority of them would have failure cases - e.g. when
reading the state.

Also, you might pass deps and env arguments to all your query handlers for consistency.
I'm not too fond of this, as it introduces unnecessary boilerplate which doesn't read well, but
I also agree with the consistency argument - I leave it to your judgment.

Structuring the contract


You can see that our contract is becoming a bit bigger now. About 50 lines are maybe not so
much, but there are many different entities in a single file, and I think we can do better. I can
already distinguish three different types of entities in the code: entry points, messages, and

https://book.cosmwasm.com/print.html 14/102
24/06/2023, 20:53 CosmWasm book

handlers. In most contracts, we would divide them across three files. Start with extracting all
the messages to src/msg.rs :

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct GreetResp {
pub message: String,
}

#[derive(Serialize, Deserialize)]
pub enum QueryMsg {
Greet {},
}

You probably noticed that I made my GreetResp fields public. It is because they have to be
now accessed from a different module. Now move forward to the src/contract.rs file:

use crate::msg::{GreetResp, QueryMsg};


use cosmwasm_std::{
to_binary, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response,
StdResult,
};

pub fn instantiate(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: Empty,
) -> StdResult<Response> {
Ok(Response::new())
}

pub fn query(_deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {


use QueryMsg::*;

match msg {
Greet {} => to_binary(&query::greet()?),
}
}

mod query {
use super::*;

pub fn greet() -> StdResult<GreetResp> {


let resp = GreetResp {
message: "Hello World".to_owned(),
};

Ok(resp)
}
}

I moved most of the logic here, so my src/lib.rs is just a very thin library entry with
nothing else but module definitions and entry points definition. I removed the #
https://book.cosmwasm.com/print.html 15/102
24/06/2023, 20:53 CosmWasm book

[entry_point] attribute from my query function in src/contract.rs . I will have a function


with this attribute. Still, I wanted to split functions' responsibility further - not the
contract::query function is the top-level query handler responsible for dispatching the
query message. The query function on crate-level is only an entry point. It is a subtle
distinction, but it will make sense in the future when we would like not to generate the entry
points but to keep the dispatching functions. I introduced the split now to show you the
typical contract structure.

Now the last part, the src/lib.rs file:

use cosmwasm_std::{
entry_point, Binary, Deps, DepsMut, Empty, Env, MessageInfo, Response,
StdResult,
};

mod contract;
mod msg;

#[entry_point]
pub fn instantiate(deps: DepsMut, env: Env, info: MessageInfo, msg: Empty)
-> StdResult<Response>
{
contract::instantiate(deps, env, info, msg)
}

#[entry_point]
pub fn query(deps: Deps, env: Env, msg: msg::QueryMsg)
-> StdResult<Binary>
{
contract::query(deps, env, msg)
}

Straightforward top-level module. Definition of submodules and entry points, nothing more.

Now, when we have the contract ready to do something, let's go and test it.

https://book.cosmwasm.com/print.html 16/102
24/06/2023, 20:53 CosmWasm book

Testing a query
Last time we created a new query, now it is time to test it out. We will start with the basics -
the unit test. This approach is simple and doesn't require knowledge besides Rust. Go to the
src/contract.rs and add a test in its module:

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn greet_query() {
let resp = query::greet().unwrap();
assert_eq!(
resp,
GreetResp {
message: "Hello World".to_owned()
}
);
}
}

If you ever wrote a unit test in Rust, nothing should surprise you here. Just a simple test-only
module contains local function unit tests. The problem is - this test doesn't build yet. We
need to tweak our message types a bit. Update the src/msg.rs :

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub struct GreetResp {
pub message: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub enum QueryMsg {
Greet {},
}

I added three new derives to both message types. PartialEq is required to allow
comparing types for equality - so we can check if they are equal. The Debug is a trait
generating debug-printing utilities. It is used by assert_eq! to display information about
mismatch if an assertion fails. Note that because we are not testing the QueryMsg in any
way, the additional trait derives are optional. Still, it is a good practice to make all messages
both PartialEq and Debug for testability and consistency. The last one, Clone is not
needed for now yet, but it is also good practice to allow messages to be cloned around. We
will also require that later, so I added it already not to go back and forth.

Now we are ready to run our test:

https://book.cosmwasm.com/print.html 17/102
24/06/2023, 20:53 CosmWasm book

$ cargo test

...
running 1 test
test contract::tests::greet_query ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;


finished in 0.00s

Yay! Test passed!

Contract as a black box


Now let's go a step further. The Rust testing utility is a friendly tool for building even higher-
level tests. We are currently testing smart contract internals, but if you think about how your
smart contract is visible from the outside world. It is a single entity that is triggered by some
input messages. We can create tests that treat the whole contract as a black box by testing it
via our query function. Let's update our test:

#[cfg(test)]
mod tests {
use cosmwasm_std::from_binary;
use cosmwasm_std::testing::{mock_dependencies, mock_env};

use super::*;

#[test]
fn greet_query() {
let resp = query(
mock_dependencies().as_ref(),
mock_env(),
QueryMsg::Greet {}
).unwrap();
let resp: GreetResp = from_binary(&resp).unwrap();

assert_eq!(
resp,
GreetResp {
message: "Hello World".to_owned()
}
);
}
}

We needed to produce two entities for the query functions: the deps and env instances.
Hopefully, cosmwasm-std provides utilities for testing those - mock_dependencies and
mock_env functions.

You may notice the dependencies mock of a type OwnedDeps instead of Deps , which we
need here - this is why the as_ref function is called on it. If we looked for a DepsMut object,
https://book.cosmwasm.com/print.html 18/102
24/06/2023, 20:53 CosmWasm book

we would use as_mut instead.

We can rerun the test, and it should still pass. But when we think about that test reflecting
the actual use case, it is inaccurate. The contract is queried, but it was never instantiated! In
software engineering, it is equivalent to calling a getter without constructing an object -
taking it out of nowhere. It is a lousy testing approach. We can do better:

#[cfg(test)]
mod tests {
use cosmwasm_std::from_binary;
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};

use super::*;

#[test]
fn greet_query() {
let mut deps = mock_dependencies();
let env = mock_env();

instantiate(
deps.as_mut(),
env.clone(),
mock_info("sender", &[]),
Empty {},
)
.unwrap();

let resp = query(deps.as_ref(), env, QueryMsg::Greet {}).unwrap();


let resp: GreetResp = from_binary(&resp).unwrap();
assert_eq!(
resp,
GreetResp {
message: "Hello World".to_owned()
}
);
}
}

A couple of new things here. First, I extracted the deps and env variables to their variables
and passed them to calls. The idea is that those variables represent some blockchain
persistent state, and we don't want to create them for every call. We want any changes to
the contract state occurring in instantiate to be visible in the query . Also, we want to
control how the environment differs on the query and instantiation.

The info argument is another story. The message info is unique for each message sent. To
create the info mock, we must pass two arguments to the mock_info function.

First is the address performing a call. It may look strange to pass sender as an address
instead of some mysterious wasm followed by hash, but it is a valid address. For testing
purposes, such addresses are typically better, as they are way more verbose in case of
failing tests.

https://book.cosmwasm.com/print.html 19/102
24/06/2023, 20:53 CosmWasm book

The second argument is funds sent with the message. For now, we leave it as an empty slice,
as I don't want to talk about token transfers yet - we will cover it later.

So now it is more a real-case scenario. I see just one problem. I say that the contract is a
single black box. But here, nothing connects the instantiate call to the corresponding
query . It seems that we assume there is some global contract. But it seems that if we would
like to have two contracts instantiated differently in a single test case, it would become a
mess. If only there would be some tool to abstract this for us, wouldn't it be nice?

https://book.cosmwasm.com/print.html 20/102
24/06/2023, 20:53 CosmWasm book

Introducing multitest
Let me introduce the multitest - library for creating tests for smart contracts in Rust.

The core idea of multitest is abstracting an entity of contract and simulating the
blockchain environment for testing purposes. The purpose of this is to be able to test
communication between smart contracts. It does its job well, but it is also an excellent tool
for testing single-contract scenarios.

First, we need to add a multitest to our Cargo.toml .

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }

[dev-dependencies]
cw-multi-test = "0.13.4"

I added a new [dev-dependencies] section with dependencies not used by the final binary
but which may be used by tools around the development process - for example, tests.

When we have the dependency ready, update our test to use the framework:

https://book.cosmwasm.com/print.html 21/102
24/06/2023, 20:53 CosmWasm book

#[allow(dead_code)]
pub fn execute(
_deps: DepsMut,
_env: Env,
_info: MessageInfo,
_msg: Empty
) -> StdResult<Response> {
unimplemented!()
}

#[cfg(test)]
mod tests {
use cosmwasm_std::Addr;
use cw_multi_test::{App, ContractWrapper, Executor};

use super::*;

#[test]
fn greet_query() {
let mut app = App::default();

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&Empty {},
&[],
"Contract",
None,
)
.unwrap();

let resp: GreetResp = app


.wrap()
.query_wasm_smart(addr, &QueryMsg::Greet {})
.unwrap();

assert_eq!(
resp,
GreetResp {
message: "Hello World".to_owned()
}
);
}
}

You probably notice that I added the function for an execute entry point. I didn't add the
entry point itself or the function's implementation, but for the multitest purposes contract
has to contain at least instantiate, query, and execute handlers. I attributed the function as
#[allow(dead_code)] , so, cargo will not complain about it not being used anywhere.
Enabling it for tests only with #[cfg(test)] would also be a way.

https://book.cosmwasm.com/print.html 22/102
24/06/2023, 20:53 CosmWasm book

Then at the beginning of the test, I created the App object. It is a core multitest entity
representing the virtual blockchain on which we will run our contracts. As you can see, we
can call functions on it just like we would interact with blockchain using wasmd !

Right after creating app , I prepared the representation of the code , which would be
"uploaded" to the blockchain. As multitests are just native Rust tests, they do not involve any
Wasm binaries, but this name matches well what happens in a real-life scenario. We store
this object in the blockchain with the store_code function, and as a result, we are getting
the code id - we would need it to instantiate a contract.

Instantiation is the next step. In a single instantiate_contract call, we provide everything


we would provide via wasmd - the contract code id, the address which performs
instantiation,

the message triggering it, and any funds sent with the message (again - empty for now). We
are adding the contract label and its admin for migrations - None , as we don't need it yet.

And after the contract is online, we can query it. The wrap function is an accessor for
querying Api (queries are handled a bit differently than other calls), and the
query_wasm_smart queries are given a contract with the message. Also, we don't need to
care about query results as Binary - multitest assumes that we would like to deserialize
them to some response type, so it takes advantage of Rust type elision to provide us with a
nice Api.

Now it's time to rerun the test. It should still pass, but now we nicely abstracted the testing
contract as a whole, not some internal functions. The next thing we should probably cover is
making the contract more interesting by adding some state.

https://book.cosmwasm.com/print.html 23/102
24/06/2023, 20:53 CosmWasm book

Contract state
The contract we are working on already has some behavior that can answer a query.
Unfortunately, it is very predictable with its answers, and it has nothing to alter them. In this
chapter, I introduce the notion of state, which would allow us to bring true life to a smart
contract.

The state would still be static for now - it would be initialized on contract instantiation. The
state would contain a list of admins who would be eligible to execute messages in the
future.

The first thing to do is to update Cargo.toml with yet another dependency - the storage-
plus crate with high-level bindings for CosmWasm smart contracts state management:

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
cw-storage-plus = "0.13.4"

[dev-dependencies]
cw-multi-test = "0.13.4"

Now create a new file where you will keep a state for the contract - we typically call it
src/state.rs :

use cosmwasm_std::Addr;
use cw_storage_plus::Item;

pub const ADMINS: Item<Vec<Addr>> = Item::new("admins");

And make sure we declare the module in src/lib.rs :

mod state;

The new thing we have here is the ADMINS constant of type Item<Vec<Addr>> . You could
ask an excellent question here - how is the state constant? How do I modify it if it is a
constant value?

The answer is tricky - this constant is not keeping the state itself. The state is stored in the
blockchain and is accessed via the deps argument passed to entry points. The storage-plus

https://book.cosmwasm.com/print.html 24/102
24/06/2023, 20:53 CosmWasm book

constants are just accessor utilities helping us access this state in a structured way.

In CosmWasm, the blockchain state is just massive key-value storage. The keys are prefixed
with metainformation pointing to the contract which owns them (so no other contract can
alter them in any way), but even after removing the prefixes, the single contract state is a
smaller key-value pair.

storage-plus handles more complex state structures by additionally prefixing items keys
intelligently. For now, we just used the simplest storage entity - an Item<_> , which holds a
single optional value of a given type - Vec<Addr> in this case. And what would be a key to
this item in the storage? It doesn't matter to us - it would be figured out to be unique, based
on a unique string passed to the new function.

Before we would go into initializing our state, we need some better instantiate message. Go
to src/msg.rs and create one:

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub struct InstantiateMsg {
pub admins: Vec<String>,
}

Now go forward to instantiate the entry point in src/contract.rs , and initialize our state to
whatever we got in the instantiation message:

use crate::state::ADMINS;
// --snip--
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
let admins: StdResult<Vec<_>> = msg
.admins
.into_iter()
.map(|addr| deps.api.addr_validate(&addr))
.collect();
ADMINS.save(deps.storage, &admins?)?;

Ok(Response::new())
}

We also need to update the message type on entry point in src/lib.rs :

https://book.cosmwasm.com/print.html 25/102
24/06/2023, 20:53 CosmWasm book

use msg::InstantiateMsg;
// --snip--
#[entry_point]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
contract::instantiate(deps, env, info, msg)
}

Voila, that's all that is needed to update the state!

First, we need to transform the vector of strings into the vector of addresses to be stored.
We cannot take addresses as a message argument because not every string is a valid
address. It might be a bit confusing when we were working on tests. Any string could be
used in the place of address. Let me explain.

Every string can be technically considered an address. However, not every string is an actual
existing blockchain address. When we keep anything of type Addr in the contract, we
assume it is a proper address in the blockchain. That is why the addr_validate function
exits - to check this precondition.

Having data to store, we use the save function to write it into the contract state. Note that
the first argument of save is &mut Storage , which is actual blockchain storage. As
emphasized, the Item object stores nothing and is just an accessor. It determines how to
store the data in the storage given to it. The second argument is the serializable data to be
stored.

It is a good time to check if the regression we have passes - try running our tests:

https://book.cosmwasm.com/print.html 26/102
24/06/2023, 20:53 CosmWasm book

> cargo test

...

running 1 test
test contract::tests::greet_query ... FAILED

failures:

---- contract::tests::greet_query stdout ----


thread 'contract::tests::greet_query' panicked at 'called `Result::unwrap()` on
an `Err` value: error executing WasmMsg:
sender: owner
Instantiate { admin: None, code_id: 1, msg: Binary(7b7d), funds: [], label:
"Contract" }

Caused by:
Error parsing into type contract::msg::InstantiateMsg: missing field
`admins`', src/contract.rs:80:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

failures:
contract::tests::greet_query

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out;


finished in 0.00s

error: test failed, to rerun pass '--lib'

Damn, we broke something! But be calm. Let's start with carefully reading an error message:

Error parsing into type contract::msg::InstantiateMsg: missing field admins ',


src/contract.rs:80:14

The problem is that in the test, we send an empty instantiation message in our test, but right
now, our endpoint expects to have an admin field. Multi-test framework tests contract from
the entry point to results, so sending messages using MT functions first serializes them.
Then the contract deserializes them on the entry. But now it tries to deserialize the empty
JSON to some non-empty message! We can quickly fix it by updating the test:

https://book.cosmwasm.com/print.html 27/102
24/06/2023, 20:53 CosmWasm book

#[test]
fn greet_query() {
let mut app = App::default();

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg { admins: vec![] },
&[],
"Contract",
None,
)
.unwrap();

let resp: GreetResp = app


.wrap()
.query_wasm_smart(addr, &QueryMsg::Greet {})
.unwrap();

assert_eq!(
resp,
GreetResp {
message: "Hello World".to_owned()
}
);
}

Testing state
When the state is initialized, we want a way to test it. We want to provide a query to check if
the instantiation affects the state. Just create a simple one listing all admins. Start with
adding a variant for query message and a corresponding response message in src/msg.rs .
We'll call the variant AdminsList , the response AdminsListResp , and have it return a vector
of cosmwasm_std::Addr :

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub struct AdminsListResp {
pub admins: Vec<Addr>,
}

[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub enum QueryMsg {
Greet {},
AdminsList {},
}

And implement it in src/contract.rs :

https://book.cosmwasm.com/print.html 28/102
24/06/2023, 20:53 CosmWasm book

use crate::msg::{AdminsListResp, GreetResp, InstantiateMsg, QueryMsg};


pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
use QueryMsg::*;

match msg {
Greet {} => to_binary(&query::greet()?),
AdminsList {} => to_binary(&query::admins_list(deps)?),
}
}

mod query {
pub fn admins_list(deps: Deps) -> StdResult<AdminsListResp> {
let admins = ADMINS.load(deps.storage)?;
let resp = AdminsListResp { admins };
Ok(resp)
}
}

Now when we have the tools to test the instantiation, let's write a test case:

https://book.cosmwasm.com/print.html 29/102
24/06/2023, 20:53 CosmWasm book

use crate::msg::{AdminsListResp, GreetResp, InstantiateMsg, QueryMsg};


#[cfg(test)]
mod tests {
#[test]
fn instantiation() {
let mut app = App::default();

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg { admins: vec![] },
&[],
"Contract",
None,
)
.unwrap();

let resp: AdminsListResp = app


.wrap()
.query_wasm_smart(addr, &QueryMsg::AdminsList {})
.unwrap();

assert_eq!(resp, AdminsListResp { admins: vec![] });

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg {
admins: vec!["admin1".to_owned(), "admin2".to_owned()],
},
&[],
"Contract 2",
None,
)
.unwrap();

let resp: AdminsListResp = app


.wrap()
.query_wasm_smart(addr, &QueryMsg::AdminsList {})
.unwrap();

assert_eq!(
resp,
AdminsListResp {
admins: vec![Addr::unchecked("admin1"),
Addr::unchecked("admin2")],
}
);
}
}

https://book.cosmwasm.com/print.html 30/102
24/06/2023, 20:53 CosmWasm book

The test is simple - instantiate the contract twice with different initial admins, and ensure the
query result is proper each time. This is often the way we test our contract - we execute
bunch o messages on the contract, and then we query it for some data, verifying if query
responses are like expected.

We are doing a pretty good job developing our contract. Now it is time to use the state and
allow for some executions.

https://book.cosmwasm.com/print.html 31/102
24/06/2023, 20:53 CosmWasm book

Execution messages
We went through instantiate and query messages. It is finally time to introduce the last basic
entry point - the execute messages. It is similar to what we have done so far that I expect
this to be just chilling and revisiting our knowledge. I encourage you to try implementing
what I am describing here on your own as an exercise - without checking out the source
code.

The idea of the contract will be easy - every contract admin would be eligible to call two
execute messages:

AddMembers message would allow the admin to add another address to the admin's
list
Leave would allow and admin to remove himself from the list

Not too complicated. Let's go coding. Start with defining messages:

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub enum ExecuteMsg {
AddMembers { admins: Vec<String> },
Leave {},
}

And implement entry point:

https://book.cosmwasm.com/print.html 32/102
24/06/2023, 20:53 CosmWasm book

use crate::msg::{AdminsListResp, ExecuteMsg, GreetResp, InstantiateMsg,


QueryMsg};

#[allow(dead_code)]
pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
use ExecuteMsg::*;

match msg {
AddMembers { admins } => exec::add_members(deps, info, admins),
Leave {} => exec::leave(deps, info),
}
}

mod exec {
use cosmwasm_std::StdError;

use super::*;

pub fn add_members(
deps: DepsMut,
info: MessageInfo,
admins: Vec<String>,
) -> StdResult<Response> {
let mut curr_admins = ADMINS.load(deps.storage)?;
if !curr_admins.contains(&info.sender) {
return Err(StdError::generic_err("Unauthorised access"));
}

let admins: StdResult<Vec<_>> = admins


.into_iter()
.map(|addr| deps.api.addr_validate(&addr))
.collect();

curr_admins.append(&mut admins?);
ADMINS.save(deps.storage, &curr_admins)?;

Ok(Response::new())
}

pub fn leave(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {


ADMINS.update(deps.storage, move |admins| -> StdResult<_> {
let admins = admins
.into_iter()
.filter(|admin| *admin != info.sender)
.collect();
Ok(admins)
})?;

Ok(Response::new())

https://book.cosmwasm.com/print.html 33/102
24/06/2023, 20:53 CosmWasm book

}
}

The entry point itself also has to be created in src/lib.rs :

use cosmwasm_std::{entry_point, Binary, Deps, DepsMut, Env, MessageInfo,


Response, StdResult};
use msg::{ExecuteMsg, InstantiateMsg, QueryMsg};

mod contract;
mod msg;
mod state;

#[entry_point]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
contract::instantiate(deps, env, info, msg)
}

#[entry_point]
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) ->
StdResult<Response> {
contract::execute(deps, env, info, msg)
}

#[entry_point]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
contract::query(deps, env, msg)
}

There are a couple of new things, but nothing significant. First is how do I reach the message
sender to verify he is an admin or remove him from the list - I used the info.sender field of
MessageInfo , which is how it looks like - the member. As the message is always sent from
the proper address, the sender is already of the Addr type - no need to validate it. Another
new thing is the update function on an Item - it makes a read and update of an entity
potentially more efficient. It is possible to do it by reading admins first, then updating and
storing the result.

You probably noticed that when working with Item , we always assume something is there.
But nothing forces us to initialize the ADMINS value on instantiation! So what happens there?
Well, both load and update functions would return an error. But there is a may_load
function, which returns StdResult<Option<T>> - it would return Ok(None) in case of empty
storage. There is even a possibility to remove an existing item from storage with the remove
function.

https://book.cosmwasm.com/print.html 34/102
24/06/2023, 20:53 CosmWasm book

One thing to improve is error handling. While validating the sender to be admin, we are
returning some arbitrary string as an error. We can do better.

Error handling
In our contract, we now have an error situation when a user tries to execute AddMembers
not being an admin himself. There is no proper error case in StdError to report this
situation, so we have to return a generic error with a message. It is not the best approach.

For error reporting, we encourage using thiserror crate. Start with updating your
dependencies:

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
cw-storage-plus = "0.13.4"
thiserror = "1"

[dev-dependencies]
cw-multi-test = "0.13.4"

Now we define an error type in src/error.rs :

use cosmwasm_std::{Addr, StdError};


use thiserror::Error;

#[derive(Error, Debug, PartialEq)]


pub enum ContractError {
#[error("{0}")]
StdError(#[from] StdError),
#[error("{sender} is not contract admin")]
Unauthorized { sender: Addr },
}

We also need to add the new module to src/lib.rs :

mod contract;
mod error;
mod msg;
mod state;

https://book.cosmwasm.com/print.html 35/102
24/06/2023, 20:53 CosmWasm book

Using thiserror we define errors like a simple enum, and the crate ensures that the type
implements std::error::Error trait. A very nice feature of this crate is the inline definition
of Display trait by an #[error] attribute. Also, another helpful thing is the #[from]
attribute, which automatically generates proper From implementation, so it is easy to use ?
operator with thiserror types.

Now update the execute endpoint to use our new error type:

use crate::error::ContractError;
use crate::msg::{AdminsListResp, ExecuteMsg, GreetResp, InstantiateMsg,
QueryMsg};

pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
use ExecuteMsg::*;

match msg {
AddMembers { admins } => exec::add_members(deps, info, admins),
Leave {} => exec::leave(deps, info).map_err(Into::into),
}
}

mod exec {
use super::*;

pub fn add_members(
deps: DepsMut,
info: MessageInfo,
admins: Vec<String>,
) -> Result<Response, ContractError> {
let mut curr_admins = ADMINS.load(deps.storage)?;
if !curr_admins.contains(&info.sender) {
return Err(ContractError::Unauthorized {
sender: info.sender,
});
}

let admins: StdResult<Vec<_>> = admins


.into_iter()
.map(|addr| deps.api.addr_validate(&addr))
.collect();

curr_admins.append(&mut admins?);
ADMINS.save(deps.storage, &curr_admins)?;

Ok(Response::new())
}
}

The entry point return type also has to be updated:

https://book.cosmwasm.com/print.html 36/102
24/06/2023, 20:53 CosmWasm book

use error::ContractError;

#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
contract::execute(deps, env, info, msg)
}

Custom error and multi-test


Using proper custom error type has one nice upside - multi-test is maintaining error type
using the anyhow crate. It is a sibling of thiserror , designed to implement type-erased
errors in a way that allows getting the original error back.

Let's write a test that verifies that a non-admin cannot add himself to a list:

https://book.cosmwasm.com/print.html 37/102
24/06/2023, 20:53 CosmWasm book

#[cfg(test)]
mod tests {
#[test]
fn unauthorized() {
let mut app = App::default();

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg { admins: vec![] },
&[],
"Contract",
None,
)
.unwrap();

let err = app


.execute_contract(
Addr::unchecked("user"),
addr,
&ExecuteMsg::AddMembers {
admins: vec!["user".to_owned()],
},
&[],
)
.unwrap_err();

assert_eq!(
ContractError::Unauthorized {
sender: Addr::unchecked("user")
},
err.downcast().unwrap()
);
}
}

Executing a contract is very similar to any other call - we use an execute_contract function.
As the execution may fail, we get an error type out of this call, but instead of calling unwrap
to extract a value out of it, we expect an error to occur - this is the purpose of the
unwrap_err call. Now, as we have an error value, we can check if it matches what we
expected with an assert_eq! . There is a slight complication - the error returned from
execute_contract is an anyhow::Error error, but we expect it to be a ContractError .
Hopefully, as I said before, anyhow errors can recover their original type using the downcast
function. The unwrap right after it is needed because downcasting may fail. The reason is
that downcast doesn't magically know the type kept in the underlying error. It deduces it by
some context - here, it knows we expect it to be a ContractError , because of being
compared to it - type elision miracles. But if the underlying error would not be a
ContractError , then unwrap would panic.

https://book.cosmwasm.com/print.html 38/102
24/06/2023, 20:53 CosmWasm book

We just created a simple failure test for execution, but it is not enough to claim the contract
is production-ready. All reasonable ok-cases should be covered for that. I encourage you to
create some tests and experiment with them as an exercise after this chapter.

https://book.cosmwasm.com/print.html 39/102
24/06/2023, 20:53 CosmWasm book

Events attributes and data


The only way our contract can communicate to the world, for now, is by queries. Smart
contracts are passive - they cannot invoke any action by themselves. They can do it only as a
reaction to a call. But if you tried playing with wasmd , you know that execution on the
blockchain can return some metadata.

There are two things the contract can return to the caller: events and data. Events are
something produced by almost every real-life smart contract. In contrast, data is rarely used,
designed for contract-to-contract communication.

Returning events
As an example, we would add an event admin_added emitted by our contract on the
execution of AddMembers :

https://book.cosmwasm.com/print.html 40/102
24/06/2023, 20:53 CosmWasm book

use cosmwasm_std::{
to_binary, Binary, Deps, DepsMut, Env, Event, MessageInfo, Response,
StdResult,
};

mod exec {
pub fn add_members(
deps: DepsMut,
info: MessageInfo,
admins: Vec<String>,
) -> Result<Response, ContractError> {
let mut curr_admins = ADMINS.load(deps.storage)?;
if !curr_admins.contains(&info.sender) {
return Err(ContractError::Unauthorized {
sender: info.sender,
});
}

let events = admins


.iter()
.map(|admin| Event::new("admin_added").add_attribute("addr",
admin));
let resp = Response::new()
.add_events(events)
.add_attribute("action", "add_members")
.add_attribute("added_count", admins.len().to_string());

let admins: StdResult<Vec<_>> = admins


.into_iter()
.map(|addr| deps.api.addr_validate(&addr))
.collect();

curr_admins.append(&mut admins?);
ADMINS.save(deps.storage, &curr_admins)?;

Ok(resp)
}
}

An event is built from two things: an event type provided in the new function and attributes.
Attributes are added to an event with the add_attributes or the add_attribute call.
Attributes are key-value pairs. Because an event cannot contain any list, to achieve reporting
multiple similar actions taking place, we need to emit multiple small events instead of a
collective one.

Events are emitted by adding them to the response with add_event or add_events call.
Additionally, there is a possibility to add attributes directly to the response. It is just sugar.
By default, every execution emits a standard "wasm" event. Adding attributes to the result
adds them to the default event.

We can check if events are properly emitted by contract. It is not always done, as it is much
of boilerplate in test, but events are, generally, more like logs - not necessarily considered
main contract logic. Let's now write single test checking if execution emits events:

https://book.cosmwasm.com/print.html 41/102
24/06/2023, 20:53 CosmWasm book

#[cfg(test)]
mod tests {
#[test]
fn add_members() {
let mut app = App::default();

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg {
admins: vec!["owner".to_owned()],
},
&[],
"Contract",
None,
)
.unwrap();

let resp = app


.execute_contract(
Addr::unchecked("owner"),
addr,
&ExecuteMsg::AddMembers {
admins: vec!["user".to_owned()],
},
&[],
)
.unwrap();

let wasm = resp.events.iter().find(|ev| ev.ty == "wasm").unwrap();


assert_eq!(
wasm.attributes
.iter()
.find(|attr| attr.key == "action")
.unwrap()
.value,
"add_members"
);
assert_eq!(
wasm.attributes
.iter()
.find(|attr| attr.key == "added_count")
.unwrap()
.value,
"1"
);

let admin_added: Vec<_> = resp


.events
.iter()
.filter(|ev| ev.ty == "wasm-admin_added")
.collect();
assert_eq!(admin_added.len(), 1);

https://book.cosmwasm.com/print.html 42/102
24/06/2023, 20:53 CosmWasm book

assert_eq!(
admin_added[0]
.attributes
.iter()
.find(|attr| attr.key == "addr")
.unwrap()
.value,
"user"
);
}
}

As you can see, testing events on a simple test made it clunky. First of all, every string is
heavily string-based - a lack of type control makes writing such tests difficult. Also, even
types are prefixed with "wasm-" - it may not be a huge problem, but it doesn't clarify
verification. But the problem is, how layered events structure are, which makes verifying
them tricky. Also, the "wasm" event is particularly tricky, as it contains an implied attribute -
_contract_addr containing an address called a contract. My general rule is - do not test
emitted events unless some logic depends on them.

Data
Besides events, any smart contract execution may produce a data object. In contrast to
events, data can be structured. It makes it a way better choice to perform any
communication logic relies on. On the other hand, it turns out it is very rarely helpful outside
of contract-to-contract communication. Data is always only one single object on the
response, which is set using the set_data function. Because of its low usefulness in a single
contract environment, we will not spend time on it right now - an example of it will be
covered later when contract-to-contract communication will be discussed. Until then, it is
just helpful to know such an entity exists.

https://book.cosmwasm.com/print.html 43/102
24/06/2023, 20:53 CosmWasm book

Dealing with funds


When you hear smart contracts, you think blockchain. When you hear blockchain, you often
think of cryptocurrencies. It is not the same, but crypto assets, or as we often call them:
tokens, are very closely connected to the blockchain. CosmWasm has a notion of a native
token. Native tokens are assets managed by the blockchain core instead of smart contracts.
Often such assets have some special meaning, like being used for paying gas fees or staking
for consensus algorithm, but can be just arbitrary assets.

Native tokens are assigned to their owners but can be transferred by their nature.
Everything had an address in the blockchain is eligible to have its native tokens. As a
consequence - tokens can be assigned to smart contracts! Every message sent to the smart
contract can have some funds sent with it. In this chapter, we will take advantage of that and
create a way to reward hard work performed by admins. We will create a new message -
Donate , which will be used by anyone to donate some funds to admins, divided equally.

Preparing messages
Traditionally we need to prepare our messages. We need to create a new ExecuteMsg
variant, but we will also modify the Instantiate message a bit - we need to have some way
of defining the name of a native token we would use for donations. It would be possible to
allow users to send any tokens they want, but we want to simplify things for now.

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub struct InstantiateMsg {
pub admins: Vec<String>,
pub donation_denom: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


pub enum ExecuteMsg {
AddMembers { admins: Vec<String> },
Leave {},
Donate {},
}

We also need to add a new state part, to keep the donation_denom :

use cosmwasm_std::Addr;
use cw_storage_plus::Item;

pub const ADMINS: Item<Vec<Addr>> = Item::new("admins");


pub const DONATION_DENOM: Item<String> = Item::new("donation_denom");

And instantiate it properly:

https://book.cosmwasm.com/print.html 44/102
24/06/2023, 20:53 CosmWasm book

use crate::state::{ADMINS, DONATION_DENOM};

pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
let admins: StdResult<Vec<_>> = msg
.admins
.into_iter()
.map(|addr| deps.api.addr_validate(&addr))
.collect();
ADMINS.save(deps.storage, &admins?)?;
DONATION_DENOM.save(deps.storage, &msg.donation_denom)?;

Ok(Response::new())
}

What also needs some corrections are tests - instantiate messages have a new field. I leave it
to you as an exercise. Now we have everything we need to implement donating funds to
admins. First, a minor update to the Cargo.toml - we will use an additional utility crate:

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[features]
library = []

[dependencies]
cosmwasm-std = { version = "1.0.0-beta8", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
cw-storage-plus = "0.13.4"
thiserror = "1"
schemars = "0.8.1"
cw-utils = "0.13"

[dev-dependencies]
cw-multi-test = "0.13.4"
cosmwasm-schema = { version = "1.0.0" }

Then we can implement the donate handler:

https://book.cosmwasm.com/print.html 45/102
24/06/2023, 20:53 CosmWasm book

use cosmwasm_std::{
coins, to_binary, BankMsg, Binary, Deps, DepsMut, Env, Event, MessageInfo,
Response, StdResult,
};

pub fn execute(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
use ExecuteMsg::*;

match msg {
AddMembers { admins } => exec::add_members(deps, info, admins),
Leave {} => exec::leave(deps, info).map_err(Into::into),
Donate {} => exec::donate(deps, info),
}
}

mod exec {
pub fn donate(deps: DepsMut, info: MessageInfo) -> Result<Response,
ContractError> {
let denom = DONATION_DENOM.load(deps.storage)?;
let admins = ADMINS.load(deps.storage)?;

let donation = cw_utils::must_pay(&info, &denom)?.u128();

let donation_per_admin = donation / (admins.len() as u128);

let messages = admins.into_iter().map(|admin| BankMsg::Send {


to_address: admin.to_string(),
amount: coins(donation_per_admin, &denom),
});

let resp = Response::new()


.add_messages(messages)
.add_attribute("action", "donate")
.add_attribute("amount", donation.to_string())
.add_attribute("per_admin", donation_per_admin.to_string());

Ok(resp)
}
}

Sending the funds to another contract is performed by adding bank messages to the
response. The blockchain would expect any message which is returned in contract response
as a part of an execution. This design is related to an actor model implemented by
CosmWasm. The whole actor model will be described in detail later. For now, you can
assume this is a way to handle token transfers. Before sending tokens to admins, we have to
calculate the amount of donation per admin. It is done by searching funds for an entry
describing our donation token and dividing the number of tokens sent by the number of
admins. Note that because the integral division is always rounding down.

https://book.cosmwasm.com/print.html 46/102
24/06/2023, 20:53 CosmWasm book

As a consequence, it is possible that not all tokens sent as a donation would end up with no
admins accounts. Any leftover would be left on our contract account forever. There are
plenty of ways of dealing with this issue - figuring out one of them would be a great exercise.

The last missing part is updating the ContractError - the must_pay call returns a
cw_utils::PaymentError which we can't convert to our error type yet:

use cosmwasm_std::{Addr, StdError};


use cw_utils::PaymentError;
use thiserror::Error;

#[derive(Error, Debug, PartialEq)]


pub enum ContractError {
#[error("{0}")]
StdError(#[from] StdError),
#[error("{sender} is not contract admin")]
Unauthorized { sender: Addr },
#[error("Payment error: {0}")]
Payment(#[from] PaymentError),
}

As you can see, to handle incoming funds, I used the utility function - I encourage you to take
a look at its implementation - this would give you a good understanding of how incoming
funds are structured in MessageInfo .

Now it's time to check if the funds are distributed correctly. The way for that is to write a
test.

https://book.cosmwasm.com/print.html 47/102
24/06/2023, 20:53 CosmWasm book

#[cfg(test)]
mod tests {
#[test]
fn donations() {
let mut app = App::new(|router, _, storage| {
router
.bank
.init_balance(storage, &Addr::unchecked("user"), coins(5,
"eth"))
.unwrap()
});

let code = ContractWrapper::new(execute, instantiate, query);


let code_id = app.store_code(Box::new(code));

let addr = app


.instantiate_contract(
code_id,
Addr::unchecked("owner"),
&InstantiateMsg {
admins: vec!["admin1".to_owned(), "admin2".to_owned()],
donation_denom: "eth".to_owned(),
},
&[],
"Contract",
None,
)
.unwrap();

app.execute_contract(
Addr::unchecked("user"),
addr.clone(),
&ExecuteMsg::Donate {},
&coins(5, "eth"),
)
.unwrap();

assert_eq!(
app.wrap()
.query_balance("user", "eth")
.unwrap()
.amount
.u128(),
0
);

assert_eq!(
app.wrap()
.query_balance(&addr, "eth")
.unwrap()
.amount
.u128(),
1
);

assert_eq!(
app.wrap()

https://book.cosmwasm.com/print.html 48/102
24/06/2023, 20:53 CosmWasm book

.query_balance("admin1", "eth")
.unwrap()
.amount
.u128(),
2
);

assert_eq!(
app.wrap()
.query_balance("admin2", "eth")
.unwrap()
.amount
.u128(),
2
);
}
}

Fairly simple. I don't particularly appreciate that every balance check is eight lines of code,
but it can be improved by enclosing this assertion into a separate function, probably with
the #[track_caller] attribute.

The critical thing to talk about is how app creation changed. Because we need some initial
tokens on a user account, instead of using the default constructor, we have to provide it
with an initializer function. Unfortunately, new documentation is not easy to follow - even if
a function is not very complicated. What it takes as an argument is a closure with three
arguments - the Router with all modules supported by multi-test, the API object, and the
state. This function is called once during contract instantiation. The router object contains
some generic fields - we are interested in bank in particular. It has a type of BankKeeper ,
where the init_balance function sits.

Plot Twist!
As we covered most of the important basics about building Rust smart contracts, I have a
serious exercise for you.

The contract we built has an exploitable bug. All donations are distributed equally across
admins. However, every admin is eligible to add another admin. And nothing is preventing
the admin from adding himself to the list and receiving twice as many rewards as others!

Try to write a test that detects such a bug, then fix it and ensure the bug nevermore occurs.

Even if the admin cannot add the same address to the list, he can always create new
accounts and add them, but this is something unpreventable on the contract level, so do not
prevent that. Handling this kind of case is done by properly designing whole applications,
which is out of this chapter's scope.

https://book.cosmwasm.com/print.html 49/102
24/06/2023, 20:53 CosmWasm book

Good practices
All the relevant basics are covered. Now let's talk about some good practices.

JSON renaming
Due to Rust style, all our message variants are spelled in a camel-case. It is standard
practice, but it has a drawback - all messages are serialized and deserialized by serde using
those variant names. The problem is that it is more common to use snake cases for field
names in the JSON world. Hopefully, there is an effortless way to tell serde, to change the
names casing for serialization purposes. Let's update our messages with a #[serde]
attribute:

https://book.cosmwasm.com/print.html 50/102
24/06/2023, 20:53 CosmWasm book

use cosmwasm_std::Addr;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


#[serde(rename_all = "snake_case")]
pub struct InstantiateMsg {
pub admins: Vec<String>,
pub donation_denom: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
AddMembers { admins: Vec<String> },
Leave {},
Donate {},
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


#[serde(rename_all = "snake_case")]
pub struct GreetResp {
pub message: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


#[serde(rename_all = "snake_case")]
pub struct AdminsListResp {
pub admins: Vec<Addr>,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]


#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
Greet {},
AdminsList {},
}

JSON schema
Talking about JSON API, it is worth mentioning JSON Schema. It is a way of defining a shape
for JSON messages. It is good practice to provide a way to generate schemas for contract
API. The problem is that writing JSON schemas by hand is a pain. The good news is that
there is a crate that would help us with that. Go to the Cargo.toml :

https://book.cosmwasm.com/print.html 51/102
24/06/2023, 20:53 CosmWasm book

[package]
name = "contract"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]

[dependencies]
cosmwasm-std = { version = "1.1.4", features = ["staking"] }
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
cw-storage-plus = "0.15.1"
thiserror = "1"
schemars = "0.8.1"
cosmwasm-schema = "1.1.4"

[dev-dependencies]
cw-multi-test = "0.13.4"

There is one additional change in this file - in crate-type I added "rlib". "cdylib" crates
cannot be used as typical Rust dependencies. As a consequence, it is impossible to create
examples for such crates.

Now go back to src/msg.rs and add a new derive for all messages:

https://book.cosmwasm.com/print.html 52/102
24/06/2023, 20:53 CosmWasm book

use schemars::JsonSchema;

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]


#[serde(rename_all = "snake_case")]
pub struct InstantiateMsg {
pub admins: Vec<String>,
pub donation_denom: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]


#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
AddMembers { admins: Vec<String> },
Leave {},
Donate {},
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]


#[serde(rename_all = "snake_case")]
pub struct GreetResp {
pub message: String,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]


#[serde(rename_all = "snake_case")]
pub struct AdminsListResp {
pub admins: Vec<Addr>,
}

#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]


#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
Greet {},
AdminsList {},
}

You may argue that all those derives look slightly clunky, and I agree. Hopefully, the
cosmwasm-schema crate delivers a utility cw_serde macro, which we can use to reduce a
boilerplate:

https://book.cosmwasm.com/print.html 53/102
24/06/2023, 20:53 CosmWasm book

use cosmwasm_schema::cw_serde

#[cw_serde]
pub struct InstantiateMsg {
pub admins: Vec<String>,
pub donation_denom: String,
}

#[cw_serde]
pub enum ExecuteMsg {
AddMembers { admins: Vec<String> },
Leave {},
Donate {},
}

#[cw_serde]
pub struct GreetResp {
pub message: String,
}

#[cw_serde]
pub struct AdminsListResp {
pub admins: Vec<Addr>,
}

#[cw_serde]
pub enum QueryMsg {
Greet {},
AdminsList {},
}

Additionally, we have to derive the additional QueryResponses trait for our query message
to correlate the message variants with responses we would generate for them:

use cosmwasm_schema::{cw_serde, QueryResponses}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(GreetResp)]
Greet {},
#[returns(AdminsListResp)]
AdminsList {},
}

The QueryResponses is a trait that requires the #[returns(...)] attribute to all your query
variants to generate additional information about the query-response relationship.

Now, we want to make the msg module public and accessible by crates depending on our
contract (in this case - for schema example). Update a src/lib.rs :

https://book.cosmwasm.com/print.html 54/102
24/06/2023, 20:53 CosmWasm book

pub mod contract;


pub mod error;
pub mod msg;
pub mod state;

I changed the visibility of all modules - as our crate can now be used as a dependency. If
someone would like to do so, he may need access to handlers or state.

The next step is to create a tool generating actual schemas. We will do it by creating an
binary in our crate. Create a new bin/schema.rs file:

use contract::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};


use cosmwasm_schema::write_api;

fn main() {
write_api! {
instantiate: InstantiateMsg,
execute: ExecuteMsg,
query: QueryMsg
}
}

Cargo is smart enough to recognize files in src/bin directory as utility binaries for the crate.
Now we can generate our schemas:

$ cargo run schema


Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/schema schema`
Removing "/home/hashed/confio/git/book/examples/03-basics/schema/contract.json"

Exported the full API as /home/hashed/confio/git/book/examples/03-
basics/schema/contract.json

I encourage you to go to generated file to see what the schema looks like.

The problem is that, unfortunately, creating this binary makes our project fail to compile on
the Wasm target - which is, in the end, the most important one. Hopefully, we don't need to
build the schema binary for the Wasm target - let's align the .cargo/config file:

[alias]
wasm = "build --target wasm32-unknown-unknown --release --lib"
wasm-debug = "build --target wasm32-unknown-unknown --lib"
schema = "run schema"

The --lib flag added to wasm cargo aliases tells the toolchain to build only the library
target - it would skip building any binaries. Additionally, I added the convenience schema
alias so that one can generate schema calling simply cargo schema .

https://book.cosmwasm.com/print.html 55/102
24/06/2023, 20:53 CosmWasm book

Disabling entry points for libraries


Since we added the "rlib" target for the contract, it is, as mentioned before, useable as a
dependency. The problem is that the contract depended on ours would have Wasm entry
points generated twice - once in the dependency and once in the final contract. We can work
this around by disabling generating Wasm entry points for the contract if the crate is used as
a dependency. We would use feature flags for that.

Start with updating Cargo.toml :

[features]
library = []

This way, we created a new feature for our crate. Now we want to disable the entry_point
attribute on entry points - we will do it by a slight update of src/lib.rs :

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
contract::instantiate(deps, env, info, msg)
}

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
contract::execute(deps, env, info, msg)
}

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
contract::query(deps, env, msg)
}

The cfg_attr attribute is a conditional compilation attribute, similar to the cfg we used
before for the test. It expands to the given attribute if the condition expands to true. In our
case - it would expand to nothing if the feature "library" is enabled, or it would expand just
to #[entry_point] in another case.

Since now to add this contract as a dependency, don't forget to enable the feature like this:

https://book.cosmwasm.com/print.html 56/102
24/06/2023, 20:53 CosmWasm book

[dependencies]
my_contract = { version = "0.1", features = ["library"] }

https://book.cosmwasm.com/print.html 57/102
24/06/2023, 20:53 CosmWasm book

Floating point types


Now you are ready to create smart contracts on your own. It is time to discuss an important
limitation of CosmWasm smart contracts - floating-point numbers.

The story is short: you cannot use floating-point types in smart contracts. Never. CosmWasm
virtual machine on purpose does not implement floating-point Wasm instructions, even such
basics as F32Load . The reasoning is simple: they are not safe to work with in the blockchain
world.

The biggest problem is that contract will compile, but uploading it to the blockchain would
fail with an error message claiming there is a floating-point operation in the contract. A tool
that verifies if the contract is valid (it does not contain any fp operations but also has all
needed entry points and so on) is called cosmwasm-check utility.

This limitation has two implications. First, you always have to use decimal of fixed-point
arithmetic in your contracts. It is not a problem, considering that cosmwasm-std provides
you with the Decimal and Decimal256 types.

The other implication is tricky - you must be careful with the crates you use. In particular,
one gotcha in the serde crate - deserialization of usize type is using floating-point
operations. That means you can never use usize (or isize ) types in your deserialized
messages in the contract.

Another thing that will not work with serde is untagged enums deserialization. The
workaround is to create custom deserialization of such enums using serde-cw-value crate.
It is a fork of serde-value crate which avoids generating floating-point instructions.

https://book.cosmwasm.com/print.html 58/102
24/06/2023, 20:53 CosmWasm book

Actor model
This section describes the fundaments of CosmWasm smart contracts architecture, which
determines how do they communicate with each other. I want to go through this before
teaching step by step how to create multiple contracts relating to each other, to give you a
grasp of what to expect. Don't worry if it will not be clear after the first read - I suggest going
through this chapter once now and maybe giving it another take in the future when you
know the practical part of this.

The whole thing described here is officially documented in the SEMANTICS.md, of the
cosmwasm repository.

https://book.cosmwasm.com/print.html 59/102
24/06/2023, 20:53 CosmWasm book

Idea behind an Actor Model


The actor model is the solution to the problem of communication between smart contracts.
Let's take a look at the reasons why this particular solution is chosen in CosmWasm, and
what are the consequences of that.

The problem
Smart contracts can be imagined as sandboxed microservices. Due to SOLID principles, it is
valuable to split responsibilities between entities. However, to split the work between
contracts themselves, there is a need to communicate between them, so if one contract is
responsible for managing group membership, it is possible to call its functionality from
another contract.

The traditional way to solve this problem in SW engineering is to model services as functions
that would be called with some RPC mechanism, and return its result as a response. Even
though this approach looks nice, it creates sort of problems, in particular with shared state
consistency.

The other approach which is far more popular in business-level modeling is to treat entities
as actors, which can perform some tasks, but without interrupting it with calls to other
contracts. Any calls to other contracts can only be called after the whole execution is
performed. When "subcall" is finished, it will call the original contract back.

This solution may feel unnatural, and it requires different kinds of design solutions, but it
turns out to work pretty well for smart contract execution. I will try to explain how to reason
about it, and how it maps to contract structure step by step.

The Actor
The most important thing in the whole model is an Actor itself. So, what is this? The Actor is
a single instantiation of a contract, which can perform several actions. When the actor
finishes his job, he prepares a summary of it, which includes the list of things that have to be
done, to complete the whole scheduled task.

An example of an actor is the Seller in the KFC restaurant. The first thing you do is order
your BSmart, so you are requesting action from him. So, from the system user, you can think
about this task as "sell and prepare my meal", but the action performed by the seller is just
"Charge payment and create order". The first part of this operation is to create a bill and
charge you for it, and then it requests the Sandwich and Fries to be prepared by other
actors, probably chefs. Then when the chef is done with his part of the meal, he checks if all
https://book.cosmwasm.com/print.html 60/102
24/06/2023, 20:53 CosmWasm book

meals are ready. If so, it calls the last actor, the waiter, to deliver the food to you. At this
point, you can receive your delivery, and the task is considered complete.

The above-described workflow is kind of simplified. In particular - in a typical restaurant, a


waiter would observe the kitchen instead of being triggered by a chef, but in the Actor
model, it is not possible. Here, entities of the system are passive and cannot observe the
environment actively - they only react to messages from other system participants. Also in
KFC, the seller would not schedule subtasks for particular chefs; instead, he would leave
tasks to be taken by them, when they are free. It is not the case, because as before - chefs
cannot actively listen to the environment. However, it would be possible to create a contract
for being a chef's dispatcher which would collect all orders from sellers, and balance them
across chefs for some reason.

The Action
Actors are the model entities, but to properly communicate with them, we need some kind
of protocol. Every actor is capable of performing several actions. In my previous KFC
example, the only action seller can do is "Charge payment and create order". However, it is
not always the case - our chefs were proficient at performing both "Prepare fries" and
"Prepare Sandwich" actions - and also many more.

So, when we want to do something in an actor system, we schedule some action to the actor
being the closest to us, very often with some additional parameters (as we can pick if we
want to exchange fries with salad).

However, naming the action after the exact thing which happened in the very contract would
be misleading. Take a look at the KFC example once again. As I mentioned, the action
performed by a seller is "Charge payment and create order". The problem is, that for the
client who schedules this action, it doesn't matter what exactly is the responsibility of the
actor himself - what the client is scheduling is "Prepare Meal" with some description of what
exactly to prepare. So, we can say, that the action is the thing performed by the contract
itself, plus all the sub-actions it schedules.

Multi-stage Actions
So as the whole idea makes some sense, there is the problem created by the actor model:
what if I want to perform some action in my contract, but to completely finalize some steps,
the contract has to make sure that some sub-action he scheduled are finished?

Imagine that in the previous KFC situation, there is no dedicated Waiter. Instead the Seller
was serving you a meal when the Chefs finished their job.

https://book.cosmwasm.com/print.html 61/102
24/06/2023, 20:53 CosmWasm book

This kind of pattern is so important and common that in CosmWasm, we developed a special
way to handle it, which is dedicated Reply action.

So when Seller is scheduling actions for chefs, he assigns some number to this action (like
order id) and passes it to chefs. He also remembers how many actions he scheduled for
every order id. Now every time chef is finished with his action; he would call the special
Reply action on Seller, in which he would pass back the order id. Then, Seller would
decrease the number of actions left for this order, and if it reached zero, he would serve a
meal.

Now you can say, that the Reply action is completely not needed, as Chefs could just
schedule any arbitrary action on Seller, like Serve , why is there the special Reply for? The
reason is abstraction and reusability. The Chefs task is to prepare a meal, and that is all.
There is no reason for him to know why he is even preparing Fries - if it is part of the bigger
task (like order for a client), or the seller is just hungry. It is possible that not only the seller is
eligible to call the chef for food - possibly any restaurant employee can do that just for
themselves. Therefore, we need a way to be able to react to an actor finishing his job in
some universal way, to handle this situation properly in any context.

It is worth noting that the Reply can contain some additional data. The id assigned
previously is the only required information in the Reply call, but the actor can pass some
additional data - events emitted, which are mostly metadata (to be observed by non-
blockchain applications mostly), and any arbitrary data it wants to pass.

State
Up until this point, we were considering actors as entities performing some job, like
preparing the meal. If we are considering computer programs, such a job would be to show
something on the screen, maybe print something. This is not the case with Smart Contracts.
The only thing which can be affected by the Smart Contract is their internal state. So, the
state is arbitrary data that is kept by the contract. Previously in the KFC example I
mentioned, the Seller is keeping in mind how many actions he scheduled for chefs are not
yet finished - this number is part of the Seller's state.

To give a more realistic example of a contract state, let's think about a more real-life Smart
Contract than the restaurant. Let's imagine we want to create our currency - maybe we want
to create some smart contracts-based market for some MMORPG game. So, we need some
way to be able to at least transfer currency between players. We can do that, by creating the
contract we would call MmoCurrency , which would support the Transfer action to transfer
money to another player. Then what would be the state of such a contract? It would be just a
table mapping player names to the amount of currency they own. The contract we just
invited exists in CosmWasm examples, and it is called the cw20-base contract (it is a bit
more complicated, but it is its core idea).

https://book.cosmwasm.com/print.html 62/102
24/06/2023, 20:53 CosmWasm book

And now there is a question - how is this helpful to transfer currency if I cannot check how
much of it do I own? It is a very good question, and the answer to that is simple - the whole
state of every contract in our system is public. It is not universal for every Actor model, but it
is how it works in CosmWasm, and it is kind of forced by the nature of blockchain. Everything
happening in blockchain has to be public, and if some information should be hidden, it has
to be stored indirectly.

There is one very important thing about the state in CosmWasm, and it is the state being
transactional. Any updates to the state are not applied immediately, but only when the
whole action succeeds. It is very important, as it guarantees that if something goes wrong in
the contract, it is always left in some proper state. Let's consider our MmoCurrency case.
Imagine, that in the Transfer action we first increase the receiver currency amount (by
updating the state), and only then do we decrease the sender amount. However, before
decreasing it, we need to check if a sender possesses enough funds to perform the
transaction. In case we realize that we cannot do it, we don't need to do any rolling back by
hand - we would just return a failure from the action execution, and the state would not be
updated. So, when in the contract state is updated, it is just a local copy of this state being
altered, but the partial changes would never be visible by other contracts.

Queries
There is one building block in the CosmWasm approach to the Actor model, which I haven't
yet cover. As I said, the whole state of every contract is public and available for everyone to
look at. The problem is that this way of looking at state is not very convenient - it requires
users of contracts to know its internal structure, which kind of violates the SOLID rules
(Liskov substitution principle in particular). If, for example a contract is updated and its state
structure changes a bit, another contract looking at its state would just nevermore work.
Also, it is often the case, that the contract state is kind of simplified, and information that is
relevant to the observer would be calculated from the state.

This is where queries come into play. Queries are the type of messages to contract, which
does not perform any actions, so do not update any state, but can return an answer
immediately.

In our KFC comparison, the query would be if Seller goes to Chef to ask "Do we still have
pickles available for our cheeseburgers"? It can be done while operating, and response can
be used in it. It is possible because queries can never update their state, so they do not need
to be handled in a transactional manner.

However, the existence of queries doesn't mean that we cannot look at the contract's state
directly - the state is still public, and the technique of looking at them directly is called Raw
Queries . For clarity, non-raw queries are sometimes denoted as Smart Queries .

https://book.cosmwasm.com/print.html 63/102
24/06/2023, 20:53 CosmWasm book

Wrapping everything together - transactional call flow


So, we touched on many things here, and I know it may be kind of confusing. Because of
that, I would like to go through some more complicated calls to the CosmWasm contract to
visualize what the "transactional state" means.

Let's imagine two contracts:

1. The MmoCurrency contract mentioned before, which can perform the Transfer action,
allows transferring some amount of currency to some receiver .
2. The WarriorNpc contract, which would have some amount of our currency, and he
would be used by our MMO engine to pay the reward out for some quest player could
perform. It would be triggered by Payout action, which can be called only by a specific
client (which would be our game engine).

Now here is an interesting thing - this model forces us to make our MMO more realistic in
terms of the economy that we traditionally see - it is because WarriorNpc has some amount
of currency, and cannot create more out of anything. It is not always the case (the previously
mentioned cw20 has a notion of Minting for this case), but for the sake of simplicity let's
assume this is what we want.

To make the quest reasonable for longer, we would make a reward for it to be always
between 1 mmo and 100 mmo , but it would be ideally 15% of what Warrior owns. This
means that the quest reward decreases for every subsequent player, until Warrior would be
broke, left with nothing, and will no longer be able to payout players.

So, what would the flow look like? The first game would send a Payout message to the
WarriorNpc contract, with info on who should get the reward. Warrior would keep track of
players who fulfilled the quest, to not pay out the same person twice - there would be a list
of players in his state. First, he would check the list looking for players to pay out - if he is
there, he will finish the transaction with an error.

However, in most cases the player would not be on the list - so then WarriorNpc would add
him to the list. Now the Warrior would finish his part of the task, and schedule the Transfer
action to be performed by MmoCurrency .

But there is the important thing - because Transfer action is actually part of the bigger
Payout flow, it would not be executed on the original blockchain state, but on the local copy
of it, to which the player's list is already applied to. So if the MmoCurrency would for any
reason takes a look at WarriorNpc internal list, it would be already updated.

Now MmoCurrency is doing its job, updating the state of Warrior and player balance (note,
that our Warrior is here just treated as another player!). When it finishes, two things may
happen:

1. There was an error - possibly Warrior is out of cash, and it can nevermore pay for the
task. In such case, none of the changes - neither updating the list of players
https://book.cosmwasm.com/print.html 64/102
24/06/2023, 20:53 CosmWasm book

succeeding, nor balance changes are not applied to the original blockchain storage, so
they are like they never happened. In the database world, it is denoted as rolling back
the transaction.
2. Operation succeed - all changes on the state are now applied to the blockchain, and
any further observation of MmoCurrency or WarriorNpc by the external world would
see updated data.

There is one problem - in this model, our list is not a list of players who fulfilled the quest (as
we wanted it to be), but the list of players who paid out (as in transfer failure, the list is not
updated). We can do better.

Different ways of handling responses


Note that we didn't mention a Reply operation at all. So why was it not called by
MmoCurrency on WarriorNpc ? The reason is that this operation is optional. When
scheduling sub-actions on another contract we may choose when Reply how the result
should be handled:

1. Never call Reply , action fails if sub-message fails


2. Call Reply on success
3. Call Reply on failure
4. Always call Reply

So, if we do not request Reply to be called by subsequent contract, it will not happen. In
such a case if a sub-call fails, the whole transaction is rolled back - sub-message failure
transitively causes the original message failure. It is probably a bit complicated for now, but I
promise it would be simple if you would did some practice with that.

When handling the reply, it is important to remember, that although changes are not yet
applied to the blockchain (the transaction still can be failed), the reply handler is already
working on the copy of the state with all changes made by sub-message so far applied. In
most cases, it would be a good thing, but it has a tricky consequence - if the contract is
calling itself recursively, it is possible that subsequent call overwrote things set up in the
original message. It rarely happens, but may need special treatment in some cases - for now
I don't want to go deeply into details, but I want you to remember about what to expect after
state in the actor's flow.

Now let's take a look at handling results with 2 - 4 options. It is actually interesting, that
using 2 , even if the transaction is performed by sub-call succeed, we may now take a look at
the data it returned with Reply , and on its final state after it finished, and we can still
decide, that act as a whole is a failure, in which case everything would be rolled back - even
currency transfer performed by external contract.

https://book.cosmwasm.com/print.html 65/102
24/06/2023, 20:53 CosmWasm book

In our case, an interesting option is 3 . So, if the contract would call Reply on failure, we can
decide to claim success, and commit a transaction on the state if the sub call failed. Why
may it be relevant for us? Possibly because our internal list was supposed to keep the list of
players succeeding with the quest, not paid out! So, if we have no more currency, we still
want to update the list!

The most common way to use the replies (option 2 in particular) is to instantiate another
contract, managed by the one called. The idea is that in those use cases, the creator contract
wants to keep the address of the created contract in its state. To do so it has to create an
Instantiate sub-message, and subscribe for its success response, which contains the
address of the freshly created contract.

In the end, you can see that performing actions in CosmWasm is built with hierarchical state
change transactions. The sub-transaction can be applied to the blockchain only if everything
succeeds, but in case that sub-transaction failed, only its part may be rolled back, end other
changes may be applied. It is very similar to how most database systems work.

Conclusion
Now you have seen the power of the actor model to avoid reentrancy, properly handle
errors, and safely sandbox contracts. This helps us provide the solid security guarantees of
the CosmWasm platform. Let’s get started playing around with real contracts in the wasmd
blockchain.

https://book.cosmwasm.com/print.html 66/102
24/06/2023, 20:53 CosmWasm book

Actors in blockchain
Previously we were talking about actors mostly in the abstraction of any blockchain-specific
terms. However, before we would dive into the code, we need to establish some common
language, and to do so we would look at contracts from the perspective of external users,
instead of their implementation.

In this part, I would use the wasmd binary to communicate with the malaga testnet. To
properly set it up, check the Quick start with wasmd .

Blockchain as a database
It is kind of starting from the end, but I would start with the state part of the actor model.
Relating to traditional systems, there is one particular thing I like to compare blockchain with
- it is a database.

Going back to the previous section we learned that the most important part of a contract is
its state. Manipulating the state is the only way to persistently manifest work performed to
the world. But What is the thing which purpose is to keep the state? It is a database!

So here is my (as a contract developer) point of view on contracts: it is a distributed


database, with some magical mechanisms to make it democratic. Those "magical
mechanisms" are crucial for BC's existence and they make they are reasons why even use
blockchain, but they are not relevant from the contract creator's point of view - for us,
everything that matters is the state.

But you can say: what about the financial part?! Isn't blockchain ( wasmd in particular) the
currency implementation? With all of those gas costs, sending funds seems very much like a
money transfer, not database updates. And yes, you are kind of right, but I have a solution
for that too. Just imagine, that for every native token (by "native tokens" we meant tokens
handled directly by blockchain, in contradiction to for example cw20 tokens) there is a
special database bucket (or table if you prefer) with mapping of address to how much of a
token the address possesses. You can query this table (querying for token balance), but you
cannot modify it directly. To modify it you just send a message to a special build-in bank
contract. And everything is still a database.

But if blockchain is a database, then where are smart contracts stored? Obviously - in the
database itself! So now imagine another special table - this one would contain a single table
of code-ids mapped to blobs of wasm binaries. And again - to operate on this table, you use
"special contract" which is not accessible from another contract, but you can use it via
wasmd binary.

https://book.cosmwasm.com/print.html 67/102
24/06/2023, 20:53 CosmWasm book

Now there is a question - why do I even care about BC being a DB? So the reason is that it
makes reasoning about everything in blockchain very natural. Do you remember that every
message in the actor model is transactional? It perfectly matches traditional database
transactions (meaning: every message starts a new transaction)! Also, when we later talk
about migrations, it would turn out, that migrations in CosmWasm are very much
equivalents of schema migrations in traditional databases.

So, the thing to remember - blockchain is very similar to a database, having some specially
reserved tables (like native tokens, code repository), with a special bucket created for every
contract. A contract can look at every table in every bucket in the whole blockchain, but it
can modify the only one he created.

Compile the contract


I will not go into the code for now, but to start with something we need compiled contract
binary. The cw4-group contract from cw-plus is simple enough to work with, for now, so we
will start with compiling it. Start with cloning the repository:

$ git clone git@github.com:CosmWasm/cw-plus.git

Then go to cw4-group contract and build it:

$ cd cw-plus/contracts/cw4-group
$ docker run --rm -v "$(pwd)":/code \
--mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
cosmwasm/workspace-optimizer:0.12.6

Your final binary should be located in the cw-plus/artifacts folder ( cw-plus being where
you cloned your repository).

Contract code
When the contract binary is built, the first interaction with CosmWasm is uploading it to the
blockchain (assuming you have your wasm binary in the working directory):

$ wasmd tx wasm store ./cw4-group.wasm --from wallet $TXFLAG -y -b block

As a result of such an operation you would get json output like this:

https://book.cosmwasm.com/print.html 68/102
24/06/2023, 20:53 CosmWasm book

..
logs:
..
- events:
..
- attributes:
- key: code_id
value: "1069"
type: store_code

I ignored most of not fields as they are not relevant for now - what we care about is the
event emitted by blockchain with information about code_id of stored contract - in my case
the contract code was stored in blockchain under the id of 1069 . I can now look at the code
by querying for it:

$ wasmd query wasm code 1069 code.wasm

And now the important thing - the contract code is not an actor. So, what is a contract code?
I think that the easiest way to think about that is a class or a type in programming. It
defines some stuff about what can be done, but the class itself is in most cases not very
useful unless we create an instance of a type, on which we can call class methods. So now
let's move forward to instances of such contract classes.

Contract instance
Now we have a contract code, but what we want is an actual contract itself. To create it, we
need to instantiate it. Relating to analogy to programming, instantiation is calling a
constructor. To do that, I would send an instantiate message to my contract:

$ wasmd tx wasm instantiate 1069 '{"members": []}' --from wallet --label "Group
1" --no-admin $TXFLAG -y

What I do here is create a new contract and immediately call the Instantiate message on
it. The structure of such a message is different for every contract code. In particular, the
cw4-group Instantiate message contains two fields:

members field which is the list of initial group members optional admin
field which defines an address of who can add or remove a group member

In this case, I created an empty group with no admin - so which could never change! It may
seem like a not very useful contract, but it serves us as a contract example.

As the result of instantiating, I got the result:

https://book.cosmwasm.com/print.html 69/102
24/06/2023, 20:53 CosmWasm book

..
logs:
..
- events:
..
- attributes:
- key: _contract_address
value: wasm1u0grxl65reu6spujnf20ngcpz3jvjfsp5rs7lkavud3rhppnyhmqqnkcx6
- key: code_id
value: "1069"
type: instantiate

As you can see, we again look at logs[].events[] field, looking for interesting event and
extracting information from it - it is the common case. I will talk about events and their
attributes in the future but in general, it is a way to notify the world that something
happened. Do you remember the KFC example? If a waiter is serving our dish, he would put
a tray on the bar, and she would yell (or put on the screen) the order number - this would be
announcing an event, so you know some summary of operation, so you can go and do
something useful with it.

So, what use can we do with the contract? We obviously can call it! But first I want to tell you
about addresses.

Addresses in CosmWasm
Address in CosmWasm is a way to refer to entities in the blockchain. There are two types of
addresses: contract addresses, and non-contracts. The difference is that you can send
messages to contract addresses, as there is some smart contract code associated with them,
and non-contracts are just users of the system. In an actor model, contract addresses
represent actors, and non-contracts represent clients of the system.

When operating with blockchain using wasmd , you also have an address - you got one when
you added the key to wasmd :

# add wallets for testing


$ wasmd keys add wallet3
- name: wallet3
type: local
address: wasm1dk6sq0786m6ayg9kd0ylgugykxe0n6h0ts7d8t
pubkey:
'{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"Ap5zuScYVRr5Clz7QLzu0CJNTg07+7G
mnemonic: ""

You can always check your address:

https://book.cosmwasm.com/print.html 70/102
24/06/2023, 20:53 CosmWasm book

$ wasmd keys show wallet


- name: wallet
type: local
address: wasm1um59mldkdj8ayl5gknp9pnrdlw33v40sh5l4nx
pubkey:
'{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A5bBdhYS/4qouAfLUH9h9+ndRJKvK0c
mnemonic: ""

Having an address is very important because it is a requirement for being able to call
anything. When we send a message to a contract it always knows the address which sends
this message so it can identify it - not to mention that this sender is an address that would
play a gas cost.

Querying the contract


So, we have our contract, let's try to do something with it - query would be the easiest thing
to do. Let's do it:

$ wasmd query wasm contract-state smart


wasm1u0grxl65reu6spujnf20ngcpz3jvjfsp5rs7lkavud3rhppnyhmqqnkcx6 '{
"list_members": {} }'
data:
members: []

The wasm... string is the contract address, and you have to substitute it with your contract
address. { "list_members": {} } is query message we send to contract. Typically, CW
smart contract queries are in the form of a single JSON object, with one field: the query
name ( list_members in our case). The value of this field is another object, being query
parameters - if there are any. list_members query handles two parameters: limit , and
start_after , which are both optional and which support result pagination. However, in our
case of an empty group they don't matter.

The query result we got is in human-readable text form (if we want to get the JSON from - for
example, to process it further with jq , just pass the -o json flag). As you can see response
contains one field: members which is an empty array.

So, can we do anything more with this contract? Not much. But let's try to do something with
a new one!

https://book.cosmwasm.com/print.html 71/102
24/06/2023, 20:53 CosmWasm book

Executions to perform some actions


The problem with our previous contract is that for the cw4-group contract, the only one
who can perform executions on it is an admin, but our contract doesn't have one. This is not
true for every smart contract, but it is the nature of this one.

So, let's make a new group contract, but this time we would make ourselves an admin. First,
check our wallet address:

$ wasmd keys show wallet

And instantiate a new group contract - this time with proper admin:

$ wasmd tx wasm instantiate 1069 '{"members": [], "admin":


"wasm1um59mldkdj8ayl5gknp9pnrdlw33v40sh5l4nx"}' --from wallet --label "Group 1"
--no-admin $TXFLAG -y
..
logs:
- events:
..
- attributes:
- key: _contract_address
value: wasm1n5x8hmstlzdzy5jxd70273tuptr4zsclrwx0nsqv7qns5gm4vraqeam24u
- key: code_id
value: "1069"
type: instantiate

You may ask, why do we pass some kind of --no-admin flag, if we just said, we want to set
an admin to the contract? The answer is sad and confusing, but... it is a different admin. The
admin we want to set is one checked by the contract itself and managed by him. The admin
which is declined with --no-admin flag, is a wasmd-level admin, which can migrate the
contract. You don't need to worry about the second one at least until you learn about
contract migrations - until then you can always pass the --no-admin flag to the contract.

Now let's query our new contract for the member's list:

$ wasmd query wasm contract-state smart


wasm1n5x8hmstlzdzy5jxd70273tuptr4zsclrwx0nsqv7qns5gm4vraqeam24u '{
"list_members": {} }'
data:
members: []

Just like before - no members initially. Now check an admin:

$ wasmd query wasm contract-state smart


wasm1n5x8hmstlzdzy5jxd70273tuptr4zsclrwx0nsqv7qns5gm4vraqeam24u '{ "admin": {}
}'
data:
admin: wasm1um59mldkdj8ayl5gknp9pnrdlw33v40sh5l4nx

https://book.cosmwasm.com/print.html 72/102
24/06/2023, 20:53 CosmWasm book

So, there is an admin, it seems like the one we wanted to have there. So now we would add
someone to the group - maybe ourselves?

wasmd tx wasm execute


wasm1n5x8hmstlzdzy5jxd70273tuptr4zsclrwx0nsqv7qns5gm4vraqeam24u '{
"update_members": { "add": [{ "addr": "wasm1um59mldkdj8ayl5gkn
p9pnrdlw33v40sh5l4nx", "weight": 1 }], "remove": [] } }' --from wallet $TXFLAG -
y

The message for modifying the members is update_members and it has two fields: members
to remove, and members to add. Members to remove are just addresses. Members to add
have a bit more complex structure: they are records with two fields: address and weight.
Weight is not relevant for us now, it is just metadata stored with every group member - for
us, it would always be 1.

Let's query the contract again to check if our message changed anything:

$ wasmd query wasm contract-state smart


wasm1n5x8hmstlzdzy5jxd70273tuptr4zsclrwx0nsqv7qns5gm4vraqeam24u '{
"list_members": {} }'
data:
members:
- addr: wasm1um59mldkdj8ayl5gknp9pnrdlw33v40sh5l4nx
weight: 1

As you can see, the contract updated its state. This is basically how it works - sending
messages to contracts causes them to update the state, and the state can be queried at any
time. For now, to keep things simple we were just interacting with the contract directly by
wasmd , but as described before - contracts can communicate with each other. However, to
investigate this we need to understand how to write contracts. Next time we will look at the
contract structure and we will map it part by part to what we have learned until now.

https://book.cosmwasm.com/print.html 73/102
24/06/2023, 20:53 CosmWasm book

Smart contract as an actor


In previous chapters, we talked about the actor model and how it is implemented in the
blockchain. Now it is time to look closer into the typical contract structure to understand
how different features of the actor model are mapped to it.

This will not be a step-by-step guide on contract creation, as it is a topic for the series itself.
It would be going through contract elements roughly to visualize how to handle architecture
in the actor model.

The state
As before we would start with the state. Previously we were working with the cw4-group
contract, so let's start by looking at its code. Go to cw-plus/contracts/cw4-group/src . The
folder structure should look like this:

 src
├──  contract.rs
├──  error.rs
├──  helpers.rs
├──  lib.rs
├──  msg.rs
└──  state.rs

As you may already figure out, we want to check the state.rs first.

The most important thing here is a couple of constants: ADMIN , HOOKS , TOTAL , and
MEMBERS . Every one of such constants represents a single portion of the contract state - as
tables in databases. The types of those constants represent what kind of table this is. The
most basic ones are Item<T> , which keeps zero or one element of a given type, and Map<K,
T> which is a key-value map.

You can see Item is used to keep an admin and some other data: HOOKS , and TOTAL .
HOOKS is used by the cw4-group to allow subscription to any changes to a group - a contract
can be added as a hook, so when the group changes, a message is sent to it. The TOTAL is
just a sum of all members' weights.

The MEMBERS in the group contract is the SnapshotMap - as you can imagine, it is a Map , with
some steroids - this particular one, gives us access to the state of the map at some point in
history, accessing it by the blockchain height . height is the count of blocks created since
the beggining of blockchain, and it is the most atomic time representation in smart
contracts. There is a way to access the clock time in them, but everything happening in a
single block is considered happening in the same moment.

https://book.cosmwasm.com/print.html 74/102
24/06/2023, 20:53 CosmWasm book

Other types of storage objects not used in group contracts are:

IndexedMap - another map type, that allows accessing values by a variety of keys
IndexedSnapshotMap - IndexedMap and SnapshotMap married

What is very important - every state type in the contract is accessed using some name. All of
those types are not containers, just accessors to the state. Do you remember that I told you
before that blockchain is our database? And that is correct! All those types are just ORM to
this database - when we use them to get actual data from it, we pass a special State object
to them, so they can retrieve items from it.

You may ask - why all that data for a contract are not auto-fetched by whatever is running it.
That is a good question. The reason is that we want contracts to be lazy with fetching.
Copying data is a very expensive operation, and for everything happening on it, someone
has to pay - it is realized by gas cost. I told you before, that as a contract developer you don't
need to worry about gas at all, but it was only partially true. You don't need to know exactly
how gas is calculated, but by lowering your gas cost, you would may execution of your
contracts cheaper which is typically a good thing. One good practice to achieve that is to
avoid fetching data you will not use in a particular call.

Messages
In a blockchain, contracts communicate with each other by some JSON messages. They are
defined in most contracts in the msg.rs file. Take a look at it.

There are three types on it, let's go through them one by one. The first one is an
InstantiateMsg . This is the one, that is sent on contract instantiation. It typically contains
some data which is needed to properly initialize it. In most cases, it is just a simple structure.

Then there are two enums: ExecuteMsg , and QueryMsg . They are enums because every
single variant of them represents a different message which can be sent. For example, the
ExecuteMsg::UpdateAdmin corresponds to the update_admin message we were sending
previously.

Note, that all the messages are attributed with #[derive(Serialize, Deserialize)] , and #
[serde(rename_all="snake_case")] . Those attributes come from the serde crate, and they
help us with deserialization of them (and serialization in case of sending them to other
contracts). The second one is not required, but it allows us to keep a camel-case style in our
Rust code, and yet still have JSONs encoded with a snake-case style more typical to this
format.

I encourage you to take a closer look at the serde documentation, like everything there, can
be used with the messages.

https://book.cosmwasm.com/print.html 75/102
24/06/2023, 20:53 CosmWasm book

One important thing to notice - empty variants of those enums, tend to use the empty
brackets, like Admin {} instead of more Rusty Admin . It is on purpose, to make JSONs
cleaner, and it is related to how serde serializes enum.

Also worth noting is that those message types are not set in stone, they can be anything.
This is just a convention, but sometimes you would see things like ExecuteCw4Msg , or
similar. Just keep in mind, to keep your message name obvious in terms of their purpose -
sticking to ExecuteMsg / QueryMsg is generally a good idea.

Entry points
So now, when we have our contract message, we need a way to handle them. They are sent
to our contract via entry points. There are three entry points in the cw4-group contract:

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn instantiate(
deps: DepsMut,
env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
// ...
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
// ..
}
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
// ..
}

Those functions are called by the CosmWasm virtual machine when a message is to be
handled by contract. You can think about them as the main function of normal programs,
except they have a signature that better describes the blockchain itself.

What is very important is that the names of those entry points (similarly to the main
function) are fixed - it is relevant, so the virtual machine knows exactly what to call.

So, let's start with the first line. Every entry point is attributed with #[cfg_attr(not(feature
= "library"), entry_point)] . It may look a bit scary, but it is just a conditional equivalent
of #[entry_point] - the attribute would be there if and only if the "library" feature is not
set. We do this to be able to use our contracts as dependencies for other contracts - the final
https://book.cosmwasm.com/print.html 76/102
24/06/2023, 20:53 CosmWasm book

binary can contain only one copy of each entry point, so we make sure, that only the top-
level one is compiled without this feature.

The entry_point attribute is a macro that generates some boilerplate. As the binary is run
by WASM virtual machine, it doesn't know much about Rust types - the actual entry point
signatures are very inconvenient to use. To overcome this issue, there is a macro created,
which generates entry points for us, and those entry points are just calling our functions.

Now take a look at functions arguments. Every single entry point takes as the last argument
a message which triggered the execution of it (except for reply - I will explain it later). In
addition to that, there are additional arguments provided by blockchain:

Deps or DepsMut object is the gateway to the world outside the smart contract
context. It allows accessing the contract state, as well as querying other contracts, and
also delivers an Api object with a couple of useful utility functions. The difference is
that DepsMut allows updating state, while Deps allows only to look at it.
Env object delivers information about the blockchain state at the moment of
execution - its height, the timestamp of execution and information about the executing
contract itself.
MessageInfo object is information about the contract call - it contains the address
which sends the message, and the funds sent with the message.

Keep in mind, that the signatures of those functions are fixed (except the messages type), so
you cannot interchange Deps with DepsMut to update the contract state in the query call.

The last portion of entry points is the return type. Every entry point returns a Result type,
with any error which can be turned into a string - in case of contract failure, the returned
error is just logged. In most cases, the error type is defined for a contract itself, typically
using a thiserror crate. Thiserror is not required here, but is strongly recommended -
using it makes the error definition very straightforward, and also improves the testability of
the contract.

The important thing is the Ok part of Result . Let's start with the query because this one is
the simplest. The query always returns the Binary object on the Ok case, which would
contain just serialized response. The common way to create it is just calling a to_binary
method on an object implementing serde::Serialize , and they are typically defined in
msg.rs next to message types.

Slightly more complex is the return type returned by any other entry point - the
cosmwasm_std::Response type. This one keep everything needed to complete contract
execution. There are three chunks of information in that.

The first one is an events field. It contains all events, which would be emitted to the
blockchain as a result of the execution. Events have a really simple structure: they have a
type, which is just a string, and a list of attributes which are just string-string key-value pairs.

https://book.cosmwasm.com/print.html 77/102
24/06/2023, 20:53 CosmWasm book

You can notice that there is another attributes field on the Response . This is just for
convenience - most executions would return only a single event, and to make it a bit easier
to operate one, there is a set of attributes directly on response. All of them would be
converted to a single wasm event which would be emitted. Because of that, I consider
events and attributes to be the same chunk of data.

Then we have the messages field, of SubMsg type. This one is the clue of cross-contact
communication. Those messages would be sent to the contracts after processing. What is
important - the whole execution is not finished, unless the processing of all sub-messages
scheduled by the contract finishes. So, if the group contract sends some messages as a
result of update_members execution, the execution would be considered done only if all the
messages sent by it would also be handled (even if they failed).

So, when all the sub-messages sent by contract are processed, then all the attributes
generated by all sub-calls and top-level calls are collected and reported to the blockchain.
But there is one additional piece of information - the data . So, this is another Binary field,
just like the result of a query call, and just like it, it typically contains serialized JSON. Every
contract call can return some additional information in any format. You may ask - in this
case, why do we even bother returning attributes? It is because of a completely different way
of emitting events and data. Any attributes emitted by the contract would be visible on
blockchain eventually (unless the whole message handling fails). So, if your contract emitted
some event as a result of being sub-call of some bigger use case, the event would always be
there visible to everyone. This is not true for data. Every contract call would return only a
single data chunk, and it has to decide if it would just forward the data field of one of the
sub-calls, or maybe it would construct something by itself. I would explain it in a bit more
detail in a while.

Sending submessages
I don't want to go into details of the Response API, as it can be read directly from
documentation, but I want to take a bit closer look at the part about sending messages.

The first function to use here is add_message , which takes as an argument the CosmosMsg
(or rather anything convertible to it). A message added to response this way would be sent
and processed, and its execution would not affect the result of the contract at all.

The other function to use is add_submessage , taking a SubMsg argument. It doesn't differ
much from add_message - SubMsg just wraps the CosmosMsg , adding some info to it: the
id field, and reply_on . There is also a gas_limit thing, but it is not so important - it just
causes sub-message processing to fail early if the gas threshold is reached.

The simple thing is reply_on - it describes if the reply message should be sent on
processing success, on failure, or both.

https://book.cosmwasm.com/print.html 78/102
24/06/2023, 20:53 CosmWasm book

The id field is an equivalent of the order id in our KFC example from the very beginning. If
you send multiple different sub-messages, it would be impossible to distinguish them
without that field. It would not even be possible to figure out what type of original message
reply handling is! This is why the id field is there - sending a sub-message you can set it to
any value, and then on the reply, you can figure out what is happening based on this field.

An important note here - you don't need to worry about some sophisticated way of
generating ids. Remember, that the whole processing is atomic, and only one execution can
be in progress at once. In most cases, your contract sends a fixed number of sub-messages
on very concrete executions. Because of that, you can hardcode most of those ids while
sending (preferably using some constant).

To easily create submessages, instead of setting all the fields separately, you would typically
use helper constructors: SubMsg::reply_on_success , SubMsg::reply_on_error and
SubMsg::reply_always .

CosmosMsg
If you took a look at the CosmosMsg type, you could be very surprised - there are so many
variants of them, and it is not obvious how they relate to communication with other
contracts.

The message you are looking for is the WasmMsg ( CosmosMsg::Wasm variant). This one is very
much similar to what we already know - it has a couple of variants of operation to be
performed by contracts: Execute , but also Instantiate (so we can create new contracts in
contract executions), and also Migrate , UpdateAdmin , and ClearAdmin - those are used to
manage migrations (will tell a bit about them at the end of this chapter).

Another interesting message is the BankMsg ( CosmosMsg::Bank ). This one allows a contract
to transfer native tokens to other contracts (or burn them - equivalent to transferring them
to some black whole contract). I like to think about it as sending a message to a very special
contract responsible for handling native tokens - this is not a true contract, as it is handled
by the blockchain itself, but at least to me it simplifies things.

Other variants of CosmosMsg are not very interesting for now. The Custom one is there to
allow other CosmWasm-based blockchains to add some blockchain-handled variant of the
message. This is a reason why most message-related types in CosmWasm are generic over
some T - this is just a blockchain-specific type of message. We will never use it in the
wasmd . All other messages are related to advanced CosmWasm features, and I will not
describe them here.

https://book.cosmwasm.com/print.html 79/102
24/06/2023, 20:53 CosmWasm book

Reply handling
So now that we know how to send a submessage, it is time to talk about handling the reply.
When sub-message processing is finished, and it is requested to reply, the contract is called
with an entry point:

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn reply(deps: DepsMut, env: Env, msg: Reply) -> Result<Response,
ContractError> {
// ...
}

The DepsMut , and Env arguments are already familiar, but there is a new one, substituting
the typical message argument: the cosmwasm_std::Reply .

This is a type representing the execution status of the sub-message. It is slightly processed
cosmwasm_std::Response . The first important thing it contains is an id - the same, which
you set sending sub-message, so now you can identify your response. The other one is the
ContractResult , which is very similar to the Rust Result<T, String> type, except it is
there for serialization purposes. You can easily convert it into a Result with an
into_result function.

In the error case of ContracResult , there is a string - as I mentioned before, errors are
converted to strings right after execution. The Ok case contains SubMsgExecutionResponse
with two fields: events emitted by sub-call, and the data field embedded on response.

As said before, you never need to worry about forwarding events - CosmWasm would do it
anyway. The data however, is another story. As mentioned before, every call would return
only a single data object. In the case of sending sub-messages and not capturing a reply, it
would always be whatever is returned by the top-level message. But it is not the case when
reply is called. If a a reply is called, then it is a function deciding about the final data . It can
decide to either forward the data from the sub-message (by returning None ) or to overwrite
it. It cannot choose, to return data from the original execution processing - if the contract
sends sub-messages waiting for replies, it is supposed to not return any data, unless replies
are called.

But what happens if multiple sub-messages are sent? What would the final data contain?
The rule is - the last non-None. All sub-messages are always called in the order of adding
them to the Response . As the order is deterministic and well defined, it is always easy to
predict which reply would be used.

https://book.cosmwasm.com/print.html 80/102
24/06/2023, 20:53 CosmWasm book

Migrations
I mentioned migrations earlier when describing the WasmMsg . So, migration is another action
possible to be performed by contracts, which is kind of similar to instantiate. In software
engineering, it is a common thing to release an updated version of applications. It is also a
case in the blockchain - SmartContract can be updated with some new features. In such
cases, a new code is uploaded, and the contract is migrated - so it knows that from this
point, its messages are handled by another, updated contract code.

However, it may be that the contract state used by the older version of the contract differs
from the new one. It is not a problem if some info was added (for example some additional
map - it would be just empty right after migration). But the problem is, when the state
changes, for example, the field is renamed. In such a case, every contract execution would
fail because of (de)serialization problems. Or even more subtle cases, like adding a map, but
one which should be synchronized with the whole contract state, not empty.

This is the purpose of the migration entry point. It looks like this:

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response<T>,
ContracError> {
// ..
}

MigrateMsg is the type defined by the contract in msg.rs . The migrate entry point would
be called at the moment of performing the migration, and it is responsible for making sure
the state is correct after the migration. It is very similar to schema migrations in traditional
database applications. And it is also kind of difficult, because of version management
involved - you can never assume, that you are migrating a contract from the previous
version - it can be migrated from any version, released anytime - even later than that version
we are migrating to!

It is worth bringing back one issue from the past - the contract admin. Do you remember the
--no-admin flag we set previously on every contract instantiation? It made our contract
unmigrateable. Migrations can be performed only by contract admin. To be able to use it,
you should pass --admin address flag instead, with the address being the address that
would be able to perform migrations.

Sudo
Sudo is the last basic entry point in CosmWasm , and it is the one we would never use in
wasmd . It is equivalent to CosmosMsg::Custom , but instead of being a special blockchain-
specific message to be sent and handled by a blockchain itself, it is now a special blockchain-
specific message sent by the blockchain to contract in some conditions. There are many
https://book.cosmwasm.com/print.html 81/102
24/06/2023, 20:53 CosmWasm book

uses for those, but I will not cover them, because would not be related to CosmWasm itself.
The signature of sudo looks like this:

#[cfg_attr(not(feature = "library"), entry_point)]


pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> Result<Response,
ContractError> {
// ..
}

The important difference is that because sudo messages are blockchain specific, the
SudoMsg type is typically defined by some blockchain helper crate, not the contract itself.

https://book.cosmwasm.com/print.html 82/102
24/06/2023, 20:53 CosmWasm book

Cross contract communication


We already covered creating a single isolating contract. However, SOLID principles tell us
that entities should be as small as reasonably possible - such as they have a single
responsibility. Entities we are focusing on now are smart contracts, and we want to make
sure that every smart contract has a sole responsibility it takes care of.

But we also want to build complex systems using smart contracts. To do so, we need to be
able to communicate between them. We already talked about what such communication
looks like using an actor model. Now it's time to use this knowledge in practice.

In this chapter, we will improve the previously created administration group model to solve
the problem I brought - the possibility of adding own multiple addresses by a single admin
to take bigger donation parts.

We would also give admins some work to do besides being admins.

https://book.cosmwasm.com/print.html 83/102
24/06/2023, 20:53 CosmWasm book

Design
This time we will start discussing the design of our system a bit. Building multi-contract
systems tend to be a bit more complicated than just isolated contracts, so I want to give you
some anchor on what we are building in this chapter. If you feel lost with a design, don't
worry - it will get clear while implementing contracts. For now, go through it to get a general
idea.

First, let's think about the problem we want to solve. Our admins are a vector of addresses.
Anyone already an admin can add anyone he wants to the list. But this "anyone" can be a
second instance of the same admin account, so he counts twice for donations!

This issue is relatively simple to fix, but there is another problem - as we already learned, the
admin could create a smart contract which he and only he can withdraw tokens from and
register as another admin in the group! Instantiating it multiple times, he can achieve his
goal even if we prevent adding the same address multiple times. There would be many
distinct addresses that the same person owns.

It looks like an unpleasant situation, but there are ways to manage it. The one we would
implement is voting. Instead of being able to add another admin to the list, admins would be
allowed to propose their colleagues as new admins. It would start a voting process -
everyone who was an admin at the time of the proposal creation would be able to support
it. If more than half admins would support the new candidate, he would immediately
become an admin.

It is not the most convoluted voting process, but it would be enough for our purposes.

Voting process
To achieve this goal, we would create two smart contracts. First, one would be reused
contract from the Basics chapter - it would be an admin contract. Additionally, we would
add a voting contract. It would be responsible for managing a single voting process. It
would be instantiated by an admin contract whenever an admin wants to add his friend to a
list. Here is a diagram of the contracts relationship:

https://book.cosmwasm.com/print.html 84/102
24/06/2023, 20:53 CosmWasm book

admin

admins: Map<Addr, Timestamp>


voting
votings: Map<Addr, Addr>
votes: Vec<Addr>
propose_admin(candidate: Addr) manages votes_needed: u64
add_admin()
closed: bool
leave()
donate() accept()
  votes_list() -> Vec<Addr>
admins_list() -> Vec<Addr>
join_time() -> Timestamp

Here is adding an admin flowchart - assuming there are 5 admins on the contract already,
but 2 of them did nothing:

Admin 1 Admin 2 Admin 3 Admin Contract

exec propose_admin { addr: new_admin }

instantiate { addr: "new_admin", required: 3 }

Votes

exec accept {}

query join_time { admin: "admin2" }

resp join_time_resp { joined: ... }

add vote

exec accept {}

query join_time { admin: "admin3" }

resp join_time_resp { joined: ... }

add vote

add_admin { addr: new_admin }

Admin 1 Admin 2 Admin 3 Admin Contract Votes

I already put some hints about contracts implementation, but I will not go into them yet.

https://book.cosmwasm.com/print.html 85/102
24/06/2023, 20:53 CosmWasm book

Messages forwarding
There is one other thing we want to add - some way to give admins work. The admin
contract would behave like a proxy to call another contract. That means that some other
external contract would just set our admin instance as a specific address that can perform
executions on it, and admins would perform actions this way. The external contract would
see execution as the admin contract would do it. Here is an updated contracts diagram:

admin

admins: Map<Addr, Timestamp>


votings: Map<Addr, Addr> voting
propose_admin(candidate: Addr) votes: Vec<Addr>
add_admin() manages votes_needed: u64
leave() closed: bool
donate()
accept()
execute(contract: Addr, message: Binary)
votes_list() -> Vec<Addr>
 
admins_list() -> Vec<Addr>
join_time() -> Timestamp

forwards to

external

And calling external contract flowchart:

Admin Admin Contract External Contract

exec execute { addr: "external_contract", msg: message_to_execute }

exec message_to_execute

Admin Admin Contract External Contract

Note that the msg on execute admin contract message is some arbitrary message just
forwarded to the external contract. It would be a base64-encoded message in the real world,
but it is just an implementation detail.

https://book.cosmwasm.com/print.html 86/102
24/06/2023, 20:53 CosmWasm book

Ultimately, we will create a simple example of an external contract to understand how to use
such a pattern.

https://book.cosmwasm.com/print.html 87/102
24/06/2023, 20:53 CosmWasm book

Fixing admin contract


Now that we know what we want to achieve, we can start by aligning the contract we already
have to become an admin contract. It is primarily fine at this point, but we want to do a
cleanup.

Cleaning up queries
The first thing to do is to get rid of the Greet query - it was good as a starter query example,
but it has no practical purpose and only generates noise.

We want to remove the unnecessary variant from the query enum:

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
#[returns(AdminsListResp)]
AdminsList {},
}

Then we also remove the invalid path in the query dispatcher:

pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {


use QueryMsg::*;

match msg {
AdminsList {} => to_binary(&query::admins_list(deps)?),
}
}

Finally, we remove the irrelevant handler from the contract::query module. We also need
to make sure all references to it are gone (eg. if there are any in the tests).

Generating the library output


At the very beginning of the book, we set the crate-type in Cargo.toml as "cdylib" . It
was required to generate the wasm output, but it comes with a drawback - the dynamic
libraries, as this cannot be used as dependencies in other crates. It was not a problem
before, but in practice we often want to depend contract on others to get access to some
types of them - for example, defined messages.

https://book.cosmwasm.com/print.html 88/102
24/06/2023, 20:53 CosmWasm book

Good for us. It is easy to fix. You might notice that the crate-type is an array, not a single
string. The reason for that is that our project can emit several targets - in particular, we can
add there the default "rlib" crate type to make it generate a "rust library" output - which is
what we need to use as a dependency. Let's update our Cargo.toml :

[package]
name = "admin"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "rlib"]
#
# [features]
# library = []
#
# [dependencies]
# cosmwasm-std = { version = "1.1.4", features = ["staking"] }
# serde = { version = "1.0.103", default-features = false, features = ["derive"]
}
# cw-storage-plus = "0.15.1"
# thiserror = "1"
# schemars = "0.8.1"
# cw-utils = "0.15.1"
# cosmwasm-schema = "1.1.4"
#
# [dev-dependencies]
# cw-multi-test = "0.15.1"

Also, note I changed the contract name - "contract" is not very descriptive, so I updated it to
"admin".

Project structure
Last but not least - we want to better structure our project. So far, we have only one
contract, so we just worked on it as a whole project. Now we want some directory tree that
reflects relations between contracts we create.

First, create a directory for the project. Then we want to create a "contracts" subdirectory in
it. It is not technically required from Rust's POV, but there are tools in our environment, like
the workspace optimizer, which would assume it is where it should look for a contract. It is a
common pattern you will see in CosmWasm contracts repos.

Then we copy the whole project directory from the previous chapter into the contracts ,
renaming it to admin .

Finally, we want to couple all our projects (for now, it is just one, but we know there will be
more there). To do so, we create the workspace-level Cargo.toml file in the top-level project
directory:
https://book.cosmwasm.com/print.html 89/102
24/06/2023, 20:53 CosmWasm book

[workspace]
members = ["contracts/*"]
resolver = "2"

This Cargo.toml differs slightly from the typical project-level one - it defines the workspace.
The most important field here is the members - it defines projects being part of the
workspace.

The other field is the resolver . It is something to remember to add - it instructs cargo to
use version 2 of the dependency resolver. This has been the default for non-workspaces
since Rust 2021, but because of compatibility reasons, the default couldn't be changed for
workspaces - but it is advised to add it to every single newly created workspace.

The last field which might be useful for workspaces is exclude - it allows to create projects in
the workspace directory tree, which is not a part of this workspace - we will not use it, but it
is good to know about it.

Now just for clarity, let's see the top-level directory structure:

.
├── Cargo.lock
├── Cargo.toml
├── contracts
│ └── admin
└── target
├── CACHEDIR.TAG
└── debug

You can see the target directory and Cargo.lock files existing in the tree - it is because I
already built and ran tests for the admin contract - in Rust workspaces, `cargo`` knows to
build everything in the top level, even if it would be built from the inner directory.

https://book.cosmwasm.com/print.html 90/102
24/06/2023, 20:53 CosmWasm book

Map storage
There is one thing to be immediately improved in the admin contract. Let's check the
contract state:

pub const ADMINS: Item<Vec<Addr>> = Item::new("admins");


pub const DONATION_DENOM: Item<String> = Item::new("donation_denom");

Note that we keep our admin list as a single vector. However, in the whole contract, in most
cases, we access only a single element of this vector.

This is not ideal, as now, whenever we want to access the single admin entry, we have first to
deserialize the list containing all of them and then iterate over them until we find the
interesting one. This might consume a serious amount of gas and is completely unnecessary
overhead - we can avoid that using the Map storage accessor.

The Map storage


First, let's define a map - in this context, it would be a set of keys with values assigned to
them, just like a HashMap in Rust or dictionaries in many languages. We define it as similar
to an Item , but this time we need two types - the key type and the value type:

use cw_storage_plus::Map;

pub const STR_TO_INT_MAP: Map<String, u64> = Map::new("str_to_int_map");

Then to store some items on the Map , we use a save method - same as for an Item :

STR_TO_INT_MAP.save(deps.storage, "ten".to_owned(), 10);


STR_TO_INT_MAP.save(deps.storage, "one".to_owned(), 1);

Accessing entries in the map is also as easy as reading an item:

let ten = STR_TO_INT_MAP.load(deps.storage, "ten".to_owned())?;


assert_eq!(ten, 10);

let two = STR_TO_INT_MAP.may_load(deps.storage, "two".to_owned())?;


assert_eq!(two, None);

Obviously, if the element is missing in the map, the load function will result in an error -
just like for an item. On the other hand - may_load returns a Some variant when element
https://book.cosmwasm.com/print.html 91/102
24/06/2023, 20:53 CosmWasm book

exits.

Another very useful accessor that is specific to the map is the has function, which checks
for the existence of the key in the map:

let contains = STR_TO_INT_MAP.has(deps.storage, "three".to_owned())?;


assert!(!contains);

Finally, we can iterate over elements of the maps - either its keys or key-value pairs:

use cosmwasm_std::Order;

for k in STR_TO_INT_MAP.keys(deps.storage, None, None, Order::Ascending) {


let _addr = deps.api.addr_validate(k?);
}

for item in STR_TO_INT_MAP.range(deps.storage, None, None, Order::Ascending) {


let (_key, _value) = item?;
}

First, you might wonder about extra values passed to keys and range - those are in order:
lower and higher bounds of iterated elements, and the order elements should be traversed.

While working with typical Rust iterators, you would probably first create an iterator over all
the elements and then somehow skip those you are not interested in. After that, you will
stop after the last interesting element.

It would more often than not require accessing elements you filter out, and this is the
problem - it requires reading the element from the storage. And reading it from the storage
is the expensive part of working with data, which we try to avoid as much as possible. One
way to do it is to instruct the Map where to start and stop deserializing elements from
storage so it never reaches those outside the range.

Another critical thing to notice is that the iterator returned by both keys and range functions
are not iterators over elements - they are iterators over Result s. It is a thing because, as it
is rare, it might be that item is supposed to exist, but there is some error while reading from
storage - maybe the stored value is serialized in a way we didn't expect, and deserialization
fails. This is actually a real thing that happened in one of the contracts I worked on in the
past - we changed the value type of the Map, and then forgot to migrate it, which caused all
sorts of problems.

Maps as sets
So I imagine you can call me crazy right now - why do I spam about a Map , while we are
working with vector? It is clear that those two represent two distinct things! Or do they?
https://book.cosmwasm.com/print.html 92/102
24/06/2023, 20:53 CosmWasm book

Let's reconsider what we keep in the ADMINS vector - we have a list of objects which we
expect to be unique, which is a definition of a mathematical set. So now let me bring back
my initial definition of the map:

First, let's define a map - in this context, it would be a set of keys with values assigned
to them, just like a HashMap in Rust or dictionaries in many languages.

I purposely used the word "set" here - the map has the set built into it. It is a generalization
of a set or reversing the logic - the set is a particular case of a map. If you imagine a set that
map every single key to the same value, then the values become irrelevant, and such a map
becomes a set semantically.

How can you make a map mapping all the keys to the same value? We pick a type with a
single value. Typically in Rust, it would be a unit type ( () ), but in CosmWasm, we tend to use
the Empty type from CW standard crate:

use cosmwasm_std::{Addr, Empty};


use cw_storage_plus::Map;

pub const ADMINS: Map<Addr, Empty> = Map::new("admins");

We now need to fix the usage of the map in our contract. Let's start with contract
instantiation:

use crate::msg::InstantiateMsg;
use crate::state::{ADMINS, DONATION_DENOM};
use cosmwasm_std::{
DepsMut, Empty, Env, MessageInfo, Response, StdResult,
};

pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
for addr in msg.admins {
let admin = deps.api.addr_validate(&addr)?;
ADMINS.save(deps.storage, admin, &Empty {})?;
}
DONATION_DENOM.save(deps.storage, &msg.donation_denom)?;

Ok(Response::new())
}

It didn't simplify much, but we no longer need to collect our address. Then let's move to the
leaving logic:

https://book.cosmwasm.com/print.html 93/102
24/06/2023, 20:53 CosmWasm book

use crate::state::ADMINS;
use cosmwasm_std::{DepsMut, MessageInfo};

pub fn leave(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {


ADMINS.remove(deps.storage, info.sender.clone());

let resp = Response::new()


.add_attribute("action", "leave")
.add_attribute("sender", info.sender.as_str());

Ok(resp)
}

Here we see a difference - we don't need to load a whole vector. We remove a single entry
with the remove function.

What I didn't emphasize before, and what is relevant, is that Map stores every single key as a
distinct item. This way, accessing a single element will be cheaper than using a vector.

However, this has its downside - accessing all the elements is more gas-consuming using
Map! In general, we tend to avoid such situations - the linear complexity of the contract
might lead to very expensive executions (gas-wise) and potential vulnerabilities - if the user
finds a way to create many dummy elements in such a vector, he may make the execution
cost exceeding any gas limit.

Unfortunately, we have such an iteration in our contract - the distribution flow becomes as
follows:

https://book.cosmwasm.com/print.html 94/102
24/06/2023, 20:53 CosmWasm book

use crate::error::ContractError;
use crate::state::{ADMINS, DONATION_DENOM};
use cosmwasm_std::{
coins, BankMsg,DepsMut, MessageInfo, Order, Response
};

pub fn donate(deps: DepsMut, info: MessageInfo) -> Result<Response,


ContractError> {
let denom = DONATION_DENOM.load(deps.storage)?;
let admins: Result<Vec<_>, _> = ADMINS
.keys(deps.storage, None, None, Order::Ascending)
.collect();
let admins = admins?;

let donation = cw_utils::must_pay(&info, &denom)?.u128();

let donation_per_admin = donation / (admins.len() as u128);

let messages = admins.into_iter().map(|admin| BankMsg::Send {


to_address: admin.to_string(),
amount: coins(donation_per_admin, &denom),
});

let resp = Response::new()


.add_messages(messages)
.add_attribute("action", "donate")
.add_attribute("amount", donation.to_string())
.add_attribute("per_admin", donation_per_admin.to_string());

Ok(resp)
}

If I had to write a contract like this, and this donate would be a critical, often called flow, I
would advocate for going for an Item<Vec<Addr>> here. Hopefully, it is not the case - the
distribution does not have to be linear in complexity! It might sound a bit crazy, as we have
to iterate over all receivers to distribute funds, but this is not true - there is a pretty nice way
to do so in constant time, which I will describe later in the book. For now, we will leave it as it
is, acknowledging the flaw of the contract, which we will fix later.

The final function to fix is the admins_list query handler:

https://book.cosmwasm.com/print.html 95/102
24/06/2023, 20:53 CosmWasm book

use crate::state::ADMINS;
use cosmwasm_std::{Deps, Order, StdResult};

pub fn admins_list(deps: Deps) -> StdResult<AdminsListResp> {


let admins: Result<Vec<_>, _> = ADMINS
.keys(deps.storage, None, None, Order::Ascending)
.collect();
let admins = admins?;
let resp = AdminsListResp { admins };
Ok(resp)
}

Here we also have an issue with linear complexity, but it is far less of a problem.

First, queries are often purposed to be called on local nodes, with no gas cost - we can query
contracts as much as we want.

And then, even if we have some limit on execution time/cost, there is no reason to query all
the items every single time! We will fix this function later, adding pagination - to limit the
execution time/cost of the query caller would be able to ask for a limited amount of items
starting from the given one. Knowing this chapter, you can probably figure implementation
of it right now, but I will show the common way we do that when I go through common
CosmWasm practices.

Reference keys
There is one subtlety to improve in our map usage.

The thing is that right now, we index the map with the owned Addr key. That forces us to
clone it if we want to reuse the key (particularly in the leave implementation). This is not a
huge cost, but we can avoid it - we can define the key of the map to be a reference:

use cosmwasm_std::{Addr, Empty};


use cw_storage_plus::Map;

pub const ADMINS: Map<&Addr, Empty> = Map::new("admins");


pub const DONATION_DENOM: Item<String> = Item::new("donation_denom");

Finally, we need to fix the usages of the map in two places:

https://book.cosmwasm.com/print.html 96/102
24/06/2023, 20:53 CosmWasm book

pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
for addr in msg.admins {
let admin = deps.api.addr_validate(&addr)?;
ADMINS.save(deps.storage, &admin, &Empty {})?;
}

// ...

Ok(Response::new())
}

pub fn leave(deps: DepsMut, info: MessageInfo) -> StdResult<Response> {


ADMINS.remove(deps.storage, &info.sender);

// ...

Ok(resp)
}

https://book.cosmwasm.com/print.html 97/102
24/06/2023, 20:53 CosmWasm book

Working with time


The concept of time in the blockchain is tricky - as in every distributed system, it is not easy
to synchronize the clocks of all the nodes.

However, there is the notion of a time that is even monotonic - which means that it should
never go "backward" between executions. Also, what is important is - time is always unique
throughout the whole transaction - and even the entire block, which is built of multiple
transactions.

The time is encoded in the Env type in its block field, which looks like this:

pub struct BlockInfo {


pub height: u64,
pub time: Timestamp,
pub chain_id: String,
}

You can see the time field, which is the timestamp of the processed block. The height field
is also worth mentioning - it contains a sequence number of the processed block. It is
sometimes more useful than time, as it is guaranteed that the height field is guaranteed to
increase between blocks, while two blocks may be executed with the same time (even
though it is rather not probable).

Also, many transactions might be executed in a single block. That means that if we need a
unique id for the execution of a particular message, we should look for something more.
This thing is a transaction field of the Env type:

pub struct TransactionInfo {


pub index: u32,
}

The index here contains a unique index of the transaction in the block. That means that to
get the unique identifier of a transaction through the whole block, we can use the (height,
transaction_index) pair.

Join time
We want to use the time in our system to keep track of the join time of admins. We don't yet
add new members to the group, but we can already set the join time of initial admins. Let's
start updating our state:

https://book.cosmwasm.com/print.html 98/102
24/06/2023, 20:53 CosmWasm book

use cosmwasm_std::{Addr, Timestamp};


use cw_storage_plus::Map;

pub const ADMINS: Map<&Addr, Timestamp> = Map::new("admins");

As you can see, our admins set became a proper map - we will assign the join time to every
admin.

Now we need to update how we initialize a map - we stored the Empty data previously, but it
nevermore matches our value type. Let's check an updated instantiation function:

You might argue to create a separate structure for the value of this map, so in the future, if
we would need to add something there, but in my opinion, it would be premature - we can
also change the entire value type in the future, as it would be the same breaking change.

Now we need to update how we initialize a map - we stored the Empty data previously, but
it nevermore matches our value type. Let's check an updated instantiation function:

use crate::state::{ADMINS, DONATION_DENOM};


use cosmwasm_std::{
DepsMut, Env, MessageInfo, Response, StdResult,
};

pub fn instantiate(
deps: DepsMut,
env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
for addr in msg.admins {
let admin = deps.api.addr_validate(&addr)?;
ADMINS.save(deps.storage, &admin, &env.block.time)?;
}
DONATION_DENOM.save(deps.storage, &msg.donation_denom)?;

Ok(Response::new())
}

Instead of storing &Empty {} as an admin value, we store the join time, which we read from
&env.block.time . Also, note that I removed the underscore from the name of the env
block - it was there only to ensure the Rust compiler the variable is purposely unused and
not some kind of a bug.

Finally, remember to remove any obsolete Empty imports through the project - the compiler
should help you point out unused imports.

https://book.cosmwasm.com/print.html 99/102
24/06/2023, 20:53 CosmWasm book

Query and tests


The last thing to add regarding join time is the new query asking for the join time of a
particular admin. Everything you need to do that was already discussed, I'll leave it for you
as an exercise. The query variant should look like:

#[returns(JoinTimeResp)]
JoinTime { admin: String },

And the example response type:

#[cw_serde]
pub struct JoinTimeResp {
pub joined: Timestamp,
}

You may question that in response type, I suggest always returning a joined value, but
what to do when no such admin is added? Well, in such a case, I would rely on the fact that
load function returns a descriptive error of missing value in storage - however, feel free to
define your own error for such a case or even make the joined field optional, and be
returned if requested admin exists.

Finally, there would be a good idea to make a test for new functionality - call a new query
right after instantiation to verify initial admins has proper join time (possibly by extending
the existing instantiation test).

One thing you might need help with in tests might be how to get the time of execution.
Using any OS-time would be doomed to fail - instead, you can call the block_info function
to reach the BlockInfo structure containing the block state at a particular moment in the
app - calling it just before instantiation would make you sure you are working with the same
state which would be simulated on the call.

https://book.cosmwasm.com/print.html 100/102
24/06/2023, 20:53 CosmWasm book

Legal Information
Infomation according to § 5 TMG

Provider
Confio GmbH
7th Floor
Potsdamer Platz 1
10785 Berlin

Managing Director
Simon Warta

Contact
hello@confio.gmbh

Commercial Register
HRB 221575, Amtsgericht Charlottenburg

VAT number
DE339802279

Responsible for the content


Simon Warta
c/o Confio GmbH
7th Floor
https://book.cosmwasm.com/print.html 101/102
24/06/2023, 20:53 CosmWasm book

Potsdamer Platz 1
10785 Berlin

https://book.cosmwasm.com/print.html 102/102

You might also like