Published on
Hardhat

วิธีการสร้าง Custom Task สำหรับ Hardhat

create-custom-task-hardhat

วันนี้มาลองทำ custom tasks สำหรับ Hardhat กันดีกว่า ซึ่งปกติแล้ว คำสั่งที่ผมมักใช้บ่อยๆ สำหรับ Hardhat คือ run กับ test

npx hardhat run <SCRIPT_FILE>
npx hardhat test

ข้อดีของ Hardhat task คือ ทำให้เราสามารถเล่นกับ Command Line ได้มากขึ้น เช่น อยากส่ง argument, options ต่างๆ เพิ่มเติม นอกเหนือจาก คำสั่งของ Hardhat ปกติ เราแค่กำหนด task และกำหนด params ให้มัน ก็ทำให้เราสามารถใช้ options ได้แล้ว

Create sample Hardhat project

ทดสอบสร้างโปรเจ็ค Hardhat ขึ้นมาแบบง่ายๆ

yarn init -y
yarn add hardhat -D

จากนั้น Init Project แบบ 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.3 👷‍

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

หลังจากที่เรา Init project แล้ว จะมีไฟล์ hardhat.config.js ข้างใน มี custom task อันนึงชื่อว่า accounts

hardhat.config.js
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);
  }
});

Hardhat tasks

การดูว่า Hardhat มี tasks อะไรให้ใช้บ้าง ก็สามารถดูได้ด้วยคำสั่ง

npx hardhat

หรือ

npx hardhat --help

จะได้ผลลัพธ์แบบนี้

Hardhat version 2.9.3

Usage: hardhat [GLOBAL OPTIONS] <TASK> [TASK OPTIONS]

GLOBAL OPTIONS:

  --config           	A Hardhat config file.
  --emoji            	Use emoji in messages.
  --help             	Shows this message, or a task's help if its name is provided
  --max-memory       	The maximum amount of memory that Hardhat can use.
  --network          	The network to connect to.
  --show-stack-traces	Show stack traces.
  --tsconfig         	A TypeScript config file.
  --verbose          	Enables Hardhat verbose logging
  --version          	Shows hardhat's version.


AVAILABLE TASKS:

  accounts	Prints the list of accounts
  check   	Check whatever you need
  clean   	Clears the cache and deletes all artifacts
  compile 	Compiles the entire project, building all artifacts
  console 	Opens a hardhat console
  flatten 	Flattens and prints contracts and their dependencies
  help    	Prints this message
  node    	Starts a JSON-RPC server on top of Hardhat Network
  run     	Runs a user-defined script after compiling the project
  test    	Runs mocha tests

To get help for a specific task run: npx hardhat help [task]

ซึ่งถ้าเราสังเกตตรง AVAILABLE TASKS จะเห็น

accounts	Prints the list of accounts

เหมือนกับ task ที่กำหนดไว้ใน hardhat.config.js เลย

Create new task

ลองเพิ่ม Task ง่ายๆ แบบง่ายสุดคือ task ชื่อ ahoy เพื่อทำการแสดง Hello World ที่ไฟล์ hardhat.config.js

hardhat.config.js
task("ahoy", "Prints Hello World", async (taskArgs, hre) => {
  console.log("Hello World!");
});

เมื่อรัน npx hardhat จะเห็นว่ามี Available Task เพิ่มมาแล้ว

AVAILABLE TASKS:

  accounts	Prints the list of accounts
  ahoy    	Prints Hello World

ลองรันคำสั่งดู

npx hardhat ahoy

ได้ผลลัพธ์ :

Hello World!

Balance Task

ลองสร้าง Task สำหรับ check balance ดูบ้าง (เวลาที่ต้องการดูว่า task นั้นๆ ใช้คำสั่งอะไรมี option อะไรบ้าง ใช้ npx hardhat help <TASK>)

hardhat.config.js
task("balance", "Prints an account's balance")
  .addParam("account", "The account's address")
  .setAction(async (taskArgs) => {
    const account = taskArgs.account;
    const balance = await hre.ethers.provider.getBalance(account);
    console.log(`Account balance : ${balance}`);
  });
  • addParams() - คือกำหนด option ให้กับ task ครับ พร้อมคำอธิบาย
  • setAction() - เป็นการกำหนด action ให้กับ task โดยใช้ taskArgs ก็คือค่าที่ส่ง option จาก command line
  • hre - เป็น Hardhat runtime environment เป็น global variable ถ้าเราใช้คำสั่ง npx hardhat
  • hre.ethers เป็นตัว hardhat-ethers ที wrap ethers.js และมี helper functions เพิ่มมานิดหน่อย

ทดสอบรัน script :

npx hardhat balance --account 0x90F79bf6EB2c4f870365E785982E1f101E93b906

ตัว option เราสามารถทำเป็น optional ได้ เช่น task เดิม แต่เปลี่ยน ถ้าไม่ส่ง --account จะใช้ default

hardhat.config.js
task("balance", "Prints an account's balance")
  .addOptionalParam("account", "The account's address")
  .setAction(async (taskArgs) => {
    const account = taskArgs.account || (await hre.ethers.getSigner()).address;
    const balance = await hre.ethers.provider.getBalance(account);
    console.log(`Account balance : ${balance}`);
  });

Create tasks folder

นอกจากเราสร้าง task ใน hardhat.config.js เรายังสามารถสร้าง task ไว้ที่ไหนก็ได้ แล้วก็ import มาใช้ เช่น ตัวอย่าง สร้าง task ที่โฟลเดอร์ tasks ชื่อว่า block-number.js

tasks/block-number.js
task(
  'block-number',
  'Prints the current block number',
  async (taskArgs, hre) => {
    await hre.ethers.provider.getBlockNumber().then((blockNumber) => {
      console.log(`Block number : ${blockNumber}`);
    });
  }
);

ทีนี้ใน hardhat.config.js เราก็แค่ import ไฟล์นี้มาใช้

require('./tasks/block-number');

แค่นี้เราก็ใช้ task ที่เราสร้างขึ้นมาได้แล้ว

npx hardhat block-number

สรุป

บทความนี้ก็เป็นตัวอย่างการใช้ Hardhat task เบื้องต้นด้วย JavaScript คิดว่าหลายๆ คนน่าจะพอเห็นภาพ และนำไปประยุกต์ใช้ได้หลากหลายครับ เช่น สร้าง task เอาไว้ ลอง test transfer ลอง approve ลอง logic เล็กๆ น้อยๆ รวมถึงลองใช้เป็นแบบ TypeScript จะเข้าใจง่ายกว่า เพราะจะรู้ว่าแต่ละ options, tasks, actions รับค่าอะไรบ้าง

ซึ่งจริงๆ ตัว task ของ hardhat ก็ยังทำอะไรได้มากกว่านี้ ตัวอย่างบทความ ที่น่าสนใจ อ่านเพิ่มเติมครับ Building your own Custom Hardhat Plugins from scratch

Happy Coding ❤️

Reference

Authors
Discord