😺

【Ethereum】HardhatでDAppsのTDD(テスト駆動)開発の環境構築をする

2021/08/25に公開

Docker + Hardhatでする、DAppsのTDD開発環境の構築ことはじめ

HardhatによるDApps開発の中で、yarnで各PKGインストール中「error Couldn't find the binary git」のエラーメッセージに遭遇しました。単純なトラブルシュートでしたが、実装に時間も取りたくないなと、Dockerを使った環境構築の記事をおこしました。

EthereumのDApps開発をTDD(テスト駆動開発)でやるための構築情報を整理をしたいことが、本記事のモチベーションです。

ERC20/721の実装、Infuraとの連携、フロントエンドの実装、などなどは今後の記事にとしてスコープ外にしています。


開発環境

Macbook OS BigSur 11系
docker
Node.js v16系 ※Versionはお好きなもので


フロー

  1. Docker環境の構築
  2. hardhatの導入
  3. 一部PKGのインストール
  4. TypeScriptsの導入

※導入は個人の責任でお願いします(お約束文)


各ステップの解説

  • ステップ1の中で、「error Couldn't find the binary git」エラーを解決しています。
  • ステップ2の中で、TDD(テスト駆動開発)のため、hardhat test,hardhat console(hardhat/console.sol)を行っています。
  • ステップ3で、DApps開発のため、openzeppelinなどPKGのインストールをしています。
  • ステップ4は、TypeScriptsの導入と、それに伴うファイル編集をしています。

STEP_1: Docker環境の構築

プロジェクトのルートディレクトリの直下に、docker-compose.yamlファイルと、docker/contracts/Dockerfileを作成して進めてください。(以下、参考です)

touch docker-compose.yaml
mkdir -p docker/hardhat_contracts
touch docker/hardhat_contracts/Dockerfile
  1. docker/hardhat_contracts/Dockerfileの編集

gitインストールしてなかっただけのエラーのため、「apk add git」をします(解決)

FROM node:16.3-alpine

RUN apk update && \
  apk add git

RUN yarn install && yarn add -D \
  hardhat

WORKDIR /hardhat_contracts
  1. docker-compose.yamlファイルを作成する

本記事ではポート番号は特に気にする必要はありません。および設定はお好みで

version: '3.8'
services:
  hardhat_contracts:
    container_name: hardhat_contracts_container
    build: ./docker/hardhat_contracts
    ports:
      - 13040:3000
    volumes: 
      - ./hardhat_contracts:/hardhat_contracts
    tty: true
    environment: 
      - TZ=Asia/Tokyo
    networks:
      - default

networks: 
  default:

※本記事ではあつかいませんが、アプリ(フロントエンド)側を構築する予定です。

docker build

docker-compose build --no-cache

※ --no-cacheは念のため

docker-compose up -d

docker-compose up -d

contractsの空ファイルができていればOKです。

docker、もしくは、docker-composeのお好きなコマンドでcontainerへ接続してください。
※下記はdockerコマンドで接続しています(参考)

docker exec -it hardhat_contracts_container sh

STEP_2: Hardhatの導入

dockerのhardhat_contracts_containerへ接続して、hardhatのセットアップをすすめます。

Hardhatのセットアップ

  1. npx hardhat init
npx hardhat init
  1. Create a basic sample Projectを選択します。

  1. 各項目はそのまま[エンターキー]で進めます

こんな感じでディレクトリが作成されます。

Hardhatの動作チェック

1.packege.jsonファイルの編集

npx hardhat testでも動作できますが、packege.jsonファイルへscriptsを追記します。

"scripts": {
	"compile": "hardhat compile",
	"test": "hardhat test",
	"console": "hardhat console"
}

2. hardhat testを実行する

yarn test

作成されていたGreeterコントラクトが正常にpassingされればOK!


3. hardhat consoleを実行する

yarn console

以下のように、コンソールのプロンプトが表示されればOKです。
参考:ctrl+D で、コンソールからぬけれます。

3-1. hardhat consoleにより、コントラクトのデプロイをテストします。

以下をコンソールへ入力します。

 const Greeter = await hre.ethers.getContractFactory("Greeter");
 const greeter = await Greeter.deploy("Hello, Hardhat!");

このようになっていればOKです。

3-2. コントラクトをdeployします

await greeter.deployed();

コントラクトのdeploy

実行後、正常にコントラクトがdeployされれば、以下のように、createsと、chainIDが出力されます。

3-3. deployしたコントラクをログにより確認する

console.log("Greeter deployed to:", greeter.address);

deployしたcreatesが表示されていますね!(OK)

コントラクトのデプロイを、コンソールによりチェックできました。

参考

実は、hardhat console上で実行したスクリプトは、scriptsディレクトリの中にある、sample-scripts.jsを1行ずつ実行しています。迷った時は、こちらのファイルを参照して確認しながらコンソールに入力でOKです。

scripts/sample-scripts.js(抜粋)

 const Greeter = await hre.ethers.getContractFactory("Greeter");
 const greeter = await Greeter.deploy("Hello, Hardhat!");

  await greeter.deployed();

  console.log("Greeter deployed to:", greeter.address);

STEP_3: 一部PKGのインストール

  • openzeppelin     ERC20/721などのライブラリ
  • @nomiclabs/ethereumjs-vm

この2つに関して、本記事ではスコープ外の内容のため、特に以降の記載はありません。

yarn add @openzeppelin/contracts
yarn add -D @nomiclabs/ethereumjs-vm

「error Couldn't find the binary git」エラーで、yarn installでPKG追加ができませんでしたが、問題なくインストールを完了できました。(めでたし)


STEP_4: TypeScriptsの導入

公式(参考)

tsconfig.jsonファイル

  1. tsconfig.jsonファイルを作成する
touch tsconfig.json
  1. tsconfig.jsonファイルを編集する
{
  "compilerOptions": {
    "target": "es2018",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  },
  "include": ["./scripts", "./test"],
  "files": ["./hardhat.config.ts"]
}

PKGインストール

hardhat init より、sample projectでインストールされた、chaiなどは除外しています。

yarn add -D ts-node typescript @types/node @types/mocha @types/chai

各ファイルの編集

hardhat.config.jsファイル

  1. hardhat.config.jsファイルの拡張子を.tsへ変更する
mv hardhat.config.js hardhat.config.ts
  1. hardhat.config.tsファイルを編集する
import { task } from 'hardhat/config'
import '@nomiclabs/hardhat-waffle';
import { HardhatArguments, HardhatRuntimeEnvironment } from 'hardhat/types'

task("accounts", "Prints the list of accounts", async (args: HardhatArguments, hre: HardhatRuntimeEnvironment):Promise<void> => {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(await account.address);
  }
});

module.exports = {
  solidity: "0.8.4",
};

test/sample-test.jsファイル

  1. test/sample-test.jsファイルの拡張子を.tsへ変更する
mv test/sample-test.js test/sample-test.ts
  1. test/sample-test.tsファイルを編集する
import { expect } from 'chai'
import { ethers } from 'hardhat'

describe("Greeter", ():void => {
  it("Should return the new greeting once it's changed", async ():Promise<void> => {
        const Greeter = await ethers.getContractFactory("Greeter");
        const greeter = await Greeter.deploy("Hello, world!");
        await greeter.deployed();
    
        expect(await greeter.greet()).to.equal("Hello, world!");
    
        const setGreetingTx = await greeter.setGreeting("Hola, mundo!");

        await setGreetingTx.wait();    
        expect(await greeter.greet()).to.equal("Hola, mundo!");
      });
})

scripts/sample-script.jsファイル

  1. scripts/sample-script.jsファイルの拡張子を.tsへ変更する
mv scripts/sample-script.js scripts/sample-script.ts
  1. scripts/sample-script.tsファイルを編集する
import { run, ethers } from 'hardhat'

async function main():Promise<void> {
  const Greeter = await ethers.getContractFactory("Greeter");
  const greeter = await Greeter.deploy("Hello, Hardhat!");

  await greeter.deployed();

  console.log("Greeter deployed to:", greeter.address);
}

main()
  .then(():void => process.exit(0))
  .catch((err):Error => {
    console.error(err);
    process.exit(1);
  })

hardhatの動作チェック

  1. hardhat testを実行する
yarn test

作成されていたGreeterコントラクトが正常にpassingされればOK!

  1. hardhat consoleを実行する
yarn console

また各コードを順番に実行していきます。

  const Greeter = await ethers.getContractFactory("Greeter");
  const greeter = await Greeter.deploy("Hello, Hardhat!");
  await greeter.deployed();
  console.log("Greeter deployed to:", greeter.address);

コントラクトがdeployされていればOKです。

お疲れさまでした。

実際にはここから、インストールをした、openzeppelin、@eth-optimism/smockを使用してアプリケーション開発(フロントエンドなど)を進めます。

ボリューム的に別の記事へ

時期は未定ですが、(たぶん)きっとそんな遠くない未来に。

Discussion