protocols/hardhat-guide

Hardhat Development Framework Guide

ethereumguide🏛️ Officialconfidence highhealth 100%
v1.0.0·Updated 3/20/2026

Initialization

npm install --save-dev hardhat
npx hardhat init  # Select TypeScript project
npm install --save-dev @nomicfoundation/hardhat-toolbox  # Includes ethers, chai, mocha

Key hardhat.config.ts Configuration

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
  solidity: { version: "0.8.24", settings: { optimizer: { enabled: true, runs: 200 } } },
  networks: {
    sepolia: { url: process.env.SEPOLIA_RPC_URL!, accounts: [process.env.PRIVATE_KEY!] },
    mainnet: { url: process.env.MAINNET_RPC_URL!, accounts: [process.env.PRIVATE_KEY!] },
  },
  etherscan: { apiKey: process.env.ETHERSCAN_API_KEY },
};
export default config;

Writing Tests

import { expect } from "chai";
import { ethers } from "hardhat";

describe("MyToken", function () {
  async function deployFixture() {
    const [owner, user] = await ethers.getSigners();
    const Token = await ethers.getContractFactory("MyToken");
    const token = await Token.deploy(ethers.parseEther("1000000"));
    return { token, owner, user };
  }

  it("should mint tokens to owner", async function () {
    const { token, owner } = await loadFixture(deployFixture);
    expect(await token.balanceOf(owner.address)).to.equal(ethers.parseEther("1000000"));
  });
  
  it("should transfer tokens", async function () {
    const { token, owner, user } = await loadFixture(deployFixture);
    await token.transfer(user.address, ethers.parseEther("100"));
    expect(await token.balanceOf(user.address)).to.equal(ethers.parseEther("100"));
  });
});

Fork Mainnet Testing

// hardhat.config.ts
networks: {
  hardhat: {
    forking: { url: process.env.MAINNET_RPC_URL!, blockNumber: 19000000 }
  }
}

// Impersonate whale in tests
const whale = await ethers.getImpersonatedSigner("0xWhaleAddress")
await ethers.provider.send("hardhat_setBalance", [whale.address, "0x56BC75E2D63100000"])

Deployment Script

import { ethers } from "hardhat";

async function main() {
  const Token = await ethers.getContractFactory("MyToken");
  const token = await Token.deploy(ethers.parseEther("1000000"));
  await token.waitForDeployment();
  console.log("Token deployed to:", await token.getAddress());
}

main().catch(console.error);
npx hardhat run scripts/deploy.ts --network sepolia
npx hardhat verify --network sepolia DEPLOYED_ADDRESS "1000000000000000000000000"

Common Commands

npx hardhat compile          # Compile
npx hardhat test             # Run tests
npx hardhat test --grep "transfer"  # Filter tests
npx hardhat coverage         # Coverage report
npx hardhat node             # Local node
npx hardhat console          # Interactive console

Common Pitfalls

  • loadFixture uses snapshots for rollback, 10x faster than redeploying each time
  • When fork testing, pay attention to blockNumber — blocks that are too old may have incorrect state
  • When verifying, constructor parameter order must match exactly with deployment