Hardhat utility tasks and helper functions.
npm install @klaytn/hardhat-utils
- Installation
- Table of contents
- Import the tasks
- Import the helper functions
- Required plugins
- Tasks
- Helper functions
- In
hardhat.config.js
- Import all tasks
require("@klaytn/hardhat-utils");
- Import selectively (see src/tasks/ for the list)
require("@klaytn/hardhat-utils/tasks/accounts"); require("@klaytn/hardhat-utils/tasks/klaytnNode");
- Import all tasks
- In
hardhat.config.ts
- Import all tasks
import "@klaytn/hardhat-utils";
- Import selectively (see src/tasks/ for the list)
import "@klaytn/hardhat-utils/tasks/accounts"; import "@klaytn/hardhat-utils/tasks/klaytnNode";
- Import all tasks
- In your
.js
scriptconst { deriveAccounts } = require("@klaytn/hardhat-utils/helpers");
- In your
.ts
scriptimport { deriveAccounts } from "@klaytn/hardhat-utils/helpers";
This plugin depends on other plugins. Make sure to require or import them in your hardhat.config.js
or hardhat.config.ts
.
npm install @nomiclabs/hardhat-ethers hardhat-deploy
// hardhat.config.js
require("@nomiclabs/hardhat-ethers");
require("hardhat-deploy");
// hardhat.config.ts
import "@nomiclabs/hardhat-ethers";
import "hardhat-deploy";
Type hh <task name> --help
for detailed help. Below paragraphs outlines notable use cases.
(Recommended) Install hardhat shorthand. Below paragraphs assumes hardhat-shorthand is installed, but you can still use the tasks
with npx hardhat
.
npm install --global hardhat-shorthand
npx hardhat --version
hh --version
Choose the network via
- Configure the
HARDHAT_NETWORK
environmentexport HARDHAT_NETWORK=localhost hh accounts
- Attach the
--network
option at each commandhh --network localhost accounts
Print account addresses and balances. Useful for checking the curent hardhat network.
hh accounts
address balance
0 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 10000000.0
1 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 10000000.0
2 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC 10000000.0
3 0x90F79bf6EB2c4f870365E785982E1f101E93b906 10000000.0
4 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 10000000.0
5 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc 10000000.0
6 0x976EA74026E726554dB657fA54763abd0C3a0aa9 10000000.0
7 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 10000000.0
8 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f 10000000.0
9 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 10000000.0
Decrypt JSON keystore file to print the address and private key. It also accepts the KIP-3 (Klaytn keystore v4) in which case multiple addresses and private keys are printed.
hh decrypt-keystore keystore.json --password "mypass"
address private key
0 0x0cc57a3c4E276A37AB0A98ba6899CAf6037996fB 278c3d035328daf04ab2597da96dd2d8868fd61a8837030f7d8a85f27b7f1bad
Transfer native coins in batch. Useful when you top up balances for gas fee.
hh faucet --from 0 --to 1,2,3
Send from 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 to 3 accounts 1 ETH each
to 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 txid 0x9574b62242f7d7f4b2ba040b775345aad8e4bfe38d588c783590298d861cc52f
to 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC txid 0xf594661765fcf2f7b17994661818d256af4db84aac4c518e3fd2e775790844c0
to 0x90F79bf6EB2c4f870365E785982E1f101E93b906 txid 0xe4e41e5750cdb5a25fd41f75f19e9feef96cc1ea7445fe503b17d9a44e5d4cda
Print addresses and private keys derived from a BIP-39 mnemonic and BIP-32 path.
By default, the Hardhat default mnemonic (test test test test test test test test test test test junk
) and Ethereum deriation path (m/44'/60'/0'/0/i
) is used.
hh mnemonic
address private key
0 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
1 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
2 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC 5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
3 0x90F79bf6EB2c4f870365E785982E1f101E93b906 7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
4 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
5 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc 8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
6 0x976EA74026E726554dB657fA54763abd0C3a0aa9 92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e
7 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356
8 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97
9 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
Print ABIs of compiled or deployed contracts.
hh abi
# contracts/Counter.sol:Counter
function increment() // 0xd09de08a
function number() view returns (uint256) // 0x8381f58a
function setNumber(uint256 newNumber) // 0x3fb5c1cb
You can customize the output.
# Print in JSON
hh abi --json
# Specify a contract
hh abi Counter
Print the deployed contract addresses.
hh addr
{
"Counter": "0x39dD11C243Ac4Ac250980FA3AEa016f73C509f37"
}
Call a read-only function of a deployed contract.
hh call Counter number
[
"0x00"
]
You can customize the call.
# specify the function signature (in case the ABI is broken or nonexistent)
hh call MyToken "balanceOf(address)" 0x1234
# specify 'from' address (in case the result differs by msg.sender)
hh call --from 1 Counter number
# override contract address (in case the contract is not saved in 'deployments/')
hh call --to 0xaddr Counter number
Deploy tasks is not part of hardhat-utils, but describing it here because it is essential for the contract tasks. See hardhat-deploy plugin docs for details.
Deploys contracts according to the scripts under the deploy/
directory.
hh deploy
deploying "Counter" (tx: 0x2f15606c21060c20a60ea6a251f031de61cb143b6c64b6eeb9b52d9d2421939b)...: deployed at 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 with 185065 gas
Import a deployment (i.e. address and ABI) of an existing contract. As a result, addresses and ABI will be saved under deployments/<network>
.
Use it when the contract is deployed by other party but you want to reference it.
hh import Counter 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Send a function invoking transaction to a deployed contract.
hh send Counter increment
sent Counter#increment (tx: 0xd9624e9d5a711812cb77169b3467761eb4952a9656aea970b64dba5102a84a9c)...ok (block 3, gas used: 44778)
emit SetNumber(uint256) [
"0x01"
]
You can customize the transaction.
# specify the function signature (in case the ABI is broken or nonexistent)
hh send WKLAY "withdraw(uint256)" 1000
# specify 'from' address (in case the result differs by msg.sender)
hh send --from 1 Counter increment
# override contract address (in case the contract is not saved in 'deployments/')
hh send --to 0xaddr Counter increment
# print unsigned transaction (in case private key is in another machine)
hh send --unsigned Counter increment
Similar to hh call
but calls the debug_traceCall
API.
hh tracecall Counter setNumber 2
CallTrace
CALL 0xbdab4f279fbd7886b75d8729ffa820f20d3e6523
gasUsed: 48440, value: 0.0, error: ''
You can customize the trace.
# Simulate the call at a specific block number
hh tracecall --block 1234 Counter setNumber 2
# Use the {tracer: null} option, in which case the opcode-level StructLogger is used.
hh tracecall --network localhost --tracer struct Counter setNumber 2
# Use the {tracer: "callTracer"} option, where internal transaction calls are traced.
hh tracecall --network localhost --tracer call Counter setNumber 2
# Use the {tracer: "revertTracer"} option, where the revert reason is printed, if any.
hh tracecall --network localhost --tracer revert Counter setNumber 2
# Use the StackUp bundler trace scripts BundlerCollectorTracer.js and BundlerExecutionTracer.js
# https://github.com/stackup-wallet/stackup-bundler/tree/main/pkg/tracer
hh tracecall --network localhost --tracer stackupcol Counter setNumber 2
hh tracecall --network localhost --tracer stackupexe Counter setNumber 2
Trace output examples:
# --tracer struct
StructTrace
gasUsed: 48440, failed: false, returnValue: ''
pc opcode gasCost gasLeft ccCost ccLeft
00000 PUSH1 3 9999975400 120 149999880
00002 PUSH1 3 9999975397 120 149999760
00004 MSTORE 12 9999975394 288 149999472
00005 CALLVALUE 2 9999975382 149 149999323
00006 DUP1 3 9999975380 190 149999133
# --tracer call
CallTrace
CALL 0x72df0a4521a17987742112c226353c4e299bf3ab
gasUsed: 530313, value: 0.0, error: ''
DELEGATECALL 0x6eeade4e5b9497747ac79053503b76b09ff248a9
gasUsed: 498261, value: 0.0, error: ''
STATICCALL 0xc8452baba9c02efb47eada8e2308e229ba2ea749
gasUsed: 7716, value: 0.0, error: ''
DELEGATECALL 0xf802b2bba4865714525fe5c5484467371efc391c
gasUsed: 264, value: 0.0, error: ''
CALL 0xc8452baba9c02efb47eada8e2308e229ba2ea749
gasUsed: 3753, value: 0.0, error: ''
# --tracer revert
RevertTrace
revert reason: 'Pausable: paused'
Calls the debug_traceTransaction
API for the given transaction hash.
hh --network baobab tracetx --tracer revert 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
RevertTrace
revert reason: 'Pausable: paused'
You can customize the trace.
# Use the {tracer: null} option, in which case the opcode-level StructLogger is used.
hh tracetx --network baobab --tracer struct 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
# Use the {tracer: "callTracer"} option, where internal transaction calls are traced.
hh tracetx --network baobab --tracer call 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
# Use the {tracer: "revertTracer"} option, where the revert reason is printed, if any.
hh tracetx --network baobab --tracer revert 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
# Use the StackUp bundler trace scripts BundlerCollectorTracer.js and BundlerExecutionTracer.js
# https://github.com/stackup-wallet/stackup-bundler/tree/main/pkg/tracer
hh tracetx --network baobab --tracer stackupcol 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
hh tracetx --network baobab --tracer stackupexe 0xdc0d176de3aeaa396fb558c8ce6d6d9718d979e455c60e5131dcada512b5e5dd
Upload ABI to online database services.
hh upload-abi --byte4
Uploading 8 function and event signatures..
POST https://www.4byte.directory/api/v1/import-abi/ 201 Created
{
"num_processed": 8,
"num_imported": 0,
"num_duplicates": 8,
"num_ignored": 0
}
Type hh upload-abi --help
to see list of supported services.
hh upload-abi --help
OPTIONS:
--byte4 Upload to https://www.4byte.directory/
--sigdb Upload to https://openchain.xyz/signatures
TODO
Launch the ERC-4337 bundler for the current network. Do not use with public endpoints since bundler generates a lot of RPC traffic. Supports stackup-bundler.
hh aa-bundler
[+] Using env: {
DOCKER_IMAGE: 'stackupwallet/stackup-bundler:latest',
DOCKER_LISTEN: '0.0.0.0:4337',
BUNDLER_NODE_RPC: 'http://host.docker.internal:8545/',
BUNDLER_PRIVATE_KEY: 'ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
BUNDLER_ENTRYPOINT: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789'
}
[+] Starting ERC-4337 bundler at http://0.0.0.0:4337/
[+] Building 0.0s (0/0) docker:desktop-linux
[+] Running 2/0
✔ Network bundler_default Created 0.0s
✔ Container bundler-stackup-1 Created 0.0s
Attaching to bundler-stackup-1
bundler-stackup-1 | debconf: delaying package configuration, since apt-utils is not installed
bundler-stackup-1 | checking eth_chainId... {"jsonrpc":"2.0","id":1,"result":"0x7a69"}connected to RPC 'http://host.docker.internal:8545/'
bundler-stackup-1 | badger 2023/11/28 06:48:00 INFO: All 0 tables opened in 0s
bundler-stackup-1 | badger 2023/11/28 06:48:00 INFO: Discard stats nextEmptySlot: 0
bundler-stackup-1 | badger 2023/11/28 06:48:00 INFO: Set nextTxnTs to 0
You can customize the instance.
# Use specific version
hh aa-bundler --docker-image-id stackupwallet/stackup-bundler:latest
# Use different sender account
hh aa-bundler --index 10
# Use different RPC port
hh aa-bundler --port 4000
Launch the BlockScout block explorer for current network. Do not use with public endpoints since explorer generates a lot of RPC traffic. Supports BlockScout v5.x with only a few services enabled (including smart-contract-verifier).
After running the task, go to http://localhost:4000.
hh explorer
[+] Using env: {
DOCKER_RPC_HTTP_URL: 'http://host.docker.internal:8545/', DOCKER_TAG: '4.1.8', DOCKER_LISTEN: '0.0.0.0:4000',
DOCKER_DISABLE_TRACER: 'true', DOCKER_DEBUG: '0' }
[+] Open in the browser: http://localhost:4000 [+] Building 0.0s (0/0) docker:desktop-linux [+] Running 6/6
✔ Network blockscout_default Created 0.0s ✔ Container blockscout-db-1 Started 0.0s
✔ Container blockscout-frontend-1 Started 0.0s ✔ Container blockscout-redis_db-1 Started 0.0s
✔ Container blockscout-smart-contract-verifier-1 Started 0.0s ✔ Container blockscout-backend-1 Started 0.0s
[+] Building 0.0s (0/0) docker:desktop-linux [+] Running 6/0
✔ Container blockscout-frontend-1 Running 0.0s
✔ Container blockscout-smart-contract-verifier-1 Running 0.0s
✔ Container blockscout-redis_db-1 Running 0.0s
✔ Container blockscout-db-1 Running 0.0s
✔ Container blockscout-backend-1 Running 0.0s
✔ Container blockscout-proxy-1 Created 0.0s
Attaching to blockscout-proxy-1
Launch a Klaytn consensus node. Analogous to hh node
or anvil
.
hh klaytn-node
[+] Using nodekey: ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
[+] Available accounts (each having ${balance} KLAY):
address private key
0 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
1 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
2 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC 0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a
3 0x90F79bf6EB2c4f870365E785982E1f101E93b906 0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6
4 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
5 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc 0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
6 0x976EA74026E726554dB657fA54763abd0C3a0aa9 0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e
7 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356
8 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f 0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97
9 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6
[+] Using env: {
DOCKER_IMAGE: 'klaytn/klaytn:latest',
DOCKER_LISTEN: '0.0.0.0:8545',
DOCKER_DEBUG: '0'
}
[+] Starting JSON-RPC server at http://0.0.0.0:8545/
To attach to the console,
npx hardhat klaytn-node --attach
Press Ctrl+C to stop
After running the task, type hh klaytn-node --attach
to use the console.
hh klaytn-node --attach
Welcome to the Klaytn JavaScript console!
instance: Klaytn/v1.11.1/linux-amd64/go1.20.6
datadir: /klaytn
modules: admin:1.0 debug:1.0 eth:1.0 governance:1.0 istanbul:1.0 klay:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0
>
You can customize the instance.
# Use specific version
hh klaytn-node --docker-image-id klaytn/klaytn:dev
# Configure fork level
hh klaytn-node --hardfork cancun
# Configure zero fee network
hh klaytn-node --base-fee 0 --unit-price 0
See src/helpers/ for full list.
import { deriveAccounts } from "@klaytn/hardhat-utils/helpers";
const accounts = deriveAccounts();
console.log(accounts[0].address);
// 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266