在開發區塊鏈 DApp 時,常常需要對智能合約做測試,但大班哥之前都是把合約上鏈到以太鏈測試網 Rinkeby / Reopen ,然後直接測試,雖然不會真的花到以太幣,但還是希望能在 local 端就可以直接測試跟智能合約的互動,而 Hardhat 就可以解決這個問題,它可以快速搭建一個以太坊開發的 local 環境,以下是大班哥使用的過程跟心得。
DApp 名詞解釋: DApp 全名是去中心化應用程式 (Decentralized Application),相對於過往運行在中心化服務器的App/Web, DApp 的程式部署在分散式的網絡上,例如以太坊上。

透過製作打賞 DApp 來學習 Hardhat
大班哥想透過實際開發一款 DApp 來學習使用 Hardhat ,
於是便想到「打賞」這個結合虛擬貨幣支付跟部落格受益相關的主題,
這個 DApp 的使用情境是:
讀者在逛部落格時,認為內容有所幫助,
可以透過打賞 APP的介面使用以太幣打賞來支持我持續創作
這邊的打賞就是支付 0.01 ETH 比太幣,
預計是要做成一個小部件 widget 可以放在網站的側邊,
最終完成流程顯示如下:

DEMO 連結 – 大班哥打賞箱 https://donate-me.vercel.app/ ,歡迎大家前往打賞贊助 🤩
可能獲得的打賞福利:
大班哥也有在想,收到打賞後,除了單純支持,能不能有更多的價值回饋使用者,
先來市場調查,問看看大家:
只是先調查唷,不一定會做,大家不要太有得失心,還是希望大家用有能力範圍內的錢來打賞,單純支持我繼續創作下去。
以下開始正式介紹 Hardhat,
Hardhat 的用處
看完 Demo 大家應該很好奇, Hardhat 在開發之中是到底是扮演什麼角色吧,
最主要是解決,在開發以太坊時能夠快速搭建一個開發環境,也能讓開發人員方便測試智能約,大班哥列出主要以下功能:
- 建立 Solidity 智能合約的基礎環境
- 使用 Hardhat 的測試網 Debug 智能合約
- 可以編譯 (Compile) 跟 部署 (Deploy) 智能合約到 Hardhat 測試網 / 以太主網 / 以太測試網
- 搭配用 Ethers.js 跟 Waffle 實現自動化/單元測試
安裝 Hardhat
在安裝 hardhat 前要先用 homebrew 安裝 NodeJS
brew install node
▼ 安裝 hardhat 套件
npm init --yes
npm install --save-dev hardhat
安裝後,因為 nodeJS 預設內建 npx 命令,所以可以直接使用 npx 啟動
(npx 跟 npm 的差別只在 npx 安裝是只在當下專案,不會全局安裝)
▼ 初始化 hardhat 開發環境,以下指令
npx hardhat

大班哥是選擇 Create a basic sample project ,開始基本的開發
Hardhat 的運行
hardhat 是圍繞著 任務 (Task) 跟 外掛 (Plugins) 來運行的,
▼ 可以透過以下指令來查看可用的 Task
npx hardhat help


撰寫並編譯智能合約
要完成打賞這個動作,合約的內容就很重要,其實就是「轉帳」,只要能讓使用者同意,願意轉帳錢包中的 0.01 顆以太幣,就可以完成這個網站的核心功能,
▼ 下方為大班哥打賞功能的合約 Solidity 程式碼
//SPDX-License-Identifier: MIT License pragma solidity ^0.8.0; contract DonateBigBen { address payable public owner; event BigBenEvent( address indexed from, uint256 timestamp ); constructor() payable { owner = payable(msg.sender); } function donateMe(uint256 pay) public payable { uint256 lowerBound = 0.0009 ether; require(pay > lowerBound, "Insufficient donate amount"); (bool success, ) = owner.call{value: pay}(""); require(success, "Donate failed"); emit BigBenEvent(msg.sender, block.timestamp); } }
安裝 Waffle ,測試智能合約
Waffle 是專門用在智能合約上的一個測試套件,搭配 Mocha + Chai 專門跑 BDD 單元測試的套件,
讓測試智能合約時能更方便,撰寫測試也能讓可讀性更高,測試更容易,
▼ 配合 hardhat 使用時,可用以下指令安裝 Waffle 跟 Chai
install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai
▼ 開始撰寫測試,這邊測試大班哥的合約裡,call DonateBigBen() 的結果,
如果成功,就會發射(emit) BigBenEvent 出來
const { expect } = require("chai"); const { ethers } = require("hardhat"); describe("DonateBigBen contract", function () { it("it should emit success event after donate complete", async function () { const Token = await ethers.getContractFactory("DonateBigBen"); const hardhatToken = await Token.deploy(); let amount = ethers.utils.parseEther("0.001"); await expect(hardhatToken.donateMe(amount,{ value:amount, gasLimit: 100000, })) .to.emit(hardhatToken, "BigBenEvent") }); });
▼開始跑測試
npx hardhat test
▼ 顯示 1 passing ,表示上面撰寫的測試通過囉

把合約部署到區塊鏈上
在智能合約撰寫完後,就可以開始部署到區塊了,
以部署到 Hardhat 測試網為例,
▼ 需要先去 hardhat.config.js 設定 networks
module.exports = { solidity: "0.8.4", networks: { hardhat: { chainId: 31337 } } };
▼ 利用 Deploy.js 來把合約部署
async function main() { // This is just a convenience check if (network.name === "hardhat") { console.warn( "You are trying to deploy a contract to the Hardhat Network, which" + "gets automatically created and destroyed every time. Use the Hardhat" + " option '--network localhost'" ); } // ethers is available in the global scope const Token = await ethers.getContractFactory("DonateBigBen"); const token = await Token.deploy(); await token.deployed(); }
▼ 開始跑 script 就可以部署了
npx hardhat run scripts/deploy.js --network localhost
▼如果想要部署到以太鏈測試網 Rinkeby,可以利用 infura 這樣的服務,
到 hardhat.config.js 裡的 networks 加上 rinkeby 的設定
把 infura 申請好的API Key 填入 url ,
加上測試 Wallet 的 private key,大班哥是另外再申請一個 Metamsk 錢包並導出私鑰專門測試用
const RINKEBY_PRIVATE_KEY = "Private Key"; networks: { rinkeby: { url: "API Key", accounts: [`${RINKEBY_PRIVATE_KEY}`] } }
使用 React + Ethers.js 製作 DApp
大班哥是用 React 這個前端框架來打造 DApp,
▼ 可以安裝/初始化專案
npx create-react-app my-app
▼ 跟以太鏈溝通是用到 Ethers.js 套件
<meta charset="utf-8">install --save-dev @nomiclabs/hardhat-ethers ethers
▼React 加入後,跟 Hardhat 的整合,大班哥用一個測試小專案,目錄架構最後長這樣,
- /fe: 表示 front-end,即 React 專案
- /contracts:智能合約 Solidity 檔案,可能是 xxxxx.sol
- /scripts:hardhat 要跑的客製化 script,例如 deploy.js
- /test:hardhat 跑單元測試
- package.config.js:設定 hardhat 環境參數,例如要跑什麼鏈

使用 Metamask 通過 Hardhat Network 來測試 DApp
▼ 以下指令,會運行一個 WebSocket server 開啟 Hardhat Network ,
讓外部可以透過 JSON-RPC 來使用,例如 Metamask 或是其他 script
npx hardhat node
可以看到會有好幾組可以使用的測試錢包

如果要讓 Metamask 可以用,要先去設定
Step 1.顯示測試網:到 Metamsk -> 「設定」-> 「進階」-> 「Show tests networks」
Step 2.網路點選: 選擇 Localhost:8545,並確認 port 是 31337 跟 hardhat.config.js 設定要一樣
跑 npx hardhat node 時記得加上 --network localhost
.
小結
在這次製作網站 DApp 的過程中,Hardhat 真的是比想像中的方便使用,特別是在智能合約的測試,而且還能寫單元測試來跑,在開發中需要快速驗證合約內容時,算是有幫助到,蠻推薦有在開發以太坊智能合約跟 DApp 的開發者使用,在部署合約前可以更有信心,以上分享。