NEAR Test Drive - javascript for Web3

끼리·2022년 6월 23일
0
post-thumbnail

이번 컨센서스 2022의 세션에서 자바스트립트를 이용하여,니어 스마트 컨트랙트를 실습하는 세션이 있었다.

NEAR-SDK_JS에 대한 간단한 소개와 간단한 실습과정의 내용이 담겨 있다.
해당 세션을 들으면서, 직접 실습했던 내용을 정리해보려고 한다.

What is NEAR?

  • Layer 1 Blockchain
  • Proof of Stake & Certified Carbon Neutral by SouthPole
  • Almost infinitely scalable through sharding
  • ~1-2 second block production time
  • interoperable w/ ETH using Rainbow Bridge

와 같은 특징이 있다

NEAR에는 Native contract language로는
Rust 와 AssemblyScript 가 있지만 해당 세션에서는 자바스크립트를 이용한다

Why Javascript?

가장 큰 이유로는 익숙함이 크다.

  • ~7 million JS Devs (50%+ Dev Community)
  • Easy onboarding for web2 devs
  • Build dApps in a single familiar language

해당 실습을 위해서는 먼저

Background

Rust -> near-sdk-rs
AssemblyScript -> near-sdk-as
을 사용한다고 생각하면 된다.

near-sdk-js는 새로운 프로그래밍 언어를 배울 필요 없이 NEAR에서 스마트 계약 개발의 기초를 배울 수 있게 해준다. 💪

Wasm 과 Jsvm 의 장단점은 다음과 같다.

Requirements

  1. Node.js & npm
  2. near-cli

Creating a Project

Setup

직접 폴더 생성후, package.json 파일을 생성하여 셋업할 수 있지만
해당 깃허브를 통해 깃 클론을 진행하였다.

스마트 컨트랙트 살펴보기

깃클론 후, 클론한 폴더들과 파일들은 다음과 같이 구성되어있다.

먼저 프론트엔드에는 프론트엔드 코드들이 작성되었으며, 컨트랙트는 src에 구성되어있다.
src/index.js 에 작성된 컨트랙트를 살펴보자

1. Import 부분

near-sdk-js에서 4개의 종속성을 가져온다.
1.NearContract: 올바른 형식으로 스마트 계약을 만들기 위한 구성 클래스입니다.
2.NearBindgen: 계약을 JSVM과 호환되는 base64로 컴파일할 수 있습니다.
3.call, view: 계약의 기능을 발견하고 상호 작용할 수 있도록 합니다.

2.NearContract 부분

NearContract를 확장하는 새 클래스를 생성

1. NearBindgen을 사용하여 이 코드를 WebAssembly로 컴파일할 수 있다.
2.NEAR 컨트랙트 생성자 실행

여기서, 해당 생성자를 실행하면 계약의 메시지 상태 변수가 'Hello Web3 World!'로 기본 설정된다.

3. 그 다음 이어지는 View 함수

해당 함수는, 이제 블록체인에서 이 메시지를 검색할 수 있게 한다.
view는 가스비가 없으며 무료로 볼 수 있다.

이제 계약을 초기화하고 현재 설정된 인사말(greeting)을 받을 수 있다.

4. 메시지 변경 함수

그런 다음 새 변수를 문자열로 전달하여 메시지를 변경하는 방법을 만든다.

@call 은 함수를 바꾸는 역할을 한다.
이는 블록체인의 상태를 변하게 만들며, 비용이 든다는 특징이 있다.

Build

스마트 컨트랙트 작성이 완료되었다면, 컴파일 하여 베이스64로 인코딩이 필요하다.
따라서 build을 진행해보면,

npm run build
## Deploy 계약을 배포하는 가장 쉬운 방법은 near-cli 명령 dev-deploy를 사용하는 것이다. 이렇게 하면 새로운 개발 계정이 생성될 뿐만 아니라 이 계정을 사용하여 JSVM에 계약을 배포할 수 있다.
near js dev-deploy --base64File build/contract.base64 --deposit 0.1

Interact

계약이 배포되었다면 작성한 메서드와 함수에 대해 계약 호출을 수행하여 계약과 상호 작용할 수 있다.

[순서]
1.계정 ID를 환경 변수로 export후,
2.default greeting으로 set을 진행하여 초기화,
3.초기화후 view 호출하여 확인
4.set_greeting통해 greeting 값 변경

코드는 다음과 같다.

export JS_CONTRACT="dev-1655958509706-56090909688195"
near js call $JS_CONTRACT init --accountId $JS_CONTRACT --deposit 0.1
near js view $JS_CONTRACT view_greeting
near js call $JS_CONTRACT set_greeting '{"message": "GO TEAM!"}' --accountId $JS_CONTRACT --deposit 0.1

여기까진 간단한 실습

CoinFlip Game 실습

간단한 near-sdk-js 퀵스타트에 이어, 브랜치를 변경하여 실습을 징행하였다

먼저 브랜치를 "skeleton"으로 변경하였다.

git checkout skeleton

변경후, index.js을 확인해본 결과 다음과 같은 코드가 있었다.

실습 동안 추가 된, 두함수의 추카 코드 부분은 다음과 같다.

콜함수 내용 추가

뷰함수 내용 추가

전체코드

import {NearContract, NearBindgen, call, view, near} from 'near-sdk-js'

@NearBindgen
class CoinFlip extends NearContract {
    constructor() {
        //execute the NEAR Contract's constructor
        super()
        //set default values for the points
        this.points = {}
    }

    /*
        Flip a coin. Pass in the side (heads or tails) and a random number will be chosen
        indicating whether the flip was heads or tails. If you got it right, you get a point.
    */
    @call
    flipCoin({side}) {
        let player = near.predecessorAccountId();
        if(!(player in this.points)){
          this.points[player]=0
        }

        env.log(`${player} chose ${side}`);

        const randomNumber = near.jsvmCall('random-hub.examples.testnet','generateRandomNumber','');
        let outcome = randomNumber == 0 ? "heads" : "tails" ;

        if(side== outcome){
          env.log(`You get point! The result was ${outcome}`);
          this.points[player] +=1;
        }
        else{
          env.log(`You lost a point... The result was ${outcome}`);
          this.points[player] = this.points[player] ==0?0: this.points[player]-1;
        }


    }

    // View how many points a specific player has
    @view
    viewPoints({player}) {
        if(player in this.points){
          return this.points[player]

        }
        return null
    }
}

코드 배포

yarn deploy


배포를 하게되면 다음과 같이 뜬다.
account id : dev-1655966981942-68231741839603
앞서 진행한 간단한 실습처럼 계약이 배포된 계정 ID를 환경 변수로 내보낸다.

export JS_CONTRACT=dev-1655966981942-68231741839603
near js view $JS_CONTRACT viewPoints '{"player":"'$JS_CONTRACT'"}'

  • 한번도 게임을 하지않았으니 null값이 뜬다.
near js call $JS_CONTRACT flipCoin '{"side": "heads"}' --accountId $JS_CONTRACT --deposit 0.1


결과값을 보면 lost a point 부분을 확인 할 수 있다. 따라서 다시 view 로 확인하면

제로 포인트인것을 확인 할 수 있다.
다시 한번 콜을 하여, 점수를 얻은 것을 확인 할 수 있었다.

프론트엔드와의 interact 실습

yarn start


테스트를 위해서, 테스트넷에 새로운 계정을 생성후 sign in 을 진행해보았다.

SIGN IN 후, 화면은 다음과 같다.

컨트랙트와 상호작용하느느 코드는 frontend/utils/utils.js 파일에 있다.

export async function flip_coin(side, points){
  if (points == null) {
    console.log("First Time Playing!");
  }

  let account = window.walletConnection.account();

  // Use near-api-js to perform the function call. Since this is using the JS SDK, 
  // the jsContract boolean must be set to true.
  const result = await account.functionCall({
    contractId: nearConfig.contractName,
    methodName: 'flipCoin',
    args: {
      "side": side
    },
    gas: "300000000000000",
    attachedDeposit: points == null ? parseNearAmount("0.1") : "0",
    jsContract: true,
  });
  
  return result
}

포인트가 null이라면 한번도 게임을 진행하지 않음것이므로 0으로 설정한다.

Sumbit => prove 진행 후 트랜잭션 일어남 0.1 near 발생

0개의 댓글