#Ⅰ. はじめに
ERC20規格の自作トークンを作成した際の手順を残した備忘録です。流れに沿えば、初めてのかたでも手軽にオリジナルトークンを作成できる内容となっています。詳細な説明等は今回省いた点も多いので、適宜他記事やブログご参考いただければと思います。なお、Truffleを利用しての関連記事は比較的多いので、この度は主にhardhatのフレームワーク利用しています。
#Ⅱ. 環境
更新日:2021/07/
OS:Windows10
開発環境:Visual Studio
#Ⅲ. 作業概要
##1. 準備編
###(1)npmインストール
###(2)プロジェクトディレクトリ作成
###(3)OpenZepplinインストール
###(4)hardhatインストール
###(5)metamask設定とsecretファイル作成
###(6)INFURAアカウント取得
###(7)secretファイル作成
###(8)開発用EHTを無料で入手
##2. ファイル作成編
###(1)contractsファイル作成
###(2)contractsファイル(.sol)コンパイル
###(3)hardhat.config.jsファイル作成
###(4)scriptsファイル作成
###(5)テスト用ファイル作成
##3. テスト&デプロイ編
###(1)Hardhatネットワークに接続
###(2)hardhat.config.jsにネットワーク情報追加
###(3)テスト
###(4)デプロイ
###(5)metamaskアセット表示
##4. 仕上編
###(1)Solidityソースコードの登録
###(2)etherscanでの所有権表明
###(3)トークン詳細登録
##参考公式サイト
#Ⅳ. 作業詳細
##1. 準備編
###(1)インストール
公式:https://nodejs.org/en/
JavaScript用のパッケージ。推奨版でおそらく良い。
C:\Users\mydir\AppData\Roaming\npm
$ node --version
v14.17.2
###(2)プロジェクトディレクトリ作成
// (例)Cドライブの下などに「h_tokens」などの名前でディレクトリを作成
$ mkdir h_tokens
// (例)あらかじめOSのコマンドラインで作成および当該ディレクトリに移動しておく
$ cd h_tokens
###(3)OpenZepplinインストール
https://openzeppelin.com/
// token/package.jsonが作成される
$ npm init -f
$ npm install openzeppelin-solidity
// OpenZeppelinのContractsライブラリ最新更新分インストール
$ npm install --save-dev @openzeppelin/contracts
以下のディレクトリやファイルができる。
token/node_modules/…
token/package-lock.json
###(4)hardhatインストール
https://hardhat.org/tutorial/creating-a-new-hardhat-project.html
$ npm install --save-dev hardhat
// ethersプラグイン&chaiインストール
$ npm install --save-dev @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
// ガスレポーターインストール
$ npm install hardhat-gas-reporter --save-dev
// etherscanインストール
$ npm install --save-dev @nomiclabs/hardhat-etherscan
// ディレクトリとファイルを自動作成
$ npx hardhat
① 矢印キー上下↑↓で「Create a sample project」選択
② インストール先に新規作成したディレクトリ指定「Hardhat project root: » C:\Users\micro\h_tokens」
→'y'入力
以下のディレクトリやファイルができる。
contracts/Greeter.sol
scripts/sample-script.js
test/sample-test.js
.gitignore
hardhat.config.js
###(5)metamaskアカウント取得
まずは検証用のmetamaskアカウントを新規作成する。
// ニーモニック(12語のセット・要保存!)発行
$ npx mnemonics
drama film snack motion …
metamaskをブラウザより起動し、「シークレット リカバリー フレーズでアカウントを復元する」より上記ニーモニックでアカウント設定。
※ニーモニックは安全かつ機密性をもって保管すること。
###(6)INFURAアカウント取得
https://infura.io/
アカウント取得後「CREATE NEW PROJECT」して詳細を開く。
###(7)secretファイル作成
① 以下の形式のsecrets.jsonファイルを作成。
{
"mnemonic": "drama film snack motion ...",
"infuraApiKey": "JPV2..."
}
"mnemonic":取得したニーモニックをペースト。
"infuraApiKey":取得したProjectIDをペースト。
② 'hardhat.config.js'と同じディレクトリに置く。
なお、secretファイル安全かつ機密性をもって保管維持すること。
また、のちの工程でもinfura画面は参照するので見られるようにしておくこと。
###(8)開発用EHTを無料で入手
以下のサイトでできる限り送付してもらう。Ropstenネットにはぜひ送ってほしい。
https://gitter.im/kovan-testnet/faucet
https://faucet.rinkeby.io/
https://blog.fukuball.com/dapp/faucet/
https://faucet.ropsten.be/
https://faucet.metamask.io/
https://goerli-faucet.slock.it/
※時間がかかったり、怪しいところもあるので自己責任で。
##2. ファイル作成編
###(1)contractsファイル作成
トークンの仕様を決めるメインファイル。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Greeter is ERC20 {
constructor() ERC20("Greeter", "MMT2") {
_mint(msg.sender, 222222222222 * 10 ** decimals());
}
}
オリジナルのコントラクトを作成する場合、openzeppelinのウィザードを利用する方法が簡単である。
https://docs.openzeppelin.com/contracts/4.x/wizard
Name : アセットの名称
Synbol : アセットのシンボル
Premint : 初期発行枚数
Mintable : 管理者の新規発行権限
Burnable : 管理者による発行済アセットの焼却権限
Pausable : 管理者によるシステム停止権限
Snapshots : 管理者による、ある一時点におけるスナップショット取得権限。
Permit : トークン所有者は、ガスを支払うことなく、第三者が自分のアカウントから転送できる。(!要調査不明点あり)
Ownable : すべての管理者が同じ権限を持つ。
Roles : 個々の管理者によって権限の範囲を個別に決めることができる。
Transparent : 調査中
UUPS : 調査中
※注意点
コントラクトの内容を充実させればさせるだけ、mainnetにデプロイする際のガス代が大幅にコスト高になる。(1ETHくらいになることZARA)
###(2)contractsファイル(.sol)コンパイル
$ npx hardhat compile
成功すると以下のように表示される。
※コントラクトファイルの内容を少しでも変更することあれば、その都度上記作業が必要。
###(3)hardhat.config.jsファイル作成
https://docs.openzeppelin.com/learn/deploying-and-interacting#deploying-a-smart-contract
require("@nomiclabs/hardhat-waffle");
require('@nomiclabs/hardhat-ethers');
require("@nomiclabs/hardhat-etherscan");
require('@openzeppelin/hardhat-upgrades');
require("hardhat-gas-reporter");
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
/**
* @type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.4",
};
###(4)scriptsファイル作成
コントラクトをネットワークにデプロイするために必要。
https://docs.openzeppelin.com/learn/deploying-and-interacting#deploying-a-smart-contract
const hre = require("hardhat");
async function main() {
const Greeter = await hre.ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy(); // 引数は入れないほうがよさそう
await greeter.deployed();
// コントラクトアドレス
console.log("Greeter deployed contracts address to:", greeter.address);
// TXアドレス
console.log("Greeter deployed hash to:", greeter.deployTransaction.hash);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
###(5)テスト用ファイル作成
https://hardhat.org/tutorial/testing-contracts.html
const { expect } = require("chai");
describe("Greeter contract", function () {
it("Deployment should assign the total supply of tokens to the owner", async function () {
const [owner] = await ethers.getSigners();
const greeter = await ethers.getContractFactory("Greeter");
const hardhatToken = await greeter.deploy();
const ownerBalance = await hardhatToken.balanceOf(owner.address);
expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
});
});
##3. テスト&デプロイ編
###(1)Hardhatネットワークに接続
// ウォレットまたはDappをHardhatネットワークに接続する
$ npx hardhat node
接続に成功すると以下形式でずらっと表示される。
Accounts
========
Account #n: 0xf39fd6e51aad88f6f………fffb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff94………
・
・
・
作業中継続して起動させておく必要あり。コマンドをもう一つ別に開き作業を続ける。(この時再度作業ディレクトリにcd…で変更)
###(2)Ropsten,Rinkeby,Mainnetネットワークに接続
注意!
本番環境であるMainnetにデプロイする前にRopsten,Rinkebyでそれぞれテストをする。(便宜上、この記事ではRopstenから説明する。)
それそれのネットワーク解説はこちら : https://docs.openzeppelin.com/learn/connecting-to-public-test-networks#testnet-list
「2. ファイル作成編-(5)hardhat.config.jsファイル作成」に以下の内容を書き足す。
https://docs.openzeppelin.com/learn/connecting-to-public-test-networks#configuring-the-network
ネットワーク接続先によってネットワーク名および、(infuraキャプチャ画面の緑のアンダーラインURL)の部分を切り替える。
+ const { infuraApiKey, mnemonic } = require('./secrets.json');
...
module.exports = {
+ networks: {
+ ropsten: {
+ url: `https://(infuraキャプチャ画面の緑のアンダーラインURL)/${infuraApiKey}`,
+ accounts: { mnemonic: mnemonic },
+ },
+ },
...
};
###(3)テスト編
ファイルを個別指定しないと、testディレクトリにあるファイルがすべて精査の対象となること注意。
$ npx hardhat test
// 個別指定する場合は $ npx hardhat test test/sample-test.js
成功すると、ガス代情報と合わせ以下のように表示される。
参考
https://hardhat.org/plugins/hardhat-gas-reporter.html
https://dapps.gamewith.jp/?p=90
###(4)デプロイ
① --networkのパラメータを検証対象のネットワーク名に上書き。(例 : Ropsten)
② デプロイ
// デプロイ
$ npx hardhat run scripts/sample-script.js --network ropsten
Greeter deployed contracts address to: 0xEA3B81eDc45726CE6A3314bd3…cA200A……
Greeter deployed hash to: 0xb5cd97870c97934d0765…3f59f4aa6649fbbb6f0…f7fa94c…64dee9………
③ トランザクションが通っているかを確認。
ropsten : https://ropsten.etherscan.io/
デプロイした時の「Greeter deployed hash to: 」右のTXアドレスを検索窓に貼り付けて検索。
成功していることを確認。
###(5)metamaskアセット表示
① 「トークンの追加」を押下。
② デプロイした時の「Greeter deployed hash to: 」右のTXアドレスを追加して「次へ」押下。
③ 最終的にアセットのリストに追加される。
他、Rinkebyについても同じテスト、動作確認、作業を実施しておく。
+ const { infuraApiKey, mnemonic } = require('./secrets.json');
...
module.exports = {
+ networks: {
+ rinkeby: {
+ url: `https://infuraキャプチャ画面の緑のアンダーラインURL/${infuraApiKey}`,
+ accounts: { mnemonic: mnemonic },
+ },
+ },
...
};
rinkeby : https://rinkeby.etherscan.io/
本番環境ネットワーク(mainnet)も同様につつがなく作業。
+ const { infuraApiKey, mnemonic } = require('./secrets.json');
...
module.exports = {
+ networks: {
+ mainnet: {
+ url: `https://infuraキャプチャ画面の緑のアンダーラインURL/${infuraApiKey}`,
+ accounts: { mnemonic: mnemonic },
+ },
+ },
...
};
mainnet : https://etherscan.io/
##4. 仕上編
###(1)Solidityソースコードの登録
コントラクトをメインネットにデプロイ後、ソースコードの確認をする。(SolidityコードをEtherscanやEtherchainなどのサードパーティに送信)
参考
https://docs.openzeppelin.com/learn/preparing-for-mainnet
https://hardhat.org/plugins/nomiclabs-hardhat-etherscan.html
① https://etherscan.io/ アカウント取得
② login後、「API-KEYs」にて新規APIキー発行。
③ 以下のようなファイルを作成。
{
"etherscanApiKey": "(APIキー)…YQFH…VVPY3…XMA4K…FWR32…"
}
'hardhat.config.js'と同じディレクトリに置く。
④ 'hardhat.config.js' に以下の記述を足す。
...
const { etherscanApiKey } = require('./etherscanapikey.json');
...
module.exports = {
networks: {
mainnet: { ... }
},
etherscan: {
apiKey: etherscanApiKey
}
};
⑤ verifyする
$ npx hardhat verify --network mainnet --contract contracts/Greeter.sol:Greeter (コントラクトアドレス付加)0x0c…88317e2d7304887…626dcc…c3c34… (引数)1
もしも引数がなければ(不要であれば)以下のような赤字エラーが表示される。
Error in plugin @nomiclabs/hardhat-etherscan: The constructor for contracts/Greeter.sol:Greeter has 0 parameters
but 1 arguments were provided instead.
その時は引数は削除する。成功すると以下のような表示となる。
Compiling 1 file with 0.8.4
Successfully submitted source code for contract
contracts/Greeter.sol:Greeter at 0x0c…88317e2d7304887…626dcc…c3c34…
for verification on Etherscan. Waiting for verification result...
Successfully verified contract Greeter on Etherscan.
https://etherscan.io/address/0x0c…88317e2d7304887…626dcc…c3c34…#code
なお、ブラウザで以下URLにアクセスすると、etherscan画面でも確認できる。
https://etherscan.io/address/0x0c…88317e2d7304887…626dcc…c3c34…#code
###(2)etherscanでの所有権表明
ログイン後、以下画面に遷移
https://etherscan.io/myverify_address
「Add」ボタンでコントラクトアドレスを入力し、画面の指示に従いながら先に進む。
参考
https://info.etherscan.com/how-to-verify-address-ownership/
###(3)トークン詳細登録
トークン詳細画面に戻り
https://etherscan.io/token/0x0c…88317e2d7304887…626dcc…c3c34…
Profile Summary の [Edit] リンクからプロフィールをなるべく詳細に登録して、etherscan 運営からのお便りを待つ。
一旦ここで今回は終了!
###参考公式サイト
https://ethereum.org/ja/developers/
https://www.trufflesuite.com/
https://openzeppelin.com/
https://vittominacori.github.io/erc20-generator/