【保存版】Hardhatによるコントラクトのデプロイ方法について
こんにちは、CryptoGamesの高橋です。
クリスペの会社です。
また、CryptoMaidsのアンバサダーを務めさせていただいております。
始める前に
・秘密鍵を扱うことになります。慣れないうちは、テストアカウントで実施するようにお願いします。秘密鍵の扱いは厳重にお願いします。
・全く同じように実行してもエラーが出ることは多々あります。個々のPCの設定が関係していることが少なくありません。その場合、私では解決ができませんので、ググるなどして、ご自身で解決に向かうようお願いします。
0 事前準備
Hardhatを扱うためにはNode.jsのインストールが必要です。
MacとWindowsではやり方が異なりますので、ご自身のPCに応じて、インストールを行ってください。
1 Hardhatのインストール
次のようにしてHardhatのインストールを行いましょう。
mkdir hardhat-tutorial
cd hardhat-tutorial
npm init --yes
npm install --save-dev hardhat
下のようにやってなります。
「npm init --yes」を行うことで、「package.json」というファイルができました。
「npm install --save-dev hardhat」を行うことで依存関係(関係してくるファイルなど)をインストールできました。
2 設定ファイル「hardhat.config.js」を作ろう
Hardhatの肝である、「hardhat.config.js」を作りましょう。
次のコマンドを実行しましょう。
npx hardhat
初回実行時は、次のようになると思います。
「Create an empty hardhat.config.js」を実行して行きましょう。
<ここからは上の画面がでない場合>
ちなみに、すでに作ったことがある方は、下のような状態になると思います。
今回の目的は、あくまでも「hardhat.config.js」ができれば良いので、下のようにファイルを作って行きましょう。
require("@nomiclabs/hardhat-waffle");
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.7.3",
};
↑こちらをコピペ
3 便利なプラグインをインストールしよう
とても使い勝手の良いプラグインである
①Ethers.js
②Waffle
をインストールしましょう。
npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
これでインストールができました。
4 コントラクトのファイルを作成しよう
まずは、空のsolidityファイルを作ってみましょう。
下のように「contracts」フォルダと、その中に「Token.sol」というファイルを作ってください。
空のファイルができましたら、公式のサンプルコードを貼り付けましょう。
ざっくりみたところ、「MHT」というトークンを作っていそうですね。
こちらです。
// Solidity files have to start with this pragma.
// It will be used by the Solidity compiler to validate its version.
pragma solidity ^0.7.0;
// This is the main building block for smart contracts.
contract Token {
// Some string type variables to identify the token.
// The `public` modifier makes a variable readable from outside the contract.
string public name = "My Hardhat Token";
string public symbol = "MHT";
// The fixed amount of tokens stored in an unsigned integer type variable.
uint256 public totalSupply = 1000000;
// An address type variable is used to store ethereum accounts.
address public owner;
// A mapping is a key/value map. Here we store each account balance.
mapping(address => uint256) balances;
/**
* Contract initialization.
*
* The `constructor` is executed only once when the contract is created.
*/
constructor() {
// The totalSupply is assigned to transaction sender, which is the account
// that is deploying the contract.
balances[msg.sender] = totalSupply;
owner = msg.sender;
}
/**
* A function to transfer tokens.
*
* The `external` modifier makes a function *only* callable from outside
* the contract.
*/
function transfer(address to, uint256 amount) external {
// Check if the transaction sender has enough tokens.
// If `require`'s first argument evaluates to `false` then the
// transaction will revert.
require(balances[msg.sender] >= amount, "Not enough tokens");
// Transfer the amount.
balances[msg.sender] -= amount;
balances[to] += amount;
}
/**
* Read only function to retrieve the token balance of a given account.
*
* The `view` modifier indicates that it doesn't modify the contract's
* state, which allows us to call it without executing a transaction.
*/
function balanceOf(address account) external view returns (uint256) {
return balances[account];
}
}
5 コンパイルしてみよう
では、コントラクトのコードができたので、コンパイルをしてみましょう。
こちらのコードです。
npx hardhat compile
このようになれば、成功です。
6 テストコードを作成しよう
では、コンパイルができたので、次はテストをしてみましょう。
まずは、下のように空のテストファイルを用意します。
では、公式のサンプルコードをコピペしましょう。
大まかには、発行した総トークン量と、発行者が持っている総トークン量が一致しているかを確認するテストです。
↓こちらのコードです。
const { expect } = require("chai");
describe("Token contract", function () {
it("Deployment should assign the total supply of tokens to the owner", async function () {
const [owner] = await ethers.getSigners();
const Token = await ethers.getContractFactory("Token");
const hardhatToken = await Token.deploy();
const ownerBalance = await hardhatToken.balanceOf(owner.address);
expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
});
});
7 テストを実行しよう
では、テストコードができたので、実際にテストをしてみましょう。
↓こちらのコードを実行しましょう。
npx hardhat test
このようになれば、テスト成功です。
8 コントラクトの実行準備
8ー1 .envのインストール
秘密鍵などのコードへのべたうちは避けたいので、ここでは「dotenv」を使って行きます。
次のようにインストールしましょう。
npm install dotenv --save
8ー2 .gitignoreファイルを設定する(大事!)
重要
前提として、私は、自分で自信を持って操作できるようになるまでは秘密鍵を扱ったコードはGitに上げない方が良いと思っています。
誤って上げてしまった場合、秘密鍵が漏れてしまいます。
私は、上記のように考えておりますが、もし上げた場合に備えて、「.env」ファイルをgitにコミットされないようにします。
上のように「hardhat-tutorial」直下に空の「.gitignore」を作成し、中に「.env」と入力します。
これで、後に作る「.env」というファイルはgitの管理から外れます。
9 コントラクトの実行ファイルを作る
さて、準備ができましたので、デプロイ用の実行ファイルを作って行きます。
Remixの場合は「deploy」ボタンを押すだけだったので、面倒だと感じるかもしれません。
しかし、実はファイルで実行することにより、複雑な操作を行うことができるようになるため、後々便利さを実感できると思います。
まずは、上のように「scripts」フォルダとその中に「deploy.js」を作ってみましょう。
できましたら、公式のサンプルコードを貼り付けましょう。
↓こちらです。
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);
});
10 テストとして、実行しましょう
デプロイ時には、「どのネットワークに」と指定しますが、まずは仮でテストとして実行してみましょう。
npx hardhat run scripts/deploy.js
今回はコントラクトの中身には触れませんが、何やらトークンの発行に成功していそうですね。
11 インフラキーを取得する
これから、Rinkebyネットワークとやり取りをするためのゲートウェイを取得します。
今回はこちらの「Infura」を利用しようと思います。
まずは登録を行ってください。(無料でできます。)
できましたら、下の手順に沿って「Project ID」を取得してください。
「Create New Project」を選択
Productは「Ethereum」、名前は任意のもので「Create」
すると、下のようにできました。
こちらの「Project ID」を次のパートで使います。
12 Rinkebyテストネットで実行しましょう。
12ー1 .envファイルを設定しよう
注意
ここから秘密鍵を扱うことになります。
自分で流れをしっかりと理解し、責任を持って実行ができるまでは、必ずテストアカウントで実行をしてください。
また秘密鍵の扱いには十分ご注意ください。
まずは、「hardhat-tutorial」の直下に「.env」ファイルを作成してください。
ファイルの中に前章で取得したInfuraのProject IDと秘密鍵を入れます。
繰り返しになりますが、秘密鍵はテストアカウントのものを使い、扱いには十分気をつけてください。
INFURA_KEY=""
PRIVATE_KEY=""
12ー2 hardhat.config.jsを追記しよう
Hardhatの設定ファイルである、「hardhat.config.js」を下のように書き換えましょう。
これで、dotenvとRinkebyネットワークが使えるようになりました。
require("@nomiclabs/hardhat-waffle");
require("dotenv").config();
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.7.3",
networks: {
rinkeby: {
url: "https://rinkeby.infura.io/v3/" + process.env.INFURA_KEY,
accounts: [`${process.env.PRIVATE_KEY}`],
},
},
};
13 Rinkebyで実行しよう
では、準備ができましたので、実行しましょう。
npx hardhat run scripts/deploy.js --network rinkeby
こちらのコードで、Rinkebyネットワークでの実施を指定しています。
このように、うまく実施ができました!
なお、RinkebyのETHがないと失敗しますのでご注意ください。
こちら、参考です。
14 メタマスクで見てみよう
では、実際にできたかをメタマスクで見てみましょう。
今回はトークンを作るコントラクトでした。
下に、先ほどできたコントラクトアドレスなどを入れます。
「Import Tokens」を選択すると。。
できました!
これで、無事にHardhatを使って、実際のデプロイを行うことができました!
今回は以上です。