[KO] [NEAR 101] 1편: NEAR Counter 컨트랙트 톺아보기

Suji Yoon
DSRV
Published in
28 min readAug 1, 2022

[NEAR 101] 1편: NEAR Counter 컨트랙트 톺아보기

DSRV Dev Guild에서는 더 많은 개발자들과 Web3 인프라를 만들어가기 위해, 다양한 메인넷과 스마트 컨트랙트에 대한 가이드를 연재합니다.

Disclaimer: 이 글은 정보 전달을 위한 목적으로 작성되었으며, 특정 프로젝트에 대한 투자 권고, 법률적 자문 등 목적으로 하지 않습니다. 모든 투자의 책임은 개인에게 있으며, 이로 발생된 결과에 대해 어떤 부분에서도 DSRV는 책임을 지지 않습니다. 본문이 포괄하는 내용들은 특정 자산에 대한 투자를 추천하는 것이 아니며, 언제나 본문의 내용만을 통한 의사결정은 지양하시길 바랍니다.

[NEAR 101 시리즈]

  1. Counter 컨트랙트 톺아보기
  2. Frontend 연결하기

What is NEAR?

NEAR는 지분 증명(PoS) 알고리즘을 사용하고, 샤딩(Sharding)을 통해 확장성을 지원하는 Layer 1 블록체인입니다. 이번 NEAR 101 시리즈에서는 NEAR에서 스마트 컨트랙트를 개발하고, 배포하고, 프론트엔드에서 배포한 컨트랙트와 통신하는 방법을 자세히 설명하고자 합니다.

본 글에서는 그 중에서도 스마트 컨트랙트에 대한 내용을 톺아보는 시간을 갖겠습니다.

본격적으로 컨트랙트 코드를 살펴보기 전에 NEAR의 계정(Accounts), 스마트 컨트랙트, 스토리지(Storage)에 대해 간단히 설명하겠습니다. NEAR의 계정 ID는 NEAR의 가장 큰 특징 중 하나인데요. 일반적인 블록체인에서 계정의 ID로 0x71C7656EC7ab88b098defB751B7401B5f6d8976F 와 같이 공개 키 해시 값을 사용하는 것과 다르게 NEAR의 계정 ID는 suji.near 처럼 사람이 읽고 이해할 수 있는 이름을 가져 사용자가 사용하기에 더욱 직관적인 환경을 제공합니다. 각각의 NEAR 계정은 계정 당 하나의 스마트 컨트랙트만 배포하고 활성화할 수 있으며, 서브 계정을 생성해서 여러 개의 스마트 컨트랙트를 배포할 수도 있습니다. 서브 계정에 대한 자세한 설명과 생성 방법은 실습을 진행하면서 알아보겠습니다.

NEAR의 스마트 컨트랙트는 WebAssembly로 컴파일되어야 합니다. 참고로, WebAssembly에 대한 자세한 설명은 CosmWasm 101 1편에서 확인하실 수 있습니다. NEAR에서는 현재 near-sdk 와 연동되는 언어로 AssemblyScriptRust를 지원합니다. 컨트랙트 개발자는 두 언어 중 자유롭게 선택해서 스마트 컨트랙트를 NEAR에서 작성할 수 있으며, 컨트랙트가 Wasm 파일로 컴파일된 후에는 어느 언어로 작성하던 지 동일한 과정으로 배포하고 실행할 수 있습니다. 배포된 스마트 컨트랙트는 언제든지 업데이트할 수 있지만 제거할 수는 없습니다.

마지막으로 NEAR는 스토리지 스테이킹(storage staking)을 사용합니다. 즉, 스마트 컨트랙트가 배포된 계정은 컨트랙트에 저장된 데이터 양에 따라 필요한 스토리지 비용을 지불할 수 있는 충분한 잔액을 가지고 있어야 합니다. 계정에 충분한 잔액이 없는 상태에서 온체인 저장을 시도하면 계정에 NEAR 토큰을 추가하라는 오류가 발생할 것입니다. 이러한 정책을 통하여 스마트 컨트랙트를 사용하는 유저가 비용을 지불하지 않고, 스마트 컨트랙트의 주인이 비용을 지불하도록 함으로서 사용자가 dApp을 더욱 사용할 수 있도록 하는 경제적 유인책이 될 수 있습니다.

Counter Example 톺아보기

⭐️ NEAR Counter 컨트랙트를 이해하려면 다음의 선수 지식이 필요해요!1. AssemblyScript는 TypeScript로 작성하기 때문에 TypeScript의 기초적인 문법을 이해해야 합니다.
2. Rust의 기초적인 문법을 이해해야 합니다. 공식 문서에서 1-4장 내용을 사전에 보고 오시면 좋아요.
3. CosmWasm 101 시리즈의 Counter Example과 구현 요구사항이 동일합니다. CosmWasm 101 1편을 읽고 오시면 좋아요.

NEAR의 스마트 컨트랙트는 모두 WebAssembly 형태로 컴파일됩니다. WebAssembly에 대한 자세한 설명은 CosmWasm 101 1편에서 확인하실 수 있습니다. 그리고 NEAR에서는 현재 near-sdk 와 연동되는 언어로 AssemblyScriptRust를 지원합니다. 컨트랙트 개발자는 두 언어 중 자유롭게 선택해서 스마트 컨트랙트를 NEAR에서 작성할 수 있으며, 컨트랙트가 Wasm 파일로 컴파일된 후에는 어느 언어로 작성하던지 동일한 과정으로 배포하고 실행할 수 있습니다.

본 글에서는 동일한 Counter 컨트랙트를 AssemblyScript와 Rust 두 언어로 구현한 예제를 모두 살펴볼 예정입니다.

AssemblyScript

AssemblyScript는 TypeScript 언어를 Binaryen이라는 컴파일러를 사용해서 WebAssembly로 컴파일할 수 있습니다. JavaScript에 친숙한 개발자들이 상대적으로 쉽게 스마트 컨트랙트를 개발할 수 있다는 장점이 있습니다. 하지만 AssemblyScript의 NEAR SDK인 near-sdk-as 의 코드 메인테이닝이 활발하게 이루어지지 않는 다는 점에서 DeFi와 같이 금융 관련 컨트랙트를 제작할 때 AssemblyScript를 사용하는 것은 추천되지 않습니다.

AssemblyScript로 스마트 컨트랙트 개발을 시작하기 전에 저장소에 다음 패키지를 추가해야 합니다.

yarn global add near-cli
yarn global add assemblyscript
yarn global add asbuild
  • near-cli: 스마트 컨트랙트와 통신하는 API를 제공하는 NEAR의 CLI 도구
  • assemblyscript: AssemblyScript 언어
  • asbuild: AssemblyScript의 빌드 도구

그럼 이제 코드를 함께 보면서 설명해보도록 하겠습니다. 다음 명령어를 통해 컨트랙트를 로컬에 다운받아보도록 합시다.

git clone https://github.com/DSRV-DevGuild/near-counter-example.git
cd AssemblyScript && yarn install

지금부터 루트 디렉토리를 AssembyScript라고 생각하겠습니다. AssemblyScript의 디렉토리 구조는 다음과 같습니다.

AssemblyScript
├── as-pect.config.js
├── asconfig.json
├── assembly
│ ├── __tests__
│ │ ├── as-pect.d.ts
│ │ └── main.spec.ts
│ ├── as_types.d.ts
│ ├── index.ts
│ └── tsconfig.json
├── package.json
└── yarn.lock

AssemblyScript로 스마트 컨트랙트를 작성하기 위해서는 필요한 설정 파일들이 있습니다. /asconfig.json 파일에는 다음과 같이 near-sdk-as를 이용해서 컴파일하기 위한 옵션이 지정되어 있습니다.

/AssemblyScript/asconfig.json

/assembly/tsconfig.json 파일은 TypeScript 프로젝트를 컴파일하기 위한 루트 레벨 파일과 컴파일러 옵션을 지정합니다.

/AssemblyScript/assembly/tsconfig.json

/assembly/as_types.d.ts 파일은 AssemblyScript 코드의 타입을 정의합니다. 우리는 near-sdk-as의 타입을 import해서 사용합니다.

/AssemblyScript/assembly/as_types.d.ts

다음으로 assembly/index.ts 파일에서 Counter 컨트랙트 코드를 살펴보겠습니다.

블록체인에 상태를 저장하기 위해서는 near-sdk-as에서 제공하는 storage 객체를 사용해야 합니다. 이 객체는 블록체인의 storage와 소통할 수 있는 인터페이스를 제공하며, key-value 쌍으로 이루어져 있습니다. 이때 keystring 값을 가지고, valuestring, bytes, u64 등의 다양한 타입을 가질 수 있습니다.

/AssemblyScript/assembly/index.ts

이제 storage를 사용해서 카운터 값을 저장할 수 있습니다. 먼저 저장된 카운터 값을 읽어오는 get_num 함수를 살펴봅시다.

get_num 함수는 스마트 컨트랙트의 외부에서 호출할 수 있어야 하기 때문에 export 키워드를 사용합니다. 그리고 카운터 값을 반환하기 때문에 반환 타입을 i8이라고 명시해줍니다.

/AssemblyScript/assembly/index.ts
💡 DSRV’s Tip: getPrimitive 메소드는 무엇인가요?getPrimitive<T>(key: string, defaultValue: T): T 함수는 storage에서 key 값에 해당하는 value를 찾아서 반환합니다. 이때, key 값에 해당하는 value가 없는 경우에 대신 리턴하는 defaultValue 값을 지정할 수 있습니다.

다음으로 인자로 count 값을 전달하고 해당 값만큼 storage의 카운터 값에 더해주는 increment 함수를 살펴보겠습니다. get_num을 통해 현재 storage의 카운터 값을 가져오고 인자로 받은 count값을 더한 후에 set<T>(key: string, value: T): void 함수를 사용해서 새로운 값을 storage에 저장합니다.

/AssemblyScript/assembly/index.ts

위의 코드에서 safeguard_overflow 함수는 i8 타입으로 선언된 count 값의 Integer overflow를 체크하기 위한 조건입니다. assert<T>(isTrueish: T, message?: string): T함수는 AssemblyScript가 제공해주는 함수로 조건이 false인 경우 message를 로그에 출력하고 에러를 발생시킵니다.

/AssemblyScript/assembly/index.ts

마지막으로 storage의 카운터 값을 0으로 초기화하는 reset 함수입니다. increment 함수에서 사용했던 set 메소드를 사용합니다.

/AssemblyScript/assembly/index.ts

이렇게 스마트 컨트랙트를 모두 살펴봤습니다. 다음으로 컨트랙트가 제대로 작동하는 지 테스트 코드를 작성하여 테스트를 해보도록 하겠습니다. /assembly/tests/as-pect.d.ts 에서 AssemblyScript 테스트를 위한 모듈을 추가한 것을 확인할 수 있습니다. 해당 모듈은 JavaScript의 Jest 테스팅 라이브러리가 제공하는 test(), describe()등의 함수를 포함하고 있습니다.

/AssemblyScript/assembly/__tests__/as-pect.d.ts

assembly/__tests__/main.spec.ts 에는 increment, get_num, reset 함수가 제대로 동작하는 지 테스트하고 마지막으로 overflow 를 테스트하는 네 가지 테스트 코드가 작성되어 있습니다.

전체 코드는 다음과 같습니다.

/AssemblyScript/assembly/__tests__/main.spec.ts

다음의 명령어를 통해 테스트를 진행할 수 있습니다.

yarn test

package.json의 옵션을 통해 위의 명령어를 실행하면 yarn asp —nolog 명령어가 실행되며 테스트가 진행됩니다. 테스트가 성공하면 다음과 같은 화면이 출력될 것입니다.

AssemblyScript 컨트랙트 테스트 성공 화면. 출처: DSRV

Rust

Rust는 NEAR에서 스마트 컨트랙트를 작성할 때 제일 추천되는 언어입니다. 먼저 다음의 명령어를 통해 개발 환경을 설치해줍니다.

# install rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# configure your current shell
source $HOME/.cargo/env
# add wasm target to your toolchain
rustup target add wasm32-unknown-unknown
# install near-cli
npm install -g near-cli

Rust 컨트랙트 코드는 AssemblyScript와 동일한 위치의 Rust 폴더에서 확인할 수 있습니다. src/lib.rs 파일의 코드를 분석하며 Counter 컨트랙트의 구현을 살펴보도록 하겠습니다. 지금부터는 Rust 폴더를 루트 디렉토리라고 생각하고 진행하겠습니다. Rust 폴더의 디렉토리 구조는 다음과 같습니다.

Rust
├── Cargo.toml
└── src
└── lib.rs

src/lib.rs 코드의 제일 상단에는 /Cargo.toml 파일에 선언된 near_sdk 에 접근해서 스마트 컨트랙트 작성에 필요한 모듈을 import 했습니다.

/Rust/src/lib.rs
  • self : BorshDeseiralizeBorshSerialize가 작동하기 위해 필요합니다. 스마트 컨트랙트 자기 자신을 참조합니다.
  • BorshDeserialize : 스마트 컨트랙트의 함수를 호출하면서 인자를 함께 전달할 때, JSON 타입의 인자를 역직렬화합니다.
  • BorshSerialize : 스마트 컨트랙트에서 결과를 다시 보낼 때 JSON으로 직렬화합니다.
  • near_bindgen : 스마트 컨트랙트라는 것을 알려주는 어노테이션으로 각 컨트랙트마다 near_bindgen 어노테이션과 함께 선언된 struct가 적어도 하나씩은 있어야 합니다.
💡DSRV’s Tip: Borsh란 무엇인가요?Rust를 주로 다뤄보셨던 분들은 Serde라는 데이터 직렬화 및 역직렬화 프레임워크에 익숙하실 것 같습니다. 하지만 NEAR는 Borsh라는 별도의 Rust용 프레임워크를 만들었습니다. Borsh는 Serde보다 속도와 안정성 측면에서 우수하다고 주장합니다.

다음으로 struct를 선언합니다. Struct 선언자 위의 attributes 들은 WebAssembly로 컴파일된 파일이 NEAR 블록체인에서 호환될 수 있도록 해줍니다. Default는 컨트랙트의 기본 생성자로, 컨트랙트를 배포한 후 함수를 실행하려 할 때 함수 실행 전에 NEAR의 가상머신이 기본값으로 컨트랙트를 초기화합니다.

아래 코드의 경우 vali8 타입이기 때문에 기본값인 0으로 초기화가 될 것입니다. pub 는 스마트 컨트랙트가 public 하게 접근 가능하다는 것을 의미합니다.

/Rust/src/lib.rs

만약 기본값이 아닌 다른 값으로 컨트랙트를 초기화하고 싶다면 아래와 같이 구현할 수 있습니다.

/Rust/src/lib.rs

이제 impl을 사용해서 컨트랙트의 실제 함수들을 구현할 것입니다. NEAR의 스마트 컨트랙트 내부에 속하는 함수라는 사실을 명시하기 위해, 앞서 Struct에서 보았던 것처럼 near_bindgen 어노테이션을 추가해 줍니다.

/Rust/src/lib.rs

Rust에서 스마트 컨트랙트를 작성할 때는 이렇게 struct와 실제 함수를 구현하는 impl 을 가지는 패턴으로 작성하는 것이 일반적입니다. 함수를 더 자세히 들여다보도록 하겠습니다.

위의 AssemblyScript로 작성한 카운터 예제와 마찬가지로 get_num, increment, reset 세 가지 함수가 구현되어 있습니다. 먼저 get_num 함수 코드는 다음과 같습니다.

인자로 전달하는 &selfstruct의 인스턴스를 참조하고, i8 타입의 카운터 값을 반환하는 함수이기 때문에 리턴 타입을 명시해줍니다.

/Rust/src/lib.rs

다음으로 인자로 count 값을 전달하고 해당 값만큼 storage의 카운터 값에 더해주는 increment 함수를 살펴보겠습니다. get_num 과는 다르게 increment 함수는 컨트랙트 내부의 값을 변경합니다. &mutmutable이라는 뜻으로 &mut selfself 변수에 대한 mutable한 참조를 생성합니다.

/Rust/src/lib.rs

마지막으로 컨트랙트의 카운터 값을 0으로 초기화하는 reset 함수입니다. increment 함수와 마찬가지로 컨트랙트 내부의 값을 변경하기 때문에 &mut self 를 이용합니다.

/Rust/src/lib.rs

이렇게 스마트 컨트랙트 코드를 모두 살펴보았는데요. 다음으로 테스트 코드를 살펴보도록 하겠습니다.

mod tests 는 말 그대로 tests 라는 이름의 모듈을 의미합니다. cfg는 괄호 안의 조건이 true인 경우에만 모듈을 컴파일하라는 컴파일 명령어입니다. 아래의 경우에는 cargo test 명령을 실행할 때만 (test) 조건이 true가 되기 때문에 테스트를 실행하지 않으면 해당 모듈은 컴파일되지 않습니다.

/Rust/src/lib.rs

테스트 코드는 총 3개로 increment 함수의 경우에는 먼저 counter 값을 0으로 초기화한 Counter 인스턴스를 생성한 후, increment(5) 를 실행하고 다시 get_num으로 값을 가져와서 5로 잘 더해졌는지 확인합니다.

/Rust/src/lib.rs

increment_and_reset 함수는 위와 동일하게 Counter 인스턴스를 생성한 후 incrementreset을 차례로 실행시켜서 마지막에 get_num으로 가져온 값이 0으로 잘 초기화되었는 지 확인합니다.

/Rust/src/lib.rs

마지막 panics_on_overflow 함수는 should_panic 이라는 attributes를 가지고 있는데요. 해당 테스트는 오류가 예상되는 테스트로 오류가 발생하면 테스트를 통과합니다.

/Rust/src/lib.rs

이제 Rust 폴더에서 아래의 명령어를 실행해서 테스트를 진행합니다.

cargo test

테스트가 성공할 경우 아래와 같은 화면이 출력될 것입니다.

Rust 컨트랙트 cargo test 성공 화면. 출처: DSRV

AllThatNode를 사용하여 Counter 컨트랙트 배포하기

이제 각각의 컨트랙트를 AllThatNode를 사용하여 NEAR Testnet에 배포해보도록 하겠습니다. AllThatNode에서는 멀티체인의 노드를 무료로 제공합니다. AllThatNode 사이트에 들어가 로그인을 한 후 Protocol에서 NEAR를 선택합니다.

ATN에서 제공하는 RPC 엔드포인트를 사용하기 위해서는 먼저 API 키를 발급받아야 합니다. Create New Project 버튼을 눌러 프로젝트를 생성합니다.

ATN — NEAR protocol 화면 캡처. 출처: DSRV

프로젝트의 이름을 적은 후 Create 버튼을 클릭하면 다음과 같은 화면이 나타납니다. 조건을 확인한 후 다시 Create 버튼을 클릭합니다.

ATN — Create New Project 화면 캡처. 출처: DSRV

그러면 다음과 같이 Dashboard 화면에서 NEAR 프로젝트가 성공적으로 만들어진 것을 확인할 수 있고, API KEY 버튼을 클릭하면 API KEY를 복사할 수 있습니다.

ATN — Dashboard 화면 캡처. 출처: DSRV

터미널을 열어서 다음의 명령어를 통해 near-cli 에 RPC 서버와 API KEY를 추가해줍니다.

near set-api-key <rpc server> <x-api-key>

위 명령어를 입력하면 다음과 같이 출력될 것입니다.

near set-api-key 명령어 입력 화면 캡처. 출처: DSRV

컨트랙트 컴파일하기

  • AssemblyScript

먼저 AssemblyScript 컨트랙트를 컴파일해보도록 하겠습니다. AssemblyScript 폴더에서 아래의 명령어를 실행해주세요. 이 명령어는 앞서 설치한 asbuild 라이브러리를 이용해서 빌드를 실행시키는 명령어입니다.

yarn asb

컴파일이 성공하면 AssemblyScript 폴더 안에 build/release/counter_contract.wasm 파일이 생성될 것입니다.

  • Rust

다음으로 Rust 컨트랙트를 컴파일해보도록 하겠습니다. CosmWasm 시리즈에서 컴파일했던 것과 동일한 방법을 사용합니다. 우선 Rust 폴더로 이동한 후에 다음의 명령어를 실행합니다.

cargo build --target wasm32-unknown-unknown --release

컴파일이 성공하면 Rust 폴더 안에 target/wasm32-unknown-unknown/release/counter_contract.wasm 파일이 생성되는 걸 확인할 수 있습니다.

컨트랙트 배포하기

NEAR에서는 하나의 계정 당 하나의 스마트 컨트랙트만 가질 수 있습니다. 테스트넷에서는 dev-accounts 라는 임시 계정을 생성해서 컨트랙트를 배포할 수도 있지만 배포한 컨트랙트가 영구적으로 보존되길 원한다면 계정을 직접 만들고 해당 계정에 컨트랙트를 배포해야 합니다. 본 글에서는 dev-accounts를 이용해 배포하는 방법과 계정을 생성해서 배포하는 방법 두 가지를 모두 실습해보겠습니다.

먼저 임시 계정을 만들어서 테스트넷에 배포하는 방법을 시도해보겠습니다. AssemblyScript 폴더로 위치를 이동하고 아래의 명령어를 입력합니다.

near dev-deploy --wasmFile=build/release/counter_contract.wasm --nodeUrl='https://near-testnet-rpc.allthatnode.com:3030'

near dev-deploy 는 테스트넷에서만 사용이 가능한 명령어로, 배포를 위한 임시 계정을 자동으로 생성해서 스마트 컨트랙트를 배포합니다. 명령어를 실행하면 현재 디렉토리에 ./neardev/dev-account 파일이 존재하는 지 먼저 찾은 후, 존재하지 않는 경우에는 새로운 dev-account 파일을 생성합니다.

파일 안에는 dev- 로 시작하는 dev-account 계정 ID가 담겨져 있습니다. 퍼블릭 키와 개인 키페어도 ~/.near-credentials/testnet/[dev-account-id].json 에 자동으로 생성되어 저장됩니다.

--wasmFile 은 앞서 컴파일한 Wasm 파일의 위치를 알려주고, —-nodeUrl 은 RPC URL을 지정하는 옵션입니다.

배포가 완료되면 다음과 같은 화면이 출력됩니다. 익스플로어를 통해서 배포된 컨트랙트를 확인할 수도 있습니다. Account id: 다음에 나오는 dev- 로 시작되는 값이 임시로 생성한 계정입니다. 해당 값을 통해 배포된 스마트 컨트랙트와 통신할 수 있으니 미리 복사해놓으시길 바랍니다.

near dev-deploy 성공 시 출력 화면. 출처: DSRV

다음은 테스트넷에 계정을 직접 만들어서 로그인을 한 후 해당 계정에 스마트 컨트랙트를 배포해보도록 하겠습니다. 먼저 NEAR Wallet 사이트에서 테스트넷 계정을 생성합니다. 이때 NEAR 테스트넷 토큰을 이미 가지고 있는 채로 계정이 생성되기 때문에 따로 테스트 토큰을 받을 필요는 없습니다.

다음으로 near-cli를 통해서 로그인을 해보도록 합니다.

near login

위 명령어를 실행하면 아래와 같이 near wallet에 연결되는 브라우저가 나타날 것입니다. Next 버튼을 클릭한 후 Connect 버튼을 눌러 계정에 대한 Full access 권한을 가질 수 있도록 허용합니다.

💡 DSRV's Tip: NEAR의 Access Keys 에 대해 알아보기NEAR의 Access Key는 계정의 public/private 키 페어로 이루어져 있고 Full Access KeyFunction Call Key 두 종류가 있습니다.Full Access Key는 말 그대로 계정에 대한 전체 권한을 가지고, Function Call Key는 non-payable 함수를 호출할 수 있는 권한만 가집니다. non-payable 함수란 NEAR 토큰을 deposit 으로 갖고 있지 않은 함수를 뜻합니다.Function Call Key를 이용하면 트랜잭션을 서명할 때마다 사용자의 지갑으로 리다이렉트하여 승인을 요청할 필요가 없이, 사용자의 단 1회 승인 만으로 트랜잭션을 지속적으로 보낼 수 있습니다. 단, Function Call Key 기능은 non-payable 함수에 한하여 사용할 수 있습니다.
near login 화면 1. 출처: DSRV
near login 화면 2. 출처: DSRV

로그인이 성공했다면 아래와 같은 화면이 출력될 것입니다.

near login 화면 3 — 성공 화면. 출처: DSRV

다음으로 컨트랙트를 배포할 서브 계정을 만들어보도록 하겠습니다. near-cli 를 이용하면 간단히 하나의 계정에서 여러 개의 서브 계정을 만들어서 관리할 수 있습니다. 서브 계정을 만드는 명령어는 다음과 같습니다.

near create-account ${SUBACCOUNT_ID}.${ACCOUNT_ID} --masterAccount ${ACCOUNT_ID} --initialBalance ${INITIAL_BALANCE}
  • SUBACCOUNT_ID - 서브 계정 아이디
  • ACCOUNT_ID - 본 계정 아이디
  • INITIAL_BALANCE - 서브 계정의 NEAR 토큰량

명령어를 실행하면 다음과 같이 계정이 생성됩니다.

near create-account 실행 화면. 출처: DSRV
💡 DSRV's Tip: NEAR의 Subaccounts 에 대해 알아보기NEAR의 계정은 원하는 만큼 서브 계정을 만들 수 있습니다. 서브 계정의 네이밍 패턴은 웹사이트 도메인과 유사한 규칙을 따릅니다. 또한 오직 부모 계정만이 서브 계정을 만들 수 있는 권한을 가집니다.예를 들어 suji.nearsub.suji.near를 생성할 수 있고, sub.suji.nearexample.sub.suji.near를 생성할 수 있습니다. suji.nearexample.sub.suji.near를 생성할 권한이 없습니다.

방금 우리가 만든 서브 계정에, Rust로 작성해 컴파일한 Wasm 파일을 배포해보겠습니다. Rust 폴더로 위치를 이동한 후 다음 명령어를 실행해주세요.

near deploy --accountId=contract.myaccount8.testnet --wasmFile=target/wasm32-unknown-unknown/release/counter_contract.wasm --nodeUrl='https://near-testnet-rpc.allthatnode.com:3030'

near deploy 명령어는 —-wasmFile 위치에 있는 컴파일된 Wasm 파일을 —-accountId 계정에 배포하는 명령어입니다. 이 때 배포하고자 하는 계정에 near login을 통해 미리 로그인을 해서 Full Access Key를 받아야 합니다.

배포가 완료되면 다음과 같은 화면이 출력됩니다. Account Id 값이 스마트 컨트랙트가 배포된 계정의 아이디이고 익스플로어를 통해 배포된 컨트랙트를 확인할 수 있습니다.

near deploy 성공 시 출력 화면. 출처: DSRV

컨트랙트 실행하기

이렇게 우리는 NEAR 테스트넷에 near dev-deploynear deploy 명령어를 통해 AssemblyScript와 Rust로 작성한 카운터 예제 스마트 컨트랙트를 각각 배포해보았습니다. 마지막으로 near-cli 를 통해서 배포한 컨트랙트가 잘 동작하는지 실행해보도록 하겠습니다.

near-cli 로 컨트랙트를 호출하는 방법에는 viewcall 두 가지가 있습니다. view 는 컨트랙트의 상태를 조회하는 함수를 호출할 때 사용하는 것으로서 가스 비용을 지불할 필요가 없습니다.

near view ${CONTRACT_ACCOUNT_ID} ${METHOD_NAME} ${PAYLOAD}
  • ${CONTRACT_ACCOUNT_ID} - 스마트 컨트랙트가 배포된 계정의 ID
  • ${METHOD_NAME} - 호출할 함수의 이름
  • ${PAYLOAD} - 함수에 전달해야 할 인자
  • ${ACCOUNT_ID} - 컨트랙트를 호출할 계정의 ID

call은 컨트랙트 내부의 상태를 변화시키는 함수를 호출할 때 사용하는 것으로, 가스 비용을 지불해야 하기 때문에 컨트랙트를 호출하는 계정의 아이디를 같이 인자로 넘겨줘야 합니다.

near call ${CONTRACT_ACCOUNT_ID} ${METHOD_NAME} ${PAYLOAD} --accountId=${ACCOUNT_ID}
  • get_num

get_num 함수는 컨트랙트 내부의 카운터 값을 읽어오는 함수이므로 view 명령어를 사용해서 컨트랙트를 호출합니다.

# near deploy
near view mycontract.myaccount8.testnet get_num
# near dev-deploy
near view dev-1657270929046-54526785269639 get_num
get_num 함수 호출 출력 화면 캡처. 출처: DSRV
  • increment

increment 함수는 인자로 count 값을 받아서 컨트랙트 내부의 카운터 값에 더해주는 함수이므로 call 명령어를 사용해서 컨트랙트를 호출합니다.

# near deploy
near call mycontract.myaccount8.testnet increment '{"count": 5}' --accountId=myaccount8.testnet
# near dev-deploy
near call dev-1657270929046-54526785269639 increment '{"count": 5}' --accountId=myaccount8.testnet
increment 함수 호출 출력 화면 캡처. 출처: DSRV
  • reset

reset 함수는 컨트랙트 내부의 카운터 값을 0으로 초기화해주는 함수이므로 call 명령어를 사용해서 컨트랙트를 호출합니다.

# near deploy
near call mycontract.myaccount8.testnet reset --accountId=myaccount8.testnet
# near dev-deploy
near call dev-1657270929046-54526785269639 reset --accountId=myaccount8.testnet
reset 함수 호출 출력 화면 캡처. 출처: DSRV

글을 마무리하며..

이번 시간에는 near-sdk 가 공식으로 지원하는 두 언어인 AssemblyScript와 Rust를 사용해서 간단한 Counter 스마트 컨트랙트 예제를 살펴보고 AllThatNodenear-cli를 사용해 컨트랙트를 NEAR Testnet에 직접 배포해보았습니다. AssemblyScript와 Rust는 모두 Wasm 파일로 컴파일되고, 컴파일 된 후에는 어느 언어로 작성하든지 동일한 과정을 거쳐 배포되고 실행되는 것을 확인할 수 있었습니다.

또한 NEAR의 모든 컨트랙트는 자신만의 계정을 가지고 있고, 테스트넷의 경우에는 dev-deploy 명령어를 통해 임시 계정을 생성하여 배포할 수도 있었습니다.

다음 시간에는 간단한 Clicker 게임 예제를 구현해보며 테스트넷에 배포한 Counter 컨트랙트와 프론트엔드가 통신하는 방법을 실습해 볼 예정입니다. 이 글이 NEAR 공부를 시작하고자 했던 많은 개발자분들께서 NEAR에 쉽게 입문하는데 도움이 되었길 바라며, 다음 글로 또 찾아오도록 하겠습니다. 이 글을 읽는데 귀중한 시간을 할애해주셔서 감사합니다.

Author
Suji Yoon of DSRV, Developer Evangelist Intern (Twitter @suji_forcrypto)

Reviewed by
Sigrid Jin of DSRV, Technical Writer & Developer Evangelist (Twitter @sigridjin_eth)
Owen Hwang of DSRV, Research Manager (Twitter @journeywith_eth)

--

--

Suji Yoon
DSRV
Writer for

Software Engineer Intern @DSRV / Ewhachain / Twitter: @suji_forcrypto