Module 5 - Understanding CosmWasm Code
File Structure
In this Module, We’ll be Understanding the CosmWasm Code and how it is Being Integrated. The Files under src/
Directory are -
Directorysrc/
Directorybin/
- schema.rs
- contract.rs
- error.rs
- helpers.rs
- integration_tests.rs
- lib.rs
- msg.rs
- state.rs
contract.rs
Below is the Explaination of contract.rs
file -
Imports and Configuration
#[cfg(not(feature = "library"))]use cosmwasm_std::entry_point;use cosmwasm_std::{to_json_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};
This Section Imports necessary Modules -
- The
entry_point
macro is Conditionally Imported Based on whether the “library” feature is enabled. - Various types from
cosmwasm_std
are Imported for handling Contract Interactions. set_contract_version
is imported fromcw2
for Setting the Contract Version.- Custom Types are Imported from Other files in the Project -
ContractError
fromerror.rs
- Message types from
msg.rs
- State-related types from
state.rs
Contract Information
const CONTRACT_NAME: &str = "crates.io:project-name";const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
These Constants Define the Contract’s Name and Version. The Version is set to the Crate’s Version using the env!
macro.
Instantiate Function
#[cfg_attr(not(feature = "library"), entry_point)]pub fn instantiate( deps: DepsMut, _env: Env, info: MessageInfo, msg: InstantiateMsg,) -> Result<Response, ContractError> { // ... (implementation)}
This function is called when the Contract is first Uploaded to the Blockchain. It -
- Creates a new
State
Instance. - Sets the Contract Version using
set_contract_version
. - Saves the State using
STATE.save
. - Returns a
Response
with attributes about the Instantiation.
Execute Function
#[cfg_attr(not(feature = "library"), entry_point)]pub fn execute( deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg,) -> Result<Response, ContractError> { match msg { ExecuteMsg::Increment {} => execute::increment(deps), ExecuteMsg::Reset { count } => execute::reset(deps, info, count), }}
This function handles all Execute Messages sent to the Contract. It matches on the ExecuteMsg
enum (defined in msg.rs
) and Calls the appropriate handler function.
Execute Handlers
pub mod execute { // ... (implementation of increment and reset functions)}
This Module Contains the Implementation of the increment
and reset
functions, which modify the Contract’s State.
Query Function
#[cfg_attr(not(feature = "library"), entry_point)]pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> { match msg { QueryMsg::GetCount {} => to_json_binary(&query::count(deps)?), }}
This function handles all Query Messages sent to the Contract. It matches on the QueryMsg
enum (defined in msg.rs
) and Calls the appropriate query handler.
Query Handlers
pub mod query { // ... (implementation of count function)}
This Module Contains the Implementation of the count
Query, which retrieves the Current count from the Contract’s State.
Tests
#[cfg(test)]mod tests { // ... (test implementations)}
This Module Contains Unit Tests for the Contract’s functions. It includes Tests for proper Initialization, Incrementing the Counter, and resetting the Counter.
Relation to Other Files
-
msg.rs
: Defines the message Types (InstantiateMsg
,ExecuteMsg
,QueryMsg
,GetCountResponse
) used in this Contract. -
state.rs
: Defines theState
Struct andSTATE
Storage item used to manage the Contract’s State. -
error.rs
: Defines theContractError
Type used for Custom Error Handling. -
lib.rs
: Likely the Entry Point of the Crate, which may re-export items fromcontract.rs
. -
Cargo.toml
: Defines the Project Dependencies and Metadata, including the Version Number used inCONTRACT_VERSION
.
error.rs
Below is the Explaination of error.rs
file -
Imports and Configuration
use cosmwasm_std::StdError;use thiserror::Error;
These Lines Import necessary Types -
StdError
fromcosmwasm_std
: This is the Standard Error Type provided by the CosmWasm Framework.Error
fromthiserror
: This is a Derive Macro that helps in Creating Custom Error Types.
Enum
#[derive(Error, Debug)]pub enum ContractError { // ...}
This Defines a Custom Error Enum called ContractError
. The #[derive(Error, Debug)]
attribute automatically Implements the std::error::Error
Trait and the Debug
Trait for our Enum.
#[error("{0}")] Std(#[from] StdError),
This Variant allows our ContractError
to Wrap a StdError
. The #[from]
attribute automatically Implements From<StdError>
for ContractError
, allowing easy Conversion. The #[error("{0}")]
attribute Defines how this error Variant should be Displayed, in this case, it will use the Display Implementation of the Wrapped StdError
.
#[error("Unauthorized")] Unauthorized {},
This is a Custom Error Variant for Unauthorized Actions. The #[error("Unauthorized")]
attribute Defines the Error Message for this Variant.
Relation to Other Files
-
contract.rs
: TheContractError
type is used throughout the contract implementation. For example:pub fn instantiate(// ...) -> Result<Response, ContractError> {// ...}pub fn execute(// ...) -> Result<Response, ContractError> {// ...}pub fn reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result<Response, ContractError> {STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {if info.sender != state.owner {return Err(ContractError::Unauthorized {});}// ...})?;// ...}The
Unauthorized
Error is Specifically used in thereset
function when someone other than the Owner tries to reset the count. -
lib.rs
: This file might re-export theContractError
Type to make it available to Other Parts of the Crate or to Users of the Crate. -
Cargo.toml
: This file (not shown) would include the necessary Dependencies -[dependencies]cosmwasm-std = "1.0.0"thiserror = "1.0.21"
helpers.rs
Below is the Explaination of helpers.rs
file -
Imports and Configuration
use schemars::JsonSchema;use serde::{Deserialize, Serialize};
use cosmwasm_std::{ to_json_binary, Addr, CosmosMsg, CustomQuery, Querier, QuerierWrapper, StdResult, WasmMsg, WasmQuery,};
use crate::msg::{ExecuteMsg, GetCountResponse, QueryMsg};
These Lines Import necessary Types and Traits -
JsonSchema
fromschemars
: Used for Generating JSON Schema for Types.Deserialize
andSerialize
fromserde
: Used for Serialization and Deserialization.- Various types from
cosmwasm_std
: These are Standard CosmWasm Types used for Interacting with the Blockchain. ExecuteMsg
,GetCountResponse
, andQueryMsg
from the Localmsg.rs
file.
CwTemplateContract Struct
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]pub struct CwTemplateContract(pub Addr);
This Defines a Wrapper Struct around Addr
(which represents a blockchain address). The Derive macros add Various Useful Traits to the Struct, including Serialization, Deserialization, and JSON Schema Generation.
CwTemplateContract Implementation
impl CwTemplateContract { pub fn addr(&self) -> Addr { self.0.clone() }
pub fn call<T: Into<ExecuteMsg>>(&self, msg: T) -> StdResult<CosmosMsg> { let msg = to_json_binary(&msg.into())?; Ok(WasmMsg::Execute { contract_addr: self.addr().into(), msg, funds: vec![], } .into()) }
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_json_binary(&msg)?, } .into(); let res: GetCountResponse = QuerierWrapper::<CQ>::new(querier).query(&query)?; Ok(res) }}
This Implementation Block provides helper methods for the CwTemplateContract
-
-
addr
: Returns the WrappedAddr
. -
call
: Creates aCosmosMsg
for Executing a Message on this Contract. It takes any Type that can be Converted into anExecuteMsg
. -
count
: Queries the Contract for its Current Count. It uses aQuerier
to send aGetCount
Query to the Contract and returns the result.
Relation to Other Files
-
msg.rs
: TheExecuteMsg
,QueryMsg
, andGetCountResponse
Types are Imported from this file. These Types Define the Structure of Messages that can be sent to or received from the Contract. -
contract.rs
: While not Directly referenced here, theCwTemplateContract
Struct and its methods provide a Convenient way to Interact with the Contract Defined incontract.rs
. For example -- The
call
method can be used to Create Messages for theexecute
function incontract.rs
. - The
count
method Corresponds to theGetCount
Query handled in thequery
function ofcontract.rs
.
- The
-
state.rs
: Thecount
method retrieves the Count, which is likely Stored in the Contract’s State Defined instate.rs
. -
error.rs
: TheStdResult
Type used in the return Values of these methods can Potentially containContractError
Types Defined inerror.rs
.
This helpers file provides a Convenient Abstraction Layer for Interacting with the Contract. It Encapsulates the Logic for Creating Execute Messages and Queries, making it easier for other Parts of the Project to Interact with this Contract.
integration_tests.rs
It Contains the Test Scripts for all Smart Contracts.
lib.rs
The lib.rs
file Serves as the Root of the Rust Crate and Defines the Public API of the Library. Let’s Go through it Line by Line -
Imports and Configuration
pub mod contract; // This Line makes the `contract` module Public, allowing External Code to access its Contents. The `contract` Module likely Contains the main Smart Contract Logic, including the `instantiate`, `execute`, and `query` functions we saw earlier.
mod error; // This Declares the `error` Module, but keeps it Private to the Crate. This Module Contains the `ContractError` enum we saw earlier, which Defines Custom Error Types for the Contract.
pub mod helpers; // This makes the `helpers` Module Public. This Module Contains the `CwTemplateContract` Struct and its Implementation, which provides helper functions for Interacting with the Contract.
pub mod integration_tests; // This Declares a Public `integration_tests` Module.
pub mod msg; // This makes the `msg` Module Public. This Module Defines the Message Types used for Interacting with the Contract, including `InstantiateMsg`, `ExecuteMsg`, `QueryMsg`, and `GetCountResponse`.
pub mod state; // This Declares the `state` Module as Public. This Module likely Defines the Contract's State Structure and provides methods for Interacting with the Contract's Storage.
pub use crate::error::ContractError; // This Line re-exports the `ContractError` Type from the `error` Module, making it Directly accessible to Users of this Crate without needing to Import it through the `error` Module.
Relation to Other Files
-
contract.rs
: Made public here, allowing external code to access the contract’s main functions. -
error.rs
: Kept private, but itsContractError
type is re-exported for public use. -
helpers.rs
: Made public, allowing external code to use the helper functions for interacting with the contract. -
msg.rs
: Made public, allowing external code to use the message types defined for this contract. -
state.rs
: Made public, potentially allowing external code to understand and interact with the contract’s state structure. -
integration_tests.rs
: Made public, though this is likely more for organization within the project rather than for external use.
msg.rs
The msg.rs
file Defines the Message Structures used for Interacting with the Smart Contract. Let’s go through it -
Imports and Configuration
use cosmwasm_schema::{cw_serde, QueryResponses};
This Line Imports the cw_serde
and QueryResponses
macros from the cosmwasm_schema
Crate. These macros are used to automatically Derive Serialization, Deserialization, and Schema Generation Traits for the Message Structures.
#[cw_serde]pub struct InstantiateMsg { pub count: i32,}
This Defines the Structure for the Instantiation Message. The #[cw_serde]
macro automatically Derives Serialize
, Deserialize
, JsonSchema
, Clone
, and Debug
Traits for this Struct. The InstantiateMsg
Contains a single field count
of type i32
, which is used to set the initial count when the Contract is Instantiated.
#[cw_serde]pub enum ExecuteMsg { Increment {}, Reset { count: i32 },}
This enum Defines the possible Execute Messages that can be sent to the Contract. Again, #[cw_serde]
is used to Derive necessary Traits. There are Two Variants -
Increment
: An Empty Struct, likely used to Increment the count.Reset
: Contains acount
field, Likely used to reset the count to a specific value.
#[cw_serde]#[derive(QueryResponses)]pub enum QueryMsg { #[returns(GetCountResponse)] GetCount {},}
This enum Defines the possible Query Messages. The #[derive(QueryResponses)]
attribute is used to Generate Metadata about the return types of Queries, which is useful for Tooling and Client Generation. There’s only one Query Type -
GetCount
: An Empty Struct that returns aGetCountResponse
.
#[cw_serde]pub struct GetCountResponse { pub count: i32,}
This Struct Defines the response format for the GetCount
Query. It Contains a single count
field of type i32
.
Relation to Other Files
-
contract.rs
: The Message Types Defined here are used in theinstantiate
,execute
, andquery
functions incontract.rs
. For Example -pub fn instantiate(deps: DepsMut,_env: Env,info: MessageInfo,msg: InstantiateMsg,) -> Result<Response, ContractError> {// ...}pub fn execute(deps: DepsMut,_env: Env,info: MessageInfo,msg: ExecuteMsg,) -> Result<Response, ContractError> {match msg {ExecuteMsg::Increment {} => execute::increment(deps),ExecuteMsg::Reset { count } => execute::reset(deps, info, count),}}pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {match msg {QueryMsg::GetCount {} => to_json_binary(&query::count(deps)?),}} -
state.rs
: Thecount
field in these Messages likely Corresponds to the State Variable Defined instate.rs
. -
helpers.rs
: TheCwTemplateContract
Struct inhelpers.rs
uses these Message Types in its methods -pub fn call<T: Into<ExecuteMsg>>(&self, msg: T) -> StdResult<CosmosMsg> {// ...}pub fn count<Q, T, CQ>(&self, querier: &Q) -> StdResult<GetCountResponse>whereQ: Querier,T: Into<String>,CQ: CustomQuery,{let msg = QueryMsg::GetCount {};// ...} -
lib.rs
: Themsg
Module is made Public inlib.rs
, allowing these Message Types to be used by External Code Interacting with this Contract. -
error.rs
: While not Directly related, theContractError
Defined inerror.rs
is Often used as the Error Type in functions that handle these Messages.
msg.rs
Let’s go through the state.rs
file Line by Line -
Imports and Configuration
// These Lines Import the necessary Traits for JSON Schema Generation (`JsonSchema`) and serialization/deserialization (`Deserialize`, `Serialize`).use schemars::JsonSchema;use serde::{Deserialize, Serialize};
This Imports the `Addr` Type from `cosmwasm_std`, which represents a Validated Address on the Blockchain.use cosmwasm_std::Addr;
// This Imports the `Item` Type from `cw_storage_plus`, which is a helper for handling Storage in CosmWasm Contracts.use cw_storage_plus::Item;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]pub struct State { pub count: i32, pub owner: Addr,}
This defines the State
Struct, which represents the State of the Contract. It has two fields -
count
: Ani32
that Stores the current count.owner
: AnAddr
that Stores the address of the Contract Owner.
The Derive Macros add various Useful Traits to the Struct, including Serialization, Deserialization, Cloning, Debugging, Equality Comparison, and JSON Schema Generation.
pub const STATE: Item<State> = Item::new("state");
This Line Creates a Constant STATE
of Type Item<State>
. Item
is a Wrapper provided by cw_storage_plus
that helps with Storing and retrieving a Single Item from Contract Storage. The state
argument is the Key under which this Item will be Stored.
Relation to Other Files
-
contract.rs
: TheState
Struct andSTATE
Constants are used extensively in the Contract Logic. For Example -pub fn instantiate(deps: DepsMut,_env: Env,info: MessageInfo,msg: InstantiateMsg,) -> Result<Response, ContractError> {let state = State {count: msg.count,owner: info.sender.clone(),};STATE.save(deps.storage, &state)?;// ...}pub fn execute::increment(deps: DepsMut) -> Result<Response, ContractError> {STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {state.count += 1;Ok(state)})?;// ...} -
msg.rs
: Thecount
field in theState
Struct corresponds to thecount
field in various Messages Defined inmsg.rs
, such asInstantiateMsg
,ExecuteMsg::Reset
, andGetCountResponse
. -
helpers.rs
: While not Directly using theState
struct, the helper functions Interact with the Contract’s State indirectly through Execute and Query Messages. -
error.rs
: TheContractError
might be used when Operations on theSTATE
fail, although we don’t see this Directly in the provided Code. -
lib.rs
: Thestate
Module is made Public inlib.rs
, allowing External Code to Understand the Structure of the Contract’s State if needed.