Hardhat Setup
Installed as a node package using npm or yarn
Accessed via yarn hardhat
Contracts compiled via yarn hardhat compile
Deploying SimpleStorage (Method 1)
yarn hardhat run scripts/deploy.js
const { ethers } = require("hardhat");
async function main() {
const SimpleStorageFactory = await ethers.getContractFactory("SimpleStorage");
console.log("Deploying contract...");
const simpleStorage = await SimpleStorageFactory.deploy();
await simpleStorage.deployed();
console.log(`Deployed contract to: ${simpleStorage.address}`);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.log(error);
process.exit(1);
});
Networks in Hardhat
Hardhat contains default hardhat network, rpc and wallet by default
We can edit hardhat.config.js
file to change default settings
We can also explicitly select network while running hardhat i.e yarn hardhat run scripts/deploy.js --network goerli
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
const GOERLI_RPC_URL = process.env.GOERLI_RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
defaultNetwork: "hardhat",
networks: {
goerli: {
url: GOERLI_RPC_URL,
accounts: [PRIVATE_KEY],
chainId: 5,
},
},
solidity: "0.8.17",
};
Programatic Verification
In our code script, we can automatically verify our contract code upon deployment
Works on block explorers like etherScan, might not work on other explorers
We can use etherScan API or use hardhat plugins hardhat-etherscan
hardhat.config.js
// ...
require("@nomiclabs/hardhat-etherscan");
// ...
module.exports = {
// ...
solidity: "0.8.17",
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
};
deploy.js
// Run package allows us to run any hardhat task in code
// Network package gives us network information
const { ethers, run, network } = require("hardhat");
async function main() {
// ...
// Only verify if we are on goerli test network
/*
4 == 4 -> true
4 == "4" -> true
4 === "4" -> false (no type conversion is done)
*/
if (network.config.chainId === 5 && process.env.ETHERSCAN_API_KEY) {
console.log("Waiting for block txes...");
await simpleStorage.deployTransaction.wait(6);
await verify(simpleStorage.address, []);
}
}
async function verify(contractAddress, args) {
console.log("Verifying contract...");
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
});
} catch (e) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already Verified!");
} else {
console.log(e);
}
}
}
Interacting with Contracts in Hardhat
deploy.js
const currentValue = await simpleStorage.retrieve();
console.log(`Current Value is: ${currentValue}`);
const transactionResponse = await simpleStorage.store(7);
await transactionResponse.wait(1);
const updatedValue = await simpleStorage.retrieve();
console.log(`Updated Value is: ${updatedValue}`);
Artifacts Troubleshooting
Delete the cache and artifacts folder if any issue arises (yarn hardhat clean
)
Hardhat will re compile and generate the artifacts
Custom Hardhat Tasks
Can be defined in hardhat.config.js
Generally created in tasks
folder
Can be accessed via yarn hardhat block-number
tasks/block-number.js
const { task } = require("hardhat/config");
task("block-number", "Prints the current block number").setAction(
// hre is like importing hardhat, gives access to all functionalities
async (taskArgs, hre) => {
const blockNumber = await hre.ethers.provider.getBlockNumber();
console.log(`Current block number: ${blockNumber}`);
}
);
module.exports = {};
hardhat.config.js
// ...
require("./tasks/block-number");
// ...
Hardhat Localhost Node
yarn hardhat node
spins up a local blockchain node as ganache, gives us accounts and rpc
The rpc url must be added to hardhat config like before in order to use that localnode
Hardhat console
let us run interactive commands to interact with blockchain
yarn hardhat console --network <network>
Running Tests
Hardhat works with mocha
framework which is a javascript framework for running tests
chai
framework is required for assert and expect
statements
We can run individual tests using grep pattern matching in it
description like yarn hardhat test --grep store
We can also use it.only
keyword which will ignore all other test cases and run only this test case
test/test-deploy.js
const { ethers } = require("hardhat");
const { expect, assert } = require("chai");
describe("SimpleStorage", function () {
let simpleStorageFactory, simpleStorage;
beforeEach(async function () {
simpleStorageFactory = await ethers.getContractFactory("SimpleStorage");
simpleStorage = await simpleStorageFactory.deploy();
});
it("Should start with a favorite number of 0", async function () {
const currentValue = await simpleStorage.retrieve();
const expectedValue = "0";
// expect(currentValue.toString()).to.equal(expectedValue)
assert.equal(currentValue.toString(), expectedValue);
});
it("Should update when we call store", async function () {
const expectedValue = "7"
const transactionResponse = await simpleStorage.store(expectedValue)
await transactionResponse.wait(1)
const currentValue = await simpleStorage.retrieve()
assert.equal(currentValue.toString(), expectedValue)
})
});
Hardhat Gas Reporter
Popular hardhat extension to see how much gas our funciton costs
Automatically gets attached to our tests
Can also specify which tokens to test gas for
hardhat.config.js
require("hardhat-gas-reporter")
// ...
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
gasReporter: {
enabled: true,
outputFile: "gas-reports.txt",
noColors: true,
currency: "USD",
coinmarketcap: COINMARKETCAP_API_KEY,
token: "MATIC"
}
Solidity Coverage
A hardhat plugin that checks how many lines of our .sol code is covered in a test
Added in hardhat.config.js
on the top as require("solidity-coverage")
Also generates a folder and file called coverage
and coverage.json
Hardhat Waffle
Advanced testing framework for solidity by hardhat