【Ethereum】HardhatでDAppsのTDD(テスト駆動)開発の環境構築をする
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はお好きなもので
フロー
- Docker環境の構築
- hardhatの導入
- 一部PKGのインストール
- 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
- 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
- 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のセットアップ
- npx hardhat init
npx hardhat init
- Create a basic sample Projectを選択します。
- 各項目はそのまま[エンターキー]で進めます
こんな感じでディレクトリが作成されます。
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ファイル
- tsconfig.jsonファイルを作成する
touch tsconfig.json
- 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ファイル
- hardhat.config.jsファイルの拡張子を.tsへ変更する
mv hardhat.config.js hardhat.config.ts
- 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ファイル
- test/sample-test.jsファイルの拡張子を.tsへ変更する
mv test/sample-test.js test/sample-test.ts
- 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ファイル
- scripts/sample-script.jsファイルの拡張子を.tsへ変更する
mv scripts/sample-script.js scripts/sample-script.ts
- 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の動作チェック
- hardhat testを実行する
yarn test
作成されていたGreeterコントラクトが正常にpassingされればOK!
- 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