さて、LEARNの第1回「ETH-dApp」 のSection 1。
何が待ち受けているのか楽しみ。
Lesson 1. 環境構築
- スマートコントラクト作成
- スマートコントラクトをブロックチェーン上にデプロイ
- Webアプリケーション(dApp)作成
ローカル環境でやっていこうという話だが・・・ローカルが汚れるのが嫌いなので、大好きなCloud9でやります。
まずインストールするのはHardhat。
Flexible. Extensible. Fast.
Ethereum development environment for professionals
柔軟性があって、拡張性があって、高速らしい。
プロフェッショナルのためのEtheruem開発環境。
使わずには、やっていけませんよ、という感じ。
ツールとしては3つあって、
- Runner: the main component
- Network: a local ethereum network node for development
- VSCode: a VSCode extension
で、VSCodeは・・・個人的には使わなそう。
なんだけど、さらにその前にCloud9を整備します。
$ sudo yum update $ npm -v 8.19.3 $ node -v v16.19.0
あ、Amazon Managed Blockchainはあるけど、、、別で確認しよう。
npmのバージョンもnodeのバージョンもあんまり整備することはなかったので早速Hardhatをインストール。
$ npm install --save-dev hardhat added 300 packages, and audited 301 packages in 25s 61 packages are looking for funding run `npm fund` for details found 0 vulnerabilities npm notice npm notice New major version of npm available! 8.19.3 -> 9.2.0 npm notice Changelog: https://github.com/npm/cli/releases/tag/v9.2.0 npm notice Run npm install -g npm@9.2.0 to update! npm notice
整備したと思ったけど、、、npmの最新は9.2.0、nodeの方は19.4.0っぽい。。。
Hardhat Get Started
とりあえず、ここからはHardhatのGet Startedを実施。
プロジェクト作成
$ 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.12.5 ✔ What do you want to do? · Create a JavaScript project ✔ Hardhat project root: · /home/ec2-user/environment/ETH-dApp/my-wave-portal ✔ Do you want to add a .gitignore? (Y/n) · y ✔ Help us improve Hardhat with anonymous crash reports & basic usage data? (Y/n) · y ✔ Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)? (Y/n) · y npm install --save-dev @nomicfoundation/hardhat-toolbox@^2.0.0 npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm WARN deprecated har-validator@5.1.5: this library is no longer supported npm WARN deprecated request-promise-native@1.0.9: request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142 npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated debug@3.2.6: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797) npm WARN deprecated uuid@2.0.1: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. npm WARN deprecated debug@3.2.6: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797) added 403 packages, and audited 704 packages in 41s 121 packages are looking for funding run `npm fund` for details 8 vulnerabilities (5 high, 3 critical) To address all issues (including breaking changes), run: npm audit fix --force Run `npm audit` for details. Project created See the README.md file for some example tasks you can run Give Hardhat a star on Github if you're enjoying it!Please take a moment to complete the 2022 Solidity Survey: https://hardhat.org/solidity-survey-2022GitHub - NomicFoundation/hardhat: Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. Get Solidity stack traces & console.log.
Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. Get Solidity stack traces & console.log. - GitHub - NomicFoundation/hardhat: Hardhat is a development environment to compile, deploy, test, and debug your Ethereum software. Get Solidity stack traces & console.log.
コンパイル
$ npx hardhat compile Downloading compiler 0.8.17 Compiled 1 Solidity file successfully
テスト
$ npx hardhat test Lock Deployment ✔ Should set the right unlockTime (1784ms) ✔ Should set the right owner ✔ Should receive and store the funds to lock ✔ Should fail if the unlockTime is not in the future (57ms) Withdrawals Validations ✔ Should revert with the right error if called too soon (43ms) ✔ Should revert with the right error if called from another account ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it Events ✔ Should emit an event on withdrawals (42ms) Transfers ✔ Should transfer the funds to the owner (62ms) 9 passing (2s)
デプロイ
$ npx hardhat run scripts/deploy.js Lock with 1 ETH and unlock timestamp 1704785451 deployed to xxxxx
イーサリアムのテストネットワークの立ち上げ
$ npx hardhat node Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/ Accounts ======== WARNING: These accounts, and their private keys, are publicly known. Any funds sent to them on Mainnet or any other live network WILL BE LOST. Account #0: xxxxx (10000 ETH) Private Key: xxxxx Account #1: xxxxx (10000 ETH) Private Key: xxxxx Account #2: xxxxx (10000 ETH) Private Key: xxxxx Account #3: xxxxx (10000 ETH) Private Key: xxxxx Account #4: xxxxx (10000 ETH) Private Key: xxxxx Account #5: xxxxx (10000 ETH) Private Key: xxxxx Account #6: xxxxx (10000 ETH) Private Key: xxxxx Account #7: xxxxx (10000 ETH) Private Key: xxxxx Account #8: xxxxx (10000 ETH) Private Key: xxxxx Account #9: xxxxx (10000 ETH) Private Key: xxxxx Account #10: xxxxx (10000 ETH) Private Key: xxxxx Account #11: xxxxx (10000 ETH) Private Key: xxxxx Account #12: xxxxx (10000 ETH) Private Key: xxxxx Account #13: xxxxx (10000 ETH) Private Key: xxxxx Account #14: xxxxx (10000 ETH) Private Key: xxxxx Account #15: xxxxx (10000 ETH) Private Key: xxxxx Account #16: xxxxx (10000 ETH) Private Key: xxxxx Account #17: xxxxx (10000 ETH) Private Key: xxxxx Account #18: xxxxx (10000 ETH) Private Key: xxxxx Account #19: xxxxx (10000 ETH) Private Key: xxxxx WARNING: These accounts, and their private keys, are publicly known. Any funds sent to them on Mainnet or any other live network WILL BE LOST.
ここで、UNCHAINサイトに戻って、hardhat-toolbox
も必要ということなのでインストール。
これでLesson 1は完了。
Lesson 2. コントラクト作成
pragma solidity ^0.8.9;
import "hardhat/console.sol";
contract WavePortal {
constructor() {
console.log("Here is my first smart contract!");
}
}
contract
はclassのようなもの。
constructor
はいわゆるコンストラクター。
・・・あれ、これでおわり!?
Lesson 3. コントラクト実行
scripts/run.js
を記載。
const main = async () => {
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
const wavePortal = await waveContract.deployed();
console.log("WavePortal address: ", wavePortal.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
で、実行。
$ npx hardhat run scripts/run.js Compiled 2 Solidity files successfully Here is my first smart contract! WavePortal address: xxxxx
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
const wavePortal = await waveContract.deployed();
main
関数でやっていることはシンプルで、
hre.ethers
のgetContractFactory
でContractFactory生成- ContractFactoryの
deploy
でContract生成(デプロイ) - Contractの
deployed
でデプロイするのを待って、、、別のインスタンスを返している???(要確認)
hre
とはHardhat Runtime Environment(HRE)のこと。
ここもこれで終了。
Lesson 4. データ保存
保存ができてくると、アプリケーションっぽくなってくる。
import "hardhat/console.sol";
contract WavePortal {
uint256 totalWaves;
constructor() {
console.log("Here is my first smart contract!");
}
function wave() public {
totalWaves += 1;
console.log("%s has waved!", msg.sender);
}
function getTotalWaves() public view returns (uint256) {
console.log("We have %d total waves!", totalWaves);
return totalWaves;
}
}
uint256 totalWaves;
の感じで、contract
自体に変数を持たすと、ストレージに永続的に保存されるらしい。
function wave() public {
public
が最後に来るのが気になるけど、、、
Solidityは4つの修飾子
- public: 基本どこからでも呼び出しOK。→デフォルト(修飾子なし)はpublicだって。怖くないのか!?
- private: 定義されたコントラクト内。
- internal: 定義されたコントラクト内と継承されたコントラクトなので、protected的な。
- external: 外部からのみ。→これは初めての概念・・・
console.log("%s has waved!", msg.sender);
msg
はどこにも宣言されてないのに使ってOKなものらしい。
msg.sender
は当然「送信者」のことで、
function getTotalWaves() public view returns (uint256) {
viewのように関数にだけつく修飾子があるとのこと。
- view: 読み取り専用の関数。状態変数が変更されないようにする。
- pure: 状態変数の読み込みや変更をしないで、「純粋に」パラメータ、ローカル変数だけを使用して値を返す。
これによってガス代が大きく変わる模様。
状態変数を事前に取ってきたりして、余計なメモリを展開しなくていいってことなんだろう。
実行してみる
main
関数を更新する。
const main = async () => {
const [owner, randomPerson] = await hre.ethers.getSigners();
const waveContractFactory = await hre.ethers.getContractFactory("WavePortal");
const waveContract = await waveContractFactory.deploy();
const wavePortal = await waveContract.deployed();
console.log("Contract deployed to:", wavePortal.address);
console.log("Contract deployed by:", owner.address);
let waveCount;
waveCount = await waveContract.getTotalWaves();
let waveTxn = await waveContract.wave();
await waveTxn.wait();
waveCount = await waveContract.getTotalWaves();
};
まずは最初の変更。
const [owner, randomPerson] = await hre.ethers.getSigners();
hre.ethers.getSigners()
はHardhatが提供する任意のアドレスを返す関数・・・ということはテスト用?開発用???
あ、やはりシミュレーション用とのこと。
const [owner, randomPerson, randomPerson2] = await hre.ethers.getSigners();
と複数のrandomPerson
を返すこともできる。
Lesson 5. コントラクトデプロイ(ローカル環境)
$ npx hardhat node
これでイーサリアムネットワークが立ち上がる。
※このネットワークにデプロイするので、Ctrl+Cとかで切らないように置いておく。
(別ターミナルにて)
次に、scripts/deploy.js
の編集。
const main = async () => {
const [deployer] = await hre.ethers.getSigners();
const accountBalance = await deployer.getBalance();
const waveContract = await hre.ethers.getContractFactory("WavePortal");
const wavePortal = await waveContract.deploy();
console.log("Deploying contracts with account: ", deployer.address);
console.log("Account balance: ", accountBalance.toString());
console.log("Contract deployed to: ", wavePortal.address);
console.log("Contract deployed by: ", deployer.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.error(error);
process.exit(1);
}
};
runMain();
scripts/deploy.js
では余計なことをせずデプロイだけするような記述。
なので、scripts/run.js
がテスト用、scripts/deploy.js
が本番用と思っておけば良さそう。
scripts/run.js
は名前変えた方が良さそう。
で、デプロイ。
$ npx hardhat run scripts/deploy.js --network localhost Deploying contracts with account: xxxxx Account balance: 10000000000000000000000 Contract deployed to: xxxxx Contract deployed by: xxxxx
デプロイも問題なくなくできた。
$ npx haradhat node
側のコンソールにも出力あり。
eth_accounts eth_chainId (2) eth_getBalance eth_accounts eth_blockNumber eth_chainId (2) eth_estimateGas eth_getBlockByNumber eth_feeHistory eth_sendTransaction Contract deployment: WavePortal Contract address: xxxxx Transaction: xxxxx From: xxxxx Value: 0 ETH Gas used: 345526 of 345526 Block #1: xxxxx console.log: Here is my first smart contract! eth_chainId eth_getTransactionByHash
これでSection 1も完了。
まとめ
とりあえず、簡単にCloud9でバックエンドの開発環境を整備できることがわかった。
あとは、Hardhatに尽きる。
サンプルのスマートコントラクトは、現状シンプルなので特に難しくないし。
とりあえず、Hardhatを使って、
- プロジェクト作成(
npx hardhat
) - コンパイル(
npx hardhat compile
) ※これは結局使っていない。実行と同時にコンパイルが走るのかな。 - テスト(
npx hardhat test
) ※これは結局使っていない。おそらくmochaとかのテストフレームワークを使うとか書いていた。 - 実行(
npx hardhat run scripts/***.js
) - ネットワーク立ち上げ(
npx hardhat
node)
ができるようになれば、このSection 1は完璧でしょう。