끄적끄적

이더리움 dApp 개발을 위한 Hardhat 시작하기 본문

개발/블록체인

이더리움 dApp 개발을 위한 Hardhat 시작하기

코리이 2023. 6. 3. 22:53

 

이전 포스팅에서 이더리움 dApp 개발을 위해 Truffle 과 Ganache 를 세팅해 보았었다. 물론 Truffle 의 경우 현재도 많은 회사에서 사용중이지만 최근 트랜드에서는 블록체인 개발자 대다수가 개발 환경으로 Hardhat 을 사용한다. 둘 다 npm 을 활용해서 설치하는데 기간을 길게 보아도 Hardhat 사용자 수가 Truffle 을 넘어선지는 꽤 오래되었다. 또한 필자의 회사에서도 현재는 Truffle 보다는 Hardhat 을 주로 사용하고 있다.

공식 문서를 확인해보면 Hardhat 을 아래와 같이 설명하고 있다.

smart contract 와 dApp을 편집, 컴파일, 디버그, 배포하는 데 필요한 다양한 요소로 구성되어 있는 이더리움 소프트웨어 개발 환경이다.

 

결국에는 trffule 과 용도가 같은 이더리움 환경의 개발도구라는 뜻이다. 하지만 필자의 회사에서 truffle 이 아니라 hardhat 을 활용한 가장 큰 이유 두 가지는 typescript 와 호환성이 좋다는 점과 이더스캔 verify 기능이 된다는 점이였다. 이전에 테스트 코드를 짜거나 배포 후 회사 서버에서 컨트랙트를 사용하기 위해서는 개발 외적으로 불편한 점이 많았었는데, 이를 사용하니 통합적으로 사용할 수 있는게 가장 큰 장점이였다. 또한 opensea 에 verify 하기 위해서는 코드를 복사한 후 사이트에 저복해서 직접 붙혀넣기 하는 등 여러가지 불편한 점이 존재했었다.

 

물론 다른 개발자분들이 가장 많이 말하는 ganache 가 굳이 필요 없다는 점도 장점이 맞겠지만 실제 개발시에 이는 크게 문제되지 않았었다. 개인적으로는 내장된 것 보단 실제로 띄워서 사용하는 걸 선호하기 때문이기도 하다. 물론 Hardhat 이 Truffle 보다 무조건적으로 좋은게 아니라 둘 사이에는 여러 차이점이 존재한다고 하니 궁금하신 분들은 찾아보면 좋을 듯 싶다.

설치

앞에서 이야기한대로 Hardhat 은 npm 을 활용해서 설치한다. 개발할 디렉터리로 이동해서 npm init 후 hardhat 을 설치한다. 

# npm 프로젝트 시작
$ npm init -y

# hardhat 설치
$ npm install --save-dev hardhat

# 추후 환경변수 설정을 위한 dotenv 설치
npm install --save-dev dotenv

# hardhat 프로젝트 세팅
$ npx hardhat

npx hardhat 을 입력하면 어느 프로젝트로 세팅할지 선택할 수 있다. hardhat 의 가장 큰 장점이라고 할 수 있는 typescript 기반으로 프로젝트를 생성했다. 그러면 아래와 같은 질문들이 나오는데 그냥 다 y 를 눌러줘도 된다.

  • 프로젝트 root 설정
  • gitignore 에 추가할지
  • 리포트 설정할지 (원하는대로 해도 된다.)
  • hardhat-toolbox 설치 여부 (hardhat toolbox 가 hardhat 을 사용하기 위한 종속성을 대부분 포함하므로 설치하도록 한다.)

설치가 완료되면 아래와 같은 프로젝트 구조가 만들어진다. Lock 컨트랜트의 경우 예시 컨트랙트로 참고해서 다른 컨트랙트를 사용할 수 있다. 

  • contracts:  smart contract 소스 코드가 위치하는 디렉토리
  • test: 테스트 코드 위치 (스마트 컨트랙트 테스트를 할 수 있다)
  • scripts: 자동화 스크립트 위치 (배포 등의 스크립트를 만든다.)
  • hardhat.config.ts: Hardhat 의 설정파일로 네트워크 연결 정보, 컴파일 정보 등을 설정할 수 있다. 

hardhat.config.ts 파일은 네트워크 연결 정보를 수정하거나 컴파일할 솔리디티 버전 선택, 이더스캔 verify 등을 사용할 수 있다. 블록체인 노드의 경우 현재 많은 회사에서 사용중인 Alchemy (infra 를 사용해도 무방하다.) 를 활용할 것이며 테스트넷으로 이제 ropsten, rinkeby 등은 사용할 수 없기 때문에 Sepolia(세폴리아) 테스트넷을 사용해 볼까 한다. 배포 및 컴파일을 위해 facet 을 통해 테스트 코인을 꾸준히 받아두도록 하자. 

컴파일 및 테스트, 배포

이번 포스팅에서는 따로 smart contract 를 새로 개발하거나 하지 않고 제공되는 Lock 컨트랙트를 활용해서 작성할 예정이다. 따라서 바로 컴파일 명령어를 입력해보자.

$ npx hardhat compile

그러면 아래와 같이 artifacts 와 cache 디렉터리에 컴파일된 결과물이 나온다.  서버 연동에 필요한 ABI 의 경우 "artifacts/contracts/{contract}.sol/{contract}.json" 파일에 포함되어 있는걸 알 수 있다. 또한 앞에서 typescript 로 만들었으므로 개발에 필요한 typescript interface 또한 자동적으로 만들어준다. (가장 마음에 드는 부분중 하나다.)

컴파일한 후에 이제 테스트를 해볼 수 있다. 테스트 코드의 경우 내부적으로 hardhat network 에 ethers 를 이용해 연결하고, js 테스트 도구인 mocha 와 chai 를 이용한다. hardhat 컨트랙트 테스트 코드에 대한 이야기는 나중에 따로 포스팅 할 예정이다. 필자의 경우 typescript 를 주 언어로 사용하고 있다보니 mocha 와 chai 를 이용해 테스트 코드를 짜는 것은 매우 익숙해서 사용하기 편했다. 

테스트 코드를 작성했다 하고 테스트를 돌려보자. (공식문서에 어떻게 테스트코드를 짜는지에 대한 설명이 나와있다.)

참고로 이전에 truffle 사용시에는 ganache 를 직접 설치하고 띄운 후 테스트를 해야 했었는데 hardhat 의 경우 내장된 네트워크를 활용해서 테스트를 진행할 수 있다. 따라서 테스트를 위한 이더리움 노드를 따로 띄울 필요가 없다. 

$ npx hardhat test

smart contract 의 경우 다른 어떤 개발보다도 테스트 코드를 더 많이, 될만한건 모두 짜면서 진행하는 걸 권장한다. Upgradable Smart Contract 같은 패턴들이 나오고 있지만 실제 배포된 컨트랙트인 경우 기본적으로는 업데이트가 불가능하기 때문에 버그나 hole 이 발생하지 않도록 보수적으로 진행할 것을 추천한다.

 

테스트가 마무리 되었다면 실제 배포를 진행한다. 샘플 프로젝트에서 deploy.ts 파일에 배포를 위한 코드들이 적혀 있다. 실제 배포 스크립트의 경우에도 contract 를 가져오는 부분 빼고는 크게 달라질 부분은 없다. 추가적으로 upgrade 할 수 있는 스크립트 정도만 짜주면 완성될 것 같다. 

배포의 경우 테스트 처럼 내장된 네트워크를 사용할 수 없으므로 hardhat network 나 ganache 를 사용해야 한다. 공식 문서에 나와있는 대로 진행해 보자. 우선 터미널을 두개 띄워서 한곳은 로컬 노드를 실행시키고 한 곳에서는 나머지 명령어를 실행하자

# 로컬 노드 실행
$ npx hardhat node

# 실행한 로컬 이더리움 네트워크에 배포
$ npx hardhat run --network localhost scripts/deploy.ts

# 콘솔 모드 실행
$ npx hardhat console --network localhost

로컬에 배포가 된 걸 확인할 수 있다. 그리고 로컬 노드가 실행중인 터미널말고 다른 터미널에서는 콘솔모드가 진행되었을 것이다. 그럼 콘솔에서 아래 명령어를 입력해서 컨트랙트가 잘 동작하는지 확인해보자.

# Contract 가져오기
const contractAddress = '0x5fbdb2315678afecb367f032d93f642f64180aa3'
const Lock = await ethers.getContractFactory('Lock')
const lock = Lock.attach(contractAddress)

# balance 확인
ethers.utils.formatEther(await lock.provider.getBalance(contractAddress))

# 출금 실행
await lock.withdraw()

# balance 재확인
ethers.utils.formatEther(await lock.provider.getBalance(contractAddress))

balance 를 체크해보니 0.001 → 0.0 으로 모두 출금이 완료된 것을 확인할 수 있으므로 잘 배포가 되었다는 걸 체크해 볼 수 있다.

컨트랙트 verify 하기

지금까지는 제공된 프로젝트를 수정하지 않고 작업했다. 하지만 컨트랙트 verify 작업은 퍼블릭 체인에 배포해야 이더스캔에서 체크할 수 있다. 그렇기 때문에 컨트랙트를 테스트넷에 배포하기 위해 앞에서 이야기한 alchemy 에서 api 를 발급 받고 facet 을 받아두자. 또한 이더스캔에 verify 하는 것이므로 이더스캔 키도 필요하다. 참고로 지갑의 경우 당연히 있다고 가정하고 진행한다.

 

사전 작업을 모두 완료했다면 hardhat.config.ts 설정파일을 수정해야 한다. 네트워크 파트와 이더스캔 파트를 수정해 주자. 여기서 .env 파일에는 각각의 환경 변수값을 지정해 주어야 한다.

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

// dot env 추가
import * as dotenv from "dotenv";
dotenv.config();

// 환경변수 설정
const SEPOLIA_PROVIDER_URL = process.env.SEPOLIA_PROVIDER_URL; // `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY API KEY}`,
const SEPOLIA_PRIVATE_KEY = process.env.SEPOLIA_PRIVATE_KEY;
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY;

const config: HardhatUserConfig = {
  solidity: "0.8.18",

  // 네트워크 환경설정
  networks: {
    sepolia: {
      url: SEPOLIA_PROVIDER_URL || '',
      accounts: SEPOLIA_PRIVATE_KEY ? [SEPOLIA_PRIVATE_KEY] : [],
    },
  },

  // 이더스캔 설정
  etherscan: {
    apiKey: ETHERSCAN_API_KEY,
  }
};

export default config;

설정을 변경했다면 이제 테스트넷에 다시 배포해보자. 배포시에 앞에서 설정한 네트워크 이름을 주면 된다. 여기서는 sepolia 가 키 이므로  이를 입력한다.

$ npx hardhat run --network <network> scripts/deploy.ts

배포가 잘 되었는지 이더스캔(sepolia scan) 에서 주소로 확인해보자.

배포는 잘 된 것 같다. 하지만 이더스캔에서 아직 Verify 되지 않았다고 나오므로 이를 verify 하는 명령어를 실행시켜 보자. 아래의 값 중에 network 는 sepolia 이며, address 는 방금 배포한 contract address 를 입력한다. 마지막으로 생성자를 입력해줘야 하는데 샘플 프로젝트에는 unlocktime 을 입력해야 한다. 배포시에 콘솔에서 unlock time 을 출력하게 해놨으므로 이를 활용해 명령어를 실행한다. (현 포스팅에서는 1685799542 가 사용되었다.)

$ npx hardhat verify --network <network> <contract address> <constructor parameters>

성공했다면 다시 이더스캔에 접속해보자.

이더스캔에서 이전과는 다르게 이제는 smart contract 가 verified 되었다고 표시한 것을 확인 수 있다. 

마무리

dApp 개발을 remix 만으로는 활용하기 어렵기 때문에 truffle 이나 hardhat 과 같은 IDE 를 활용한다. 필자가 처음 smart contract를 개발할만 해도 Truffle 밖에 이용하지 못했었다. 하지만 Hardhat 과 같이 더 편리한 툴도 나오는 등 이 분야도 점점 발전하는 것 같다는 생각이 든다. 작년부터는 대부분 Hardhat 을 사용하고 있지만 회사에 따라 Truffle 을 사용할지 Hardhat 을 사용할지는 모르므로 둘 다 알고 있는 것이 편할 것 같다.

참고

https://hardhat.org/hardhat-runner/docs/getting-started

https://www.alchemy.com/homepage