yushakuAugust 18, 2023
Hardhat is a development environment to compile, deploy, test, and debug your Ethereum smart contract. It makes the life of a Blockchain developer very easy. Let us talk about Hardhat.
Requirements: NodeJS v18 or later. first we need to create a directory and init project with yarn
mkdir polite_cat cd polite_cat yarn init -y # install hardhat package to create structure of project yarn add --dev hardhat
Once your installation is done:
npx hardhat # select those options to have the max feature of hardhat: ✔ What do you want to do? · Create a TypeScript project ✔ Hardhat project root: . ✔ Do you want to add a .gitignore? (Y/n) · y ✔ Do you want to install this sample project’s dependencies with yarn : y
[[hardhat_init.png]]
# hardhat project tree ├── contracts│ └── Lock.sol ├── scripts │ └── deploy.ts ├── test │ └── Lock.ts ├── hardhat.config.ts ├── package.json ├── README.md ├── tsconfig.json └── yarn.lock
Let us have a look at all the project folders created during the installation. 1. contracts –In this, you will be creating your smart contracts. 2. scripts –This folder contains the deployment script to deploy your contract on the Blockchain. 3. test –This will contain the test file for your smart contract. 4. hardhat.config.js –This is the configuration file for setting the various things like the solidity compiler version, the blockchain at which you want to deploy your smart contract, etc.
yarn add -D prettier prettier-plugin-solidity
create a file .prettierrc.json
{ "plugins": ["prettier-plugin-solidity"], "overrides": [ { "files": "*.sol", "options": { "printWidth": 80, "tabWidth": 2, "useTabs": false, "singleQuote": false, "bracketSpacing": false, } } ] }
we can run script to format all solidity file:
yarn prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'
You can add a script for running prettier on all your contracts:
json package.json "scripts": { "prettier": "prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'" },
Solhint is an open source project for linting Solidity code and provides both Security and Style Guide validations.
yarn add -D @nomiclabs/hardhat-solhint
And add the following statement to your hardhat.config.ts
:
import "@nomiclabs/hardhat-solhint";
then this script into package.json
"scripts": { "prettier": "prettier --write --plugin=prettier-plugin-solidity 'contracts/**/*.sol'", "check": "yarn hardhat check" },
We will use an ERC-20 standard based on OpenZepplin. OpenZepplin↗ is an open-source standard for securing blockchain applications and provides security products to build, automate, and operate dApps.
For this, we will need the @openzeppelin/contracts
package!
yarn add @openzeppelin/contractsyarn add -D @nomiclabs/hardhat-waffle
Now, it is time to name your token! In the next steps, we will create a smart contract file. So if you’re thinking to name your token PoliteCateToken
, make sure to name the contract file exactly the same PoliteCateToken.sol
.
//SPDX-License-Identifier: Unlicense //Declare the version of solidity to compile this contract. //This must match the version of solidity in your hardhat.config.js file pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; //This function instantiates the contract and //classifies ERC20 for storage schema contract PoliteCatToken is ERC20 { //Feel free to change the initial supply of 50 token //Keep the (10**18) unchanged as it multiplies the number we want as our supply to have 18 decimal uint constant _initial_supply = 50 * (10 ** 18); // make sure to replace the "PoliteCatToken" reference //with your own ERC-20 name constructor() ERC20("PoliteCatToken", "PCT") { _mint(msg.sender, _initial_supply); } }
Compile your contract to make sure everything is good to deploy
yarn hardhat compile # output # Generating typings for: 6 artifacts in dir: typechain-types for target: ethers-v6 # Successfully generated 28 typings! # Compiled 6 Solidity files successfully # Done in 8.98s.
we’ll create a file inside the test
folder as erc20.test.ts
then import from chai
, ethers
and hardhat
.
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { expect } from "chai"; import { ethers } from "hardhat"; describe("Token contract", function () { async function deployTokenFixture() { const [owner, addr1, addr2] = await ethers.getSigners(); const hardhatToken = await ethers.deployContract("PoliteCatToken"); return { hardhatToken, owner, addr1, addr2 }; } describe("Deployment", function () { it("Should assign the total supply of tokens to the owner", async function () { const { hardhatToken, owner } = await loadFixture(deployTokenFixture); const ownerBalance = await hardhatToken.balanceOf(owner.address); expect(await hardhatToken.totalSupply()).to.equal(ownerBalance); }); }); describe("Transactions", function () { it("Should transfer tokens between accounts", async function () { const { hardhatToken, owner, addr1, addr2 } = await loadFixture( deployTokenFixture ); // Transfer 50 tokens from owner to addr1 await expect( hardhatToken.transfer(addr1.address, 50) ).to.changeTokenBalances(hardhatToken, [owner, addr1], [-50, 50]); // Transfer 50 tokens from addr1 to addr2 // We use .connect(signer) to send a transaction from another account await expect( hardhatToken.connect(addr1).transfer(addr2.address, 50) ).to.changeTokenBalances(hardhatToken, [addr1, addr2], [-50, 50]); }); it("Should emit Transfer events", async function () { const { hardhatToken, owner, addr1, addr2 } = await loadFixture( deployTokenFixture ); // Transfer 50 tokens from owner to addr1 await expect(hardhatToken.transfer(addr1.address, 50)) .to.emit(hardhatToken, "Transfer") .withArgs(owner.address, addr1.address, 50); // Transfer 50 tokens from addr1 to addr2 // We use .connect(signer) to send a transaction from another account await expect(hardhatToken.connect(addr1).transfer(addr2.address, 50)) .to.emit(hardhatToken, "Transfer") .withArgs(addr1.address, addr2.address, 50); }); it("Should fail if sender doesn't have enough tokens", async function () { const { hardhatToken, owner, addr1 } = await loadFixture( deployTokenFixture ); const initialOwnerBalance = await hardhatToken.balanceOf(owner.address); // Try to send 1 token from addr1 (0 tokens) to owner. // `require` will evaluate false and revert the transaction. await expect( hardhatToken.connect(addr1).transfer(owner.address, 1) ).to.be.revertedWith("ERC20: transfer amount exceeds balance"); // Owner balance shouldn't have changed. expect(await hardhatToken.balanceOf(owner.address)).to.equal( initialOwnerBalance ); }); }); });
and run this command to run test in hardhat
yarn hardhat test # Token contract # Deployment # ✔ Should assign the total supply of tokens to the owner (1460ms) # Transactions # ✔ Should transfer tokens between accounts (137ms) # ✔ Should emit Transfer events # ✔ Should fail if sender doesn't have enough tokens (111ms)
but if you wanna know to estimate gas consum per function. then let config this to hardhat.config.ts
get your own coin market api
here: https://coinmarketcap.com/api/pricing/
import "hardhat-gas-reporter"; import dotenv from "dotenv"; dotenv.config(); const { REPORT_GAS = false, COIN_MARKETCAP_API_KEY = "", } = process.env; const config: HardhatUserConfig = { solidity: "0.8.19", gasReporter: { enabled: Boolean(REPORT_GAS), outputFile: "gas-report.txt", noColors: true, coinmarketcap: COIN_MARKETCAP_API_KEY, currency: "USD", token: "ETH", }, };
and run test a gain then you will see a file gas-report.txt
·-------------------------------|----------------------------|-------------|-----------------------------· | Solc version: 0.8.19 · Optimizer enabled: false · Runs: 200 · Block limit: 30000000 gas │ ································|····························|·············|······························ | Methods · 55 gwei/gas · 1648.50 usd/eth │ ···················|············|··············|·············|·············|···············|·············· | Contract · Method · Min · Max · Avg · # calls · usd (avg) │ ···················|············|··············|·············|·············|···············|·············· | PoliteCatToken · transfer · 47327 · 52139 · 49733 · 10 · 4.51 │ ···················|············|··············|·············|·············|···············|·············· | Deployments · · % of limit · │ ································|··············|·············|·············|···············|·············· | PoliteCatToken · - · - · 1169497 · 3.9 % · 106.04 │ ·-------------------------------|--------------|-------------|-------------|---------------|-------------·