This site requires Javascript to be enabled.

Read and Write

Explanation

Smart contract that explains the basics of reading and writing to the state in a smart contract. The state of the smart contract is the allocated storage for the smart contract in the blockchain. The state is definted usually in a separate file state.rs that imports and uses Item and Map and other types from cw_storage_plus.

State

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]pub struct State {    pub count: i32,    pub owner: Addr,}pub const STATE: Item<State> = Item::new("state");// Map is another type of storage that stores key-value pairs in storage.pub const NAMES: Map<String, String> = Map::new("names");

Each constant variable in state is stored as a key value pair in the blockchain and therefor can be read or altered.

Writing to State

// contract.rspub fn write(deps: DepsMut) -> Result<Response, ContractError> {        /* This execute endpoint writes a new owner to state. */                // First we need to load the current state from the blockchain from `deps.storage` as mutable.        let mut state = STATE.load(deps.storage)?;        state.count = 5;                // Save the new state with the changed variables in storage.        STATE.save(deps.storage, &state)?;        // Now let us add a new key-value pair to the `NAMES` map in storage.         NAMES.save(deps.storage, "Georges".to_string(), &"Chouchani".to_string())?;                Ok(Response::new().add_attribute("action", "write"))    }Structs can be stored as an Item in storage and key-value pairs are stored as Map.Reading from StateReading from Structs or constants// contract.rspub fn count(deps: Deps) -> StdResult<GetCountResponse> {        // Loads the state from storage and checks the count variable.        let state = STATE.load(deps.storage)?;        Ok(GetCountResponse { count: state.count })    }

The constant is loaded from storage and variables inside the struct (if it is one) can be directly accessed.

Reading Maps

Maps are usually read by supplying a key and checking if a value exists. Keys and values can also be iterated through.

pub fn name(deps: Deps, first_name: String) -> StdResult<GetNameResponse> {        // Loads the NAMES Map from storage for the key `first_name` to get the `last_name`        // `may_load` returns None if the key does not exist in the map. `load` returns an error.        let res = NAMES.may_load(deps.storage, first_name)?;        Ok(GetNameResponse{family_name: res.unwrap()})    }

Example

To read and write in state with CosmWasm, you can create the following files: lib.rs contract.rs msg.rs error.rs state.rs helpers.rs

lib.rs

pub mod contract;mod error;pub mod helpers;pub mod msg;pub mod state;pub use crate::error::ContractError;

contract.rs

#[cfg(not(feature = "library"))]use cosmwasm_std::entry_point;use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};use cw2::set_contract_version;use crate::error::ContractError;use crate::msg::{ExecuteMsg, GetCountResponse, InstantiateMsg, QueryMsg};use crate::state::{State, STATE, NAMES};// version info for migration infoconst CONTRACT_NAME: &str = "crates.io:read-write-state";const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");#[cfg_attr(not(feature = "library"), entry_point)]pub fn instantiate(    deps: DepsMut,    _env: Env,    info: MessageInfo,    msg: InstantiateMsg,) -> Result<Response, ContractError> {    let state = State {        count: msg.count,        owner: info.sender.clone(),    };    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;    STATE.save(deps.storage, &state)?;    Ok(Response::new()        .add_attribute("method", "instantiate")        .add_attribute("owner", info.sender)        .add_attribute("count", msg.count.to_string()))}#[cfg_attr(not(feature = "library"), entry_point)]pub fn execute(    deps: DepsMut,    _env: Env,    _info: MessageInfo,    msg: ExecuteMsg,) -> Result<Response, ContractError> {    match msg {        ExecuteMsg::Write {} => execute::write(deps),    }}pub mod execute {    use super::*;    pub fn write(deps: DepsMut) -> Result<Response, ContractError> {        /* This execute endpoint writes a new owner to state. */                // First we need to load the current state from the blockchain from `deps.storage` as mutable.        let mut state = STATE.load(deps.storage)?;        state.count = 5;                // Save the new state with the changed variables in storage.        STATE.save(deps.storage, &state)?;        // Now let us add a new key-value pair to the `NAMES` map in storage.         NAMES.save(deps.storage, "Georges".to_string(), &"Chouchani".to_string())?;                Ok(Response::new().add_attribute("action", "write"))    }}#[cfg_attr(not(feature = "library"), entry_point)]pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {    match msg {        QueryMsg::GetCount {} => to_binary(&query::count(deps)?),        QueryMsg::GetFamilyName {first_name} => to_binary(&query::name(deps, first_name)?),    }}pub mod query {    use crate::msg::GetNameResponse;    use super::*;    pub fn count(deps: Deps) -> StdResult<GetCountResponse> {        // Loads the state from storage and checks the count variable.        let state = STATE.load(deps.storage)?;        Ok(GetCountResponse { count: state.count })    }    pub fn name(deps: Deps, first_name: String) -> StdResult<GetNameResponse> {        // Loads the NAMES Map from storage for the key `first_name` to get the `last_name`        // `may_load` returns None if the key does not exist in the map. `load` returns an error.        let res = NAMES.may_load(deps.storage, first_name)?;        Ok(GetNameResponse{family_name: res.unwrap()})    }}#[cfg(test)]mod tests {    use crate::msg::GetNameResponse;    use super::*;    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};    use cosmwasm_std::{coins, from_binary};    #[test]    fn proper_initialization() {        let mut deps = mock_dependencies();        let msg = InstantiateMsg { count: 17 };        let info = mock_info("creator", &coins(1000, "earth"));        // we can just call .unwrap() to assert this was a success        let res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();        assert_eq!(0, res.messages.len());        // it worked, let's query the state        let res = query(deps.as_ref(), mock_env(), QueryMsg::GetCount {}).unwrap();        let value: GetCountResponse = from_binary(&res).unwrap();        assert_eq!(17, value.count);    }    #[test]    fn write() {        let mut deps = mock_dependencies();        let msg = InstantiateMsg { count: 17 };        let info = mock_info("creator", &coins(2, "token"));        let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();        // Execute the function that changes the state of the blockchain.        let info = mock_info("anyone", &coins(2, "token"));        let msg = ExecuteMsg::Write {};        let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();        // The counter should now be 5        let res = query(deps.as_ref(), mock_env(), QueryMsg::GetCount {}).unwrap();        let value: GetCountResponse = from_binary(&res).unwrap();        assert_eq!(5, value.count);        // Last name of Georges can now be found.         let res = query(deps.as_ref(), mock_env(), QueryMsg::GetFamilyName { first_name: "Georges".to_string() } ).unwrap();        let value: GetNameResponse = from_binary(&res).unwrap();        assert_eq!(value.family_name, "Chouchani".to_string())    }}

msg.rs

use cosmwasm_schema::{cw_serde, QueryResponses};#[cw_serde]pub struct InstantiateMsg {    pub count: i32,}#[cw_serde]pub enum ExecuteMsg {    Write {},}#[cw_serde]#[derive(QueryResponses)]pub enum QueryMsg {    // GetCount returns the current count as a json-encoded number    #[returns(GetCountResponse)]    GetCount {},    #[returns(GetNameResponse)]    GetFamilyName {        first_name: String,    }}#[cw_serde]pub struct GetCountResponse {    pub count: i32,}#[cw_serde]pub struct GetNameResponse {    pub family_name: String,}

error.rs

use cosmwasm_std::StdError;use thiserror::Error;#[derive(Error, Debug)]pub enum ContractError {    #[error("{0}")]    Std(#[from] StdError),    #[error("Unauthorized")]    Unauthorized {},    // Add any other custom errors you like here.    // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.}

state.rs

use schemars::JsonSchema;use serde::{Deserialize, Serialize};use cosmwasm_std::Addr;use cw_storage_plus::{Item, Map};#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]pub struct State {    pub count: i32,    pub owner: Addr,}pub const STATE: Item<State> = Item::new("state");// Map is another type of storage that stores key-value pairs in storage.pub const NAMES: Map<String, String> = Map::new("names");

helpers.rs

use schemars::JsonSchema;use serde::{Deserialize, Serialize};use cosmwasm_std::{    to_binary, Addr, CosmosMsg, CustomQuery, Querier, QuerierWrapper, StdResult, WasmMsg, WasmQuery,};use crate::msg::{ExecuteMsg, GetCountResponse, QueryMsg};/// CwTemplateContract is a wrapper around Addr that provides a lot of helpers/// for working with this.#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]pub struct CwTemplateContract(pub Addr);impl CwTemplateContract {    pub fn addr(&self) -> Addr {        self.0.clone()    }    pub fn call<T: Into<ExecuteMsg>>(&self, msg: T) -> StdResult<CosmosMsg> {        let msg = to_binary(&msg.into())?;        Ok(WasmMsg::Execute {            contract_addr: self.addr().into(),            msg,            funds: vec![],        }        .into())    }    /// Get Count    pub fn count<Q, T, CQ>(&self, querier: &Q) -> StdResult<GetCountResponse>    where        Q: Querier,        T: Into<String>,        CQ: CustomQuery,    {        let msg = QueryMsg::GetCount {};        let query = WasmQuery::Smart {            contract_addr: self.addr().into(),            msg: to_binary(&msg)?,        }        .into();        let res: GetCountResponse = QuerierWrapper::<CQ>::new(querier).query(&query)?;        Ok(res)    }}

Credits: CosmWasm by example. You can check the code on Github or open it with VS code.