Writing a smart contract with CosmWasm (Part 2)
Tags: beginners, rust, cosmwasm, smartcontract
Published: 2022-09-04 02:56:17

### Smart contract explain

Welcome back to my series. In this section, I will explain how smart contract work. Don't think it is difficult. Keep it easy to imagine.

The smart contract has a state - or what we call storage. We need to interact with the state by query and state.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6lp8x02r4eeebezby1fw.png)

Imagine, developing a smart contract same as we are developing a backend application API:

| Smart contract | API Application  | Description |
| ---- | --- | ----- |
| State | Database | Store data for application |
| Query | QUERY | Get current data stored in the application |
| Execute | POST, PUT, DELETE | Change data stores in application |

And an important component is the message, it is the way we tell the smart contract do something.
Done. We have the understanding mechanism of the smart contract. Moving to the next section, we how to create a state of the smart contract.

### Create state smart contracts.

Let's start in the `src/state.rs` and update the file with the following code: 

```rust
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use cw_storage_plus::Item;

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
    pub counter: i32,
}

pub const STATE: Item<State> = Item::new("state");
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ue2yxjkre74nvd1pggdk.png)

I note something to give a quick overview:
-  `JsonSchema` allows structs to be serialized and deserialized to and from JSON
- Deserialize and Serialize provide the serialization described above.
- Item is a helper provided by storage plus. It effectively means we can store an item in storage. In this case, the STATE variable is an Item that stores a singular State struct.

We just define a schema of the state.

### Instantiating a Contract

When contracts are stored on the chain, they must be instantiated.
Instantiating a contract is achieved by a special message.
First, update the `src/msg.rs` with the code: 
```rust
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct InstantiateMsg {}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4fwnl16yit52gl5g3pet.png)

We don't need parameters when instantiating the contract in the special message `InstantiateMsg`.
Now let's use this message.

### Instantiation

Alright, open the `src/contract.rs`, this is where logic happens, update the file with the following code:

```rust
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
use cw2::set_contract_version;

use crate::error::ContractError;
use crate::msg::InstantiateMsg;
use crate::state::{State, STATE};

const CONTRACT_NAME: &str = "crates.io:cw-starter";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const ZERO_CODE: i32 = 0;

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    _info: MessageInfo,
    _msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

    let state = State { counter: 0 };

    STATE.save(deps.storage, &state)?;
    Ok(Response::new().add_attribute("counter", ZERO_CODE.to_string()))
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9rztu1ktubmn29hq6ay8.png)

This is explicit for reading. I explain it step by step. We create the first entry point, and pass some parameters to `instantiate`:
- `deps` - The dependencies, this contains your contract storage, the ability to query other contracts and balances, and some API functionality
- `env` - The environment, contains information such as its address, block information such as current height and time, as well as some optional transaction info
- `info` - Message metadata, contains the sender of the message (Addr).
- `msg` - The InstantiateMsg you define in `src/msg.rs`

The dash `_` prefix of params means we don't use it in function and the compiler will not show a warning notification.

Return of this function Result enum with Response struct from `cosmwasm_std` and enum ContractError. Then we set the contract name and contract version to storage with set_contract_version.

Now this is the main section of `instantiate`, we create an instance of struct State with a value counter equal to 0 and assign it to the `state` variable

`STATE` creates a new item in storage and saves `state` to storage.
Finally, we warp Response struct has attribute `counter` and its value is 0 by Ok.

### Testing module
Alright, we have implemented the first entry point of our contract! Let's get to testing it!
So let's look at our `src/contract.rs` file, at the bottom, add the following code:

```rust
#[cfg(test)]
mod tests {
    use crate::msg::InstantiateMsg;
    use cosmwasm_std::attr;
    use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};

    use super::{instantiate, ZERO_CODE};

    const ADDR1: &str = "addr1";

    // instantiate with provide admin address
    #[test]
    fn test_instantiate() {
        let mut deps = mock_dependencies();
        let env = mock_env();
        let info = mock_info(ADDR1, &[]);

        let msg = InstantiateMsg {};
        let resp = instantiate(deps.as_mut(), env, info, msg).unwrap();

        assert_eq!(
            resp.attributes,
            vec![attr("counter", ZERO_CODE.to_string())]
        )
    }
}
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yz390b8af1m887z6b23q.png)

We create a module test and unit test function `test_instantiate`.
First, we need to import `mock` to simulate parameters (mock_dependencies, mock_env, mock_info) and import the `instantiate` function and `ZERO_CODE` constant from above via the `super` keyword.
`asssert_eq!` is `marco` in Rust to compare two values. In this case, we compare response from `instantiate` with array vector has an element `attr("counter", ZERO_CODE.to_string())` 

Let's test the module. We have two ways:

1. Open the terminal and run `cargo test`:
<img width="100%" style="width:100%" src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/31gle47rbhrep9rvt4q7.gif">
2. Simply, press `Run Test` in VS Code:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib8x5r8osvls0ta1s76g.png)

If your output is like the below, everything is right:

```
running 1 test
test contract::tests::test_instantiate ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests cw-starter

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

It runs 1 test case, and 1 passed.

### Sumary

We just created the first **entry point** of the smart contract is `instantiate`.
We also created a module testing function.

Thanks to everyone to read the post. Part 3 I introduce how to execute the smart contract. Have a good day!