Freeman

後端工程師,想不開走在創業之路上。好旅行、咖啡、威士忌,嗜吃不嗜睡,愛寫程式不愛解Bug。

用Hardhat開發智能合約

Hardhat是一個方便在以太坊上開發應用的工具,它能幫助管理、測試、部署合約及dApp,且內置開發用的以太坊網路,讓開發過程輕鬆不少。

學習的重點:

  • 使用Hardhat開發、測試合約
  • 基於ERC20標準發行Token
  • 部署合約到測試鏈

建立Hardhat專案

我們將使用npm安裝Hardhat,npm是Node.js預設的套件管理工具

創建專案資料夾並安裝Hardhat

// 創建project folder
mkdir hardhat-tutorial
cd hardhat-tutorial

//套件初始化將產生package.json
npm init --yes 
npm install --save-dev hardhat

創建Hardhat專案,創建時請選擇Create a basic sample project

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.9.9 👷‍

? What do you want to do? …
❯ Create a basic sample project
  Create an advanced sample project
  Create an advanced sample project that uses TypeScript
  Create an empty hardhat.config.js
  Quit

接這會跳出三個選項,都按enter就可以了
最後一項是安裝兩個必要套件Ethers.js 及 Waffle
Ethers.js是與以太坊區塊鏈交互的SDK,Waffle是測試合約的輕量化工具

✔ What do you want to do? · Create a basic sample project
✔ Hardhat project root: · /hardhat-tutorial
✔ Do you want to add a .gitignore? (Y/n) · y
✔ Do you want to install this sample project's dependencies with npm (@nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers)? (Y/n) · y

Hardhat專案結構

contracts 智能合約的程式碼放在這,包括抽象合約
scripts
 部署合約的script
test
 自動化測試案例
hardhat.config.js
 Hardhat框架的配置

到這邊,一個Hardhat專案就建置完成了,我們開始開發智能合約吧

開發智能合約

智能合約中常見的標準有ERC20、ERC721、ERC1155,這邊用ERC20標準來發行Token

OpenZeppelin

OpenZeppelin具備各種標準的合約庫且經過安全審計,可以基於合約庫再擴充其他功能,是個安全又方便的開發工具

安裝OpenZeppelin到專案中

npm install --save-dev @openzeppelin/contracts 

建立ERC20合約

可以使用OpenZeppelin Wizard找到ERC20的合約範本
到資料夾contracts內,新增檔案MyToken.sol,將程式碼貼上

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";


contract MyToken is ERC20, ERC20Burnable, Ownable {
    constructor() ERC20("MyToken", "MTK") {
        _mint(msg.sender, 10000000 * 10**decimals());
    }


    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

如需參考OpenZeppelin原始碼可以點這裡

測試合約

增加測試案例,在資料夾test中新增MyToken-test.js,貼上程式碼

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyToken.sol", () => {
    let contractFactory;
    let contract;
    let owner;
    let initialSupply;
    beforeEach(async () => {
        [owner] = await ethers.getSigners();
        contractFactory = await ethers.getContractFactory("MyToken");
        contract = await contractFactory.deploy();
        initialSupply = ethers.utils.parseEther("10000000");
    });
    it("Should have correct supply", async () => {
        expect(await contract.totalSupply()).to.equal(initialSupply);
    });
    it("Owner should have all the supply", async () => {
        const ownerBalance = await contract.balanceOf(owner.address);
        expect(await contract.totalSupply()).to.equal(ownerBalance);
    });
});

接著運行指令npx hardhat test test/MyToken-test.js來執行合約測試,成功後會看到下方資訊

  MyToken.sol
    ✔ Should have correct supply
    ✔ Owner should have all the supply

  2 passing (658ms)

沒有意外的話,合約就通過測試囉!準備部署合約吧!

部署合約

我們要將完成的合約部署到測試鏈上,測試鏈有許多選擇,而這邊選用Rinkeby
部署合約之前,我們需要先準備一些測試鏈用的ETH,以及申請一個測試節點

測試用的ETH可以使用ChainLink領取,只需要連結錢包就可以了,記得在狐狸錢包內選到Rinkeby網路
節點服務可以使用Alchemy,註冊後建立app時選擇Rinkeby網路,就可以拿到api url了
另外要再取得錢包的private key,在Metamask錢包內Account旁邊的選項內找到帳戶詳情,就可以導出private key了

在部署前,我們先用dotenv來保護敏感設定的安全,下方指令安裝dotenv

npm install dotenv

在專案的根目錄下新增檔案.env,檔案內容為

PRIVATE_KEY = YOUR_PRIVATE_KEY
RINKEBY_URL = https://.....

接著將hardhat.config.js更改為

require("@nomiclabs/hardhat-waffle");
require("dotenv").config();
const { RINKEBY_URL, PRIVATE_KEY } = process.env;
module.exports = {
  solidity: "0.8.4",
  networks: {
    rinkeby: {
      url: RINKEBY_URL,
      accounts: [`0x${PRIVATE_KEY}`]
    }
  }
};

部署script

在scripts內新增MyToken-deploy.js,並貼上程式碼

async function main() {
    const [deployer] = await ethers.getSigners();
    const contractName = "MyToken";
    const contractFactory = await ethers.getContractFactory(contractName);
    const contract = await contractFactory.deploy();
    console.log("Contract address:", contract.address);
}
main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });

接著就可以執行了

npx hardhat run scripts/MyToken-deploy.js --network rinkeby  
Contract address: 0x........................   

合約部署完成!可以到Rinkeby Etherscan上查找剛剛部署的合約!
到錢包裡面,Import Token裡貼上合約地址,就可以看到我們發行的Token囉!

參考資料:
The Complete Hands-On Hardhat Tutorial

Hardhat官方Tutorial

Like my work??
Don't forget to support or like, so I know you are with me..

CC BY-NC-ND 2.0

Want to read more ?

Login with one click and join the most diverse creator community.