DEV Community

fangjun
fangjun

Posted on • Edited on

A Concise Hardhat Tutorial : Part 1

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Check the hardhat version:

yarn hardhat --version
//2.13.0
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Unit Test :

yarn hardhat test
Enter fullscreen mode Exit fullscreen mode

Deploy:

yarn hardhat run scripts/deploy.ts
//Output: 
Lock with 0.001ETH and unlock timestamp 1679119583 deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's run a standalone testnet and deploy smart contract to it.

Task ONE: in another terminal, run the testnet:

yarn hardhat node
Enter fullscreen mode Exit fullscreen mode

Output:

Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/

Accounts
========
Account #0: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 (10000 ETH)
Private Key: 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

If you want to use your mnemonic, add it in Hardhat configuration:

    hardhat: {
      accounts:{mnemonic: "your mnemonic"}
    },
Enter fullscreen mode Exit fullscreen mode

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, ...]
    }
  },
};
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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)]
}
Enter fullscreen mode Exit fullscreen mode

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);
...
   }
Enter fullscreen mode Exit fullscreen mode

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'
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)

https://dev.to/yakult/tutorial-write-upgradeable-smart-contract-proxy-contract-with-openzeppelin-1916

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

Top comments (2)

Collapse
 
isth0x_5cc3e8 profile image
isth0x_

I'm having a problem when uncommenting the code for console.log. I can't see the log on my terminal. I have tried some solutions like downgrading VSCode Solidity extension, uninstalling this, and installing Solidity+Hardhat extension, etc ... (all kinds of solutions that mentioned here ethereum.stackexchange.com/questio...). Nevertheless, I'm not seeing the console.log when interacting with the smart contract with hardhat console. Maybe, you have any idea on how to solve it? Thanks in advance.

Collapse
 
zorglob21 profile image
Yvan

Very good tutorial. I had trouble understanding the differences between each type of nodes. As always, the official documentation isn't satisfying.