0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

KenmaroAdvent Calendar 2022

Day 24

Terra Academy で公開されているチュートリアルのスマートコントラクト、クライアントコードの理解をしてみたかった

Last updated at Posted at 2022-12-23

概要

今回は、前回構築したテラチェーン上のスマートコントラクトのプログラム、
およびクライアントコードの中身を実際にみて、
SoliditySolanaとの比較が少しできたらなと思っています。

どの程度理解できるかわかりませんが、物は試しということでやってみます。

スマートコントラクト

terrainで作成したスマートコントラクトのプログラムの中身を見てみます。

今回は、コアとなっている

  • src/contract.rs
  • src/msg.rs
  • src/state.rs

をみてみます。

src/msg.rs

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

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

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Increment {},
    Reset { count: i32 },
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    // GetCount returns the current count as a json-encoded number
    GetCount {},
}

// We define a custom struct for each query response
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct CountResponse {
    pub count: i32,
}


src/state.rs

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

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

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

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

src/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::{CountResponse, ExecuteMsg, InstantiateMsg, QueryMsg};
use crate::state::{State, STATE};

// version info for migration info
const CONTRACT_NAME: &str = "crates.io:my_terra_dapp";
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::Increment {} => try_increment(deps),
        ExecuteMsg::Reset { count } => try_reset(deps, info, count),
    }
}

pub fn try_increment(deps: DepsMut) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count += 1;
        Ok(state)
    })?;

    Ok(Response::new().add_attribute("method", "try_increment"))
}

pub fn try_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 {});
        }
        state.count = count;
        Ok(state)
    })?;
    Ok(Response::new().add_attribute("method", "reset"))
}

#[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)?),
    }
}

fn query_count(deps: Deps) -> StdResult<CountResponse> {
    let state = STATE.load(deps.storage)?;
    Ok(CountResponse { count: state.count })
}

クライアントコード

チュートリアルで使われたクライアントコードは、Nextjsで構成されていました。
ウォレット接続の鍵となるプログラムは、

frontend/src/index.tsx

import { getChainOptions, WalletProvider } from '@terra-money/wallet-provider';
import App from './App';
import ReactDOM from 'react-dom';
import './index.css';

getChainOptions().then((chainOptions) => {
  ReactDOM.render(
    <WalletProvider {...chainOptions}>
      <App />
    </WalletProvider>,
    document.getElementById('root'),
  );
});


getChainOptions, WalletProviderで App以下をProviderラッピングしているところです。

次に、LocalTerra上にデプロイされたスマートコントラクトへのcontractAddressを指定しているのは refs.terrain.jsonです。

refs.terrain.json
{
  "localterra": {
    "my_terra_dapp": {
      "codeId": "11",
      "contractAddresses": {
        "default": "terra14khjxsvmklm8kg97vhrn5wc2tz3w57na5seeke3qnwashe4pxd3qmljkek"
      }
    }
  }
}


さらに、client program は terrain

terrain contract:generateClient my_terra_dapp --build-schema

によって自動生成され、frontend/src/contract/clients/MyTerraDappClient.ts
として格納され、実際にApp.tsxから呼び出されています。

まとめ

今回は、Terra Academy で公開されているチュートリアルコードのスマートコントラクト、
およびクライアントコードの理解をしてみたかったのですが、
結局のところ既存のコードを眺めるだけになってしまいました。

やはり、簡単でもいいので自分でカスタマイズしたスマートコントラクト、およびクライアントコードを実装してみて初めて、もっと理解が深まると思ったので、近いうちにやってみたいです。

みなさんもよいTerraライフを。

今回はこの辺で。

@kenmaro

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?