Hardhatとは
Ethereumソフトウェアをコンパイル、デプロイ、テスト、およびデバッグするための開発環境
公式:https://hardhat.org/
チュートリアル:https://hardhat.org/tutorial/
特徴
- ローカルでSolidityのテストやデバッグが可能
- ローカルイーサリアムネットワーク(Hardhat Network)にコントラクトを簡単にデプロイでき、トランザクションの失敗や、Solidityのエラー、console.log、および明示的なエラーメッセージを表示・確認できる
- プラグインで機能を拡張できる(公式やコミュニティーのもの以外に自作も可能)
- TypeScriptをサポートしている(このチュートリアルでは使用しません)
プロジェクトの設定
※nodeのバージョンは>=12.0
をインストールしておく
1. プロジェクトのディレクトリーを作成し、package.jsonを生成とhardhat
のインストール
$ mkdir hardhat-tutorial
$ cd hardhat-tutorial
$ npm init -y
$ npm install --save-dev hardhat
2. プロジェクトルートでnpx hardhat
を実行し、hardhat.config.js
を生成する。
$ npx hardhat
888 888 888 888 888
888 888 888 888 888
888 888 888 888 888
8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888
888 888 "88b 888P" d88" 888 888 "88b "88b 888
888 888 .d888888 888 888 888 888 888 .d888888 888
888 888 888 888 888 Y88b 888 888 888 888 888 Y88b.
888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888
Welcome to Hardhat v2.0.0
? What do you want to do? …
Create a sample project
❯ Create an empty hardhat.config.js
Quit
3. プラグインをインストールする。
各プラグインについては、ここを参照してください
npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
hardhat-waffle
を読み込む
require("@nomiclabs/hardhat-waffle");
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.7.3",
};
スマートコントラクトの作成とコンパイル
スマートコントラクトやSolidityについては以下を参照してください
※Solidityの2022/02/11時点での最新版は0.8.11
だが、このチュートリアルでは0.7.3
を使用
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.0;
contract Token {
// トークン名と識別子
string public name = "My Hardhat Token";
string public symbol = "MHT";
// トークンの量
uint256 public totalSupply = 1000000;
// コントラクトのオーナーのアドレス
address public owner;
// 各アカウント残高を保存しておく領域
mapping(address => uint256) balances;
// `constructor`はコントラクトの作成時に1回だけ実行されます。
constructor() {
// ここでの`msg.sender`はこのコントラクトをデプロイしたアドレス
balances[msg.sender] = totalSupply;
owner = msg.sender;
}
// 金額を転送する関数
function transfer(address to, uint256 amount) external {
require(balances[msg.sender] >= amount, "Not enough tokens");
balances[msg.sender] -= amount;
balances[to] += amount;
}
// アカウントのトークン残高を取得するための読み取り専用関数
function balanceOf(address account) external view returns (uint256) {
return balances[account];
}
}
コントラクトをコンパイルする
$ npx hardhat compile
コントラクトのテスト
テストフレームワークはMocha
、アサーションライブラリはChai
を使用
完全なテストコードは以下を参照
const { ethers } = require("hardhat");
const { expect } = require("chai");
describe("Token contract", function () {
let Token;
let hardhatToken;
let owner;
let addr1;
let addr2;
let addrs;
beforeEach(async function () {
Token = await ethers.getContractFactory("Token");
[owner, addr1, addr2, ...addrs] = await ethers.getSigners();
hardhatToken = await Token.deploy();
});
describe("Deployment", function () {
it("Should set the right owner", async function () {
expect(await hardhatToken.owner()).to.equal(owner.address);
});
it("Should assign the total supply of tokens to the owner", async function () {
const ownerBalance = await hardhatToken.balanceOf(owner.address);
expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
});
});
describe("Transactions", function () {
it("Should transfer tokens between accounts", async function () {
await hardhatToken.transfer(addr1.address, 50);
const addr1Balance = await hardhatToken.balanceOf(addr1.address);
expect(addr1Balance).to.equal(50);
await hardhatToken.connect(addr1).transfer(addr2.address, 50);
const addr2Balance = await hardhatToken.balanceOf(addr2.address);
expect(addr2Balance).to.equal(50);
});
// ...
});
});
テストの実行
$ npx hardhat test
Hardhat Networkでのデバッグ
hardhat/console.sol
をインポートすることでconsole.log
を使用できる
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.7.0;
import "hardhat/console.sol"; // 追加
contract Token {
//...
function transfer(address to, uint256 amount) external {
console.log("Sender balance is %s tokens", balances[msg.sender]);
console.log("Trying to send %s tokens to %s", amount, to);
//...
}
//...
}
テストを実行すると、ログ出力が表示されます。
$ npx hardhat test
Token contract
Deployment
✓ Should set the right owner
✓ Should assign the total supply of tokens to the owner
Transactions
Sender balance is 1000 tokens
Trying to send 50 tokens to 0xead9c93b79ae7c1591b1fb5323bd777e86e150d4
Sender balance is 50 tokens
Trying to send 50 tokens to 0xe5904695748fe4a84b40b3fc79de2277660bd1d3
# ...
ローカルネットワークでテストする場合
$ npx hardhat node
$ npx hardhat test --network localhost
ライブネットワークへのデプロイ
テストネットへのデプロイの前に、ライブネットワークにデプロイしてみる
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
console.log("Account balance:", (await deployer.getBalance()).toString());
const Token = await ethers.getContractFactory("Token");
const token = await Token.deploy();
console.log("Token address:", token.address);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
デプロイコードが機能することをテストする
$ npx hardhat run scripts/deploy.js
Deploying contracts with the account: 0xf39...
Account balance: 10000000000000000000000
Token address: 0x5FbD....
リモートネットワークへのデプロイ
Alchemyを使用して、イーサリアムのテストネットRopsten
へデプロイします。
テストネットには Ropsten, Kovan, Rinkeby, Goerliなどがある。
Alchemy(アルケミー)は、開発者がブロックチェーンアプリケーションを簡単かつ効率的に開発するための必要なツールを提供しているサービス
デプロイを行う際はガス代が必要なので、MetamaskにETH(ropsten-ETH)が必要です。
テストネット用のETHを配布するサービスであるfaucet
からETHを無料で入手できます。
テストネットワークやテストネットワーク用ETHについては以下を参考
※自分の環境だとMetamask Ether FaucetにMetamaskを接続してもエラーとなりETHが受け取れなかったため、Ropsten Ethereum FaucetでETHを受け取りました。(受け取りに1日ぐらいかかりました。。。)
require("@nomiclabs/hardhat-waffle");
// alchemyのAPIキー
const ALCHEMY_API_KEY = "KEY";
// Repstenネットワークを設定しているMetamaskアカウントの秘密鍵
const ROPSTEN_PRIVATE_KEY = "YOUR ROPSTEN PRIVATE KEY";
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.7.3",
// 以下を追加
networks: {
ropsten: {
url: `https://eth-ropsten.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
accounts: [`${ROPSTEN_PRIVATE_KEY}`]
}
}
};
デプロイが成功するとコントラクトのアドレスが表示されます。
$ npx hardhat run scripts/deploy.js --network ropsten
Deploying contracts with the account: 0x2af....
Account balance: 1289165500634905903
Token address: 0x2b....
最後に
最初は全然ropsten-ETHが取得できなくて心が折れそうになりました><
デプロイはあっさりできたので、今度はDefiやNFTとか作ってデプロイしようと思います!
(多分Alchemyがすごいだけ。。。)
今回のチュートリアルのコード
https://github.com/koffe0522/hardhat-tutorial
リンク
公式
引用・参考