A Concise Hardhat Tutorial : Part 1
fangjun
Posted on January 10, 2022
I prepare this concise and step-by-step tutorial to supplement Hardhat's official tutorial for beginners in Solidity. The tutorial includes an introduction and the following three sections:
1 . Install and init an (empty) sample project
2 . Write ERC20 token with OpenZeppelin
3 . Write ERC72 NFT token
(updated at 03/2023 for Hardhat V2.13.0 and Solidity 0.8.18)
Hardhat is an Ethereum development tool suite which can be used to compile, unit test, debug and deploy smart contracts. Like most Ethereum libraries and tools, Hardhat is written in JavaScript and Node.js
. Btw, you may also be interested to know foundry
which is written in Rust.
Let me explain several important features of Hardhat for you before we install Hardhat and use it.
0. Introduction
The main component of Hardhat is currently called Hardhat Runner which is a command line tool.
Hardhat Runner, Tasks and Plugins
According to Hardhat's documents, it is designed around the concepts of Tasks and Plugins.
Tasks: When we run Hardhat from command line, we run a task. Tasks are used for automation. We can check all the built-in and user-created tasks with
yarn hardhat help
.Plugins: Plugins of Hardhat are used for integrating other libraries/tools and extending the built-in functionality. It comes with official plugins such as hardhat-ethers, hardhat-waffle, hardhat-ganache, etc. We can also create our own hardhat plugins.
Hardhat Network, a local ethereum blockchain testnet
Hardhat comes with a local ethereum blockchain with EVM called Hardhat Network. You can run Hardhat Network in two modes:
In-process local blockchain, an ephemeral ethereum network that is created and destroyed with the process;
Stand-alone local blockchain, serving JSON-RPC and WebSocket requests. You can start it by running
yarn hardhat node
.
Instead of Hardhat Network, Hardhat can also be used with Ganache, the most known ethereum local blockchain testnet for developers. The Ethereum Virtual Machines (EVMs) in Hardhat Network, Ganache and Remix IDE are all based on @ethereumjs/vm
EVM implementation.
Hardhat can also fork mainnet which means "copy the state of the Ethereum mainnet into your local testnet including all balances and deployed contracts." Find more information at: https://hardhat.org/hardhat-network/guides/mainnet-forking.html .
Debugging-first: console.log()
The first reason why many developers choose Hardhat over Truffle Suite is console.log()
. Hardhat is debugging-first by providing the most-needed JavaScript style console.log()
in Solidity for debugging smart contract. It also provides Solidity stack traces and explicit error messages when transactions fail.
Hardhat's unit test uses Mocha
and Chai
currently.
Interactive console
Just as Truffle Suite, Hardhat provides an interactive JavaScript console. We can run Hardhat console by running yarn hardhat console
or yarn hardhat console --network localhost
.
I prefer to interact with my contracts step by step using this console during the development process although I surely write scripts.
1. Install Hardhat and init an (empty) Hardhat Project
In this section, we go through the process of initiating a hardhat project in 6 steps to give you an overall view of how to use Hardhat. Deep explanation of Solidity smart contract and Javascript script is deferred to later sections.
Step 1: Install Node.js and yarn
Hardhat is written in JavaScript using Node.js. To use it, we need Node.js
and yarn
(or npm
) installed.
If needed, you can download and install them from https://nodejs.org/en/. Once Node.js installed, check its version by running:
node -v
//v19.7.0
Step 2: Prepare directory and install Hardhat
We conduct 3 tasks in this step: make a directory; init a Node.js project with yarn
; and install hardhat as devDependencies in this environment.
mkdir hardhat-tut && cd hardhat-tut
yarn init --yes
yarn add hardhat
Check the hardhat version:
yarn hardhat --version
//2.13.0
Step 3: Init Hardhat project
When Hardhat is installed, we use Hardhat Runner CLI to init a sample project. Run the following command and choose "Create an advanced sample project that uses TypeScript".
yarn hardhat
It will init a project and add some dependencies. In the sample project, there are three sub-directories and a configuration file. Let's check it with tree -I node_modules/ -d -L 1
.
├── contracts
├── scripts
└── test
Sample smart contract is in the contracts
dir, unit test file is in the test
dir, and deploy script is in scripts
dir.
Now, you can choose your favorite IDE (VS Code for example) to write smart contracts in Solidity as well as unit test and deploy scripts in Javascript.
Step 4: Compile, Test and Deploy
In the basic sample project, there is already a sample smart contract Lock.sol
in contracts directory as well as unit test script Lock.ts
and deploy script deploy.ts
for it. (You may also
be interested in the Greeter.sol
in the previous version of hardhat/Remix.)
The development circle of smart contract is "Compile, Test and Deploy".
Compile :
yarn hardhat compile
Unit Test :
yarn hardhat test
Deploy:
yarn hardhat run scripts/deploy.ts
//Output:
Lock with 0.001ETH and unlock timestamp 1679119583 deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
Please note that the Lock smart contract is deployed to the in-process blockchain testnet which is destroyed with the precess.
If you want to deploy it to another network such as localhost, run yarn hardhat run scripts/deploy.ts --network localhost
. Let's continue to configure for the standalone Hardhat local blockchain testnet and deploy Lock.sol
to it.
Step 5: Config the hardhat project
The config file is hardhat.config.ts
. We can configure our hardhat project in it.
import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";
const config: HardhatUserConfig = {
solidity: "0.8.18",
};
export default config;
By default, hardhat support stand-alone localhost
network and in-process hardhat
network. So to use localhost standalone testnet, we don't need to do any modification in the configuration file.
{
localhost: {
url: "http://127.0.0.1:8545"
},
hardhat: {
// See its defaults
}
}
Let's run a standalone testnet and deploy smart contract to it.
Task ONE: in another terminal, run the testnet:
yarn hardhat node
Output:
Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/
Accounts
========
Account #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
...
Task TWO: run deploy script in the localhost:
yarn hardhat run scripts/deploy.ts --network localhost
//Lock with 0.001ETH and unlock timestamp 1679119754 deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
In the other terminal, we can see output of the testnet:
eth_sendTransaction
Contract deployment: Lock
Contract address: 0x5fbdb2315678afecb367f032d93f642f64180aa3
Transaction: 0x26b0d85de3bf5fa7530264fef2edfc89bd9eaba89730b9c338d4c5b7583ac11f
From: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
Value: 0.001 ETH
Gas used: 326016 of 326016
Block #1: 0x24288deb19e27e3ba6aa08dec267d4091c228984ec939ea2a9161cb872dbf905
If you would like to interact with the smart contract from Hardhat console or MetaMask wallet, you need to run a stand-alone local blockchain and deploy the smart contract to it.
Note on mnemonic and default accounts
The default accounts with Hardhat are generated with this mnemonic:
"test test test test test test test test test test test junk"
If you want to use your mnemonic, add it in Hardhat configuration:
hardhat: {
accounts:{mnemonic: "your mnemonic"}
},
See more about hardhat configuration at: https://hardhat.org/config/
Stand-alone local blockchain testnet serves JSON PRC at http://127.0.0.1:8545/. If you would like to use the Ethereum mainnet, public testnet Sepolia, sidechain like Polygon/BSC or L2 like Optimism/Arbitrum, you may need a RPC provider like Alchemy.
For example, if you would like to use Sepolia, you can add this network in config(via hardhat docs):
module.exports = {
networks: {
sepolia: {
url: "https://eth-sepolia.g.alchemy.com/v2/<apikey>",
accounts: [privateKey1, privateKey2, ...]
}
},
};
Change the and to your own.
Step 6: Interact with the deployed smart contact from Hardhat console
Hardhat console is an interactive Javascript console.
To open Hardhat console connecting to localhost blockchain at http://127.0.0.1:8545/ , run:
yarn hardhat console --network localhost
In Hardhat console, you can interact with smart contract using Ethers.js
. What we use here is the plugin version: hardhat-ethers.
const address = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
const contract = await ethers.getContractAt("Lock", address);
//call withdraw
await contract.withdraw()
Response is the transaction receipt:
{
hash: '0x3a0269dc290e47e4001b9a8fd1c0e7a93f4443f6673c62f21d1960e3894fcca2',
type: 2,
accessList: [],
blockHash: '0x24b49f383d7cd24704595ece03abeb9e848b3b0f15fb1484db06c717c73185f3',
blockNumber: 2,
transactionIndex: 0,
confirmations: 1,
from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
gasPrice: BigNumber { value: "768002200" },
maxPriorityFeePerGas: BigNumber { value: "0" },
maxFeePerGas: BigNumber { value: "972002784" },
gasLimit: BigNumber { value: "36493" },
to: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
value: BigNumber { value: "0" },
nonce: 1,
data: '0x3ccfd60b',
r: '0x0ab5399e355a4795535827edb08c55efc63a412176b1fd3977b02923607c4b57',
s: '0x528706dd1b049ec0ad6ff85d3746e24a4dfbef4447e2b572b0d053ec0be8f28c',
v: 1,
creates: null,
chainId: 31337,
wait: [Function (anonymous)]
}
Note on console.log
You can modify the contract and use console.log
.
// Uncomment this line to use console.log
import "hardhat/console.sol";
function withdraw() public {
// Uncomment this line, and the import of "hardhat/console.sol", to print a log in your terminal
console.log("Unlock time is %o and block timestamp is %o", unlockTime, block.timestamp);
...
}
Run the previous steps again. You may found that there is a console log in the terminal:
console.log:
Unlock time is '1679121200' and block timestamp is '1679121264'
Last Step
At the end of this section, let's terminate the localhost blockchain.
I usually clean up the project which means to delete cache files and compiling artifacts by running:
yarn hardhat clean
You can also delete the node_modules
directory as you can install dependencies by running yarn
again.
To read the Contract / Unit Test / Deploy files is a good start to understand solidity and hardhat.
.
├── contracts
│ └── Lock.sol
├── package.json
├── scripts
│ └── deploy.ts
├── test
│ └── Lock.ts
If needed, you can delete the sample contract as well as test and deploy scripts in the corresponding directories. You now have a blank hardhat project to start with.
This is Part 1 of a 3-section hardhat tutorial "A Concise Hardhat Tutorial". How to write ERC20 and ERC721 smart contract will be covered in Part 2 and Part 3.
Tutorial List:
1. A Concise Hardhat Tutorial(3 parts)
https://dev.to/yakult/a-concise-hardhat-tutorial-part-1-7eo
2. Understanding Blockchain with Ethers.js
(5 parts)
https://dev.to/yakult/01-understanding-blockchain-with-ethersjs-4-tasks-of-basics-and-transfer-5d17
3. Tutorial : build your first DAPP with Remix and Etherscan (7 Tasks)
https://dev.to/yakult/tutorial-build-your-first-dapp-with-remix-and-etherscan-52kf
4. Tutorial: build DApp with Hardhat, React and Ethers.js (6 Tasks)
https://dev.to/yakult/a-tutorial-build-dapp-with-hardhat-react-and-ethersjs-1gmi
5. Tutorial: build DAPP with Web3-React and SWR
https://dev.to/yakult/tutorial-build-dapp-with-web3-react-and-swr-1fb0
6. Tutorial: write upgradeable smart contract (proxy) using OpenZeppelin(7 Tasks)
7. Tutorial: Build a NFT marketplace DApp like Opensea(5 Tasks)
https://dev.to/yakult/tutorial-build-a-nft-marketplace-dapp-like-opensea-3ng9
If you find this tutorial helpful, follow me at Twitter @fjun99
Posted on January 10, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.