[Cosmwasm] Cosmwasm은 처음이지?(2) - 배포 및 실행하기

[Cosmwasm] Cosmwasm은 처음이지?(2) -  배포 및 실행하기
pixabay.com

Cosmwasm은 처음이지?(1) - 구성요소 알아보기 와 이어지는 글입니다.

[요약]

  • juno 테스트 네트워크 사용을 위해 juno 클라이언트 설치 및 Public RPC 설정을 진행한다.
  • rust optimzer를 통해 컴파일된 wasm 바이트 코드의 용량을 줄인다.
  • 컴파일된 바이트 코드를 배포해보고 init 트랜잭션을 보내본다.

[목차]

  1. juno 테스트 네트워크 사용 준비
  2. cw20 배포

Juno 테스트 네트워크 사용 준비

Juno는 Cosmos SDK의 wasm 모듈을 사용해 Cosmwasm 컨트랙트를 배포 및 사용할 수 있는 블록체인 네트워크이다. 우리는 이 테스트 네트워크를 이용해서 cw20 컨트랙트를 배포하고 잘 작동하는지 확인할 계획이다.

Juno의 공식 문서를 가보면 따로 퍼블릭 노드 RPC를 공개하지 않고 있고, 대신 테스트 네트워크 노드를 돌리는 법을 알려주고 있다. 글쓴이는 테스트 네트워크를 사용하고 싶은 것이지 노드를 돌리고 싶지는 않았다. 다행히 deus-labs에서 자신들의 퍼블릭 노드 RPC를 공개해 이를 사용할 것이다.

1) Juno cli 설치

Juno 네트워크를 사용하려면 노드와 통신할 수 있는 클라이언트를 먼저 설치해야 한다. Juno의 경우 이 클라이언트를 junod라고 한다. 이 junod에 어떤 노드를 연결하느냐에 따라 메인넷, 테스트넷을 사용할지 결정된다.

먼저 junod를 설치해보자.

현재 공식 문서에서 go 1.19.2 이상 등 여러 선행 프로그램을 요구하고 있으니 확인 후 따라해보자

git clone https://github.com/CosmosContracts/juno

junod는 메인넷, 테스트넷 버전에 따라 구현이 조금씩 다르다. 현재 공식 문서에 따르면 테스트 넷의 chain-id는 uni-5, 깃헙 버전 태그는 v10.0.0-alpha.2 이다. 설치하기 전에 공식 문서를 꼭 체크해 버전을 맞춰야 한다.

cd juno
# github에서 태그 정보를 가져오기
git fetch --tags
# 테스트 넷 버전으로 바꾸기
git checkout v10.0.0-alpha.2
# junod를 빌드 후 shell에서 사용할 수 있도록 설치
make build && make install
# junod 설치 확인
which junod

우리가 사용할 deus-labs의 퍼블릭 노드 RPC 정보를 다운로드 하자. 그리고 그 정보를 환경 변수에 등록하자.

# sourceJunoTestRPC라는 파일로 환경변수 목록을 저장
curl https://raw.githubusercontent.com/deus-labs/testnets/master/uni-5/defaults.env --output sourceJunoTestRPC
# 환경 변수로 설정
source sourceJunoTestRPC
# $TXFLAG 확인
echo $TXFLAG
# junod의 chain id를 테스트넷 chain id로 설정하기
junod config chain-id $CHAIN_ID
# junod chain-id 확인
junod config chain-id
# junod node를 deus-labs 퍼블릭 노드로 설정하기
junod config node $RPC
#junod node 확인
junod config node

이제 junod의 클라이언트 설정은 모두 끝났다.

2) 테스트 네트워크 지갑 주소 생성

# testAccount1 주소 생성
junod keys add testAccount1
# address 및 private key 확인
...

위 명령어는 나의 junod에 testAccount1이라는 별칭으로 새로운 주소를 생성한 것이다. 당연하게도 해당 주소는 아무런 테스트넷 토큰을 가지고 있지 않다.

테스트넷 토큰은 JunoTools에 접속해서 받을 수 있다.

https://test.juno.tools/request-tokens/

토큰을 받았다면 제대로 테스트넷 토큰이 발급되었는지 확인을 해봐야 한다.

먼저 블록 explorer에서 확인할 수 있다.

https://testnet.juno.explorers.guru/

10 junox가 들어온 것을 확인할 수 있다.

우리가 위에서 열심히 설정한 junod를 이용해도 확인을 할 수 있다.

# {address}에 조회하고 싶은 주소를 입력
junod query bank balances {address}

cw20 컨트랙트 배포

테스트 네트워크에 배포할 컨트랙트는 cw-plus의 cw20-base 컨트랙트이다. cw20은 이더리움의 ERC20 과 같은 토큰 표준인데, cw20-base 컨트랙트는 cw20 표준을 구현하여 그대로 사용할 수 있는 컨트랙트이다.

컨트랙트를 배포하려면 일단 컨트랙트 코드를 wasm 형태로 컴파일한 후에 체인으로 올려야 한다. 그냥 컴파일을 하면 바이트 코드가 매우 크기 때문에 컴파일 최적화 툴로 바이트 코드의 크기를 줄여야 한다.

Cosmwasm 재단 측에서 컴파일 최적화 툴로 rust-optimzer 툴을 제공해주기 때문에 이를 사용하면 된다.

💡
rust-optimzer의 프로세서 문제
22.12.10 rust-optimzer 레포지토리의 Readme에는 rust-optmizer 이미지는 Intel/Amd 64bit와 Arm 64bit용 두 가지를 지원한다. 그런데 Intel 버전과 Arm 버전이 생성하는 wasm artifact가 다르다.

Cosmwasm은 release 및 production에 사용하려면 무조건 Intel 버전의 optimzer를 사용하라고 한다. 하지만 지금 이 글을 쓰고 있는 글쓴이를 포함한 많은 사람들이 애플의 M1을 사용하고 있을 텐데, M1은 Arm 64bit 이미지를 사용해야 한다. 즉, 현재는 M1 맥북은 production 용으로 컨트랙트를 배포하지 못한다. Cosmwasm 재단은 이것을 빨리 해결해주었으면 좋겠다.

자신이 사용하는 프로세서가 Amd이냐 Arm이냐에 따라 사용하는 이미지가 달라진다. 이 글을 작성하는 글쓴이는 M1 맥북을 사용하고 있으므로 Arm 이미지를 사용하겠다.

cw-plus 레포지토리의 루트에서 도커를 실행시킨 뒤 아래 커맨드를 실행하면 cw-plus의 모든 컨트랙트가 컴파일이 된다. optimzer의 이미지 버전은 도커 허브를 체크하여 최신 버전을 사용하자.

docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/workspace-optimizer-arm64:0.12.8

위 명령어를 실행시키면 cw-plus/artifacts안에 cw20_base-aarch64.wasm 으로 컴파일된 바이트 코드를 확인할 수 있다.

이제 이 바이트 코드를 junod를 통해 테스트 네트워크에 배포해보자.

# junod를 사용해 cw20_base 컨트랙트 wasm 파일 배포
RES=$(junod tx wasm store artifacts/cw20_base-aarch64.wasm --from juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l $TXFLAG -y --output json -b block)
# 리턴 값 확인
echo $RES
# RES에서 code_id 확인 후 환경 변수로 셋팅
CODE_ID={code_id}
# code_id 확인
echo $CODE_ID

글을 따라 junod를 잘 셋팅했다면, echo $RES를 했을 때 height, txhash, data, raw_log 등에 값이 잘 차있을 것이다. attribute에서 key가 code_id인 부분을 찾아 $CODE_ID에 저장을 해놓자.

이제 이 CW20 컨트랙트의 인스턴스를 생성해보자. (1)편에서 살펴보았듯 배포한 뒤에 InstantiateMsg를 보내면 제출한 코드를 베이스로 컨트랙트 인터페이스가 생성된다.

cw20-base의 msg.rs에 정의되어 있는 InstantiateMsg, QueryMsg는 다음과 같다.

#[cw_serde]
#[cfg_attr(test, derive(Default))]
pub struct InstantiateMsg {
    pub name: String,
    pub symbol: String,
    pub decimals: u8,
    pub initial_balances: Vec<Cw20Coin>,
    pub mint: Option<MinterResponse>,
    pub marketing: Option<InstantiateMarketingInfo>,
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    #[returns(cw20::BalanceResponse)]
    Balance { address: String },
    #[returns(cw20::TokenInfoResponse)]
    TokenInfo {},
    ...
}
cw-plus/contracts/cw20-base/src/msg.rs

InstantiateMsg에 들어갈 파라미터가 많기 때문에, 실수를 줄이기 위해 파일에서 메시지를 정의할 것이다. 컨트랙트 초기화 이후 확인 용으로 쿼리 메시지도 같이 정의한다.

export INIT='{"name":"PGCoin","symbol":"PGCoin","decimals":6,"initial_balances":[{"address":"juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l", "amount":"1000000000000"}]}'

export QueryBalanceTestAddr1='{"balance":{"address":"juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l"}}'
export QueryBalanceTestAddr2='{"balance":{"address":"juno14e5gzzgmtfgndy8ve8s8lttv36s2j8rm85wpm3"}}'
export QueryTokenInfo='{"token_info":{}}'

export TransferToken='{"transfer":{"recipient":"juno14e5gzzgmtfgndy8ve8s8lttv36s2j8rm85wpm3", "amount":"1000"}}'
sourceTestCoinContract

InstantiateMsg에서 Option으로 정의된 파라미터는 넣지 않아도 된다. 배포한 CW20 토큰의 이름을 PGCoin으로 정하고 decimal 및 initial_balance 등을 정의한다.

# INIT 환경변수 설정
source sourceTestCoinContract
# INIT 트랜잭션 제출
junod tx wasm instantiate $CODE_ID "$INIT" --admin juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l --label "pangyoalto project" $TXFLAG --from testAccount1
# Contract 주소 저장
CONTRACT=$(junod query wasm list-contract-by-code $CODE_ID $NODE --output json | jq -r '.contracts[-1]')

잘 제출이 되었다면 컨트랙트 주소 및 트랜잭션 해시 등을 확인할 수 있다. 쿼리를 통해 컨트랙트 정보를 간단히 확인해보자.

# "juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l"가 가진 토큰 수량 확인
junod query wasm contract-state smart $CONTRACT "$QueryBalanceTestAddr1" $NODE
# 토큰 정보 확인
junod query wasm contract-state smart $CONTRACT "$QueryTokenInfo" $NODE
# 다른 주소로 토큰 전송
junod tx wasm execute $COIN_CONTRACT "$TransferToken" $TXFLAG --from juno1sulm4ga8jgd73zs5q9wsumszu7ns6nkgxxvf3l
# 받은 토큰 확인
junod query wasm contract-state smart $CONTRACT "$QueryBalanceTestAddr2" $NODE

정리

이번 글에서는 (1) juno 테스트넷을 사용하기 위해 junod 클라이언트를 설치하고 설정해보고 (2) 컨트랙트 코드 배포 및 인스턴스 생성을 해보았다.

juno 테스트넷이 아니라 다른 체인, 심지어 코스모스가 아닌 다른 메인넷들도 커맨드나 디테일한 부분만 다르지 전체적인 진행 방향성은 비슷하다.

컨트랙트 코드 배포 및 인스턴스 생성은 코스모스 생태계에서 Wasm 모듈을 사용하는 모든 체인은 동일하다. 위 글에서 했던 방식을 그대로 cosmwasm을 지원하는 어떤 체인에서도 똑같이 적용할 수 있다.

이 글을 보고 Cosmwasm으로 컨트랙트를 작성하려는 사람들이 도움이 되었길 바란다.


Reference

Smart Contract Development Quick Start on Juno
This is a very simple smart contract that we can use for learning how to interact with CosmWasm smart contracts on Juno testnet. This…