Math

In this section, you will find examples of a CosmWasm contract that demonstrates basic mathematical operations, including addition, subtraction, multiplication, division, modulo, and exponentiation.

The "execute" function showcased here accepts an enum of "ExecuteMsg," which encapsulates all the contract functions and matches them with the function the user is invoking.

pub fn execute(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
    ExecuteMsg::Operations { a, b } => execute_operations(deps,a,b),
}
}

The "execute" function receives an enum of "ExecuteMsg," which serves as a container for all the contract functions and matches them with the user's requested function. Subsequently, it invokes the "execute_operations" function:

pub fn execute_operations(deps: DepsMut, a: u128, b: u128) -> Result<Response, ContractError> {
        // Checking if numbers are not zero
        if a == 0 && b == 0 {
            return Err(ContractError::CanNotBeZero());
        }
        
        // Addition
        let addition_result = a + b;
        
        // Subtraction
        let subtraction_result = a - b;
        
        // Multiplication
        let multiplication_result = a * b;
        
        // Division
        let division_result = a / b;
        
        // Modulo
        let modulo_result = a % b;
        
        // Exponentiation
        let exponent: u32 = 3;
        let exponentiation_result: u128 = a.pow(exponent);
        
        // Create the response
        let response = OperationsResponse {
            addition_result,
            subtraction_result,
            multiplication_result,
            division_result,
            modulo_result,
            exponentiation_result,
        };
        
        // Fetching the state
        RESULT.load(deps.storage).unwrap();
        
        // Update the state
        RESULT.save(deps.storage, &response).unwrap();
        
        let res = Response::new().add_attributes(vec![
            ("action", "operations"),
            ("a", &a.to_string()),
            ("b", &b.to_string()),
            ("addition_res", &addition_result.to_string()),
            ("substraction_res", &subtraction_result.to_string()),
            ("multiplicationn_res", &multiplication_result.to_string()),
            ("division_res", &division_result.to_string()),
            ("modulo_res", &modulo_result.to_string()),
            ("exponential_res", &exponentiation_result.to_string()),
        ]);
        
        Ok(res)
    }

The execute_operations function accepts two parameters, 'a' and 'b,' for mathematical operations and stores the resulting value in the RESULT global state variable, which is located within the state.rs file:

pub const RESULT: Item<OperationsResponse> = Item::new("result");

You can utilize the following query endpoint to retrieve the results of mathematical operations:

pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, StdError> {
    match msg {
        QueryMsg::GetResponse {} => get_response(deps),
    }
}

The query function above accepts an enum of QueryMsg, which encapsulates all the contract query functions and aligns them with the user's requested function, specifically 'GetResponse' in our case. Subsequently, it invokes the get_response function:

pub fn get_response(deps: Deps) -> Result<QueryResponse, StdError> {
    let result = RESULT.load(deps.storage)?;
    to_binary(&result)
}

The get_response function mentioned above returns the result of the mathematical operation.

Example

To employ mathematical operations within CosmWasm, you should generate the following files: lib.rs, contract.rs, msg.rs, error.rs, and state.rs.

lib.rs

pub mod contract;
mod error;
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, Deps, DepsMut, Env, MessageInfo, QueryResponse, Response, StdError,
};
use cw2::set_contract_version;

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{OperationsResponse, RESULT};

// version info for migration info

const CONTRACT_NAME: &str = "crates.io:cosmwasm-math";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

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

    /* Deps allows to access:
    1. Read/Write Storage Access
    2. General Blockchain APIs
    3. The Querier to the blockchain (raw data queries) */
    
    deps: DepsMut,
    
    /* env gives access to global variables which represent environment information.
    For exaample:
    - Block Time/Height
    - contract address
    - Transaction Info */
    
    _env: Env,
    
    /* Message Info gives access to information used for authorization.
    1. Funds sent with the message.
    2. The message sender (signer). */
    
    _info: MessageInfo,
    _msg: InstantiateMsg,
) -> Result<Response, ContractError> {

    /* Instantiating the state that will be stored to the blockchain */
    
    let operation_response = OperationsResponse {
        addition_result: 0,
        subtraction_result: 0,
        multiplication_result: 0,
        division_result: 0,
        modulo_result: 0,
        exponentiation_result: 0,
    };
    
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION).unwrap();
    
    // Save the stete in deps.storage which creates a storage for contract data on the blockchain.
    RESULT.save(deps.storage, &operation_response).unwrap();
    Ok(Response::new().add_attribute("method", "instantiate"))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Operations { a, b } => execute::execute_operations(deps, a, b),
    }
}
pub mod execute {
    use super::*;
    pub fn execute_operations(deps: DepsMut, a: u128, b: u128) -> Result<Response, ContractError> {
       
         // Checking if numbers are not zero
         
        if a == 0 && b == 0 {
            return Err(ContractError::CanNotBeZero());
        }
        
        // Addition
        let addition_result = a + b;
        // Subtraction
        let subtraction_result = a - b;
        // Multiplication
        let multiplication_result = a * b;
        // Division
        let division_result = a / b;
        // Modulo
        let modulo_result = a % b;
        // Exponentiation
        let exponent: u32 = 3;
        let exponentiation_result: u128 = a.pow(exponent);
        // Create the response
        
        let response = OperationsResponse {
            addition_result,
            subtraction_result,
            multiplication_result,
            division_result,
            modulo_result,
            exponentiation_result,
        };
        
        // Fetching the state
        
        RESULT.load(deps.storage).unwrap();
        
        // Update the state
        
        RESULT.save(deps.storage, &response).unwrap();
        let res = Response::new().add_attributes(vec![
            ("action", "operations"),
            ("a", &a.to_string()),
            ("b", &b.to_string()),
            ("addition_res", &addition_result.to_string()),
            ("substraction_res", &subtraction_result.to_string()),
            ("multiplicationn_res", &multiplication_result.to_string()),
            ("division_res", &division_result.to_string()),
            ("modulo_res", &modulo_result.to_string()),
            ("exponential_res", &exponentiation_result.to_string()),
        ]);
        Ok(res)
    }
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, StdError> {
    match msg {
        QueryMsg::GetResponse {} => query::get_response(deps),
    }
}
pub mod query {
    use super::*;
    pub fn get_response(deps: Deps) -> Result<QueryResponse, StdError> {
        let result = RESULT.load(deps.storage)?;
        to_binary(&result)
    }
}
#[cfg(test)]
mod tests {
    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 {};
        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::GetResponse {}).unwrap();
        let value: OperationsResponse = from_binary(&res).unwrap();
        assert_eq!(0, value.addition_result);
        assert_eq!(0, value.subtraction_result);
        assert_eq!(0, value.multiplication_result);
        assert_eq!(0, value.division_result);
        assert_eq!(0, value.modulo_result);
        assert_eq!(0, value.exponentiation_result);
    }
    
    #[test]
    fn increment() {
        let mut deps = mock_dependencies();
        let msg = InstantiateMsg {};
        let info = mock_info("creator", &coins(2, "token"));
        let _res = instantiate(deps.as_mut(), mock_env(), info, msg).unwrap();
        
        // testing operation function
        
        let info = mock_info("anyone", &coins(2, "token"));
        let msg = ExecuteMsg::Operations { a: 5, b: 5 };
        let _res = execute(deps.as_mut(), mock_env(), info, msg).unwrap();
        
        // should get basic math operation for 5 and 5
        
        let res = query(deps.as_ref(), mock_env(), QueryMsg::GetResponse {  }).unwrap();
        let value: OperationsResponse = from_binary(&res).unwrap();
        assert_eq!(10, value.addition_result);
        assert_eq!(0, value.subtraction_result);
        assert_eq!(25, value.multiplication_result);
        assert_eq!(1, value.division_result);
        assert_eq!(0, value.modulo_result);
        assert_eq!(125, value.exponentiation_result);
    }
}

msg.rs

 use cosmwasm_schema::{cw_serde, QueryResponses};
#[cw_serde]
pub struct InstantiateMsg {}
#[cw_serde]
pub enum ExecuteMsg {
    Operations { a: u128, b: u128 },
}
#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(u128)]
    GetResponse {},
}

error.rs

use thiserror::Error;
#[derive(Error, Debug)]
pub enum ContractError {
    #[error("Numbers can not be zero")]
    CanNotBeZero(),
}

state.rs

use cosmwasm_schema::cw_serde;
use cw_storage_plus::Item;
#[cw_serde]
pub struct OperationsResponse {
    pub addition_result: u128,
    pub subtraction_result: u128,
    pub multiplication_result: u128,
    pub division_result: u128,
    pub modulo_result: u128,
    pub exponentiation_result: u128,
}

// Mapping of result of two numbers

pub const RESULT: Item<OperationsResponse> = Item::new("result");

Attribution: The code and examples are sourced from "CosmWasm by Example." You can review the code on GitHub.

Last updated