Hardhat Initial Setup: Projects and Scripts

Introduction

Hardhat is a development environment designed for compiling, deploying, testing, and debugging Ethereum smart contracts. It offers a flexible and extensible plugin system, integrated Solidity debugging, and seamless TypeScript support. Whether you’re creating simple token contracts or building complex DeFi protocols, Hardhat streamlines your workflow with powerful scripting and automation capabilities.

This article provides a comprehensive guide to setting up your first Hardhat project. We’ll cover installing dependencies, initializing projects, understanding the directory layout, configuring networks, crafting custom scripts, and best practices for production readiness.

Prerequisites

  • Node.js v14 or higher – install from https://nodejs.org/
  • npm or yarn – package managers bundled with Node.js or available separately
  • Basic knowledge of JavaScript and Solidity
  • Familiarity with the command line or terminal

Installing Hardhat

Create an empty directory for your project and install Hardhat as a development dependency:

  
npm init -y
npm install --save-dev hardhat
  

This installs the core hardhat package. Optionally, you can globally install the CLI:

  
npm install --global hardhat
  

Initializing Your Project

Run the initialization wizard to scaffold a sample project:

  
npx hardhat
  

Choose “Create a basic sample project” to generate a minimal structure:

Folder/File Description
contracts/ Your Solidity contracts
scripts/ Deployment interaction scripts
test/ Automated tests (Mocha Chai)
hardhat.config.js Project configuration file

Configuring Hardhat

The hardhat.config.js file controls compiler settings, network definitions, and plugin integrations. A typical configuration looks like this:

require(@nomiclabs/hardhat-ethers)
require(dotenv).config()

module.exports = {
  solidity: 0.8.17,
  paths: {
    sources: ./contracts,
    tests: ./test,
    artifacts: ./artifacts
  },
  networks: {
    hardhat: {},
    ropsten: {
      url: process.env.ROPSTEN_RPC_URL,
      accounts: [process.env.PRIVATE_KEY]
    }
  },
  mocha: {
    timeout: 20000
  }
}
  
  • solidity: Specify the compiler version(s).
  • paths: Customize directories.
  • networks: Define Ethereum networks (local testnets).
  • mocha: Adjust testing framework settings.

Installing Plugins

Hardhat’s power comes from its plugins. Common choices include:

Install with:

  
npm install --save-dev @nomiclabs/hardhat-ethers hardhat-gas-reporter dotenv
  

Writing Deployment Scripts

Scripts live in the scripts/ directory and are executed via the Hardhat Runtime Environment (HRE). Below is a sample deploy script deploy.js:

const hre = require(hardhat)

async function main() {
  const Token = await hre.ethers.getContractFactory(MyToken)
  const token = await Token.deploy(MyToken, MTK, 18, hre.ethers.utils.parseUnits(1000000, 18))
  await token.deployed()
  console.log(Token deployed to:, token.address)
}

main()
  .then(() => process.exit(0))
  .catch(error => {
    console.error(error)
    process.exit(1)
  })
  

Key points:

  • getContractFactory: Retrieves the contract abstraction.
  • deploy: Deploys with constructor args.
  • deployed: Ensures the transaction is mined.

Running Scripts

Execute scripts on the local network:

  
npx hardhat run scripts/deploy.js
  

Or target a testnet (e.g., Ropsten):

  
npx hardhat run --network ropsten scripts/deploy.js
  

The –network flag selects the configuration from your hardhat.config.js.

Interacting with Deployed Contracts

You can write custom scripts to call contract functions. Example interact.js:

const { ethers } = require(hardhat)

async function main() {
  const tokenAddress = 0xYourDeployedAddress
  const Token = await ethers.getContractFactory(MyToken)
  const token = Token.attach(tokenAddress)

  // Query total supply
  const totalSupply = await token.totalSupply()
  console.log(Total Supply:, ethers.utils.formatUnits(totalSupply, 18))

  // Transfer tokens
  const [owner, recipient] = await ethers.getSigners()
  const tx = await token.connect(owner).transfer(recipient.address, ethers.utils.parseUnits(100, 18))
  await tx.wait()
  console.log(Transferred 100 tokens to, recipient.address)
}

main()
  .catch(error => {
    console.error(error)
    process.exit(1)
  })
  

Testing Debugging

Hardhat integrates Mocha and Chai for unit testing. Example sample-test.js in the test/ folder:

const { expect } = require(chai)
const { ethers } = require(hardhat)

describe(MyToken, function () {
  it(Should assign the total supply to the deployer, async function () {
    const [owner] = await ethers.getSigners()
    const Token = await ethers.getContractFactory(MyToken)
    const token = await Token.deploy(MyToken, MTK, 18, ethers.utils.parseUnits(1000, 18))
    await token.deployed()
    const ownerBalance = await token.balanceOf(owner.address)
    expect(ownerBalance).to.equal(ethers.utils.parseUnits(1000, 18))
  })
})
  

Run tests with:

  
npx hardhat test
  

Advanced Tips

  • Use dotenv for managing private keys and RPC URLs securely.
  • Leverage hardhat-gas-reporter to analyze gas costs in tests.
  • Integrate solidity-coverage for code coverage metrics.
  • Configure typechain for TypeScript typings.
  • Cache builds and artifacts for CI/CD pipelines.

Conclusion

Setting up a Hardhat project involves installing dependencies, initializing the project structure, configuring networks, and writing scripts for deployment and interaction. With its rich plugin ecosystem and powerful debugging tools, Hardhat empowers developers to build, test, and deploy smart contracts efficiently.

For further reading and advanced configurations, visit the official Hardhat documentation at https://hardhat.org/getting-started/ and the Ethers.js guide at https://docs.ethers.io/v5/.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *