블록체인 뿅뿅

HardHat 튜토리얼 1편

bimppap 2023. 2. 24. 01:06

HardHat Tutorial 을 직접 번역해 봤습니다.
😎 더불어 개인적으로 유용했던 팁 또는 이해하는데 도움이 되는 개념들을 적어봤습니다.
>> 사용 스펙
MacOS
InteliJ IDE
Node.js
TypeScript
npm
Solidity

 

1. Overview

HardHat 초심자들을 위한 튜토리얼

이 튜토리얼은 빠르고 간단하게 컨트랙트 개발 환경을 구축하는 걸 목표로 한다.

이더리움 기반 구축을 용이하게 하는 개발 환경인 HardHat을 사용하면 스마트 컨트랙트 및 DApp 구축 프로세스의 반복 작업을 관리 및 자동화할 수 있으며, 관련 워크플로우에 더 많은 기능을 쉽게 도입하도록 만든다. 또한 개발을 위한 로컬 이더리움 네트워크인 Hardhat 네트워크를 통해 컨트랙트를 배포, 테스트 실행, 코드 디버깅이 가능해진다.

이 튜토리얼에선 무엇을 하나?

  • 이더리움 개발을 위한 Node.js 환경 세팅하기
  • HardHat 프로젝트를 생성하고 설정하기
  • 토큰을 가지고 있는 간단한 스마트 컨트랙트 작성하기
  • HardHat을 이용한 자동화 테스트 작성하기
  • HardHat 네트워크를 이용해 Solidity 디버깅하기
  • HardHat 네트워크와 이더리움 테스트넷에 컨트랙트 배포하기

시작하기 전에 선행되어야 하는 것

  • 타입스크립트를 사용할 수 있다.
  • 터미널을 사용할 수 있다.
  • git 을 사용할 수 있다. (8번을 안 할 경우 무시해도 된다.)
  • 스마트 컨트랙트의 개념 및 작동 원리를 알고 있다.
  • 메타마스크 지갑이 있다. (7번을 안 할 경우 무시해도 된다.)

 

2. 환경 세팅

hardhat 튜토리얼은 javascript + vscode 를 사용한다. 하지만 여기선 typescript + inteliJ를 사용하니 참고하길 바란다.

Node.js 설치

# 처음 설치가 아니라면 이 명령어는 생략한다
curl -o- <https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh> | bash

nvm install 18
nvm use 18
nvm alias default 18
npm install npm --global # Upgrade npm to the latest version

플러그인 설치

Preferences - 플러그인 - 마켓플레이스 로 들어가 Solidity 플러그인을 설치해준다.

hardhat 플러그인도 있긴 하지만 별 차이 없으니 설치는 생략한다.

 

3. HardHat 프로젝트 생성하기

아래 명령어들을 차례대로 실행한다.

mkdir hardhat-tutorial
cd hardhat-tutorial
npm init # 입력창들은 전부 엔터 쳐서 패스
npm install --save-dev hardhat typescript ts-node
npx hardhat
# > Create an empty hardhat.config.js 를 선택한다.

IDE로 프로젝트를 켜보면 아래와 같은 구조로 되어있다.

 

 

루트 디렉토리에 tsconfig.json 파일을 추가한다.

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

 

이후 아래 패키지를 설치한다.

npm install --save-dev @nomicfoundation/hardhat-toolbox

hardhat-toolbox 는 스마트 컨트랙트 배포에 필요한 기능을 hardhat에서 전부 제공해주는 만능 패키지라 보면 된다. 추후엔 필요한 기능만 골라 받으면 되지만 이 프로젝트는 실습용이니 신경 쓰지 않아도 된다.

hardhat.config의 확장자를 js에서 ts로 바꾼 후 아래와 같이 코드를 추가한다.

 

// hardhat.config.ts
import "@nomicfoundation/hardhat-toolbox";

import { HardhatUserConfig } from 'hardhat/config';

const config: HardhatUserConfig = {
  solidity: "0.8.17",
};

export default config;

이 파일은 hardhat이 프로젝트를 실행할 때 사용되는 환경 세팅 파일이다. 보통 작업 디렉토리에서 가장 가까운 위치에 있는 파일을 사용하는데 기본적으론 루트 디렉토리에 있다. hardhat 관련 설정 세팅과 필요한 패키지 import는 여기서 해주면 된다.

 

 

4. 컨트랙트 작성 및 컴파일

새 디렉토리 contracts 를 생성한 후 디렉토리 내에 Token.sol 이라는 파일을 생성한다.

.sol 은 Solidity 파일 형식자다.

//SPDX-License-Identifier: UNLICENSED

pragma solidity ^0.8.9;

// 스마트 컨트랙트의 메인 빌딩 블록
contract Token {
    // 토큰을 식별하기 위한 string 타입 변수들
    string public name = "My Hardhat Token";
    string public symbol = "MHT";

    // unsigned integer 타입 변수로 토큰의 양을 지정한다.
    // set메서드가 없는 한 변동이 불가하다.
    uint256 public totalSupply = 1000000;

    // 이더리움 주소들을 저장하기 위한 address 타입 변수
    address public owner;

    // 키-값 맵 지정방식. 여기선 주소(key)들의 토큰 잔고(value)를 저장한다.
    mapping(address => uint256) balances;

    // 이 컨트랙트에서 어떤 이벤트가 일어났는지 오프체인 애플리케이션들이 알 수 있도록 한다.
    event Transfer(address indexed _from, address indexed _to, uint256 _value);

    /**
     * 컨트랙트 생성자
     */
    constructor() {
        // 컨트랙트가 배포될 때 호출되는 메서드.
        // 배포 트랜잭션의 발신자가 컨트랙트의 오너가 되고,
        // 기입된 총 토큰 양이 발신자에게 할당된다.
        balances[msg.sender] = totalSupply;
        owner = msg.sender;
    }

    /**
     * 토큰을 전송하는 메서드.
     *
     * external는 이 메서드가 컨트랙트 외부에서'만' 호출할 수 있다고 선언하는 수식언이다.
     */
    function transfer(address to, uint256 amount) external {
        // 트랜잭션 발신인이 전송에 필요한 토큰 양을 갖고 있는지 확인한다.
        // require 수식언 내의 조건이 fasle가 되면 트랜잭션이 실패한다.
        require(balances[msg.sender] >= amount, "Not enough tokens");

        // amount 만큼의 코인 수를 to 에게 전달한다.
        balances[msg.sender] -= amount;
        balances[to] += amount;

        // 전송 정보를 오프 체인으로 알린다.
        emit Transfer(msg.sender, to, amount);
    }

    /**
     * 파라미터로 들어온 주소가 가진 토큰 양이 얼마나 되는지 알려주는 읽기 전용 메서드.
     *
     * view는 이 메서드가 컨트랙트의 상태를 변경하지 않기에,
     * 트랜잭션을 실행하지 않고 호출할 수 있다고 알려주는 수식언이다.
     */
    function balanceOf(address account) external view returns (uint256) {
        return balances[account];
    }
}

SPDX-License-Identifier

위 항목을 기재하지 않으면 컴파일 시 경고가 뜬다. 라이센스가 있으면 링크를 참고해서 따로 표기하면 된다.

 

pragma solidity

솔리디티 파일은 반드시 pragma 버전을 기입하는 걸로 시작해야 한다. 솔리디티 컴파일러가 버전을 확인할 때 사용된다.

 

event

이벤트를 선언한 뒤 특정 메서드에서 emit 하면 메서드가 실행될 때 아래와 같이 오프체인으로 기록이 남는다. 백엔드 단에서 이러한 이벤트를 수집한 뒤 앱 내에서 활용할 수 있다.

해당 로그는 여기서 볼 수 있다.

 

 

컨트랙트를 작성한 뒤 아래 명령어를 실행한다.

성공적으로 컴파일되었다면 루트 디렉토리에 artifacts, cache 디렉토리가 생긴다.

npx hardhat compile

artifacts & cache

컴파일된 파일들을 수집 및 관리하는 곳이다. 보통 gitignore 파일로 둔다. 루트 디렉토리에서 생성되지만, 다른 경로에 compile 되길 원한다면 @typechain/hardhat 을 npm install 한 후에 hardhat.config.ts 에서 아래와 같이 typechain 프로퍼티를 추가하면 된다.

const config: HardhatUserConfig = {
  solidity: "0.8.17",
	typechain: {
    outDir: 'lib/interfaces',
  },
};