# Table of Contents - [Getting started with Hardhat | Ethereum development environment for professionals by Nomic Foundation](#getting-started-with-hardhat-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Compiling your contracts | Ethereum development environment for professionals by Nomic Foundation](#compiling-your-contracts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Setting up a project | Ethereum development environment for professionals by Nomic Foundation](#setting-up-a-project-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Configuration | Ethereum development environment for professionals by Nomic Foundation](#configuration-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Writing tasks | Ethereum development environment for professionals by Nomic Foundation](#writing-tasks-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Testing contracts | Ethereum development environment for professionals by Nomic Foundation](#testing-contracts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Hardhat Runtime Environment (HRE) | Ethereum development environment for professionals by Nomic Foundation](#hardhat-runtime-environment-hre-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Deploying your contracts | Ethereum development environment for professionals by Nomic Foundation](#deploying-your-contracts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Using the Hardhat console | Ethereum development environment for professionals by Nomic Foundation](#using-the-hardhat-console-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Using TypeScript | Ethereum development environment for professionals by Nomic Foundation](#using-typescript-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Multiple Solidity versions | Ethereum development environment for professionals by Nomic Foundation](#multiple-solidity-versions-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Compilation artifacts | Ethereum development environment for professionals by Nomic Foundation](#compilation-artifacts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Verifying your contracts | Ethereum development environment for professionals by Nomic Foundation](#verifying-your-contracts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Command-line completion | Ethereum development environment for professionals by Nomic Foundation](#command-line-completion-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Getting help | Ethereum development environment for professionals by Nomic Foundation](#getting-help-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Configuration variables | Ethereum development environment for professionals by Nomic Foundation](#configuration-variables-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Writing scripts with Hardhat | Ethereum development environment for professionals by Nomic Foundation](#writing-scripts-with-hardhat-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Creating a task | Ethereum development environment for professionals by Nomic Foundation](#creating-a-task-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Building plugins | Ethereum development environment for professionals by Nomic Foundation](#building-plugins-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Using ES modules | Ethereum development environment for professionals by Nomic Foundation](#using-es-modules-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Migrating away from hardhat-waffle | Ethereum development environment for professionals by Nomic Foundation](#migrating-away-from-hardhat-waffle-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Integrating with Foundry | Ethereum development environment for professionals by Nomic Foundation](#integrating-with-foundry-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Flattening your contracts | Ethereum development environment for professionals by Nomic Foundation](#flattening-your-contracts-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Running tests in Visual Studio Code | Ethereum development environment for professionals by Nomic Foundation](#running-tests-in-visual-studio-code-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Solidity support | Ethereum development environment for professionals by Nomic Foundation](#solidity-support-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Verbose logging | Ethereum development environment for professionals by Nomic Foundation](#verbose-logging-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Oracles | Ethereum development environment for professionals by Nomic Foundation](#oracles-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Stability guarantees | Ethereum development environment for professionals by Nomic Foundation](#stability-guarantees-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Common problems | Ethereum development environment for professionals by Nomic Foundation](#common-problems-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Environment variables | Ethereum development environment for professionals by Nomic Foundation](#environment-variables-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Hardhat errors | Ethereum development environment for professionals by Nomic Foundation](#hardhat-errors-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Using a custom Solidity compiler | Ethereum development environment for professionals by Nomic Foundation](#using-a-custom-solidity-compiler-ethereum-development-environment-for-professionals-by-nomic-foundation) - [Using Viem | Ethereum development environment for professionals by Nomic Foundation](#using-viem-ethereum-development-environment-for-professionals-by-nomic-foundation) --- # Getting started with Hardhat | Ethereum development environment for professionals by Nomic Foundation [# Overview](#overview) ------------------------ Hardhat is a development environment for Ethereum software. It consists of different components for editing, compiling, debugging and deploying your smart contracts and dApps, all of which work together to create a complete development environment. Hardhat Runner is the main component you interact with when using Hardhat. It's a flexible and extensible task runner that helps you manage and automate the recurring tasks inherent to developing smart contracts and dApps. Hardhat Runner is designed around the concepts of **tasks** and **plugins**. Every time you're running Hardhat from the command-line, you're running a task. For example, `npx hardhat compile` runs the built-in `compile` task. Tasks can call other tasks, allowing complex workflows to be defined. Users and plugins can override existing tasks, making those workflows customizable and extendable. This guide will take you through the installation of our recommended setup, but as most of Hardhat's functionality comes from plugins, you are free to customize it or choose a completely different path. [# Installation](#installation) -------------------------------- TIP [Hardhat for Visual Studio Code](/hardhat-vscode) is the official Hardhat extension that adds advanced support for Solidity to VSCode. If you use Visual Studio Code, give it a try! Hardhat is used through a local installation in your project. This way your environment will be reproducible, and you will avoid future version conflicts. To install it, you need to create an npm project by going to an empty folder, running `npm init`, and following its instructions. You can use another package manager, like yarn, but we recommend you use npm 7 or later, as it makes installing Hardhat plugins simpler. Once your project is ready, you should run npm 7+ npm 6 yarn pnpm npm install --save-dev hardhat npm install --save-dev hardhat yarn add --dev hardhat pnpm add -D hardhat To use your local installation of Hardhat, you need to use `npx` to run it (i.e. `npx hardhat init`). [# Quick Start](#quick-start) ------------------------------ TIP If you are using Windows, we **strongly recommend** using [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/about) to follow this guide. We will explore the basics of creating a Hardhat project with a sample contract, tests of that contract, and a Hardhat Ignition module to deploy it. To create the sample project, run `npx hardhat init` in your project folder: $ npx hardhat init 888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 👷 Welcome to Hardhat v2.22.18 👷‍ ? What do you want to do? … ❯ Create a JavaScript project Create a TypeScript project Create a TypeScript project (with Viem) Create an empty hardhat.config.js Quit Let’s create the JavaScript or TypeScript project and go through these steps to compile, test and deploy the sample contract. We recommend using TypeScript, but if you are not familiar with it just pick JavaScript. ### [#Running tasks](#running-tasks) To first get a quick sense of what's available and what's going on, run `npx hardhat` in your project folder: $ npx hardhat Hardhat version 2.9.9 Usage: hardhat [GLOBAL OPTIONS] [TASK OPTIONS] GLOBAL OPTIONS: --config A Hardhat config file. --emoji Use emoji in messages. --help Shows this message, or a task's help if its name is provided --max-memory The maximum amount of memory that Hardhat can use. --network The network to connect to. --show-stack-traces Show stack traces. --tsconfig A TypeScript config file. --verbose Enables Hardhat verbose logging --version Shows hardhat's version. AVAILABLE TASKS: check Check whatever you need clean Clears the cache and deletes all artifacts compile Compiles the entire project, building all artifacts console Opens a hardhat console coverage Generates a code coverage report for tests flatten Flattens and prints contracts and their dependencies help Prints this message node Starts a JSON-RPC server on top of Hardhat Network run Runs a user-defined script after compiling the project test Runs mocha tests typechain Generate Typechain typings for compiled contracts verify Verifies contract on Etherscan To get help for a specific task run: npx hardhat help [task] The list of available tasks includes the built-in ones and also those that came with any installed plugins. `npx hardhat` is your starting point to find out what tasks are available to run. ### [#Compiling your contracts](#compiling-your-contracts) Next, if you take a look in the `contracts/` folder, you'll see `Lock.sol`: // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.28; // Uncomment this line to use console.log // import "hardhat/console.sol"; contract Lock { uint public unlockTime; address payable public owner; event Withdrawal(uint amount, uint when); constructor(uint _unlockTime) payable { require( block.timestamp < _unlockTime, "Unlock time should be in the future" ); unlockTime = _unlockTime; owner = payable(msg.sender); } 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); require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); emit Withdrawal(address(this).balance, block.timestamp); owner.transfer(address(this).balance); } } To compile it, simply run: npx hardhat compile If you created a TypeScript project, this task will also generate TypeScript bindings using [TypeChain](https://www.npmjs.com/package/typechain) . ### [#Testing your contracts](#testing-your-contracts) Your project comes with tests that use [Mocha](https://mochajs.org) , [Chai](https://www.chaijs.com) , [Ethers.js](https://docs.ethers.org/v6/) and [Hardhat Ignition](/ignition) . If you take a look in the `test/` folder, you'll see a test file: TypeScript JavaScript import { time, loadFixture, } from "@nomicfoundation/hardhat-toolbox/network-helpers"; import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs"; import { expect } from "chai"; import hre from "hardhat"; describe("Lock", function () { // We define a fixture to reuse the same setup in every test. // We use loadFixture to run this setup once, snapshot that state, // and reset Hardhat Network to that snapshot in every test. async function deployOneYearLockFixture() { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const ONE_GWEI = 1_000_000_000; const lockedAmount = ONE_GWEI; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; // Contracts are deployed using the first signer/account by default const [owner, otherAccount] = await hre.ethers.getSigners(); const Lock = await hre.ethers.getContractFactory("Lock"); const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); return { lock, unlockTime, lockedAmount, owner, otherAccount }; } describe("Deployment", function () { it("Should set the right unlockTime", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); expect(await lock.unlockTime()).to.equal(unlockTime); }); it("Should set the right owner", async function () { const { lock, owner } = await loadFixture(deployOneYearLockFixture); expect(await lock.owner()).to.equal(owner.address); }); it("Should receive and store the funds to lock", async function () { const { lock, lockedAmount } = await loadFixture( deployOneYearLockFixture ); expect(await hre.ethers.provider.getBalance(lock.target)).to.equal( lockedAmount ); }); it("Should fail if the unlockTime is not in the future", async function () { // We don't use the fixture here because we want a different deployment const latestTime = await time.latest(); const Lock = await hre.ethers.getContractFactory("Lock"); await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith( "Unlock time should be in the future" ); }); }); describe("Withdrawals", function () { describe("Validations", function () { it("Should revert with the right error if called too soon", async function () { const { lock } = await loadFixture(deployOneYearLockFixture); await expect(lock.withdraw()).to.be.revertedWith( "You can't withdraw yet" ); }); it("Should revert with the right error if called from another account", async function () { const { lock, unlockTime, otherAccount } = await loadFixture( deployOneYearLockFixture ); // We can increase the time in Hardhat Network await time.increaseTo(unlockTime); // We use lock.connect() to send a transaction from another account await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( "You aren't the owner" ); }); it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () { const { lock, unlockTime } = await loadFixture( deployOneYearLockFixture ); // Transactions are sent using the first signer by default await time.increaseTo(unlockTime); await expect(lock.withdraw()).not.to.be.reverted; }); }); describe("Events", function () { it("Should emit an event on withdrawals", async function () { const { lock, unlockTime, lockedAmount } = await loadFixture( deployOneYearLockFixture ); await time.increaseTo(unlockTime); await expect(lock.withdraw()) .to.emit(lock, "Withdrawal") .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg }); }); describe("Transfers", function () { it("Should transfer the funds to the owner", async function () { const { lock, unlockTime, lockedAmount, owner } = await loadFixture( deployOneYearLockFixture ); await time.increaseTo(unlockTime); await expect(lock.withdraw()).to.changeEtherBalances( [owner, lock], [lockedAmount, -lockedAmount] ); }); }); }); }); const { time, loadFixture, } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs"); const { expect } = require("chai"); describe("Lock", function () { // We define a fixture to reuse the same setup in every test. // We use loadFixture to run this setup once, snapshot that state, // and reset Hardhat Network to that snapshot in every test. async function deployOneYearLockFixture() { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const ONE_GWEI = 1_000_000_000; const lockedAmount = ONE_GWEI; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; // Contracts are deployed using the first signer/account by default const [owner, otherAccount] = await ethers.getSigners(); const Lock = await ethers.getContractFactory("Lock"); const lock = await Lock.deploy(unlockTime, { value: lockedAmount }); return { lock, unlockTime, lockedAmount, owner, otherAccount }; } describe("Deployment", function () { it("Should set the right unlockTime", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); expect(await lock.unlockTime()).to.equal(unlockTime); }); it("Should set the right owner", async function () { const { lock, owner } = await loadFixture(deployOneYearLockFixture); expect(await lock.owner()).to.equal(owner.address); }); it("Should receive and store the funds to lock", async function () { const { lock, lockedAmount } = await loadFixture( deployOneYearLockFixture ); expect(await ethers.provider.getBalance(lock.target)).to.equal( lockedAmount ); }); it("Should fail if the unlockTime is not in the future", async function () { // We don't use the fixture here because we want a different deployment const latestTime = await time.latest(); const Lock = await ethers.getContractFactory("Lock"); await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith( "Unlock time should be in the future" ); }); }); describe("Withdrawals", function () { describe("Validations", function () { it("Should revert with the right error if called too soon", async function () { const { lock } = await loadFixture(deployOneYearLockFixture); await expect(lock.withdraw()).to.be.revertedWith( "You can't withdraw yet" ); }); it("Should revert with the right error if called from another account", async function () { const { lock, unlockTime, otherAccount } = await loadFixture( deployOneYearLockFixture ); // We can increase the time in Hardhat Network await time.increaseTo(unlockTime); // We use lock.connect() to send a transaction from another account await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( "You aren't the owner" ); }); it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () { const { lock, unlockTime } = await loadFixture( deployOneYearLockFixture ); // Transactions are sent using the first signer by default await time.increaseTo(unlockTime); await expect(lock.withdraw()).not.to.be.reverted; }); }); describe("Events", function () { it("Should emit an event on withdrawals", async function () { const { lock, unlockTime, lockedAmount } = await loadFixture( deployOneYearLockFixture ); await time.increaseTo(unlockTime); await expect(lock.withdraw()) .to.emit(lock, "Withdrawal") .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg }); }); describe("Transfers", function () { it("Should transfer the funds to the owner", async function () { const { lock, unlockTime, lockedAmount, owner } = await loadFixture( deployOneYearLockFixture ); await time.increaseTo(unlockTime); await expect(lock.withdraw()).to.changeEtherBalances( [owner, lock], [lockedAmount, -lockedAmount] ); }); }); }); }); You can run your tests with `npx hardhat test`: TypeScript JavaScript $ npx hardhat test Generating typings for: 2 artifacts in dir: typechain-types for target: ethers-v6 Successfully generated 6 typings! Compiled 2 Solidity files successfully Lock Deployment ✔ Should set the right unlockTime (610ms) ✔ Should set the right owner ✔ Should receive and store the funds to lock ✔ Should fail if the unlockTime is not in the future Withdrawals Validations ✔ Should revert with the right error if called too soon ✔ Should revert with the right error if called from another account ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it Events ✔ Should emit an event on withdrawals Transfers ✔ Should transfer the funds to the owner 9 passing (790ms) $ npx hardhat test Compiled 2 Solidity files successfully Lock Deployment ✔ Should set the right unlockTime (610ms) ✔ Should set the right owner ✔ Should receive and store the funds to lock ✔ Should fail if the unlockTime is not in the future Withdrawals Validations ✔ Should revert with the right error if called too soon ✔ Should revert with the right error if called from another account ✔ Shouldn't fail if the unlockTime has arrived and the owner calls it Events ✔ Should emit an event on withdrawals Transfers ✔ Should transfer the funds to the owner 9 passing (790ms) ### [#Deploying your contracts](#deploying-your-contracts) Next, to deploy the contract we will use a Hardhat Ignition module. Inside the `ignition/modules` folder you will find a file with the following code: TypeScript JavaScript // This setup uses Hardhat Ignition to manage smart contract deployments. // Learn more about it at https://hardhat.org/ignition import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; const JAN_1ST_2030 = 1893456000; const ONE_GWEI: bigint = 1_000_000_000n; const LockModule = buildModule("LockModule", (m) => { const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); const lock = m.contract("Lock", [unlockTime], { value: lockedAmount, }); return { lock }; }); export default LockModule; // This setup uses Hardhat Ignition to manage smart contract deployments. // Learn more about it at https://hardhat.org/ignition const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules"); const JAN_1ST_2030 = 1893456000; const ONE_GWEI = 1_000_000_000n; module.exports = buildModule("LockModule", (m) => { const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); const lock = m.contract("Lock", [unlockTime], { value: lockedAmount, }); return { lock }; }); TypeScript JavaScript You can deploy it using `npx hardhat ignition deploy ./ignition/modules/Lock.ts`: $ npx hardhat ignition deploy ./ignition/modules/Lock.ts Compiled 1 Solidity file successfully (evm target: paris). You are running Hardhat Ignition against an in-process instance of Hardhat Network. This will execute the deployment, but the results will be lost. You can use --network to deploy to a different network. Hardhat Ignition 🚀 Deploying [ LockModule ] Batch #1 Executed LockModule#Lock [ LockModule ] successfully deployed 🚀 Deployed Addresses LockModule#Lock - 0x5FbDB2315678afecb367f032d93F642f64180aa3 You can deploy it using `npx hardhat ignition deploy ./ignition/modules/Lock.js`: $ npx hardhat ignition deploy ./ignition/modules/Lock.js Compiled 1 Solidity file successfully (evm target: paris). You are running Hardhat Ignition against an in-process instance of Hardhat Network. This will execute the deployment, but the results will be lost. You can use --network to deploy to a different network. Hardhat Ignition 🚀 Deploying [ LockModule ] Batch #1 Executed LockModule#Lock [ LockModule ] successfully deployed 🚀 Deployed Addresses LockModule#Lock - 0x5FbDB2315678afecb367f032d93F642f64180aa3 To learn more check out the [Hardhat Ignition documentation](/ignition) . ### [#Connecting a wallet or Dapp to Hardhat Network](#connecting-a-wallet-or-dapp-to-hardhat-network) By default, Hardhat will spin up a new in-memory instance of Hardhat Network on startup. It's also possible to run Hardhat Network in a standalone fashion so that external clients can connect to it. This could be a wallet, your Dapp front-end, or a Hardhat Ignition deployment. To run Hardhat Network in this way, run `npx hardhat node`: $ npx hardhat node Started HTTP and WebSocket JSON-RPC server at http://127.0.0.1:8545/ This will expose a JSON-RPC interface to Hardhat Network. To use it connect your wallet or application to `http://127.0.0.1:8545`. If you want to connect Hardhat to this node, for example to run a deployment against it, you simply need to run it using `--network localhost`. To try this, start a node with `npx hardhat node` and re-run the deployment using the `network` option: TypeScript JavaScript npx hardhat ignition deploy ./ignition/modules/Lock.ts --network localhost npx hardhat ignition deploy ./ignition/modules/Lock.js --network localhost To run Hardhat Network on specific port and allow incoming requests from a specific network interface or hostname, run `npx hardhat node --hostname 127.0.0.1 --port 8545`. If you want to allow incoming requests from anywhere, including external ips, use `--hostname 0.0.0.0`. Congrats! You have created a project and compiled, tested and deployed a smart contract. Show us some love by starring [our repository on GitHub!](https://github.com/NomicFoundation/hardhat) ️ --- # Compiling your contracts | Ethereum development environment for professionals by Nomic Foundation [#Compiling your contracts](#compiling-your-contracts) ======================================================= To compile your contracts in your Hardhat project, use the built-in `compile` task: $ npx hardhat compile Compiling... Compiled 1 contract successfully The compiled artifacts will be saved in the `artifacts/` directory by default, or whatever your configured artifacts path is. Look at the [paths configuration section](/hardhat-runner/docs/config#path-configuration) to learn how to change it. This directory will be created if it doesn't exist. After the initial compilation, Hardhat will try to do the least amount of work possible the next time you compile. For example, if you didn't change any files since the last compilation, nothing will be compiled: $ npx hardhat compile Nothing to compile If you only modified one file, only that file and others affected by it will be recompiled. To force a compilation you can use the `--force` argument, or run `npx hardhat clean` to clear the cache and delete the artifacts. [# Configuring the compiler](#configuring-the-compiler) -------------------------------------------------------- If you need to customize the Solidity compiler options, then you can do so through the `solidity` field in your `hardhat.config.js`. The simplest way to use this field is via the shorthand for setting the compiler version, which we recommend always doing: module.exports = { solidity: "0.8.28", }; We recommend always setting a compiler version in order to avoid unexpected behavior or compiling errors as new releases of Solidity are published. WARNING Hardhat will automatically download the versions of `solc` that you set up. If you are behind an HTTP proxy, you may need to set the `HTTP_PROXY` or `HTTPS_PROXY` environment variable to the URL of your proxy. The expanded usage allows for more control of the compiler: module.exports = { solidity: { version: "0.8.28", settings: { optimizer: { enabled: true, runs: 1000, }, }, }, }; `settings` has the same schema as the `settings` entry in the [Input JSON](https://solidity.readthedocs.io/en/v0.7.2/using-the-compiler.html#input-description) that can be passed to the compiler. Some commonly used settings are: * `optimizer`: an object with `enabled` and `runs` keys. Default value: `{ enabled: false, runs: 200 }`. * `evmVersion`: a string controlling the target evm version. For example: `istanbul`, `berlin` or `london`. Default value: managed by `solc`. If any of your contracts have a version pragma that is not satisfied by the compiler version you configured, then Hardhat will throw an error. TIP Read [this guide](/hardhat-runner/docs/advanced/multiple-solidity-versions) if you need to use multiple versions of Solidity. --- # Setting up a project | Ethereum development environment for professionals by Nomic Foundation [#Setting up a project](#setting-up-a-project) =============================================== TIP If you are using Windows, we **strongly recommend** using [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/about) to follow this guide. Hardhat projects are Node.js projects with the `hardhat` package installed and a `hardhat.config.js` file. To initialize a Node.js project you can use [npm](https://docs.npmjs.com/cli/v8) or [yarn](https://classic.yarnpkg.com/) . We recommend using npm 7 or later: npm 7+ npm 6 yarn pnpm npm init -y npm init -y yarn init -y pnpm init Then you need to install Hardhat: npm 7+ npm 6 yarn pnpm npm install --save-dev hardhat npm install --save-dev hardhat yarn add --dev hardhat pnpm add -D hardhat If you run `npx hardhat init` now, you will be shown some options to facilitate project creation: $ npx hardhat init 888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 Welcome to Hardhat v2.22.18 ? What do you want to do? … ▸ Create a JavaScript project Create a TypeScript project Create a TypeScript project (with Viem) Create an empty hardhat.config.js Quit If you select _Create an empty hardhat.config.js_, Hardhat will create a `hardhat.config.js` like the following: /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.28", }; And this is enough to run Hardhat using a default project structure. ### [#Sample Hardhat project](#sample-hardhat-project) If you select _Create a JavaScript project_, a simple project creation wizard will ask you some questions. After that, the wizard will create some directories and files and install the necessary dependencies. The most important of these dependencies is the [Hardhat Toolbox](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) , a plugin that bundles all the things you need to start working with Hardhat. The initialized project has the following structure: contracts/ ignition/modules/ test/ hardhat.config.js These are the default paths for a Hardhat project. * `contracts/` is where the source files for your contracts should be. * `ignition/modules/` is where the Ignition modules that handle contract deployments should be. * `test/` is where your tests should go. If you need to change these paths, take a look at the [paths configuration section](/hardhat-runner/docs/config#path-configuration) . ### [#Testing](#testing) When it comes to testing your contracts, the sample project comes with some useful functionality: * The built-in [Hardhat Network](/hardhat-network/docs) as the development network to test on, along with the [Hardhat Network Helpers](/hardhat-network-helpers) library to manipulate this network. * [Mocha](https://mochajs.org/) as the test runner, [Chai](https://chaijs.com/) as the assertion library, and the [Hardhat Chai Matchers](/hardhat-chai-matchers) to extend Chai with contracts-related functionality. * The [`ethers.js`](https://docs.ethers.org/v6/) library to interact with the network and with contracts. As well as other useful plugins. You can learn more about this in the [Testing contracts guide](/hardhat-runner/docs/guides/test-contracts) . ### [#External networks](#external-networks) If you need to use an external network, like an Ethereum testnet, mainnet or some other specific node software, you can set it up using the `networks` configuration entries in the exported object in `hardhat.config.js`, which is how Hardhat projects manage settings. You can make use of the `--network` CLI parameter to quickly change the network. Take a look at the [networks configuration section](/hardhat-runner/docs/config#networks-configuration) to learn more about setting up different networks. ### [#Plugins and dependencies](#plugins-and-dependencies) Most of Hardhat's functionality comes from plugins, so check out the [plugins section](/hardhat-runner/plugins) for the official list and see if there are any ones of interest to you. To use a plugin, the first step is always to install it using npm or yarn, followed by requiring it in your config file: TypeScript JavaScript import "@nomicfoundation/hardhat-toolbox"; export default { solidity: "0.8.28", }; require("@nomicfoundation/hardhat-toolbox"); module.exports = { solidity: "0.8.28", }; Plugins are **essential** to Hardhat projects, so make sure to check out all the available ones and also build your own! ### [#Setting up your editor](#setting-up-your-editor) [Hardhat for Visual Studio Code](/hardhat-vscode) is the official Hardhat extension that adds advanced support for Solidity to VSCode. If you use Visual Studio Code, give it a try! --- # Configuration | Ethereum development environment for professionals by Nomic Foundation [#Configuration](#configuration) ================================= When Hardhat is run, it searches for the closest `hardhat.config.js` file starting from the Current Working Directory. This file normally lives in the root of your project. An empty `hardhat.config.js` is enough for Hardhat to work. The entirety of your Hardhat setup (i.e. your config, plugins and custom tasks) is contained in this file. [# Available config options](#available-config-options) -------------------------------------------------------- To set up your config, you have to export an object from `hardhat.config.js`. This object can have entries like `defaultNetwork`, [`networks`](#networks-configuration) , [`solidity`](#solidity-configuration) , [`paths`](#path-configuration) and [`mocha`](#mocha-configuration) . For example: Infura Alchemy module.exports = { defaultNetwork: "sepolia", networks: { hardhat: { }, sepolia: { url: "https://sepolia.infura.io/v3/", accounts: [privateKey1, privateKey2, ...] } }, solidity: { version: "0.8.28", settings: { optimizer: { enabled: true, runs: 200 } } }, paths: { sources: "./contracts", tests: "./test", cache: "./cache", artifacts: "./artifacts" }, mocha: { timeout: 40000 } } module.exports = { defaultNetwork: "sepolia", networks: { hardhat: { }, sepolia: { url: "https://eth-sepolia.g.alchemy.com/v2/", accounts: [privateKey1, privateKey2, ...] } }, solidity: { version: "0.8.28", settings: { optimizer: { enabled: true, runs: 200 } } }, paths: { sources: "./contracts", tests: "./test", cache: "./cache", artifacts: "./artifacts" }, mocha: { timeout: 40000 } } [# Networks configuration](#networks-configuration) ---------------------------------------------------- The `networks` config field is an optional object where network names map to their configuration. There are two kinds of networks in Hardhat: [JSON-RPC](https://eth.wiki/json-rpc/API) based networks, and the built-in Hardhat Network. You can customize which network is used by default when running Hardhat by setting the config's `defaultNetwork` field. If you omit this config, its default value is `"hardhat"`. ### [#Hardhat Network](#hardhat-network) Hardhat comes built-in with a special network called `hardhat`. When using this network, an instance of the [Hardhat Network](/hardhat-network/docs) will be automatically created when you run a task, script or test your smart contracts. Hardhat Network has first-class support of Solidity. It always knows which smart contracts are being run and exactly what they do and why they fail. Learn more about it [here](/hardhat-network/docs) . See [the Hardhat Network Configuration Reference](/hardhat-network/docs/reference#config) for details on what can be configured. ### [#JSON-RPC based networks](#json-rpc-based-networks) These are networks that connect to an external node. Nodes can be running in your computer, like Ganache, or remotely, like Infura or Alchemy. This kind of network is configured with objects with the following fields: * `url`: The url of the node. This argument is required for custom networks. * `chainId`: An optional number, used to validate the network Hardhat connects to. If not present, this validation is omitted. * `from`: The address to use as default sender. If not present the first account of the node is used. * `gas`: Its value should be `"auto"` or a number. If a number is used, it will be the gas limit used by default in every transaction. If `"auto"` is used, the gas limit will be automatically estimated. Default value: `"auto"`. * `gasPrice`: Its value should be `"auto"` or a number. This parameter behaves like `gas`. Default value: `"auto"`. * `gasMultiplier`: A number used to multiply the results of gas estimation to give it some slack due to the uncertainty of the estimation process. Default value: `1`. * `accounts`: This field controls which accounts Hardhat uses. It can use the node's accounts (by setting it to `"remote"`), a list of local accounts (by setting it to an array of hex-encoded private keys), or use an [HD Wallet](#hd-wallet-config) . Default value: `"remote"`. * `httpHeaders`: You can use this field to set extra HTTP Headers to be used when making JSON-RPC requests. It accepts a JavaScript object which maps header names to their values. Default value: `undefined`. * `timeout`: Timeout in ms for requests sent to the JSON-RPC server. If the request takes longer than this, it will be cancelled. Default value: `40000` for the localhost network, `20000` for the rest. ### [#HD Wallet config](#hd-wallet-config) To use an [HD Wallet](https://github.com/ethereumbook/ethereumbook/blob/develop/05wallets.asciidoc#hd_wallets) with Hardhat you should set your network's `accounts` field to an object with the following fields: * `mnemonic`: A required string with the mnemonic phrase of the wallet. * `path`: The HD parent of all the derived keys. Default value: `"m/44'/60'/0'/0"`. * `initialIndex`: The initial index to derive. Default value: `0`. * `count`: The number of accounts to derive. Default value: `20`. * `passphrase`: The passphrase for the wallet. Default value: empty string. For example: module.exports = { networks: { sepolia: { url: "...", accounts: { mnemonic: "test test test test test test test test test test test junk", path: "m/44'/60'/0'/0", initialIndex: 0, count: 20, passphrase: "", }, }, }, }; ### [#Default networks object](#default-networks-object) { localhost: { url: "http://127.0.0.1:8545" }, hardhat: { // See its defaults } } [# Solidity configuration](#solidity-configuration) ---------------------------------------------------- The `solidity` config is an optional field that can be one of the following: * A solc version to use, e.g. `"0.8.28"`. * An object which describes the configuration for a single compiler. It contains the following keys: * `version`: The solc version to use. * `settings`: An object with the same schema as the `settings` entry in the [Input JSON](https://docs.soliditylang.org/en/latest/using-the-compiler.html#input-description) . * An object which describes multiple compilers and their respective configurations. It contains the following: * `compilers`: A list of compiler configuration objects like the one above. * `overrides`: An optional map of compiler configuration override objects. This maps file names to compiler configuration objects. Take a look at the [compilation guide](/hardhat-runner/docs/guides/compile-contracts) to learn more. [# Path configuration](#path-configuration) -------------------------------------------- You can customize the different paths that Hardhat uses by providing an object to the `paths` field with the following keys: * `root`: The root of the Hardhat project. This path is resolved from `hardhat.config.js`'s directory. Default value: the directory containing the config file. * `sources`: The directory where your contracts are stored. This path is resolved from the project's root. Default value: `'./contracts'`. * `tests`: The directory where your tests are located. This path is resolved from the project's root. Default value: `'./test'`. * `cache`: The directory used by Hardhat to cache its internal stuff. This path is resolved from the project's root. Default value: `'./cache'`. * `artifacts`: The directory where the compilation artifacts are stored. This path is resolved from the project's root. Default value: `'./artifacts'`. [# Mocha configuration](#mocha-configuration) ---------------------------------------------- You can configure how your tests are run using the `mocha` entry, which accepts the same options as [Mocha](https://mochajs.org/) . [# Quickly integrating other tools from Hardhat's config](#quickly-integrating-other-tools-from-hardhat's-config) ------------------------------------------------------------------------------------------------------------------ Hardhat's config file will always run before any task, so you can use it to integrate with other tools, like importing `@babel/register`. [# Default EVM Version](#default-evm-version) ---------------------------------------------- The default EVM version is determined by solc's choice for a given compiler version. To specify a different EVM version, modify your `hardhat.config.js`: module.exports = { solidity: { version: "0.8.21", settings: { evmVersion: "shanghai", }, }, }; Since version `0.8.20`, solc's EVM default is `shanghai`, which can lead to issues in chains that don't support the `PUSH0` opcode. To address this, starting from `0.8.20` Hardhat defaults to `paris`. This value can be overridden by using the above configuration. --- # Writing tasks | Ethereum development environment for professionals by Nomic Foundation [#Writing tasks](#writing-tasks) ================================= At its core, Hardhat is a task runner that allows you to automate your development workflow. It comes with some built-in tasks, like `compile` and `test`, but you can add your own custom tasks as well. This guide will show you how to extend Hardhat's functionality using tasks. It assumes you have initialized a sample project. If you haven't done it, please read [this guide](/hardhat-runner/docs/guides/project-setup) first. [# Writing Hardhat Tasks](#writing-hardhat-tasks) -------------------------------------------------- Let's write a very simple task that prints the list of available accounts, and explore how it works. Copy this task definition and paste it into your hardhat config file: task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { console.log(account.address); } }); Now you should be able to run it: npx hardhat accounts We are using the `task` function to define our new task. Its first argument is the name of the task, and it's what we use in the command line to run it. The second argument is the description of the task, which is printed when you use `npx hardhat help`. The third argument is an async function that gets executed when you run the task. It receives two arguments: 1. An object with the arguments for the task. We didn't define any yet. 2. The [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) or HRE, which contains all the functionality of Hardhat and its plugins. You can also find all of its properties injected into the `global` namespace during the task execution. You are free to do anything you want in this function. In this case, we use `ethers.getSigners()` to obtain all the configured accounts and print each of their addresses. You can add parameters to your tasks, and Hardhat will handle their parsing and validation for you. You can also override existing tasks, which allows you to change how different parts of Hardhat work. To learn more about tasks, please read [this guide](/hardhat-runner/docs/advanced/create-task) . --- # Testing contracts | Ethereum development environment for professionals by Nomic Foundation [#Testing contracts](#testing-contracts) ========================================= After [compiling your contracts](/hardhat-runner/docs/guides/compile-contracts) , the next step is to write some tests to verify that they work as intended. This guide explains our recommended approach for testing contracts in Hardhat. It relies on [ethers](https://docs.ethers.org/v6/) to connect to [Hardhat Network](/hardhat-network) and on [Mocha](https://mochajs.org/) and [Chai](https://www.chaijs.com/) for the tests. It also uses our custom [Chai matchers](/hardhat-chai-matchers) and our [Hardhat Network Helpers](/hardhat-network-helpers) to make it easier to write clean test code. These packages are part of the Hardhat Toolbox plugin; if you followed the previous guides, you should already have them installed. While this is our recommended test setup, Hardhat is flexible: you can customize the approach or take a completely different path with other tools. ### [#Initial setup](#initial-setup) In this guide we’ll write some tests for the sample project. If you haven’t done it yet, go and [initialize it](/hardhat-runner/docs/guides/project-setup) . We recommend you [use TypeScript](/hardhat-runner/docs/guides/typescript) to get better autocompletion and catch possible errors earlier. This guide will assume you are using TypeScript, but you can click the tabs of the code examples to see the Javascript counterpart. The setup includes some example tests in the `test/Lock.ts` file, but ignore them for now. Instead, create a `test/my-tests.ts` file. During this guide we'll only run those, by running `npx hardhat test test/my-tests.ts`, instead of just `npx hardhat test`. ### [#A simple test](#a-simple-test) In the following sections we'll write some tests for the `Lock` contract that comes with the sample project. If you haven't read it yet, please take a look at the `contracts/Lock.sol` file. For our first test we’ll deploy the `Lock` contract and assert that the unlock time returned by the `unlockTime()` getter is the same one that we passed in the constructor: TypeScript JavaScript import { expect } from "chai"; import hre from "hardhat"; import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; describe("Lock", function () { it("Should set the right unlockTime", async function () { const lockedAmount = 1_000_000_000; const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; // deploy a lock contract where funds can be withdrawn // one year in the future const lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); }); }); const { expect } = require("chai"); const hre = require("hardhat"); const { time } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Lock", function () { it("Should set the right unlockTime", async function () { const lockedAmount = 1_000_000_000; const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; // deploy a lock contract where funds can be withdrawn // one year in the future const lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); }); }); First we import the things we are going to use: the [`expect`](https://www.chaijs.com/api/bdd/) function from `chai` to write our assertions, the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) (`hre`), and the [network helpers](/hardhat-network-helpers) to interact with the Hardhat Network. After that we use the `describe` and `it` functions, which are global Mocha functions used to describe and group your tests. (You can read more about Mocha [here](https://mochajs.org/#getting-started) .) The test itself is what’s inside the callback argument to the `it` function. First we set the values for the amount we want to lock (in [wei](https://ethereum.org/en/glossary/#wei) ) and the unlock time. For the latter we use [`time.latest`](/hardhat-network-helpers/docs/reference#latest()) , a network helper that returns the timestamp of the last mined block. Then we deploy the contract itself: we call `ethers.deployContract` with the name of the contract we want to deploy and an array of constructor arguments that has the unlock time. We also pass an object with the transaction parameters. This is optional, but we'll use it to send some ETH by setting its `value` field. Finally, we check that the value returned by the `unlockTime()` [getter](https://docs.soliditylang.org/en/v0.8.13/contracts.html#getter-functions) in the contract matches the value that we used when we deployed it. Since all the functions on a contract are async, we have to use the `await` keyword to get its value; otherwise, we would be comparing a promise with a number and this would always fail. ### [#Testing a function that reverts](#testing-a-function-that-reverts) In the previous test we checked that a getter function returned the correct value. This was a read-only function that can be called without paying a fee and without any risk. Other functions, however, can modify the state of the contract, like the `withdraw` function in the `Lock` contract. This means that we want some pre-conditions to be met for this function to be called successfully. If you look at its first lines you’ll see a couple of `require` checks for that purpose: function withdraw() public { require(block.timestamp >= unlockTime, "You can't withdraw yet"); require(msg.sender == owner, "You aren't the owner"); The first statement checks that the unlock time has been reached, and the second one checks that the address calling the contract is its owner. Let’s start by writing a test for the first pre-condition: it("Should revert with the right error if called too soon", async function () { // ...deploy the contract as before... await expect(lock.withdraw()).to.be.revertedWith("You can't withdraw yet"); }); In the previous test we used `.to.equal`, which is part of Chai and is used to compare two values. Here we are using [`.to.be.revertedWith`](/hardhat-chai-matchers/docs/reference#.revertedwith) , which asserts that a transaction reverts, and that the reason string of the revert is equal to the given string. The `.to.be.revertedWith` matcher is not part of Chai itself; instead, it’s added by the [Hardhat Chai Matchers](/hardhat-chai-matchers) plugin, which is included in the sample project we are using. Notice that in the previous test we wrote `expect(await ...)` but now we are doing `await expect(...)`. In the first case we were comparing two values in a synchronous way; the inner await is just there to wait for the value to be retrieved. In the second case, the whole assertion is async because it has to wait until the transaction is mined. This means that the `expect` call returns a promise that we have to await. ### [#Manipulating the time of the network](#manipulating-the-time-of-the-network) We are deploying our `Lock` contract with an unlock time of one year. If we want to write a test that checks what happens after the unlock time has passed, we can’t wait that amount of time. We could use a shorter unlock time, like 5 seconds, but that’s a less realistic value and it's still a long time to wait in a test. The solution is to simulate the passage of time. This can be done with the [`time.increaseTo`](/hardhat-network-helpers/docs/reference#increaseto(timestamp)) network helper, which mines a new block with the given timestamp: it("Should transfer the funds to the owner", async function () { // ...deploy the contract... await time.increaseTo(unlockTime); // this will throw if the transaction reverts await lock.withdraw(); }); As we mentioned, calling `lock.withdraw()` returns a Promise. If the transaction fails, the promise will be rejected. Using `await` will throw in that case, so the test will fail if the transaction reverts. ### [#Using a different address](#using-a-different-address) The second check done by the `withdraw` function is that the function was called by the owner of the contract. By default, deployments and function calls are done with the first [configured account](/hardhat-network/docs/reference#accounts) . If we want to check that only the owner can call some function, we need to use a different account and verify that it fails. The `ethers.getSigners()` returns an array with all the configured accounts. We can use the `.connect` method of the contract to call the function with a different account and check that the transaction reverts: it("Should revert with the right error if called from another account", async function () { // ...deploy the contract... const [owner, otherAccount] = await hre.ethers.getSigners(); // we increase the time of the chain to pass the first check await time.increaseTo(unlockTime); // We use lock.connect() to send a transaction from another account await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( "You aren't the owner" ); }); Here again we are calling a function and asserting that it reverts with the correct reason string. The difference is that we are using `.connect(anotherAccount)` to call the method from a different address. ### [#Using fixtures](#using-fixtures) So far we've deployed the `Lock` contract in each test. This means that at the beginning of each test we have to get the contract factory and then deploy the contract. This might be fine for a single contract but, if you have a more complicated setup, each test will have several lines at the beginning just to set up the desired state, and most of the time these lines will be the same. In a typical Mocha test, this duplication of code is handled with a `beforeEach` hook: TypeScript JavaScript import hre from "hardhat"; import { time } from "@nomicfoundation/hardhat-toolbox/network-helpers"; describe("Lock", function () { let lock: any; let unlockTime: number; let lockedAmount = 1_000_000_000; beforeEach(async function () { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); }); it("some test", async function () { // use the deployed contract }); }); const hre = require("hardhat"); const { time } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Lock", function () { let lock; let unlockTime; let lockedAmount = 1_000_000_000; beforeEach(async function () { const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); }); it("some test", async function () { // use the deployed contract }); }); However, there are two problems with this approach: * If you have to deploy many contracts, your tests will be slower because each one has to send multiple transactions as part of its setup. * Sharing the variables like this between the `beforeEach` hook and your tests is ugly and error-prone. The `loadFixture` helper in the Hardhat Network Helpers fixes both of these problems. This helper receives a _fixture_, a function that sets up the chain to some desired state. The first time `loadFixture` is called, the fixture is executed. But the second time, instead of executing the fixture again, `loadFixture` will reset the state of the network to the point where it was right after the fixture was executed. This is faster, and it undoes any state changes done by the previous test. This is how our tests look like when a fixture is used: TypeScript JavaScript import { expect } from "chai"; import hre from "hardhat"; import { time, loadFixture, } from "@nomicfoundation/hardhat-toolbox/network-helpers"; describe("Lock", function () { async function deployOneYearLockFixture() { const lockedAmount = 1_000_000_000; const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; const lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); return { lock, unlockTime, lockedAmount }; } it("Should set the right unlockTime", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); }); it("Should revert with the right error if called too soon", async function () { const { lock } = await loadFixture(deployOneYearLockFixture); await expect(lock.withdraw()).to.be.revertedWith("You can't withdraw yet"); }); it("Should transfer the funds to the owner", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); await time.increaseTo(unlockTime); // this will throw if the transaction reverts await lock.withdraw(); }); it("Should revert with the right error if called from another account", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); const [owner, otherAccount] = await hre.ethers.getSigners(); // we increase the time of the chain to pass the first check await time.increaseTo(unlockTime); // We use lock.connect() to send a transaction from another account await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( "You aren't the owner" ); }); }); const { expect } = require("chai"); const hre = require("hardhat"); const { loadFixture, time, } = require("@nomicfoundation/hardhat-toolbox/network-helpers"); describe("Lock", function () { async function deployOneYearLockFixture() { const lockedAmount = 1_000_000_000; const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60; const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS; const lock = await hre.ethers.deployContract("Lock", [unlockTime], { value: lockedAmount, }); return { lock, unlockTime, lockedAmount }; } it("Should set the right unlockTime", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); // assert that the value is correct expect(await lock.unlockTime()).to.equal(unlockTime); }); it("Should revert with the right error if called too soon", async function () { const { lock } = await loadFixture(deployOneYearLockFixture); await expect(lock.withdraw()).to.be.revertedWith("You can't withdraw yet"); }); it("Should transfer the funds to the owner", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); await time.increaseTo(unlockTime); // this will throw if the transaction reverts await lock.withdraw(); }); it("Should revert with the right error if called from another account", async function () { const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture); const [owner, otherAccount] = await hre.ethers.getSigners(); // we increase the time of the chain to pass the first check await time.increaseTo(unlockTime); // We use lock.connect() to send a transaction from another account await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith( "You aren't the owner" ); }); }); The fixture function can return anything you want, and the `loadFixture` helper will return it. We recommend returning an object like we did here, so you can extract only the values you care about for that test. ### [#Other tests](#other-tests) There are several other things you can test, like [which events are emitted](/hardhat-chai-matchers/docs/reference#.emit) or [how the balances of the involved addresses change](/hardhat-chai-matchers/docs/reference#balance-change) . Check the `test/Lock.ts` file to see the other examples. ### [#Measuring code coverage](#measuring-code-coverage) The Hardhat Toolbox includes the [`solidity-coverage`](https://github.com/sc-forks/solidity-coverage) plugin to measure the test coverage in your project. Just run the `coverage` task and you'll get a report: npx hardhat coverage ### [#Using the gas reporter](#using-the-gas-reporter) The Hardhat Toolbox also includes the [`hardhat-gas-reporter`](https://github.com/cgewecke/hardhat-gas-reporter) plugin to get metrics of how much gas is used, based on the execution of your tests. The gas reporter is run when the `test` task is executed and the `REPORT_GAS` environment variable is set: REPORT_GAS=true npx hardhat test For Windows users, set the environment variable for the PowerShell session with `$env:REPORT_GAS="true"`: $env:REPORT_GAS="true"; npx hardhat test ### [#Running tests in parallel](#running-tests-in-parallel) You can run your tests in parallel by using the `--parallel` flag: npx hardhat test --parallel Alternatively, use `parallel: true` in the `mocha` section of your Hardhat config. Most of the time, running your tests serially or in parallel should produce the same results, but there are some scenarios where tests run in parallel will behave differently: * In serial mode all the test files share the same instance of the Hardhat Runtime Environment, but in parallel mode this is not always the case. Mocha uses a pool of workers to execute the tests, and each worker starts with its own instance of the HRE. This means that if one test file deploys a contract, then that deployment will exist in some of the other test files and it won't in others. * The `.only` modifier doesn't work in parallel mode. As an alternative, you can use `--grep` to run specific tests. * Because parallel mode uses more system resources, the duration of individual tests might be longer, so there's a chance that some tests start timing out for that reason. If you run into this problem, you can increase the tests timeout in the Mocha section of your Hardhat config or using `this.timeout()` in your tests. * The order in which tests are executed is non-deterministic. There are some other limitations related to parallel mode. You can read more about them in Mocha's docs. And if you are running into some issue when using parallel mode, you can check their Troubleshooting parallel mode section. --- # Hardhat Runtime Environment (HRE) | Ethereum development environment for professionals by Nomic Foundation [#Hardhat Runtime Environment (HRE)](#hardhat-runtime-environment-(hre)) ========================================================================= [# Overview](#overview) ------------------------ The Hardhat Runtime Environment, or HRE for short, is an object containing all the functionality that Hardhat exposes when running a task, test or script. In reality, Hardhat _is_ the HRE. When you require Hardhat (`const hardhat = require("hardhat")`) you're getting an instance of the HRE. During initialization, the Hardhat configuration file essentially constructs a list of things to be added to the HRE. This includes tasks, configs and plugins. Then when tasks, tests or scripts run, the HRE is always present and available to access anything that is contained in it. The HRE has a role of centralizing coordination across all Hardhat components. This architecture allows for plugins to inject functionality that becomes available everywhere the HRE is accessible. [# Using the HRE](#using-the-hre) ---------------------------------- By default, the HRE gives you programmatic access to the task runner and the config system, and exports an [EIP1193-compatible](https://eips.ethereum.org/EIPS/eip-1193) Ethereum provider. Plugins can extend the HRE. For example, [hardhat-ethers](https://github.com/NomicFoundation/hardhat/tree/main/packages/hardhat-ethers) adds an Ethers.js instance to it, making it available to tasks, tests and scripts. ### [#As global variables](#as-global-variables) Before running a task, test or script, Hardhat injects the HRE into the global scope, turning all of its fields into global variables. When the task execution is completed, these global variables are removed, restoring their original value, if they had one. ### [#Explicitly](#explicitly) Not everyone likes magic global variables, and Hardhat doesn't force you to use them. Everything can be done explicitly in tasks, tests and scripts. When writing tests or scripts, you can use `require("hardhat")` to import the HRE. You can read more about this in [Accessing the HRE from outside a task](#accessing-the-hre-from-outside-a-task) . You can import the config API explicitly when defining your tasks, and receive the HRE explicitly as an argument to your actions. You can read more about this in [Creating your own tasks](/hardhat-runner/docs/advanced/create-task) . [# Accessing the HRE from outside a task](#accessing-the-hre-from-outside-a-task) ---------------------------------------------------------------------------------- The HRE can be used from any JavaScript or TypeScript file. To do so, you only have to import it with `require("hardhat")`. You can do this to keep more control over your development workflow, create your own tools, or to use Hardhat with other dev tools from the node.js ecosystem. Running test directly with [Mocha](https://www.npmjs.com/package/mocha) instead of `npx hardhat test` can be done by explicitly importing the HRE in them like this: const hre = require("hardhat"); const assert = require("assert"); describe("Hardhat Runtime Environment", function () { it("should have a config field", function () { assert.notEqual(hre.config, undefined); }); }); This way, tests written for Hardhat are just normal Mocha tests. This enables you to run them from your favorite editor without the need of any Hardhat-specific plugin. For example, you can [run them from Visual Studio Code using Mocha Test Explorer](/hardhat-runner/docs/advanced/vscode-tests) . [# Extending the HRE](#extending-the-hre) ------------------------------------------ The HRE only provides the core functionality that users and plugin developers need to start building on top of Hardhat. Using it to interface directly with Ethereum in your project can be somewhat harder than expected. Everything gets easier when you use higher-level libraries, like [Ethers.js](https://docs.ethers.org/v6/) or [ethereum-waffle](https://www.npmjs.com/package/ethereum-waffle) , but these libraries need some initialization to work, and that could get repetitive. Hardhat lets you hook into the HRE construction, and extend it with new functionality. This way, you only have to initialize everything once, and your new features or libraries will be available everywhere the HRE is used. You can do this by adding an HRE extender into a queue. This extender is just a synchronous function that receives the HRE and adds fields to it with your new functionality. These new fields will also get [injected into the global scope during runtime](#exporting-globally) . For example, adding an instance of [Web3.js](https://web3js.readthedocs.io/en/latest/) to the HRE can be done by installing the `web3` package and adding the following to your `hardhat.config.js`: extendEnvironment((hre) => { const Web3 = require("web3"); hre.Web3 = Web3; // hre.network.provider is an EIP1193-compatible provider. hre.web3 = new Web3(hre.network.provider); }); --- # Deploying your contracts | Ethereum development environment for professionals by Nomic Foundation [#Deploying your contracts](#deploying-your-contracts) ======================================================= To deploy your contracts, you can use [Hardhat Ignition](/ignition) , our declarative deployment system. You can deploy the `Lock` contract from the sample project by using its accompanying Ignition module. An Ignition module is a TypeScript or JavaScript file that allows you to specify what needs to be deployed. In the sample project, the Ignition module `LockModule` which deploys the `Lock` contract, is under the `./ignition/modules` directory and looks like this: TypeScript JavaScript // This setup uses Hardhat Ignition to manage smart contract deployments. // Learn more about it at https://hardhat.org/ignition import { buildModule } from "@nomicfoundation/hardhat-ignition/modules"; const JAN_1ST_2030 = 1893456000; const ONE_GWEI: bigint = 1_000_000_000n; const LockModule = buildModule("LockModule", (m) => { const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); const lock = m.contract("Lock", [unlockTime], { value: lockedAmount, }); return { lock }; }); export default LockModule; // This setup uses Hardhat Ignition to manage smart contract deployments. // Learn more about it at https://hardhat.org/ignition const { buildModule } = require("@nomicfoundation/hardhat-ignition/modules"); const JAN_1ST_2030 = 1893456000; const ONE_GWEI = 1_000_000_000n; module.exports = buildModule("LockModule", (m) => { const unlockTime = m.getParameter("unlockTime", JAN_1ST_2030); const lockedAmount = m.getParameter("lockedAmount", ONE_GWEI); const lock = m.contract("Lock", [unlockTime], { value: lockedAmount, }); return { lock }; }); You can deploy in the `localhost` network following these steps: 1. Start a [local node](/hardhat-runner/docs/getting-started#connecting-a-wallet-or-dapp-to-hardhat-network) npx hardhat node 2. Open a new terminal and deploy the Hardhat Ignition module in the `localhost` network TypeScript JavaScript npx hardhat ignition deploy ./ignition/modules/Lock.ts --network localhost npx hardhat ignition deploy ./ignition/modules/Lock.js --network localhost As a general rule, you can target any network from your Hardhat config using: npx hardhat ignition deploy ./ignition/modules/Lock.js --network If no network is specified, Hardhat Ignition will run against an in-memory instance of Hardhat Network. In the sample `LockModule` above, two module parameters are used: `unlockTime` which will default to the 1st of Jan 2030 and `lockedAmount` which will default to one Gwei. You can learn more about overriding these values by providing your own module parameters during deployment in our [Deploying a module](/ignition/docs/guides/deploy#defining-parameters-during-deployment) guide. Read more about Hardhat Ignition generally in the [Hardhat Ignition documentation](/ignition) . --- # Using the Hardhat console | Ethereum development environment for professionals by Nomic Foundation [#Using the Hardhat console](#using-the-hardhat-console) ========================================================= Hardhat comes built-in with an interactive JavaScript console. You can use it by running `npx hardhat console`: $ npx hardhat console Welcome to Node.js v12.10.0. Type ".help" for more information. > The `compile` task will be called before opening the console prompt, but you can skip this with the `--no-compile` parameter. The execution environment for the console is the same as for tasks, scripts and tests. This means the configuration has been processed, and the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) has been initialized and injected into the global scope. For example, you'll have access in the global scope to the `config` object: > config { solidity: { compilers: [ [Object] ], overrides: {} }, defaultNetwork: 'hardhat', ... } > And if you followed the [Getting started guide](/hardhat-runner/docs/getting-started) or installed `@nomicfoundation/hardhat-ethers`, the `ethers` object: > ethers { Signer: [Function: Signer] { isSigner: [Function] }, ... provider: EthersProviderWrapper { ... }, ... getSigners: [Function: getSigners], ... getContractAt: [Function: bound getContractAt] AsyncFunction } > Anything that has been injected into the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) will be magically available in the global scope. Alternatively, if you're the more explicit kind of developer, you can instead require the HRE explicitly: > const hre = require("hardhat") > hre.ethers { Signer: [Function: Signer] { isSigner: [Function] }, ... provider: EthersProviderWrapper { ... }, ... getSigners: [Function: getSigners], ... getContractAt: [Function: bound getContractAt] AsyncFunction } ### [#History](#history) You will also notice that the console has the handy history feature you expect out of most interactive terminals, including across different sessions. Try it by pressing the up arrow key. The Hardhat console is just an instance of a Node.js console, so anything you use in Node.js will also work. ### [#Asynchronous operations and top-level await](#asynchronous-operations-and-top-level-await) Interacting with the Ethereum network, and therefore with your smart contracts, are asynchronous operations. Therefore, most APIs and libraries use JavaScript's `Promise` for returning values. To make things easier, Hardhat's console supports top-level `await` statements (e.g. `console.log(await ethers.getSigners()`). --- # Using TypeScript | Ethereum development environment for professionals by Nomic Foundation [#Using TypeScript](#using-typescript) ======================================= In this guide, we will go through the steps to get a Hardhat project working with TypeScript. This means that you can write your Hardhat config, tasks, scripts and tests in [TypeScript](https://www.typescriptlang.org/) . For a general overview of using Hardhat refer to the [Getting started guide](/hardhat-runner/docs/getting-started) . [# Enabling TypeScript support](#enabling-typescript-support) -------------------------------------------------------------- Hardhat will automatically enable its TypeScript support if your config file ends in `.ts` and is written in valid TypeScript. This requires a few changes to work properly. ### [#Installing dependencies](#installing-dependencies) TIP If you installed [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) using npm 7 or higher, you don't need to follow these steps. Hardhat uses TypeScript and `ts-node` under the hood, so you need to install them. To do it, open your terminal, go to your Hardhat project, and run: npm 7+ npm 6 yarn npm install --save-dev ts-node typescript npm install --save-dev ts-node typescript yarn add --dev ts-node typescript To be able to write your tests in TypeScript, you also need these packages: npm 7+ npm 6 yarn npm install --save-dev chai@4 @types/node @types/mocha @types/chai@4 npm install --save-dev chai@4 @types/node @types/mocha @types/chai@4 yarn add --dev chai@4 @types/node @types/mocha @types/chai@4 ### [#TypeScript configuration](#typescript-configuration) You can easily turn a JavaScript Hardhat config file into a TypeScript one. Let's see how this is done starting with a fresh Hardhat project. Open your terminal, go to an empty folder, run `npx hardhat init`, and go through the steps to create a JavaScript project. When you're done your project directory should look something like this: $ ls -l total 1200 drwxr-xr-x 3 pato wheel 96 Oct 20 12:50 contracts/ -rw-r--r-- 1 pato wheel 567 Oct 20 12:50 hardhat.config.js drwxr-xr-x 434 pato wheel 13888 Oct 20 12:52 node_modules/ -rw-r--r-- 1 pato wheel 604835 Oct 20 12:52 package-lock.json -rw-r--r-- 1 pato wheel 460 Oct 20 12:52 package.json drwxr-xr-x 3 pato wheel 96 Oct 20 12:50 ignition/modules/ drwxr-xr-x 3 pato wheel 96 Oct 20 12:50 test/ Then, you should follow the steps mentioned in the [Installing dependencies](#installing-dependencies) section above. Now, we are going to rename the config file from `hardhat.config.js` to `hardhat.config.ts`, just run: mv hardhat.config.js hardhat.config.ts We need to make a single change to your config for it to work with TypeScript: you must use `import`/`export` instead of `require`/`module.exports`. By using TypeScript, you can also type your configuration, which will save you from typos and other mistakes. For example, the sample project's config turns from this: require("@nomicfoundation/hardhat-toolbox"); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.28", }; into this: import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; const config: HardhatUserConfig = { solidity: "0.8.28", }; export default config; Finally, you need to create a [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) file. Here's our recommended one: { "compilerOptions": { "target": "es2020", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "resolveJsonModule": true } } And that's really all it takes. Now you can write your config, tests, tasks and Ignition modules in TypeScript. [# Type-checking your project](#type-checking-your-project) ------------------------------------------------------------ For performance reasons, Hardhat won't type-check your project when you run a task. You can explicitly enable type-checking with the `--typecheck` flag. For example, if you run `npx hardhat test` and one of your tests has a compilation error, the test task will be executed anyway. But if you run `npx hardhat test --typecheck`, Hardhat will detect and throw the compilation error before starting to run the tests. Since type-checking adds significant overhead, we recommend to do it only in your CI or in pre-commit/pre-push hooks. [# Writing tests and scripts in TypeScript](#writing-tests-and-scripts-in-typescript) -------------------------------------------------------------------------------------- When using JavaScript, all the properties in the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) are injected into the global scope. When using TypeScript nothing will be available in the global scope and you will need to import everything explicitly using, for example, `import { ethers } from "hardhat"`. Follow the [Getting started guide](/hardhat-runner/docs/getting-started) and create a TypeScript project for a complete example on how to write tests using TypeScript. [# Type-safe smart contract interactions](#type-safe-smart-contract-interactions) ---------------------------------------------------------------------------------- TIP If you installed [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) you can skip this section, as it includes [`@typechain/hardhat`](https://github.com/ethereum-ts/TypeChain/tree/master/packages/hardhat) . If you want Hardhat to generate types for your smart contract you should install and use [`@typechain/hardhat`](https://github.com/ethereum-ts/TypeChain/tree/master/packages/hardhat) . It generates typing files (`*.d.ts`) based on ABI's, and it requires little to no configuration. [# Support for path mappings](#support-for-path-mappings) ---------------------------------------------------------- Typescript allows defining custom [path mappings](https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping) via the [`paths`](https://www.typescriptlang.org/tsconfig#paths) configuration option: { compilerOptions: { paths: { "~/*": ["src/*"] }, // ...Other compilerOptions }, } To support this option when running Hardhat tests or scripts, you need to install the package [`tsconfig-paths`](https://www.npmjs.com/package/tsconfig-paths) and register it in your `hardhat.config.ts`: import { HardhatUserConfig } from "hardhat/config"; // This adds support for typescript paths mappings import "tsconfig-paths/register"; const config: HardhatUserConfig = { // Your type-safe config goes here }; export default config; [# Running your tests and scripts directly with `ts-node`](#running-your-tests-and-scripts-directly-with--ts-node) ------------------------------------------------------------------------------------------------------------------- When running Hardhat scripts without the CLI, you need to use `ts-node`'s [`--files` flag](https://www.npmjs.com/package/ts-node#help-my-types-are-missing) . This can also be enabled with `TS_NODE_FILES=true`. --- # Multiple Solidity versions | Ethereum development environment for professionals by Nomic Foundation [#Multiple Solidity versions](#multiple-solidity-versions) =========================================================== Hardhat supports projects that use different, incompatible versions of solc. For example, if you have a project where some files use Solidity 0.5 and others use 0.6, you can configure Hardhat to use compiler versions compatible with those files like this: module.exports = { solidity: { compilers: [\ {\ version: "0.5.5",\ },\ {\ version: "0.6.7",\ settings: {},\ },\ ], }, }; This setup means that a file with a `pragma solidity ^0.5.0` will be compiled with solc 0.5.5 and a file with a `pragma solidity ^0.6.0` will be compiled with solc 0.6.7. It might happen that a file can be compiled with more than one of your configured compilers, for example a file with `pragma solidity >=0.5.0`. In that case, the compatible compiler with the highest version will be used (0.6.7 in this example). If you don't want that to happen, you can specify for each file which compiler should be used by using overrides: module.exports = { solidity: { compilers: [...], overrides: { "contracts/Foo.sol": { version: "0.5.5", settings: { } } } } } In this case, `contracts/Foo.sol` will be compiled with solc 0.5.5, no matter what's inside the `solidity.compilers` entry. Keep in mind that: * Overrides are full compiler configurations, so if you have any additional settings you're using you should set them for the override as well. * You have to use forward slashes (`/`) even if you are on Windows. TIP Hardhat also provides a way to use a custom Solidity compiler. Learn more from the [Using a custom Solidity compiler guide](/hardhat-runner/docs/other-guides/using-custom-solc) . --- # Compilation artifacts | Ethereum development environment for professionals by Nomic Foundation [#Compilation artifacts](#compilation-artifacts) ================================================= Compiling with Hardhat generates two files per compiled contract (not each `.sol` file): an artifact and a debug file. An **artifact** has all the information that is necessary to deploy and interact with the contract. These are compatible with most tools, including Truffle's artifact format. Each artifact consists of a json with the following properties: * `contractName`: A string with the contract's name. * `abi`: A [JSON description of the contract's ABI](https://solidity.readthedocs.io/en/latest/abi-spec.html#abi-json) . * `bytecode`: A `"0x"`\-prefixed hex string of the unlinked deployment bytecode. If the contract is not deployable, this has the string `"0x"`. * `deployedBytecode`: A `"0x"`\-prefixed hex string of the unlinked runtime/deployed bytecode. If the contract is not deployable, this has the string `"0x"`. * `linkReferences`: The bytecode's link references object [as returned by solc](https://solidity.readthedocs.io/en/latest/using-the-compiler.html) . If the contract doesn't need to be linked, this value contains an empty object. * `deployedLinkReferences`: The deployed bytecode's link references object [as returned by solc](https://solidity.readthedocs.io/en/latest/using-the-compiler.html) . If the contract doesn't need to be linked, this value contains an empty object. The **debug file** has all the information that is necessary to reproduce the compilation and to debug the contracts: this includes the original solc input and output, and the solc version used to compile it. [# Build info files](#build-info-files) ---------------------------------------- Hardhat optimizes compilation by compiling the smallest possible set of files at a time. Files that are compiled together have the same solc input and output. Since having this in each debug file would be meaningfully wasteful, this information is deduplicated in build info files that are placed in `artifacts/build-info`. Each contract debug file contains a relative path to its build info file, and each build info file contains the solc input, solc output and the solc version used. You shouldn't interact with these files directly. [# Reading artifacts](#reading-artifacts) ------------------------------------------ The \[HRE\] has an `artifacts` object with helper methods. For example, you can get a list with the paths to all artifacts by calling `hre.artifacts.getArtifactPaths()`. You can also read an artifact using the name of the contract by calling `hre.artifacts.readArtifact("Bar")`, which will return the content of the artifact for the `Bar` contract. This would only work if there was just one contract named `Bar` in the whole project; it would throw an error if there were two. To disambiguate this case, you would have to use the **Fully Qualified Name** of the contract: `hre.artifacts.readArtifact("contracts/Bar.sol:Bar")`. [# Directory structure](#directory-structure) ---------------------------------------------- The `artifacts/` directory has a structure that follows the original directory structure of the contracts. For example, if your contracts look like this: contracts ├── Foo.sol ├── Bar.sol └── Qux.sol then the structure of your artifact directory would look like this: artifacts └── contracts ├── Foo.sol │ ├── Foo.json │ ├── Foo.dbg.json │ ├── Foo2.json │ └── Foo2.dbg.json ├── Bar.sol │ ├── Bar.json │ └── Bar.dbg.json └── Qux.sol ├── Qux.json └── Qux.dbg.json Each Solidity file in your source will get a directory in the artifacts structure. Each of these directories contains one artifact (`.json`) file and one debug (`.dbg.json`) file for each _contract_ in that file. `Foo.sol`, for example, contains two contracts inside. Two Solidity files can have contracts with the same name, and this structure allows for that. --- # Verifying your contracts | Ethereum development environment for professionals by Nomic Foundation [#Verifying your contracts](#verifying-your-contracts) ======================================================= Once your contract is ready, the next step is to deploy it to a live network and verify its source code. Verifying a contract means making its source code public, along with the compiler settings you used, which allows anyone to compile it and compare the generated bytecode with the one that is deployed on-chain. Doing this is extremely important in an open platform like Ethereum. In this guide we'll explain how to do this in the [Etherscan](https://etherscan.io/) explorer. TIP If you wish to verify a contract deployed outside of Hardhat Ignition or if you'd like to verify on Sourcify instead of Etherscan, you can use the [hardhat-verify plugin](/hardhat-runner/plugins/nomicfoundation-hardhat-verify) . [# Getting an API key from Etherscan](#getting-an-api-key-from-etherscan) -------------------------------------------------------------------------- The first thing you need is an API key from Etherscan. To get one, go to [their site](https://etherscan.io/login) , sign in (or create an account if you don't have one) and open the "API Keys" tab. Then click the "Add" button and give a name (like "Hardhat") to the API key you are creating. After that you'll see the newly created key in the list. Store the API key as the configuration variable `ETHERSCAN_API_KEY`: $ npx hardhat vars set ETHERSCAN_API_KEY ✔ Enter value: ******************************** TIP Learn more about setting and using configuration variable in [our guide](/guides/configuration-variables) . Open your Hardhat config and set the Etherscan API key as the stored configuration variable `ETHERSCAN_API_KEY`: TypeScript JavaScript import { vars } from "hardhat/config"; const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); export default { // ...rest of the config... etherscan: { apiKey: ETHERSCAN_API_KEY, }, }; const { vars } = require("hardhat/config"); const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); module.exports = { // ...rest of the config... etherscan: { apiKey: ETHERSCAN_API_KEY, }, }; [# Deploying and verifying a contract in the Sepolia testnet](#deploying-and-verifying-a-contract-in-the-sepolia-testnet) -------------------------------------------------------------------------------------------------------------------------- We are going to use the [Sepolia testnet](https://ethereum.org/en/developers/docs/networks/#sepolia) to deploy and verify our contract, so you need to add this network in your Hardhat config. Here we are using [Infura](https://infura.io/) to connect to the network, but you can use an alternative JSON-RPC URL like [Alchemy](https://alchemy.com/) if you want. Infura | Typescript Alchemy | Typescript Infura | Javascript Alchemy | Javascript // Go to https://infura.io, sign up, create a new API key // in its dashboard, and store it as the "INFURA_API_KEY" // configuration variable const INFURA_API_KEY = vars.get("INFURA_API_KEY"); // Replace this private key with your Sepolia account private key // To export your private key from Coinbase Wallet, go to // Settings > Developer Settings > Show private key // To export your private key from Metamask, open Metamask and // go to Account Details > Export Private Key // Store the private key as the "SEPOLIA_PRIVATE_KEY" configuration // variable. // Beware: NEVER put real Ether into testing accounts const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY"); const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); export default { // ...rest of your config... networks: { sepolia: { url: `https://sepolia.infura.io/v3/${INFURA_API_KEY}`, accounts: [SEPOLIA_PRIVATE_KEY], }, }, etherscan: { apiKey: { sepolia: ETHERSCAN_API_KEY, }, }, }; // Go to https://alchemy.com, sign up, create a new App in // its dashboard, and store it as the "ALCHEMY_API_KEY" // configuration variable const ALCHEMY_API_KEY = vars.get("ALCHEMY_API_KEY"); // Replace this private key with your Sepolia account private key // To export your private key from Coinbase Wallet, go to // Settings > Developer Settings > Show private key // To export your private key from Metamask, open Metamask and // go to Account Details > Export Private Key // Store the private key as the "SEPOLIA_PRIVATE_KEY" configuration // variable. // Beware: NEVER put real Ether into testing accounts const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY"); const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); export default { // ...rest of your config... networks: { sepolia: { url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, accounts: [SEPOLIA_PRIVATE_KEY], }, }, etherscan: { apiKey: { sepolia: ETHERSCAN_API_KEY, }, }, }; // Go to https://infura.io, sign up, create a new API key // in its dashboard, and store it as the "INFURA_API_KEY" // configuration variable const INFURA_API_KEY = vars.get("INFURA_API_KEY"); // Replace this private key with your Sepolia account private key // To export your private key from Coinbase Wallet, go to // Settings > Developer Settings > Show private key // To export your private key from Metamask, open Metamask and // go to Account Details > Export Private Key // Store the private key as the "SEPOLIA_PRIVATE_KEY" configuration // variable. // Beware: NEVER put real Ether into testing accounts const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY"); const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); module.exports = { // ...rest of your config... networks: { sepolia: { url: `https://sepolia.infura.io/v3/${INFURA_API_KEY}`, accounts: [SEPOLIA_PRIVATE_KEY], }, }, etherscan: { apiKey: { sepolia: ETHERSCAN_API_KEY, }, }, }; // Go to https://alchemy.com, sign up, create a new App in // its dashboard, and store it as the "ALCHEMY_API_KEY" // configuration variable const ALCHEMY_API_KEY = vars.get("ALCHEMY_API_KEY"); // Replace this private key with your Sepolia account private key // To export your private key from Coinbase Wallet, go to // Settings > Developer Settings > Show private key // To export your private key from Metamask, open Metamask and // go to Account Details > Export Private Key // Store the private key as the "SEPOLIA_PRIVATE_KEY" configuration // variable. // Beware: NEVER put real Ether into testing accounts const SEPOLIA_PRIVATE_KEY = vars.get("SEPOLIA_PRIVATE_KEY"); const ETHERSCAN_API_KEY = vars.get("ETHERSCAN_API_KEY"); module.exports = { // ...rest of your config... networks: { sepolia: { url: `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_API_KEY}`, accounts: [SEPOLIA_PRIVATE_KEY], }, }, etherscan: { apiKey: { sepolia: ETHERSCAN_API_KEY, }, }, }; To deploy on Sepolia you need to send some Sepolia ether to the address that's going to be making the deployment. You can get testnet ether from a faucet, a service that distributes testing-ETH for free. Here are some for Sepolia: * [Alchemy Sepolia Faucet](https://sepoliafaucet.com/) * [QuickNode Sepolia Faucet](https://faucet.quicknode.com/ethereum/sepolia) * [Ethereum Ecosystem Sepolia Faucet](https://www.ethereum-ecosystem.com/faucets/ethereum-sepolia) Now you are ready to deploy your contract, but first we are going to make the source code of our contract unique. The reason we need to do this is that the sample code from the previous section is already verified in Sepolia, so if you try to verify it you'll get an error. Open your contract and add a comment with something unique, like your GitHub's username. Keep in mind that whatever you include here will be, like the rest of the code, publicly available on Etherscan: // Author: @janedoe contract Lock { To run the deployment we will leverage the Ignition module `Lock` that we created in the [Deploying your contracts](/hardhat-runner/docs/guides/deploying) guide. Run the deployment using Hardhat Ignition and the newly added Sepolia network: TypeScript JavaScript npx hardhat ignition deploy ignition/modules/Lock.ts --network sepolia --deployment-id sepolia-deployment npx hardhat ignition deploy ignition/modules/Lock.js --network sepolia --deployment-id sepolia-deployment TIP The `--deployment-id` flag is optional, but it allows you to give a custom name to your deployment. This makes it easier to refer to later, for instance when you want to verify it. Lastly, to verify the deployed contract, you can run the `ignition verify` task and pass the deployment Id: npx hardhat ignition verify sepolia-deployment Alternatively, you can combine deployment and verification into one step, by invoking the `deploy` task with the `--verify` flag: TypeScript JavaScript npx hardhat ignition deploy ignition/modules/Lock.ts --network sepolia --verify npx hardhat ignition deploy ignition/modules/Lock.js --network sepolia --verify TIP If you get an error saying that the address does not have bytecode, it probably means that Etherscan has not indexed your contract yet. In that case, wait for a minute and then try again. After the `ignition verify` task is successfully executed, you'll see a link to the publicly verified code of your contract. --- # Command-line completion | Ethereum development environment for professionals by Nomic Foundation [#Command-line completion](#command-line-completion) ===================================================== Hardhat has a companion npm package that acts as a shorthand for `npx hardhat`, and at the same time, it enables command-line completions in your terminal. This package, `hardhat-shorthand`, installs a globally accessible binary called `hh` that runs your locally installed `hardhat`. [# Installation](#installation) -------------------------------- To use the Hardhat shorthand you need to install it **globally**: npm install --global hardhat-shorthand After doing this running `hh` will be equivalent to running `npx hardhat`. For example, instead of running `npx hardhat compile` you can run `hh compile`. ### [#Installing the command-line completions](#installing-the-command-line-completions) To enable autocomplete support you'll also need to install the shell completion script using `hardhat-completion`, which comes with `hardhat-shorthand`. Run `hardhat-completion install` and follow the instructions to install the completion script: $ hardhat-completion install ✔ Which Shell do you use ? · zsh ✔ We will install completion to ~/.zshrc, is it ok ? (y/N) · true => Added tabtab source line in "~/.zshrc" file => Added tabtab source line in "~/.config/tabtab/zsh/__tabtab.zsh" file => Wrote completion script to /home/fvictorio/.config/tabtab/zsh/hh.zsh file => Tabtab source line added to ~/.zshrc for hh package. Make sure to reload your SHELL. To try it out, open a **new** terminal, go to the directory of your Hardhat project, and try typing `hh` followed by tab: ![](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7) [# Context](#context) ---------------------- Out of best practice, Hardhat projects use a local installation of the npm package `hardhat` to make sure everyone working on the project is using the same version. This is why you need to use `npx` or npm scripts to run Hardhat. This approach has the downside of there being no way to provide autocomplete suggestions directly for the `hardhat` command, as well as making the CLI commands longer. These are the two issues that `hh` solves. [# Troubleshooting](#troubleshooting) -------------------------------------- ### [#"Autocompletion is not working"](#"autocompletion-is-not-working") First, make sure you installed the autocompletion script with `hardhat-completion install`, then either reload your shell or open a new terminal to try again. If you still have problems, make sure that your Hardhat config doesn't have any issues. You can do this by just running `hh`. If the command prints the help message, then your config is fine. If not, you'll see what the problem is. If you are using zsh, these are some other things you can try: * Run `declare -f _hh_completion`. If you don't get any output, then the completion script is not being loaded. * Check that your `.zshrc` has a line that loads a `__tabtab.zsh` file. This is the file that in turn should load the `hh` completion. * Check that this `__tabtab.zsh` exists, and that there is a `hh.zsh` file in that same directory. * Make sure that your `.zshrc` is autoloading `compinit`. This means that you should have something like `autoload -U compinit && compinit` before the `__tabtab.zsh` line. If you are using bash, try this: * Run `complete -p hh`. You should get `complete -o default -F _hh_completion hh` as the output. * Check that your `.bashrc` has a line that loads a `__tabtab.bash` file. This is the file that in turn should load the `hh` completion. * Check that this `__tabtab.bash` exists, and that there is a `hh.bash` file in that same directory. ### [#Windows user](#windows-user) `hardhat-shorthand` doesn't work well by default on Windows. Please read this to learn why and how to improve it. On Windows, the default `hh` command is associated with the HTML Help executable program (hh.exe). To use `hardhat-shorthand`, you can simply run `npx hh` instead of `hh`, but that won't work well with its autocompletion. If you want to use `hh` on Windows, you can follow these steps: 1. Run `npm config get prefix` to get the npm global packages installation location. 2. Add the npm location to the `Path` environment variable. 3. Make sure to add the npm location to `Path` before `%SystemRoot%` because default `hh.exe` is in `%SystemRoot%`, and it will take precedence over `hh-shorthand` otherwise. --- # Getting help | Ethereum development environment for professionals by Nomic Foundation [#Getting help](#getting-help) =============================== Hardhat has a strong community of users willing to help you in times of trouble. Please read this entire guide to learn where and how to ask for help more effectively. The first place to look for answers is the [GitHub Discussions section in the Hardhat repository.](https://github.com/NomicFoundation/hardhat) We recommend you search there first, as the answer may already exist. If you can't find what you are looking for on GitHub Discussions, you can [create a new Discussion](https://github.com/NomicFoundation/hardhat/discussions/new) . If you didn't have any luck on GitHub, or if you prefer a real-time chat, you can join our [Discord Server](https://hardhat.org/discord) . Please read its rules and ask for help in the right channel. [# Asking an effective question](#asking-an-effective-question) ---------------------------------------------------------------- To increase the chances of getting an answer quickly on GitHub Discussions and Discord, you need to make sure you write a good question first. To do so, you need to include: 1. A clear description of what you are trying to do. 2. The results you are getting, and how they differ from what you expect. 3. Which version of Hardhat you are running, and which plugins and their versions you are using. 4. Very specific and concise instructions on how to reproduce your problem. Ideally, provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) . Another good option is to provide a link to a public repository that provides an easy environment to reproduce the problem. [# Reporting a bug](#reporting-a-bug) -------------------------------------- If you think you've found a bug in Hardhat, please [report it](https://github.com/NomicFoundation/hardhat/issues) . However, _before_ reporting a bug, please follow these steps to ensure that a new bug report is actually warranted: 1. Make sure you are using the latest version of Hardhat and its plugins. Your problem may already be fixed. 2. Try to determine whether the issue is coming from a plugin by running your project with some of them disabled. We only accept bug reports for plugins published by us, all of which start with either `@nomiclabs/` or `@nomicfoundation/`. If you find an issue with a plugin published by someone else, you may be able to raise it with that publisher. 3. Use the search on GitHub to try to find other reports of the same problem. If you find one, please comment on the existing issue instead of creating a new one. Whenever reporting a bug, and ideally whenever commenting on an existing Issue, please include all the information described in [Asking an effective question](#asking-an-effective-question) . By providing as much information as possible, you greatly increase the chances of your problem getting fixed quickly. --- # Configuration variables | Ethereum development environment for professionals by Nomic Foundation [#Configuration variables](#configuration-variables) ===================================================== A Hardhat project can use configuration variables for user-specific values or for data that shouldn't be included in the code repository. These variables are set via tasks in the `vars` scope and can be retrieved in the config using the `vars` object. For example, if you do this in your config: const INFURA_API_KEY = vars.get("INFURA_API_KEY"); module.exports = { networks: { sepolia: { url: `https://sepolia.infura.io/v3/${INFURA_API_KEY}`, }, }, }; And then you set the `INFURA_API_KEY` with: $ npx hardhat vars set INFURA_API_KEY ✔ Enter value: ******************************** Then the URL for the `sepolia` network will be formed with the configuration variable you set. WARNING Configuration variables are stored in plain text on your disk. Avoid using this feature for data you wouldn’t normally save in an unencrypted file. Run `npx hardhat vars path` to find the storage's file location. [# Managing configuration variables](#managing-configuration-variables) ------------------------------------------------------------------------ Use the tasks under the `vars` scope to manage your configuration variables. ### [#`vars set`](#vars-set) Assigns a value to a configuration variable, or creates one if it doesn't exist: $ npx hardhat vars set TEST_API_KEY ### [#`vars get`](#vars-get) Displays a configuration variable's value: $ npx hardhat vars get TEST_API_KEY 1234abcd1234abcd1234abcd1234abcd ### [#`vars list`](#vars-list) Prints all the configuration variables stored on your machine: $ npx hardhat vars list TEST_API_KEY TEST_PK ### [#`vars delete`](#vars-delete) Removes a configuration variable: $ npx hardhat vars delete TEST_API_KEY [# Using variables in your configuration file](#using-variables-in-your-configuration-file) -------------------------------------------------------------------------------------------- Configuration variables that you have previously stored can be retrieved within your Hardhat configuration file. Use the `vars.get` method to obtain them: const { vars } = require("hardhat/config"); const INFURA_API_KEY = vars.get("INFURA_API_KEY"); module.exports = { sepolia: { url: `https://sepolia.infura.io/v3/${INFURA_API_KEY}`, accounts: [vars.get("TEST_PK")], }, }; For variables that may not exist, you can specify a default value as the second parameter: const salt = vars.get("DEPLOY_SALT", "12345"); You can also use `vars.has` to check if a variable exists: const accounts = vars.has("TEST_PK") ? [vars.get("TEST_PK")] : []; [# Setting up variables for a project](#setting-up-variables-for-a-project) ---------------------------------------------------------------------------- The `vars setup` task lists all the configuration variables used by the project. This is useful to know which ones you need to set up before running the project. ### [#Mandatory vs. optional variables](#mandatory-vs.-optional-variables) The output of `vars setup` separates mandatory variables from optional ones. A variable is considered mandatory if the configuration cannot be loaded without it. This happens when you retrieve the variable without a default value: vars.get("MANDATORY_VARIABLE"); However, when combined with `vars.has`, the variable is considered optional: vars.has("OPTIONAL_VARIABLE") ? [vars.get("OPTIONAL_VARIABLE")] : []; Variables always used with a default value are also considered optional: vars.get("ANOTHER_OPTIONAL_VARIABLE", "DEFAULT_VALUE"); [# Migrating from `dotenv`](#migrating-from--dotenv) ----------------------------------------------------- If you are using `dotenv`, we recommend you migrate to our built-in configuration variables manager. This will make it easier to share values across various Hardhat projects, and will minimize the risk of exposing sensitive data by accidentally uploading a `.env` file to a public repository. To migrate from `dotenv`, follow these steps: 1. Replace `process.env.KEY` references in your configuration with `vars.get("KEY")`. Replace conditions like `process.env.KEY !== undefined` with `vars.has("KEY")` 2. Run `npx hardhat vars setup` to identify all the variables that are used by your project. 3. Use `npx hardhat vars set` for each variable as indicated by the setup task. 4. After substituting all instances of `process.env`, you may uninstall the `dotenv` package and remove its import from your configuration. [# Overriding configuration variables with environment variables](#overriding-configuration-variables-with-environment-variables) ---------------------------------------------------------------------------------------------------------------------------------- Environment variables prefixed with `HARDHAT_VAR_` can be used to override the values of configuration variables. For example, if your config uses `vars.get("MY_KEY")` and you run Hardhat with the environment variable `HARDHAT_VAR_MY_KEY` set to some value, then that value is going to be used: HARDHAT_VAR_MY_KEY=123 npx hardhat some-task Keep in mind that changes to environment variables during the configuration execution are not recognized. For example, if you do this: process.env.HARDHAT_VAR_MY_KEY = "123"; console.log(vars.get("MY_KEY")); Then the value of `MY_KEY` _won't_ be `"123"`. --- # Writing scripts with Hardhat | Ethereum development environment for professionals by Nomic Foundation [#Writing scripts with Hardhat](#writing-scripts-with-hardhat) =============================================================== In this guide we will go through the steps of creating a script with Hardhat. For a general overview of using Hardhat refer to the [Getting started guide](/hardhat-runner/docs/getting-started) . You can write your own custom scripts that can use all of Hardhat's functionality; for example, in this guide, we will work through scripts that print the list of available accounts. There are two ways of writing a script that accesses the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) . [# Running scripts with the Hardhat CLI](#running-scripts-with-the-hardhat-cli) -------------------------------------------------------------------------------- You can write scripts that access the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) 's properties as global variables. These scripts must be run through Hardhat: `npx hardhat run script.js`. This makes it easy to port scripts that were developed for other tools and that inject variables into the global state. [# Standalone scripts: using Hardhat as a library](#standalone-scripts:-using-hardhat-as-a-library) ---------------------------------------------------------------------------------------------------- The second option leverages Hardhat's architecture to allow for more flexibility. Hardhat has been designed as a library, allowing you to get creative and build standalone CLI tools that access your development environment. This means that by simply requiring it: const hre = require("hardhat"); You can get access to all your tasks and plugins. To run these scripts you simply go through node: `node script.js`. To try this out, create a new directory called `scripts` in your project's root directory. Then, inside that directory, create a file called `accounts.js` with the following content: const hre = require("hardhat"); async function main() { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { console.log(account.address); } } main().catch((error) => { console.error(error); process.exitCode = 1; }); Now run the script: node scripts/accounts.js By accessing the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) at the top, you are allowed to run the script in a standalone fashion. ### [#Hardhat arguments](#hardhat-arguments) You can still pass arguments to Hardhat when running a standalone script. This is done by setting environment variables. Some of these are: * `HARDHAT_NETWORK`: Sets the network to connect to. * `HARDHAT_SHOW_STACK_TRACES`: Enables JavaScript stack traces of expected errors. * `HARDHAT_VERBOSE`: Enables Hardhat verbose logging. * `HARDHAT_MAX_MEMORY`: Sets the maximum amount of memory that Hardhat can use. For example, instead of doing `npx hardhat --network localhost run script.js`, you can do `HARDHAT_NETWORK=localhost node script.js`. Check our [Environment variables](/hardhat-runner/docs/reference/environment-variables) reference to learn more about this. --- # Creating a task | Ethereum development environment for professionals by Nomic Foundation [#Creating a task](#creating-a-task) ===================================== This guide will explore the creation of tasks in Hardhat, which are the core component used for automation. A task is a JavaScript async function with some associated metadata. This metadata is used by Hardhat to automate some things for you. Arguments parsing, validation, and help messages are taken care of. Everything you can do in Hardhat is defined as a task. The default actions that come out of the box are built-in tasks and they are implemented using the same APIs that are available to you as a user. To see the currently available tasks in your project, run `npx hardhat`: $ npx hardhat Hardhat version 2.9.10 Usage: hardhat [GLOBAL OPTIONS] [TASK OPTIONS] GLOBAL OPTIONS: --config A Hardhat config file. --emoji Use emoji in messages. --help Shows this message, or a task's help if its name is provided --max-memory The maximum amount of memory that Hardhat can use. --network The network to connect to. --show-stack-traces Show stack traces. --tsconfig A TypeScript config file. --verbose Enables Hardhat verbose logging --version Shows hardhat's version. AVAILABLE TASKS: check Check whatever you need clean Clears the cache and deletes all artifacts compile Compiles the entire project, building all artifacts console Opens a hardhat console flatten Flattens and prints contracts and their dependencies help Prints this message node Starts a JSON-RPC server on top of Hardhat Network run Runs a user-defined script after compiling the project test Runs mocha tests To get help for a specific task run: npx hardhat help [task] You can create additional tasks, which will appear in this list. For example, you might create a task to reset the state of a development environment, or to interact with your contracts, or to package your project. Let’s go through the process of creating one to interact with a smart contract. Tasks in Hardhat are asynchronous JavaScript functions that get access to the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) , which exposes its configuration and parameters, as well as programmatic access to other tasks and any plugin objects that may have been injected. For our example, we will use the [`@nomicfoundation/hardhat-toolbox`](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) , which includes the [ethers.js](https://docs.ethers.org/v6/) library to interact with our contracts. npm 7+ npm 6 yarn pnpm npm install --save-dev @nomicfoundation/hardhat-toolbox npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai@4 ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai@4 ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 pnpm add -D @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers chai@4 ethers Task creation code can go in `hardhat.config.js`, or whatever your configuration file is called. It’s a good place to create simple tasks. If your task is more complex, it's also perfectly valid to split the code into several files and `require` them from the configuration file. (If you’re writing a Hardhat plugin that adds a task, they can also be created from a separate npm package. Learn more about creating tasks through plugins in our [Building plugins section](/hardhat-runner/docs/advanced/building-plugins) .) **The configuration file is always executed on startup before anything else happens.** It's good to keep this in mind. We will load the Hardhat toolbox and add our task creation code to it. For this tutorial, we're going to create a task to get an account’s balance from the terminal. You can do this with the Hardhat’s config API, which is available in the global scope of `hardhat.config.js`: require("@nomicfoundation/hardhat-toolbox"); task("balance", "Prints an account's balance").setAction(async () => {}); /** @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: "0.8.28", }; After saving the file, you should be able to see the task in Hardhat: $ npx hardhat Hardhat version 2.9.10 Usage: hardhat [GLOBAL OPTIONS] [TASK OPTIONS] GLOBAL OPTIONS: --config A Hardhat config file. ... AVAILABLE TASKS: balance Prints an account's balance check Check whatever you need clean Clears the cache and deletes all artifacts ... To get help for a specific task run: npx hardhat help [task] Now let’s implement the functionality we want. We need to get the account address from the user. We can do this by adding a parameter to our task: task("balance", "Prints an account's balance") .addParam("account", "The account's address") .setAction(async () => {}); When you add a parameter to a task, Hardhat will handle its help messages for you: $ npx hardhat help balance Hardhat version 2.9.10 Usage: hardhat [GLOBAL OPTIONS] balance --account OPTIONS: --account The account's address balance: Prints an account's balance For global options help run: hardhat help Let’s now get the account’s balance. The [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment)  will be available in the global scope. By using Hardhat’s [ether.js plugin](https://github.com/NomicFoundation/hardhat/tree/main/packages/hardhat-ethers) , which is included in the Hardhat Toolbox, we get access to an ethers.js instance: task("balance", "Prints an account's balance") .addParam("account", "The account's address") .setAction(async (taskArgs) => { const balance = await ethers.provider.getBalance(taskArgs.account); console.log(ethers.formatEther(balance), "ETH"); }); Finally, we can run it: $ npx hardhat balance --account 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 10000.0 ETH And there you have it, your first fully functional Hardhat task, allowing you to interact with the Ethereum blockchain in an easy way. [# Advanced usage](#advanced-usage) ------------------------------------ You can create your own tasks in your `hardhat.config.js` file. The Config API will be available in the global environment, with functions for defining tasks. You can also import the API with `require("hardhat/config")` if you prefer to keep things explicit, and take advantage of your editor's autocomplete. Creating a task is done by calling the `task` function. It will return a `TaskDefinition` object, which can be used to define the task's parameters. The simplest task you can define is task( "hello", "Prints 'Hello, World!'", async function (taskArguments, hre, runSuper) { console.log("Hello, World!"); } ); `task`'s first argument is the task name. The second one is its description, which is used for printing help messages in the CLI. The third one is an async function that receives the following arguments: * `taskArguments` is an object with the parsed CLI arguments of the task. In this case, it's an empty object. * `hre` is the [Hardhat Runtime Environment](/hardhat-runner/docs/advanced/hardhat-runtime-environment) . * `runSuper` is only relevant if you are overriding an existing task, which we'll learn about next. Its purpose is to let you run the original task's action. Defining the action's arguments is optional. The Hardhat Runtime Environment and `runSuper` will also be available in the global scope. We can rewrite our "hello" task this way: task("hello", "Prints 'Hello, World!'", async () => { console.log("Hello, World!"); }); ### [#Tasks' action requirements](#tasks'-action-requirements) The only requirement for writing a task is that the `Promise` returned by its action must not resolve before every async process it started is finished. This is an example of a task whose action doesn't meet this requirement: task("BAD", "This task is broken", async () => { setTimeout(() => { throw new Error( "This task's action returned a promise that resolved before I was thrown" ); }, 1000); }); This other task uses a `Promise` to wait for the timeout to fire: task("delayed-hello", "Prints 'Hello, World!' after a second", async () => { return new Promise((resolve, reject) => { setTimeout(() => { console.log("Hello, World!"); resolve(); }, 1000); }); }); Manually creating a `Promise` can look challenging, but you don't have to do that if you stick to `async`/`await` and `Promise`\-based APIs. For example, you can use the npm package [`delay`](https://www.npmjs.com/package/delay) for a promisified version of `setTimeout`. ### [#Defining parameters](#defining-parameters) Hardhat tasks can receive named parameters with a value (eg `--parameter-name parameterValue`), flags with no value (eg `--flag-name`), positional parameters, or variadic parameters. Variadic parameters act like JavaScript's rest parameters. The Config API `task` function returns an object with methods to define all of them. Once defined, Hardhat takes control of parsing parameters, validating them, and printing help messages. Adding an optional parameter to the `hello` task can look like this: task("hello", "Prints a greeting") .addOptionalParam("greeting", "The greeting to print", "Hello, World!") .setAction(async ({ greeting }) => console.log(greeting)); And would be run with `npx hardhat hello --greeting Hola`. #### [#Positional parameters restrictions](#positional-parameters-restrictions) Positional and variadic parameters don't have to be named, and have the usual restrictions of a programming language: * No positional parameter can follow a variadic one * Required/mandatory parameters can't follow an optional one. Failing to follow these restrictions will result in an exception being thrown when loading Hardhat. #### [#Type validations](#type-validations) Hardhat takes care of validating and parsing the values provided for each parameter. You can declare the type of a parameter, and Hardhat will get the CLI strings and convert them into your desired type. If this conversion fails, it will print an error message explaining why. A number of types are available in the Config API through a `types` object. This object is injected into the global scope before processing your `hardhat.config.js`, but you can also import it explicitly with `const { types } = require("hardhat/config")` and take advantage of your editor's autocomplete. An example of a task defining a type for one of its parameters is task("hello", "Prints 'Hello' multiple times") .addOptionalParam( "times", "The number of times to print 'Hello'", 1, types.int ) .setAction(async ({ times }) => { for (let i = 0; i < times; i++) { console.log("Hello"); } }); Calling it with `npx hardhat hello --times notanumber` will result in an error. ### [#Overriding tasks](#overriding-tasks) Defining a task with the same name as an existing one will override the existing one. This is useful to change or extend the behavior of built-in and plugin-provided tasks. Task overriding works very similarly to overriding methods when extending a class. You can set your own action, which can call the overridden one. The only restriction when overriding tasks is that you can't add or remove parameters. Task override order is important since actions can only call the immediately overridden definition, using the `runSuper` function. Overriding built-in tasks is a great way to customize and extend Hardhat. To know which tasks to override, take a look at [src/builtin-tasks](https://github.com/NomicFoundation/hardhat/tree/main/packages/hardhat-core/src/builtin-tasks) . #### [#The `runSuper` function](#the--runsuper--function) `runSuper` is a function available to override a task's actions. It can be received as the third argument of the task or used directly from the global object. This function works like [JavaScript's `super` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) : it calls the task's previously defined action. If the task isn't overriding a previous task definition, then calling `runSuper` will result in an error. To check whether calling it would fail, you can use the `boolean` field `runSuper.isDefined`. The `runSuper` function receives a single optional argument: an object with the task arguments. If this argument isn't provided, the same task arguments received by the action calling it will be used. ### [#Subtasks](#subtasks) Creating tasks with lots of logic makes it hard to extend or customize them. Making multiple small and focused tasks that call each other is a better way to allow for extension. If you design your tasks in this way, users that want to change only a small aspect of them can override one of your subtasks. For example, the `compile` task is implemented as a pipeline of several tasks. It just calls subtasks like `compile:get-source-paths`, `compile:get-dependency-graph`, and `compile:build-artifacts`. We recommend prefixing intermediate tasks with their main task and a colon. To avoid help messages getting cluttered with lots of intermediate tasks, you can define those using the `subtask` config API function. The `subtask` function works almost exactly like `task`. The only difference is that tasks defined with it won't be included in help messages. To run a subtask, or any task whatsoever, you can use the `run` function. It takes two arguments: the name of the task to be run, and an object with its arguments. This is an example of a task running a subtask: task("hello-world", "Prints a hello world message").setAction( async (taskArgs, hre) => { await hre.run("print", { message: "Hello, World!" }); } ); subtask("print", "Prints a message") .addParam("message", "The message to print") .setAction(async (taskArgs) => { console.log(taskArgs.message); }); ### [#Scoped tasks](#scoped-tasks) You can group tasks under a _scope_. This is useful when you have several tasks that are related to each other in some way. const myScope = scope("my-scope", "Scope description"); myScope.task("my-task", "Do something") .setAction(async () => { ... }); myScope.task("my-other-task", "Do something else") .setAction(async () => { ... }); In this case, you can run these tasks with `npx hardhat my-scope my-task` and `npx hardhat my-scope my-other-task`. Scoped tasks can also be run programmatically: await hre.run({ scope: "my-scope", task: "my-task", }); --- # Building plugins | Ethereum development environment for professionals by Nomic Foundation [#Building plugins](#building-plugins) ======================================= In this section, we will explore the creation of plugins for Hardhat, which are the key component for integrating other tools and extending the built-in functionality. [# What exactly are plugins in Hardhat?](#what-exactly-are-plugins-in-hardhat?) -------------------------------------------------------------------------------- Plugins are bits of reusable configuration. Anything that you can do in a plugin can also be done in your config file. You can test your ideas in a config file and then move them into a plugin when ready. When developing a plugin the main tools available to integrate new functionality are extending the [Hardhat Runtime Environment](/advanced/hardhat-runtime-environment) , extending the Hardhat config, defining new tasks and overriding existing ones, which are all configuration actions achieved through code. Some examples of things you could achieve by creating a plugin are: running a linter when the `check` task runs, using different compiler versions for different files or generating a UML diagram for your contracts. [# Extending the Hardhat Runtime Environment](#extending-the-hardhat-runtime-environment) ------------------------------------------------------------------------------------------ Let’s go through the process of creating a plugin that adds new functionality to the Hardhat Runtime Environment. By doing this, we make sure our new feature is available everywhere. This means your plugin users can access it from tasks, tests, scripts and the Hardhat console. The Hardhat Runtime Environment (HRE) is configured through a queue of extension functions that you can add to using the `extendEnvironment()` function. It receives one parameter which is a callback which will be executed after the HRE is initialized. If `extendEnvironment` is called multiple times, its callbacks will be executed in order. For example, adding the following to `hardhat.config.js`: extendEnvironment((hre) => { hre.hi = "Hello, Hardhat!"; }); Will make `hi` available everywhere where the environment is accessible. extendEnvironment((hre) => { hre.hi = "Hello, Hardhat!"; }); task("envtest", async (args, hre) => { console.log(hre.hi); }); module.exports = {}; Will yield: $ npx hardhat envtest Hello, Hardhat! This is literally all it takes to put together a plugin for Hardhat. Now `hi` is available to be used in the Hardhat console, your tasks, tests and other plugins. [# Extending the Hardhat provider](#extending-the-hardhat-provider) -------------------------------------------------------------------- Next, we can take a look at how to add features on top of the default provider offered by Hardhat, found on `hre.network.provider`. Doing this, any extra functionality you add will be available everywhere, just as it would if you extend the [Hardhat Runtime Environment](#extending-the-hardhat-runtime-environment) . The Hardhat provider is configured through a queue of extension functions that you can add to by using the `extendProvider()` function. It receives one parameter which is a callback to be executed after the first call to `hre.network.provider.request()` is made. This happens only once. If `extendProvider` is called multiple times, its callbacks will be executed in order, and Hardhat will wait on each one to finish before executing the next one. Returning an entirely new provider is possible but not advisable. These callbacks can be `async`, and they will be `await`ed until they finish, so you should be careful when adding any functionality that might take a long time to resolve. It's important to keep in mind that after all callbacks are executed, the provider will be wrapped by Hardhat's built-in extenders. This means that the object returned by `extendProvider` is not the same as the one found on `hre.network.provider`, but its functionality is included there. For example, adding the following to `hardhat.config.js`: import { ProviderWrapper } from 'hardhat/plugins' class FixedGasProvider extends ProviderWrapper { constructor( public readonly gasPrice, protected readonly _wrappedProvider ) { super(_wrappedProvider); } public async request(args) { if (args.method === "eth_estimateGas") { return this.gasPrice; } else if (args.method === "eth_sendTransaction") { const params = this._getParams(args); const tx = params[0]; // let's pretend that EIP-1559 never happened tx.gasPrice = this.gasPrice; } return this._wrappedProvider.request(args); } } extendProvider(async (provider, config, network) => { // We fix the gas price to be set by the config or to a random high value const gasPrice = config.fixedGasPrice || "0x1000000" const newProvider = new FixedGasProvider(gasPrice, provider); return newProvider; }); Will make the `hre` provider use that gas price value everywhere it's used: task("request", async (args, hre) => { await hre.network.provider.request({method: /*{ method arguments }*/}); // this will run FixedGasProvider's request method above }); module.exports = {}; [# Using the Hardhat TypeScript plugin boilerplate](#using-the-hardhat-typescript-plugin-boilerplate) ------------------------------------------------------------------------------------------------------ For a complete example of a plugin you can take a look at the [Hardhat TypeScript plugin boilerplate project](https://github.com/NomicFoundation/hardhat-ts-plugin-boilerplate/) . Plugins don't need to be written in TypeScript, but we recommend doing it, as many of our users use it. Creating a plugin in JavaScript can lead to a subpar experience for them. ### [#Extending the HRE](#extending-the-hre) To learn how to successfully extend the [HRE](/hardhat-runner/docs/advanced/hardhat-runtime-environment) in TypeScript, and to give your users type information about your extension, take a look at [`src/index.ts`](https://github.com/NomicFoundation/hardhat-ts-plugin-boilerplate/blob/master/src/index.ts) in the boilerplate repo and read the [Extending the HRE](/hardhat-runner/docs/advanced/hardhat-runtime-environment#extending-the-hre) documentation. Make sure to keep the type extension in your main file, as that convention is used across different plugins. ### [#Extending the Hardhat config](#extending-the-hardhat-config) The boilerplate project also has an example on how to extend the Hardhat config. We strongly recommend doing this in TypeScript and properly extending the config types. An example on how to add fields to the Hardhat config can be found in [`src/index.ts`](https://github.com/NomicFoundation/hardhat-ts-plugin-boilerplate/blob/master/src/index.ts) . [# Plugin development best practices](#plugin-development-best-practices) -------------------------------------------------------------------------- ### [#Throwing errors from your plugins](#throwing-errors-from-your-plugins) To show better stack traces to your users when an error is meant to interrupt a task's execution, please consider throwing `HardhatPluginError` errors, which can be found in `hardhat/plugins`. If your error originated in your user's code, like a test or script calling one of your functions, you shouldn't use `HardhatPluginError`. ### [#Optimizing your plugin for better startup time](#optimizing-your-plugin-for-better-startup-time) Keeping startup time short is vital to give a good user experience. To do so, Hardhat and its plugins delay any slow import or initialization until the very last moment. To do so, you can use `lazyObject`, and `lazyFunction` from `hardhat/plugins`. An example on how to use them is present in [`src/index.ts`](https://github.com/NomicFoundation/hardhat-ts-plugin-boilerplate/blob/master/src/index.ts) . [# Notes on dependencies](#notes-on-dependencies) -------------------------------------------------- Knowing when to use a `dependency` or a `peerDependency` can be tricky. We recommend [these](https://yarnpkg.com/blog/2018/04/18/dependencies-done-right/) [articles](https://lexi-lambda.github.io/blog/2016/08/24/understanding-the-npm-dependency-model/) to learn about their distinctions. If you are still in doubt, these can be helpful: * **Rule of thumb #1:** Hardhat MUST be a peer dependency. * **Rule of thumb #2:** If your plugin P depends on another plugin P2, P2 should be a peer dependency of P, and P2's peer dependencies should be peer dependencies of P. * **Rule of thumb #3:** If you have a non-Hardhat dependency that your users may `require()`, it should be a peer dependency. * **Rule of thumb #4:** Every `peerDependency` should also be a `devDependency`. [# Hooking into the user's workflow](#hooking-into-the-user's-workflow) ------------------------------------------------------------------------ To integrate into your users' existing workflow, we recommend that plugin authors override built-in tasks whenever it makes sense. Examples of suggested overrides are: * Preprocessing smart contracts should override one of the `compile` subtasks. * Linter integrations should override the `check` task. * Plugins generating intermediate files should override the `clean` task. For a list of all the built-in tasks and subtasks please take a look at [`task-names.ts`](https://github.com/NomicFoundation/hardhat/blob/main/packages/hardhat-core/src/builtin-tasks/task-names.ts) --- # Using ES modules | Ethereum development environment for professionals by Nomic Foundation [#Using ES modules](#using-es-modules) ======================================= Node.js projects can use one of two module systems: CommonJS and ES Modules (ESM). Hardhat was designed mainly with CommonJS in mind, but in the last years adoption of ESM has been growing. This guide explains where you can use ESM in your Hardhat project and how to do it. [# Hardhat support for ES modules](#hardhat-support-for-es-modules) -------------------------------------------------------------------- You can write your scripts and tests as both CommonJS and ES modules. However, your Hardhat config, and any file imported by it, **must** be CommonJS modules. If your package uses ESM by default (that is, you have [`"type": "module"`](https://nodejs.org/api/packages.html#type) in your `package.json`), then your Hardhat config file must be named `hardhat.config.cjs`. Hardhat doesn't support [ESM in TypeScript projects](#esm-and-typescript-projects) . [# Using ES Modules in Hardhat](#using-es-modules-in-hardhat) -------------------------------------------------------------- The following sections explain how to use ES modules in new or existing Hardhat projects. ### [#Starting an ESM-first Hardhat project](#starting-an-esm-first-hardhat-project) If you want to start a Hardhat project that uses ES modules by default, first you have to initialize a Node.js project: npm 7+ npm 6 yarn pnpm npm init -y npm init -y yarn init -y pnpm init Open the `package.json` that was created and add a `"type": "module"` entry. This will make the project use ESM by default. After that, install Hardhat: npm 7+ npm 6 yarn pnpm npm install --save-dev hardhat npm install --save-dev hardhat yarn add --dev hardhat pnpm add -D hardhat and run `npx hardhat init` to create a Hardhat project: 888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 Welcome to Hardhat v2.22.18 ? What do you want to do? … ▸ Create a JavaScript project Create a TypeScript project (not available for ESM projects) Create an empty hardhat.config.cjs Quit Select the `Create a JavaScript project` option. This will initialize a Hardhat project where the scripts and tests are ES modules, and where the configuration has a `.cjs` extension. ### [#Migrating a project to ESM](#migrating-a-project-to-esm) If you have an existing Hardhat project and you want to convert it into an ESM project, follow these steps: 1. Edit your `package.json` and add a `"type": "module"` entry. 2. Rename your `hardhat.config.js` file to `hardhat.config.cjs`. 3. Migrate all your scripts and tests from CommonJS to ESM. Alternatively, you can rename them to have a `.cjs` extension instead of `.js`. ### [#Adding ESM files to an existing Hardhat project](#adding-esm-files-to-an-existing-hardhat-project) It's also possible to write ESM scripts and tests without making your whole project ESM by default. To do this, just create your scripts and tests with an `.mjs` extension. [# ESM and TypeScript projects](#esm-and-typescript-projects) -------------------------------------------------------------- At the moment, it's not possible to use ESM in TypeScript projects. Hardhat uses [`ts-node`](https://typestrong.org/ts-node/) to run TypeScript projects, which in turn relies on Node's loader hooks. This is all experimental and the current functionality is not enough for Hardhat's needs. If you need this feature, please let us know in [this issue](https://github.com/NomicFoundation/hardhat/issues/3385) . [# Learn more](#learn-more) ---------------------------- To learn more about ES modules in general, check these resources: * [Node.js docs](https://nodejs.org/api/packages.html) * [ES modules: A cartoon deep-dive](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/) * The [Modules chapter](https://exploringjs.com/impatient-js/ch_modules.html) of "JavaScript for impatient programmers" --- # Migrating away from hardhat-waffle | Ethereum development environment for professionals by Nomic Foundation [#Migrating away from hardhat-waffle](#migrating-away-from-hardhat-waffle) =========================================================================== In the past, our recommended setup included [Waffle](https://getwaffle.io) , by using the [`hardhat-waffle`](/hardhat-runner/plugins/nomiclabs-hardhat-waffle) plugin. However, we now recommend using [Hardhat Toolbox](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) , a plugin that bundles a curated set of useful packages. This set includes [Hardhat Chai Matchers](/hardhat-chai-matchers) and [Hardhat Network Helpers](/hardhat-network-helpers) , which work as an improved replacement for `hardhat-waffle`. Migrating to the Toolbox only takes a few minutes. If you do so, you'll get more functionality, like support for Solidity custom errors and native `bigint` support, and a more reliable testing experience. It will also make it easier for you to keep up to date with our recommended setup. [# Migrating to Hardhat Toolbox](#migrating-to-hardhat-toolbox) ---------------------------------------------------------------- Follow these steps to migrate your project to Hardhat Toolbox. 1. First you'll need to remove some packages from your project. npm 7+ npm 6 yarn pnpm npm uninstall @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai@4 ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers npm uninstall @nomiclabs/hardhat-waffle ethereum-waffle @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai@4 ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v5 @ethersproject/abi @ethersproject/providers yarn remove @nomiclabs/hardhat-waffle ethereum-waffle pnpm remove @nomiclabs/hardhat-waffle ethereum-waffle 2. Then you need to install the Toolbox. If you are using yarn or an old version of npm, you'll also have to install some other packages (the peer dependencies of the Toolbox). npm 7+ npm 6 yarn pnpm npm install --save-dev @nomicfoundation/hardhat-toolbox npm install --save-dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-ignition-ethers @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers @nomicfoundation/hardhat-ethers @nomicfoundation/hardhat-verify chai@4 ethers hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 yarn add --dev @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-ignition-ethers @nomicfoundation/hardhat-network-helpers @nomicfoundation/hardhat-chai-matchers@1 @nomiclabs/hardhat-ethers @nomiclabs/hardhat-etherscan chai@4 ethers@5 hardhat-gas-reporter solidity-coverage @typechain/hardhat typechain @typechain/ethers-v6 pnpm add -D @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-network-helpers ethers chai@4 3. Finally, remove `hardhat-waffle` from your imported plugins and import the Toolbox instead: TypeScript JavaScript - import "@nomiclabs/hardhat-waffle"; + import "@nomicfoundation/hardhat-toolbox"; - require("@nomiclabs/hardhat-waffle"); + require("@nomicfoundation/hardhat-toolbox"); Adding the Toolbox will make many other imports redundant, so you can remove any of these if you want: * `@nomicfoundation/hardhat-ethers` * `@nomicfoundation/hardhat-verify` * `@nomicfoundation/hardhat-ignition` * `@nomicfoundation/hardhat-ignition-ethers` * `hardhat-gas-reporter` * `solidity-coverage` * `@typechain/hardhat` Check the [Hardhat Chai Matchers](/hardhat-chai-matchers) and [Hardhat Network Helpers](/hardhat-network-helpers) docs to learn more about the functionality included in the Toolbox. --- # Integrating with Foundry | Ethereum development environment for professionals by Nomic Foundation [#Integrating with Foundry](#integrating-with-foundry) ======================================================= This guide explains how to combine Hardhat and [Foundry](https://book.getfoundry.sh/) in the same project using our [`@nomicfoundation/hardhat-foundry`](/hardhat-runner/plugins/nomicfoundation-hardhat-foundry) plugin. [# Setting up a hybrid project](#setting-up-a-hybrid-project) -------------------------------------------------------------- How to set up a project that combines Hardhat and Foundry depends on whether you have an existing Hardhat project or an existing Foundry project. ### [#Adding Foundry to a Hardhat project](#adding-foundry-to-a-hardhat-project) TIP Foundry relies on Git to work properly. Make sure your project is already a Git repository, or type `git init` to initialize one. If you have an existing Hardhat project and you want to use Foundry in it, you should follow these steps. First, run `forge --version` to make sure that you have Foundry installed. If you don't, go [here](https://getfoundry.sh/) to get it. After that, install the [`@nomicfoundation/hardhat-foundry`](/hardhat-runner/plugins/nomicfoundation-hardhat-foundry) plugin: npm 7+ npm 6 yarn pnpm npm install --save-dev @nomicfoundation/hardhat-foundry npm install --save-dev @nomicfoundation/hardhat-foundry yarn add --dev @nomicfoundation/hardhat-foundry pnpm add --save-dev @nomicfoundation/hardhat-foundry and import it in your Hardhat config: TypeScript JavaScript import "@nomicfoundation/hardhat-foundry"; require("@nomicfoundation/hardhat-foundry"); To complete the setup, run `npx hardhat init-foundry`. This task will create a `foundry.toml` file with the right configuration and install [`forge-std`](https://github.com/foundry-rs/forge-std) . ### [#Adding Hardhat to a Foundry project](#adding-hardhat-to-a-foundry-project) If you have an existing Foundry project and you want to use Hardhat in it, follow these steps. First, if you don't have a `package.json` already in your project, create one with `npm init`. Then install Hardhat, the [Hardhat Toolbox](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox) , and the [`@nomicfoundation/hardhat-foundry`](/hardhat-runner/plugins/nomicfoundation-hardhat-foundry) plugin: npm 7+ npm 6 yarn pnpm npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-foundry npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-foundry yarn add --dev hardhat @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-foundry pnpm add --save-dev hardhat @nomicfoundation/hardhat-toolbox @nomicfoundation/hardhat-foundry After that, initialize a Hardhat project with `npx hardhat init`. Choose the "Create an empty hardhat.config.js" option, and then import the plugin in `hardhat.config.js`: require("@nomicfoundation/hardhat-toolbox"); require("@nomicfoundation/hardhat-foundry"); You should now be able to compile your project with Hardhat and to add Hardhat scripts and tests. [# Working with a combined setup](#working-with-a-combined-setup) ------------------------------------------------------------------ Once you've set up a project as explained in the previous section, you'll be able to use both Hardhat and Foundry in it. These are some of the things you can do: * Write some tests [in JavaScript/TypeScript](/hardhat-runner/docs/guides/test-contracts) and run them with `npx hardhat test` * Write other tests [in Solidity](https://book.getfoundry.sh/forge/writing-tests) and run them with `forge test` * Compile your contracts with either `npx hardhat compile` or `forge build` * Write a [custom Hardhat task](/hardhat-runner/docs/advanced/create-task) and execute it Check [our docs](/hardhat-runner/docs) and [Foundry docs](https://book.getfoundry.sh/) to learn more. --- # Flattening your contracts | Ethereum development environment for professionals by Nomic Foundation [#Flattening your contracts](#flattening-your-contracts) ========================================================= Hardhat comes with a built-in `flatten` task that lets you combine the source code of multiple Solidity files. [# Flattening all your files](#flattening-all-your-files) ---------------------------------------------------------- If you use the `flatten` task without passing any other arguments, all the Solidity files in your project will be combined: $ npx hardhat flatten // Sources flattened with hardhat v2.12.3 https://hardhat.org // File contracts/Bar.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Bar {} // File contracts/Qux.sol ... The result will be printed to stdout. You can create a file with the flattened sources using the `>` redirection operator: $ npx hardhat flatten > Flattened.sol $ cat Flattened.sol // Sources flattened with hardhat v2.12.3 https://hardhat.org // File contracts/Bar.sol ... [# Flattening specific files](#flattening-specific-files) ---------------------------------------------------------- The `flatten` task can receive a path to the file you want to flatten: npx hardhat flatten contracts/Foo.sol In this case, the result will contain the source code of `Foo.sol` and all its transitive dependencies (the files that it imports, and the files that those files import, and so on). You can also use multiple files: npx hardhat flatten contracts/Foo.sol contracts/Bar.sol But if `Bar.sol` is a dependency of `Foo.sol`, then the result will be the same as in the previous example. As explained in the previous section, you can redirect the output to some file: npx hardhat flatten contracts/Foo.sol > Flattened.sol [# Circular dependencies](#circular-dependencies) -------------------------------------------------- Projects with circular dependencies cannot be flattened at the moment. If this is something you need, please upvote or comment [this issue](https://github.com/NomicFoundation/hardhat/issues/1486) . --- # Running tests in Visual Studio Code | Ethereum development environment for professionals by Nomic Foundation [#Running tests in Visual Studio Code](#running-tests-in-visual-studio-code) ============================================================================= TIP [Hardhat for Visual Studio Code](/hardhat-vscode) is the official Hardhat extension that adds advanced support for Solidity to VSCode. If you use Visual Studio Code, give it a try! You can run your tests from [Visual Studio Code](https://code.visualstudio.com) by using one of its Mocha integration extensions. We recommend using [Mocha Test Explorer](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-mocha-test-adapter) . To use Mocha Test Explorer, you need to install it and follow these instructions. Install Mocha locally by running this: npm 7+ npm 6 yarn npm install --save-dev mocha npm install --save-dev mocha yarn add --dev mocha Then, you just need to create a file named `.mocharc.json` in your project's root directory with the following contents: { "require": "hardhat/register", "timeout": 40000 } WARNING Running test directly from Visual Studio Code won't compile your contracts automatically. Make sure to compile them manually. [# Running TypeScript tests](#running-typescript-tests) -------------------------------------------------------- If you are writing your tests in TypeScript, you should use this `.mocharc.json` instead: { "require": "hardhat/register", "timeout": 40000, "_": ["test/**/*.ts"] } --- # Solidity support | Ethereum development environment for professionals by Nomic Foundation [#Solidity support](#solidity-support) ======================================= Hardhat Network has first-class Solidity support. It always knows which smart contracts are being run, what exactly they do, and why they fail, making smart contract development easier. To do these kinds of things, Hardhat integrates very deeply with Solidity, which means that new versions of it aren't automatically supported. This section of the docs explains which versions are supported, and what happens if you use an unsupported one. [# Supported versions](#supported-versions) -------------------------------------------- These are the versions of Solidity that you can expect to fully work with Hardhat: * Any 0.5.x version starting from 0.5.1 * Any 0.6.x version * Any 0.7.x version * Any 0.8.x version up to and including 0.8.28 We recommend against using Hardhat with newer, unsupported versions of Solidity. But if you need to do so; please read on. ### [#Using an unsupported version](#using-an-unsupported-version) When running an unsupported version of Solidity, our integration may not work or behave incorrectly. This could mean that Solidity stack traces stop working, are incorrect, or incomplete. It could also mean that `console.log` stops working. Despite these features possibly being affected, the compilation and execution of your smart contracts won't be affected. You can still trust your test results and deploy smart contracts, but Hardhat may be less useful in the process. [# Support for IR-based codegen](#support-for-ir-based-codegen) ---------------------------------------------------------------- The solc compiler has a newer, alternative way of generating bytecode through an [intermediate representation](https://docs.soliditylang.org/en/latest/ir-breaking-changes.html) . This mode of compilation can be enabled with the `viaIR` setting. At the moment, this option only works well [when the optimizer is enabled](https://github.com/ethereum/solidity/issues/12533) . Since Hardhat works much better when the optimizer is disabled, we don't completely support the `viaIR` option yet. You can still enable it to compile your contracts and run your tests, but things like stack traces might not work correctly. If you use the `viaIR` option, we recommend you set the [optimization step sequence](https://docs.soliditylang.org/en/v0.8.17/yul.html#optimization-step-sequence) to `"u"`, to make Hardhat work as well as possible: solidity: { version: "0.8.28", // any version you want settings: { viaIR: true, optimizer: { enabled: true, details: { yulDetails: { optimizerSteps: "u", }, }, }, }, } --- # Verbose logging | Ethereum development environment for professionals by Nomic Foundation [#Verbose logging](#verbose-logging) ===================================== You can enable Hardhat's verbose mode by running it with its `--verbose` flag, or by setting the `HARDHAT_VERBOSE` environment variable to `true`. This mode will print a lot of output that can be super useful for debugging. An example of a Hardhat run in verbose mode is: $ npx hardhat test --verbose hardhat:core:hre Creating HardhatRuntimeEnvironment +0ms hardhat:core:hre Running task test +93ms hardhat:core:hre Running task compile +1ms hardhat:core:hre Running task compile:get-compilation-tasks +0ms hardhat:core:hre Running task compile:solidity +0ms hardhat:core:hre Running task compile:solidity:get-source-paths +0ms hardhat:core:hre Running task compile:solidity:get-source-names +9ms hardhat:core:hre Running task compile:solidity:get-dependency-graph +4ms hardhat:core:hre Running task compile:solidity:get-compilation-jobs +10ms hardhat:core:tasks:compile The dependency graph was dividied in '1' connected components +0ms hardhat:core:hre Running task compile:solidity:get-compilation-job-for-file +1ms hardhat:core:compilation-job File '/tmp/hardhat-project/contracts/Greeter.sol' will be compiled with version '0.7.3' +0ms hardhat:core:compilation-job File '/tmp/hardhat-project/node_modules/hardhat/console.sol' added as dependency of '/tmp/hardhat-project/contracts/Greeter.sol' +0ms hardhat:core:hre Running task compile:solidity:get-compilation-job-for-file +13ms hardhat:core:compilation-job File '/tmp/hardhat-project/node_modules/hardhat/console.sol' will be compiled with version '0.7.3' +1ms hardhat:core:hre Running task compile:solidity:handle-compilation-jobs-failures +1ms hardhat:core:hre Running task compile:solidity:filter-compilation-jobs +0ms hardhat:core:tasks:compile '1' jobs were filtered out +15ms hardhat:core:hre Running task compile:solidity:merge-compilation-jobs +1ms hardhat:core:hre Running task compile:solidity:compile-jobs +1ms hardhat:core:tasks:compile No compilation jobs to compile +1ms hardhat:core:hre Running task compile:solidity:log:nothing-to-compile +0ms hardhat:core:hre Running task compile:solidity:log:compilation-result +6ms hardhat:core:hre Running task test:get-test-files +1ms hardhat:core:hre Running task test:setup-test-environment +0ms hardhat:core:hre Running task test:show-fork-recommendations +0ms hardhat:core:hre Running task test:run-mocha-tests +0ms Greeter hardhat:core:hre Creating provider for network hardhat +78ms Deploying a Greeter with greeting: Hello, world! Changing greeting from 'Hello, world!' to 'Hola, mundo!' ✓ Should return the new greeting once it's changed (769ms) 1 passing (771ms) hardhat:core:cli Killing Hardhat after successfully running task test +0ms Hardhat uses the [debug](https://github.com/visionmedia/debug) package to manage logging. The `DEBUG` environment variable can be used to turn on the verbose logging and filter it using a simple wildcard pattern. --- # Oracles | Ethereum development environment for professionals by Nomic Foundation [#Working with blockchain oracles](#working-with-blockchain-oracles) ===================================================================== _This guide is based on the [ethereum.org oracles guide](https://ethereum.org/en/developers/docs/oracles) _ Oracles provide a bridge between the real-world and on-chain smart contracts by being a source of data that smart contracts can rely on, and act upon. Oracles play a critical role in facilitating the full potential of smart contract utility. Without a reliable connection to real-world data, smart contracts cannot effectively serve the real-world. [# Why are they needed?](#why-are-they-needed?) ------------------------------------------------ With a blockchain like Ethereum, you need every node in the network to replay every transaction and end up with the same result, guaranteed. APIs introduce potentially variable data. If you were sending ETH based on an agreed $USD value using a price API, the query would return a different result from one day to the next. Not to mention, the API could be hacked or deprecated. If this happens, the nodes in the network wouldn't be able to agree on Ethereum's current state, effectively breaking [consensus](https://ethereum.org/developers/docs/consensus-mechanisms/) . Oracles solve this problem by posting the data on the blockchain. So any node replaying the transaction will use the same immutable data that's posted for all to see. To do this, an oracle is typically made up of a smart contract and some off-chain components that can query APIs, then periodically send transactions to update the smart contract's data. [# The oracle problem](#the-oracle-problem) -------------------------------------------- As we mentioned, blockchain transactions cannot access off-chain data directly. At the same time, relying on a single source of truth to provide data is insecure and invalidates the decentralization of a smart contract. This is known as the oracle problem. We can avoid the oracle problem by using a decentralized oracle network, which pulls data from multiple sources; if one data source is hacked or fails, the smart contract will still function as intended. [# Security](#security) ------------------------ An oracle is only as secure as its data source(s). If a dapp uses Uniswap as an oracle for its ETH/DAI price feed, an attacker can move the price on Uniswap to manipulate the dapp's understanding of the current price. An example of how to combat this is [a feed system](https://docs.makerdao.com/smart-contract-modules/oracle-module/oracle-security-module-osm-detailed-documentation) like the one used by MakerDAO, which collates price data from many external price feeds instead of just relying on a single source. [# Architecture](#architecture) -------------------------------- This is an example of simple Oracle architecture, however, there are more ways to trigger off-chain computation. 1. Emit a log with your [smart contract event](https://ethereum.org/developers/docs/smart-contracts/anatomy/#events-and-logs) 2. An off-chain service has subscribed (usually using something like the JSON-RPC `eth_subscribe` command) to these specific logs. 3. The off-chain service proceeds to do some tasks as defined by the log. 4. The off-chain service responds with the data requested in a secondary transaction to the smart contract. This is how to get data in a 1 to 1 manner, however to improve security you may want to decentralize how you collect your off-chain data. [# Getting Price Data](#getting-price-data) -------------------------------------------- Below is an example of how you can retrieve the latest ETH price in your smart contract using a Chainlink price feed on Goerli: // SPDX-License-Identifier: MIT pragma solidity ^0.8.7; import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; contract PriceConsumerV3 { AggregatorV3Interface internal priceFeed; /** * Network: Goerli * Aggregator: ETH/USD * Address: 0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e */ constructor() { priceFeed = AggregatorV3Interface(0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e); } /** * Returns the latest price */ function getLatestPrice() public view returns (int) { (int price) = priceFeed.latestRoundData(); return price; } } [# Randomness](#randomness) ---------------------------- Randomness in computer systems, especially on blockchains, is challenging to achieve because general-purpose blockchains like Ethereum do not have inherent randomness. Another problem is the public nature of blockchain technology which makes finding a secure source of entropy difficult. Almost any mechanism of generating on-chain randomness using Solidity is vulnerable to [MEV attacks](https://ethereum.org/en/developers/docs/mev/) . It is possible to generate the random value off-chain and send it on-chain, but doing so imposes high trust requirements on users. They must believe the value was truly generated via unpredictable mechanisms and wasn’t altered in transit. Oracles designed for off-chain computation solve this problem by securely generating random outcomes off-chain that they broadcast on-chain along with cryptographic proofs attesting to the unpredictability of the process. An example is Chainlink VRF (Verifiable Random Function), which is a provably-fair and verifiable source of randomness designed for smart contracts. Smart contract developers can use Chainlink VRF as a tamper-proof random number generation (RNG) to build smart contracts for any applications which rely on unpredictable outcomes: * Blockchain games and NFTs * Random assignment of duties and resources (e.g. randomly assigning judges to cases) * Choosing a representative sample for consensus mechanisms Random numbers are difficult because blockchains are deterministic. To start with Chainlink VRF, create a new `VRFv2Consumer.sol` smart contract, which you can get from the [Official Chainlink Documentation](https://docs.chain.link/vrf/v2/subscription/examples/get-a-random-number) . Usually, you will create and manage your subscriptions on the [VRF Subscription Management](https://vrf.chain.link/) page, but with the [`@chainlink/hardhat-chainlink`](https://www.npmjs.com/package/@chainlink/hardhat-chainlink) plugin, you can automate that process. This plugin will help you to use the Chainlink protocol inside your tests, scripts & tasks. You will need to install it by typing: npm 7+ npm 6 yarn pnpm npm install --save-dev @chainlink/hardhat-chainlink npm install --save-dev @chainlink/hardhat-chainlink yarn add --dev @chainlink/hardhat-chainlink pnpm add -D @chainlink/hardhat-chainlink And import it inside the `hardhat.config` file: TypeScript JavaScript import "@chainlink/hardhat-chainlink"; require("@chainlink/hardhat-chainlink"); Then you can just expand the deployment script which will deploy the above `VRFv2Consumer` smart contract and do the VRF Management part. To do so, first prepare the `hardhat.config` file for the deployment on the Goerli network: networks: { goerli: { url: GOERLI_RPC_URL, accounts: [PRIVATE_KEY] } } And after that, expand your deployment script: // scripts/deploy.ts import { chainlink, ethers } from "hardhat"; async function main() { // NOTE: If you already have an active VRF Subscription, proceed to step 3 // Step 1: Create a new VRF Subscription const vrfCoordinatorAddress = `0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D`; const { subscriptionId } = await chainlink.createVrfSubscription( vrfCoordinatorAddress ); // Step 2: Fund VRF Subscription const linkTokenAddress = `0x326C977E6efc84E512bB9C30f76E30c160eD06FB`; const amountInJuels = ethers.BigNumber.from(`1000000000000000000`); // 1 LINK await chainlink.fundVrfSubscription( vrfCoordinatorAddress, linkTokenAddress, amountInJuels, subscriptionId ); // Step 3: Deploy your smart contract const VRFv2ConsumerFactory = await ethers.getContractFactory("VRFv2Consumer"); const VRFv2Consumer = await VRFv2ConsumerFactory.deploy(subscriptionId); await VRFv2Consumer.deployed(); console.log("VRFv2Consumer deployed to:", VRFv2Consumer.address); // Step 4: Add VRF Consumer contract to your VRF Subscription await chainlink.addVrfConsumer( vrfCoordinatorAddress, VRFv2Consumer.address, subscriptionId ); } main().catch((error) => { console.error(error); process.exitCode = 1; }); Finally, run the deployment script by typing: npx hardhat run scripts/deploy.ts --network goerli [# Use blockchain oracles](#use-blockchain-oracles) ---------------------------------------------------- There are multiple oracle applications you can integrate into your dapp: * [Chainlink](https://chain.link/) - _Chainlink decentralized oracle networks provide tamper-proof inputs, outputs, and computations to support advanced smart contracts on any blockchain._ * [Witnet](https://witnet.io/) - _Witnet is a permissionless, decentralized, and censorship-resistant oracle helping smart contracts to react to real world events with strong crypto-economic guarantees._ * [Kleros Oracle](https://kleros.io/oracle) - _Crowd-sourced on-chain smart contract oracle in collaboration with the Reality.eth cryptoeconomic mechanism for verifying real-world events on-chain, a subjective oracle solution able to answer any question with a publicly verifiable answer._ * [UMA Oracle](https://umaproject.org/products/optimistic-oracle) - _UMA's optimistic oracle allows smart contracts to quickly and receive any kind of data for different applications, including insurance, financial derivatives, and prediction market._ * [Tellor](https://tellor.io/) - _Tellor is a transparent and permissionless oracle protocol for your smart contract to easily get any data whenever it needs it._ * [Band Protocol](https://bandprotocol.com/) - _Band Protocol is a cross-chain data oracle platform that aggregates and connects real-world data and APIs to smart contracts._ * [Provable](https://provable.xyz/) - _Provable connects blockchain dapps with any external Web API and leverages TLSNotary proofs, Trusted Execution Environments (TEEs), and secure cryptographic primitives to guarantee data authenticity._ * [Paralink](https://paralink.network/) - _Paralink provides an open source and decentralized oracle platform for smart contracts running on Ethereum and other popular blockchains._ * [Dos.Network](https://dos.network/) - _DOS Network is a decentralized oracle service network to boost blockchain usability with real-world data and computation power._ --- # Stability guarantees | Ethereum development environment for professionals by Nomic Foundation [#Stability guarantees](#stability-guarantees) =============================================== Hardhat doesn't follow semver strictly, but it still aims to be a stable and easy-to-use platform, and we won't introduce breaking changes without notice. Instead, we may introduce breaking changes in some minor versions. Those breaking changes are part of these categories: * Changing the default config of Hardhat Network * Dropping support for unmaintained Node.js versions [# Hardhat Network default config](#hardhat-network-default-config) -------------------------------------------------------------------- Hardhat Network should closely resemble Ethereum Mainnet by default. Given that Ethereum does introduce breaking changes in the form of hardforks or network upgrades, we need to do the same with its default config. For example, we would eventually change the default `hardfork` config field in the network `hardhat`. We will only introduce these changes when a hardfork activates on Mainnet. This will be introduced in a minor version that changes the default `hardfork`, but will also modify other fields, like `blockGasLimit`, to match those of Mainnet. [# Node.js versions support](#node.js-versions-support) -------------------------------------------------------- Hardhat works with every released and supported **even** Node.js version. This includes all **even** Node.js versions with a release status of: `Current`, `Active LTS` or `Maintenance`. Hardhat will cease support two months after the Node.js version's end-of-life. After that period of time, we will stop testing against it, and print a warning when trying to use it. At that point, we will release a new minor version. We recommend running Hardhat using the latest _Active LTS_ Node.js version. You can learn about more Node.js releases [here](https://github.com/nodejs/Release) . [# How to avoid the breaking changes introduced by Hardhat](#how-to-avoid-the-breaking-changes-introduced-by-hardhat) ---------------------------------------------------------------------------------------------------------------------- In general, there's no need to avoid them. Using Hardhat with any actively maintained Node.js version means that you'd be running with defaults that closely resemble Ethereum Mainnet. If you want to play extra-safe, and make sure your project will continue running years down the road using the same Node.js version, please install Hardhat using a [tilde range](https://docs.npmjs.com/cli/v6/using-npm/semver#tilde-ranges-123-12-1) . --- # Common problems | Ethereum development environment for professionals by Nomic Foundation [#Common problems](#common-problems) ===================================== This section describes common problems with working with Hardhat and how to solve them. [# Out of memory errors when compiling large projects](#out-of-memory-errors-when-compiling-large-projects) ------------------------------------------------------------------------------------------------------------ If your project has lots of smart contracts, compiling them may require more memory than what Node allows by default and crash. If you are experiencing this problem, you can use Hardhat's `--max-memory` argument: npx hardhat --max-memory 4096 compile If you find yourself using this all the time, you can set it with an environment variable in your `.bashrc` (if using bash) or `.zshrc` (if using zsh): `export HARDHAT_MAX_MEMORY=4096`. [# Using Hardhat with a proxy server](#using-hardhat-with-a-proxy-server) -------------------------------------------------------------------------- Hardhat supports the `http_proxy` environment variable. When this variable is set, Hardhat will send its requests through the given proxy for things like JSON-RPC requests, mainnet forking and downloading compilers. There's also support for the `no_proxy` variable, which accepts a comma separated list of hosts or `"*"`. Any host included in this list will not be proxied. Note that requests to `"localhost"` or `"127.0.0.1"` are never proxied. --- # Environment variables | Ethereum development environment for professionals by Nomic Foundation [#Environment variables](#environment-variables) ================================================= You can use certain environment variables to configure Hardhat's behavior. [# Setting parameters with environment variables](#setting-parameters-with-environment-variables) -------------------------------------------------------------------------------------------------- Every global flag or parameter accepted by Hardhat can also be specified using an environment variable. For example, to select the network you normally do: npx hardhat ignition deploy ./ignition/modules/Lock.js --network localhost But you can get the same behavior by setting the `HARDHAT_NETWORK` environment variable: HARDHAT_NETWORK=localhost npx hardhat ignition deploy ./ignition/modules/Lock.js In general, each flag or parameter of the form `--some-option` can be set using the `HARDHAT_SOME_OPTION` environment variable. For flags, which don't accept values, you can enable or disable them by setting them to `true` or `false`: HARDHAT_VERBOSE=true npx hardhat ignition deploy ./ignition/modules/Lock.js Options specified with the `--some-option` form have precedence over environment variables. That is, if you run: HARDHAT_NETWORK=mainnet npx hardhat ignition deploy ./ignition/modules/Lock.js --network localhost then the `localhost` network is going to be used. [# Other environment variables](#other-environment-variables) -------------------------------------------------------------- Besides the environment variables that correspond to global parameters, there are some special environment variables that affect how Hardhat works. Variables starting with `HARDHAT_EXPERIMENTAL_` are experimental and could be removed in future versions. * `HARDHAT_DISABLE_TELEMETRY_PROMPT`: if set to `true`, Hardhat won't prompt the user asking for telemetry consent. This prompt is already not shown in CIs or when the output is not a TTY, but in some cases (like automated scripts that write to stdout) you might want to set this variable. * `HARDHAT_EXPERIMENTAL_ALLOW_NON_LOCAL_INSTALLATION`: if set to `true`, Hardhat won't check if the `hardhat` package is locally installed. --- # Hardhat errors | Ethereum development environment for professionals by Nomic Foundation [#Hardhat errors](#hardhat-errors) =================================== This section contains a list of all the possible errors you may encounter when using Hardhat and an explanation of each of them. [# General errors](#general-errors) ------------------------------------ ### #[HH1: You are not inside a Hardhat project](#HH1) You are trying to run Hardhat outside of a Hardhat project. You can learn how to use Hardhat by reading the [Getting Started guide](/hardhat-runner/docs/getting-started) . ### #[HH2: Unsupported Node.js](#HH2) Hardhat doesn't support your Node.js version. Please upgrade your version of Node.js and try again. ### #[HH3: Unsupported operation](#HH3) You are trying to perform an unsupported operation. Unless you are creating a task or plugin, this is probably a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH4: Hardhat was already initialized](#HH4) Hardhat initialization was executed twice. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH5: Hardhat wasn't initialized](#HH5) Hardhat initialization failed. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH6: Hardhat Runtime Environment not created](#HH6) Hardhat initialization failed. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH7: Tried to create the Hardhat Runtime Environment twice](#HH7) The Hardhat initialization process was executed twice. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH8: Invalid Hardhat config](#HH8) You have one or more errors in your config file. Check the error message for details, or go to the [documentation](https://hardhat.org/config/) to learn more. ### #[HH9: Failed to load config file](#HH9) There was an error while loading your config file. The most common source of errors is trying to import the Hardhat Runtime Environment from your config or a file imported from it. This is not possible, as Hardhat can't be initialized while its config is being defined. You may also have accidentally imported `hardhat` instead of `hardhat/config`. Please make sure your config file is correct. To learn more about how to access the Hardhat Runtime Environment from different contexts go to [https://hardhat.org/hre](https://hardhat.org/hre) ### #[HH10: Attempted to modify the user's config](#HH10) An attempt to modify the user's config was made. This is probably a bug in one of your plugins. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH11: Invariant violation](#HH11) An internal invariant was violated. This is probably caused by a programming error in hardhat or in one of the used plugins. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH12: Hardhat is not installed or installed globally](#HH12) You tried to run Hardhat from a global installation or not installing it at all. This is not supported. Please install Hardhat locally using npm or Yarn, and try again. ### #[HH13: ts-node not installed](#HH13) You are running a Hardhat project that uses typescript, but you haven't installed ts-node. Please run this and try again: `npm install --save-dev ts-node` ### #[HH14: typescript not installed](#HH14) You are running a Hardhat project that uses typescript, but it's not installed. Please run this and try again: `npm install --save-dev typescript` ### #[HH15: You are not inside a Hardhat project and Hardhat failed to initialize a new one](#HH15) You are trying to run Hardhat outside of a Hardhat project, and we couldn't initialize one. If you were trying to create a new project, please try again using Windows Subsystem for Linux (WSL) or PowerShell. You can learn how to use Hardhat by reading the [Getting Started guide](/hardhat-runner/docs/getting-started) . ### #[HH16: conflicting files during project creation](#HH16) You are trying to create a new hardhat project, but there are existing files that would be overwritten by the creation process. Either try using a new directory name, or remove the conflicting files. ### #[HH17: Invalid big number](#HH17) Hardhat attempted to convert the input value to a BigInt, but no known conversion method was applicable to the given value. ### #[HH18: Corrupted lockfile](#HH18) Some versions of NPM are affected [by a bug](https://github.com/npm/cli/issues/4828) that leads to corrupt lockfiles being generated. This bug can only affect you if you, or someone at your team, installed the project without a lockfile, but with an existing node\_modules. To avoid it, please delete both your node\_modules and package-lock.json, and reinstall your project. Note that you don't need to do this every time you install a new dependency, but please make sure to delete your node\_modules every time you delete your package-lock.json. ### #[HH19: Hardhat config with .js extension in an ESM project](#HH19) Your project is an ESM project but your Hardhat config uses the .js extension. Hardhat config files cannot be an ES module. To fix this, rename your Hardhat config to use the .cjs extension. ### #[HH20: Initializing a TypeScript sample project in an ESM project](#HH20) Your project is an ESM project (you have "type": "module" set in your package.json) and you are trying to initialize a TypeScript project. This is not supported yet. ### #[HH21: Uninitialized provider](#HH21) You tried to access an uninitialized provider. This is most likely caused by using the internal wrapped provider directly before using it to send a request or initializing it. To initialize the provider, make sure you first call `.init()` or any method that hits a node like request, send or sendAsync. ### #[HH22: Invalid read: a directory cannot be read](#HH22) An attempt was made to read a file, but a path to a directory was provided. Please double check the file path. ### #[HH23: Hardhat project already created](#HH23) Cannot create a new Hardhat project, the current folder is already associated with a project. ### #[HH24: Not inside an interactive shell](#HH24) You are trying to initialize a project but you are not in an interactive shell. Please re-run the command inside an interactive shell. [# Network related errors](#network-related-errors) ---------------------------------------------------- ### #[HH100: Selected network doesn't exist](#HH100) You are trying to run Hardhat with a nonexistent network. Read the [documentation](https://hardhat.org/hardhat-runner/docs/config#networks-configuration) to learn how to define custom networks. ### #[HH101: Connected to the wrong network](#HH101) Your config specifies a chain id for the network you are trying to use, but Hardhat detected a different chain id. Please make sure you are setting your config correctly. ### #[HH102: Missing `data` param when calling eth\_sign.](#HH102) You called `eth_sign` with incorrect parameters. Please check that you are sending a `data` parameter. ### #[HH103: Unrecognized account](#HH103) You are trying to send a transaction or sign some data with an account not managed by your Ethereum node nor Hardhat. Please double check your accounts and the `from` parameter in your RPC calls. ### #[HH104: Missing transaction parameter](#HH104) You are trying to send a transaction with a locally managed account, and some parameters are missing. Please double check your transactions' parameters. ### #[HH105: No remote accounts available](#HH105) No local account was set and there are accounts in the remote node. Please make sure that your Ethereum node has unlocked accounts. ### #[HH106: Invalid HD path](#HH106) An invalid HD/BIP32 derivation path was provided in your config. Read the [documentation](https://hardhat.org/hardhat-runner/docs/config#hd-wallet-config) to learn how to define HD accounts correctly. ### #[HH107: Invalid JSON-RPC value](#HH107) One of your transactions sent or received an invalid JSON-RPC QUANTITY value. Please double check your calls' parameters and keep your Ethereum node up to date. ### #[HH108: Cannot connect to the network](#HH108) Cannot connect to the network. Please make sure your node is running, and check your internet connection and networks config. ### #[HH109: Network timeout](#HH109) One of your JSON-RPC requests timed out. Please make sure your node is running, and check your internet connection and networks config. ### #[HH110: Invalid JSON-RPC response](#HH110) One of your JSON-RPC requests received an invalid response. Please make sure your node is running, and check your internet connection and networks config. ### #[HH111: Could not derive an HD key](#HH111) One of your HD keys could not be derived. Try using another mnemonic or deriving less keys. ### #[HH112: Invalid JSON-RPC value](#HH112) One of your calls sent or received an invalid JSON-RPC DATA value. Please double check your calls' parameters and keep your Ethereum node up to date. ### #[HH113: Invalid `data` param when calling eth\_signTypedData\_v4.](#HH113) You called `eth_signTypedData_v4` with incorrect parameters. Please check that you are sending a `data` parameter with a JSON string or object conforming to EIP712 TypedData schema. ### #[HH114: Incompatible fee price parameters](#HH114) You are trying to send a transaction with a locally managed account, and its parameters are incompatible. You sent both gasPrice, and maxFeePerGas or maxPriorityFeePerGas. Please double check your transactions' parameters. ### #[HH115: Missing fee price parameters](#HH115) You are trying to send a transaction with a locally managed account, and no fee price parameters were provided. You need to send gasPrice, or maxFeePerGas and maxPriorityFeePerGas. Please double check your transactions' parameters. ### #[HH116: Missing `address` param when calling personal\_sign.](#HH116) You called `personal_sign` with incorrect parameters. Please check that you are sending an `address` parameter. ### #[HH117: Empty string `%value%` for network or forking URL - Expected a non-empty string.](#HH117) You are trying to connect to a network with an empty network or forking URL. Please check that you are sending a non-empty string for network or forking `URL` parameter. [# Task definition errors](#task-definition-errors) ---------------------------------------------------- ### #[HH200: Could not add positional param](#HH200) Could add a positional param to your task because there is already a variadic positional param and it has to be the last positional one. Please double check your task definitions. ### #[HH201: Repeated param name](#HH201) Could not add a param to your task because its name is already used. Please double check your task definitions. ### #[HH202: Hardhat and task param names clash](#HH202) Could not add a param to your task because its name is used as a param for Hardhat. Please double check your task definitions. ### #[HH203: Optional param followed by a required one](#HH203) Could not add param to your task because it is required and it was added after an optional positional param. Please double check your task definitions. ### #[HH204: Tried to run task without an action](#HH204) A task was run, but it has no action set. Please double check your task definitions. ### #[HH205: `runSuper` not available](#HH205) You tried to call `runSuper` from a non-overridden task. Please use `runSuper.isDefined` to make sure that you can call it. ### #[HH206: Default value has incorrect type](#HH206) One of your tasks has a parameter whose default value doesn't match the expected type. Please double check your task definitions. ### #[HH207: Required parameter has a default value](#HH207) One of your tasks has a required parameter with a default value. Please double check your task definitions. ### #[HH208: Invalid casing in parameter name](#HH208) Your parameter names must use camelCase. Please double check your task definitions. ### #[HH209: Attempted to add mandatory params to an overridden task](#HH209) You can't add mandatory (non optional) param definitions in an overridden task. The only supported param additions for overridden tasks are flags and optional params. Please double check your task definitions. ### #[HH210: Attempted to add positional params to an overridden task](#HH210) You can't add positional param definitions in an overridden task. The only supported param additions for overridden tasks are flags and optional params. Please double check your task definitions. ### #[HH211: Attempted to add variadic params to an overridden task](#HH211) You can't add variadic param definitions in an overridden task. The only supported param additions for overridden tasks are flags and optional params. Please double check your task definitions. ### #[HH212: Invalid argument type](#HH212) Tasks that can be invoked from the command line require CLIArgumentType types for their arguments. What makes these types special is that they can be represented as strings, so you can write them down in the terminal. ### #[HH213: Attempted to create a scope with a name already used by a task](#HH213) You can't create a scope if a task with that name already exists. Please double check your task definitions. ### #[HH214: Attempted to create a task with a name already used by a scope](#HH214) You can't create a task if a scope with that name already exists. Please double check your task definitions. ### #[HH215: Use of deprecated remapping task](#HH215) This task has been deprecated in favor of a new approach. [# Arguments related errors](#arguments-related-errors) -------------------------------------------------------- ### #[HH300: Invalid environment variable value](#HH300) You are setting one of Hardhat's arguments using an environment variable, but it has an incorrect value. Please double check your environment variables. ### #[HH301: Invalid argument type](#HH301) One of your Hardhat or task arguments has an invalid type. Please double check your arguments. ### #[HH302: Invalid file argument](#HH302) One of your tasks expected a file as an argument, but you provided a nonexistent or non-readable file. Please double check your arguments. ### #[HH303: Unrecognized task](#HH303) Tried to run a nonexistent task. Please double check the name of the task you are trying to run. ### #[HH304: Unrecognized command line argument](#HH304) Hardhat couldn't recognize one of your command line arguments. This may be because you are writing it before the task name. It should come after it. Please double check how you invoked Hardhat. ### #[HH305: Unrecognized param](#HH305) Hardhat couldn't recognize one of your tasks' parameters. Please double check how you invoked Hardhat or ran your task. ### #[HH306: Missing task argument](#HH306) You tried to run a task, but one of its required arguments was missing. Please double check how you invoked Hardhat or ran your task. ### #[HH307: Missing task positional argument](#HH307) You tried to run a task, but one of its required arguments was missing. Please double check how you invoked Hardhat or ran your task. ### #[HH308: Unrecognized task positional argument](#HH308) You tried to run a task with more positional arguments than expected. Please double check how you invoked Hardhat or ran your task. ### #[HH309: Repeated task parameter](#HH309) You tried to run a task with a repeated parameter. Please double check how you invoked Hardhat or ran your task. ### #[HH310: Invalid casing in command line parameter](#HH310) You tried to run hardhat with a parameter with invalid casing. They must be lowercase. Please double check how you invoked Hardhat. ### #[HH311: Invalid JSON parameter](#HH311) You tried to run a task with an invalid JSON parameter. Please double check how you invoked Hardhat or ran your task. ### #[HH312: Subtask run from the command line](#HH312) You tried to run a subtask from the command line. This is not supported. Please run the help task to see the available options. ### #[HH313: The --typecheck flag was used in a javascript project](#HH313) You tried to run Hardhat with the `--typecheck` flag in a javascript project. This flag can only be used in typescript projects. ### #[HH314: Unrecognized scope](#HH314) Tried to run a task from a nonexistent scope. Please double check the scope of the task you are trying to run. ### #[HH315: Unrecognized scoped task](#HH315) Tried to run a nonexistent scoped task. Please double check the name of the task you are trying to run. [# Dependencies resolution errors](#dependencies-resolution-errors) -------------------------------------------------------------------- ### #[HH400: Solidity file not found](#HH400) Tried to resolve a nonexistent Solidity file as an entry-point. ### #[HH401: Solidity library not installed](#HH401) One of your Solidity sources imports a library that is not installed. Please double check your imports or install the missing dependency. ### #[HH402: Missing library file](#HH402) One of your libraries' files was imported but doesn't exist. Please double check your imports or update your libraries. ### #[HH403: Illegal Solidity import](#HH403) One of your libraries tried to use a relative import to import a file outside of its scope. This is disabled for security reasons. ### #[HH404: Imported file not found](#HH404) One of your source files imported a nonexistent file. Please double check your imports. ### [#\[HH405: Invalid import: use / instead of \](#HH405)](#[hh405:-invalid-import:-use-/-instead-of-](#hh405)) A Solidity file is trying to import another file via relative path and is using backslashes (\\) instead of slashes (/). You must always use slashes (/) in Solidity imports. ### #[HH406: Invalid import: trying to use an unsupported protocol](#HH406) A Solidity file is trying to import a file using an unsupported protocol, like http. You can only import files that are available locally or installed through npm. ### #[HH407: Invalid import: absolute paths unsupported](#HH407) A Solidity file is trying to import a file using its absolute path. This is not supported, as it would lead to hard-to-reproduce compilations. ### #[HH408: Invalid import: file outside of the project](#HH408) A Solidity file is trying to import a file that is outside of the project. This is not supported by Hardhat. ### #[HH409: Invalid import: wrong file casing](#HH409) A Solidity file is trying to import a file but its source name casing was wrong. Hardhat's compiler is case sensitive to ensure projects are portable across different operating systems. ### #[HH410: Incorrect source name casing](#HH410) You tried to resolve a Solidity file with an incorrect casing. Hardhat's compiler is case sensitive to ensure projects are portable across different operating systems. ### #[HH411: Invalid import: library not installed](#HH411) A Solidity file is trying to import another which belongs to a library that is not installed. Try installing the library using npm. ### #[HH412: Invalid import: includes own package's name](#HH412) A Solidity file is trying to import another using its own package name. This is most likely caused by an existing symlink for the package in your node\_modules. Use a relative import instead of referencing the package's name. ### #[HH413: Imported mapped file not found](#HH413) One of your source files imported a nonexistent or not installed file. Please double check your imports and installed libraries. ### #[HH414: Invalid import: a directory cannot be imported](#HH414) A Solidity file is attempting to import a directory, which is not possible. Please double check your imports. ### #[HH415: Ambiguous source names](#HH415) Two different source names map to the same file. This is probably caused by multiple remappings pointing to the same source file. [# Solidity related errors](#solidity-related-errors) ------------------------------------------------------ ### #[HH500: Invalid or unreleased `solc` version](#HH500) The Solidity version in your config is invalid or hasn't been released yet. If you are certain it has been released, run `npx hardhat clean --global` and try again. ### #[HH501: `solc` download failed](#HH501) Couldn't download `solc`. Please check your internet connection and try again. ### #[HH502: Couldn't obtain `solc` version list](#HH502) Couldn't download `solc`'s version list. Please check your internet connection and try again. ### #[HH503: Downloaded `solc` checksum verification failed](#HH503) Hardhat downloaded a version of the Solidity compiler, and its checksum verification failed. Please check your internet connection and try again. If this error persists, run `npx hardhat clean --global`. ### #[HH504: The solc compiler couldn't be obtained](#HH504) Hardhat couldn't obtain a valid solc compiler. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH505: Failed to run native solc](#HH505) Hardhat successfully downloaded a native version of solc but it doesn't run. If you are running MacOS, try installing Apple Rosetta. If this error persists, run "npx hardhat clean --global". ### #[HH506: Error running solcjs](#HH506) There was an error while running the solcjs compiler. [# Built-in tasks errors](#built-in-tasks-errors) -------------------------------------------------- ### #[HH600: Compilation failed](#HH600) Your smart contracts failed to compile. Please check Hardhat's output for more details. ### #[HH601: Script doesn't exist](#HH601) Tried to use `hardhat run` to execute a nonexistent script. Please double check your script's path. ### #[HH602: Error running script](#HH602) Running a script resulted in an error. Please check Hardhat's output for more details. ### #[HH603: Flatten detected cyclic dependencies](#HH603) Hardhat flatten doesn't support cyclic dependencies. We recommend not using this kind of dependency. ### #[HH604: Error running JSON-RPC server](#HH604) There was an error while starting the JSON-RPC HTTP server. ### #[HH605: Unsupported network for JSON-RPC server.](#HH605) JSON-RPC server can only be started when running the Hardhat Network. To start the JSON-RPC server, retry the command without the --network parameter. ### #[HH606: The project cannot be compiled](#HH606) The project cannot be compiled with the current settings. ### #[HH607: Missing fork URL](#HH607) You passed a block number to fork from, but not a URL. Hardhat cannot fork if the URL of the JSON-RPC wasn't set. ### #[HH608: Unsupported solc version](#HH608) This version of solidity is not supported by Hardhat. Please use a newer, supported version. ### #[HH609: Running tests twice in an ESM project](#HH609) You have run your tests twice programmatically and your project is an ESM project (you have `"type": "module"` in your `package.json`, or some of your files have the `.mjs` extension). This is not supported by Mocha yet. [# Artifacts related errors](#artifacts-related-errors) -------------------------------------------------------- ### #[HH700: Artifact not found](#HH700) Tried to import a nonexistent artifact. Please double check that your contracts have been compiled and double check your artifact's name. ### #[HH701: Multiple artifacts found](#HH701) There are multiple artifacts that match the given contract name, and Hardhat doesn't know which one to use. Please use the fully qualified name of the contract to disambiguate it. ### #[HH702: Incorrect artifact path casing](#HH702) You tried to get an artifact file with an incorrect casing. Hardhat's artifact resolution is case sensitive to ensure projects are portable across different operating systems. [# Plugin system errors](#plugin-system-errors) ------------------------------------------------ ### #[HH800: Using a buidler plugin](#HH800) You are trying to use a Buidler plugin in Hardhat. This is not supported. Please use the equivalent Hardhat plugin instead. ### #[HH801: Plugin dependencies not installed](#HH801) You are trying to use a plugin with unmet dependencies. Please follow Hardhat's instructions to resolve this. [# Internal Hardhat errors](#internal-hardhat-errors) ------------------------------------------------------ ### #[HH900: Invalid error message template](#HH900) An error message template contains an invalid variable name. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH901: Invalid error message replacement](#HH901) Tried to replace an error message variable with a value that contains another variable name. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH902: Missing replacement value from error message template](#HH902) An error message template is missing a replacement value. This is a bug. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. ### #[HH903: Inferred artifact path doesn't exist](#HH903) The inferred artifact path doesn't exist. Please [report it](https://github.com/nomiclabs/hardhat/issues/new) to help us improve Hardhat. [# Source name errors](#source-name-errors) -------------------------------------------- ### #[HH1000: Invalid source name: absolute path](#HH1000) A Solidity source name was expected, but an absolute path was given. If you aren't overriding compilation-related tasks, please report this as a bug. ### #[HH1001: Invalid source name: relative path](#HH1001) A Solidity source name was expected, but a relative path was given. If you aren't overriding compilation-related tasks, please report this as a bug. ### #[HH1002: Invalid source name: backslashes](#HH1002) A Solidity source name was invalid because it uses backslashes (\\) instead of slashes (/). If you aren't overriding compilation-related tasks, please report this as a bug. ### #[HH1003: Invalid source name: not normalized](#HH1003) A Solidity source name was invalid because it wasn't normalized. It probably contains some "." or "..". If you aren't overriding compilation-related tasks, please report this as a bug. ### #[HH1004: Incorrect source name casing](#HH1004) You tried to resolve a Solidity file with an incorrect casing. Hardhat's compiler is case sensitive to ensure projects are portable across different operating systems. ### #[HH1005: Solidity source file not found](#HH1005) A source name should correspond to an existing Solidity file but it doesn't. Hardhat's compiler is case sensitive to ensure projects are portable across different operating systems. ### #[HH1006: File from node\_modules treated as local](#HH1006) A file was treated as local but is inside a node\_modules directory. If you aren't overriding compilation-related tasks, please report this as a bug. ### #[HH1007: File from outside the project treated as local](#HH1007) A file was treated as local but is outside the project. If you aren't overriding compilation-related tasks, please report this as a bug. [# Contract name errors](#contract-name-errors) ------------------------------------------------ ### #[HH1100: Invalid fully qualified contract name](#HH1100) A contract name was expected to be in fully qualified form, but it's not. A fully qualified name should look like file.sol [# Connfiguration variables errors](#connfiguration-variables-errors) ---------------------------------------------------------------------- ### #[HH1200: Configuration variables can only be managed from the CLI](#HH1200) Configuration variables can only be managed from the CLI. They cannot be modified programmatically. ### #[HH1201: Configuration variable is not set](#HH1201) Cannot find a value for a mandatory configuration variable. Use 'npx hardhat vars set VAR' to set it or 'npx hardhat vars setup' to list all the configuration variables used by this project. ### #[HH1202: Invalid name for a configuration variable](#HH1202) Invalid name for a configuration variable. Configuration variables can only have alphanumeric characters and underscores, and they cannot start with a number. ### #[HH1203: Invalid empty value for configuration variable](#HH1203) A configuration variable cannot have an empty value. --- # Using a custom Solidity compiler | Ethereum development environment for professionals by Nomic Foundation [#Using a custom Solidity compiler](#using-a-custom-solidity-compiler) ======================================================================= To use a custom, local version of the Solidity compiler, you need to override the `TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD` subtask in your Hardhat config. This subtask returns an object with four properties: * `compilerPath`: the path to the compiler * `isSolcJs`: a flag indicating if the compiler is a javascript module or a native binary * `version`: the short version of the compiler (for example, `0.8.24`) * `longVersion`: the long version of the compiler (for example, `0.8.24+commit.e11b9ed9`). This property is used as extra metadata in the build-info files, so you shouldn't worry too much about its value. Here is an example to override the [wasm solc build for version `0.8.24`](https://binaries.soliditylang.org/wasm/soljson-v0.8.24+commit.e11b9ed9.js) . Before proceeding, ensure you download the required solc binary to the root of your hardhat project. TypeScript JavaScript // hardhat.config.js import { HardhatUserConfig, subtask } from "hardhat/config"; const { TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, } = require("hardhat/builtin-tasks/task-names"); const path = require("path"); subtask( TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async ( args: { solcVersion: string; }, hre, runSuper ) => { if (args.solcVersion === "0.8.24") { const compilerPath = path.join( __dirname, "soljson-v0.8.24+commit.e11b9ed9.js" ); return { compilerPath, isSolcJs: true, // if you are using a native compiler, set this to false version: args.solcVersion, // This is used as extra information in the build-info files, // but other than that is not important longVersion: "0.8.24+commit.e11b9ed9", }; } // since we only want to override the compiler for version 0.8.24, // the runSuper function allows us to call the default subtask. return runSuper(); } ); const config: HardhatUserConfig = { solidity: "0.8.24", }; export default config; // hardhat.config.js const { TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, } = require("hardhat/builtin-tasks/task-names"); const path = require("path"); subtask(TASK_COMPILE_SOLIDITY_GET_SOLC_BUILD, async (args, hre, runSuper) => { if (args.solcVersion === "0.8.24") { const compilerPath = path.join( __dirname, "soljson-v0.8.24+commit.e11b9ed9.js" ); return { compilerPath, isSolcJs: true, // if you are using a native compiler, set this to false version: args.solcVersion, // This is used as extra information in the build-info files, // but other than that is not important longVersion: "0.8.24+commit.e11b9ed9", }; } // since we only want to override the compiler for version 0.8.24, // the runSuper function allows us to call the default subtask. return runSuper(); }); module.exports = { solidity: "0.8.24", }; Check our ["Creating a task" guide](/hardhat-runner/docs/advanced/create-task) to learn more about overriding tasks. --- # Using Viem | Ethereum development environment for professionals by Nomic Foundation [#Using Viem](#using-viem) =========================== [# Overview](#overview) ------------------------ Most of this documentation assumes that you are using [ethers](https://docs.ethers.org/v6/) as your connection library, but you can also use Hardhat with [Viem](https://viem.sh/docs/introduction.html) , a more lightweight and type-safe alternative. This guide explains how to setup a project that uses [the Viem-based Toolbox](/hardhat-runner/plugins/nomicfoundation-hardhat-toolbox-viem) instead of the main one. [# Quick start](#quick-start) ------------------------------ To create a new Hardhat project with Viem, initialize a project as [you normally do](/hardhat-runner/docs/guides/project-setup) , but select the _“Create a TypeScript project (with Viem)”_ option. You can also try `hardhat-viem` in an existing project, even if it uses `hardhat-ethers`, since both plugins are compatible. To do this, just install the `@nomicfoundation/hardhat-viem` package and add it to your config. ### [#Clients](#clients) Viem provides a set of interfaces to interact with the blockchain. `hardhat-viem` wraps and auto-configures these based on your Hardhat project settings for a seamless experience. These **clients** are tailored for specific interactions: * **Public Client** fetches node information from the “public” JSON-RPC API. * **Wallet Client** interacts with Ethereum Accounts for tasks like transactions and message signing. * **Test Client** performs actions that are only available in development nodes. You can access clients via `hre.viem`. Read our documentation to learn more about the [HRE](/hardhat-runner/docs/advanced/hardhat-runtime-environment) . Find below an example of how to use the public and wallet clients: 1. Create a `scripts/clients.ts` inside your project directory. 2. Add this code to `scripts/clients.ts`: import { parseEther, formatEther } from "viem"; import hre from "hardhat"; async function main() { const [bobWalletClient, aliceWalletClient] = await hre.viem.getWalletClients(); const publicClient = await hre.viem.getPublicClient(); const bobBalance = await publicClient.getBalance({ address: bobWalletClient.account.address, }); console.log( `Balance of ${bobWalletClient.account.address}: ${formatEther( bobBalance )} ETH` ); const hash = await bobWalletClient.sendTransaction({ to: aliceWalletClient.account.address, value: parseEther("1"), }); await publicClient.waitForTransactionReceipt({ hash }); } main() .then(() => process.exit()) .catch((error) => { console.error(error); process.exit(1); }); 3. Run `npx hardhat run scripts/clients.ts`. For more detailed documentation on clients, you can visit the [hardhat-viem plugin site](/hardhat-runner/plugins/nomicfoundation-hardhat-viem#clients) and [Viem's official site](https://viem.sh/docs/clients/intro.html) . ### [#Contracts](#contracts) Viem also provides functionality for interacting with contracts, and `hardhat-viem` provides wrappers for the most useful methods. Plus, it generates types for your contracts, enhancing type-checking and IDE suggestions. Use the `hre.viem` object to get these helpers, similar to how clients are used. The next example shows how to get a contract instance and call one of its methods: 1. Create a `MyToken.sol` file inside your project’s `contracts` directory: // SPDX-License-Identifier: MIT pragma solidity ^0.8.28; contract MyToken { uint256 public totalSupply; constructor(uint256 _initialSupply) { totalSupply = _initialSupply; } function increaseSupply(uint256 _amount) public { require(_amount > 0, "Amount must be greater than 0"); totalSupply += _amount; } function getCurrentSupply() public view returns (uint256) { return totalSupply; } } 2. Run `npx hardhat compile` to compile your contracts and produce types in the `artifacts` directory. 3. Create a `contracts.ts` inside the `scripts` directory: import hre from "hardhat"; async function main() { const myToken = await hre.viem.deployContract("MyToken", [1_000_000n]); const initialSupply = await myToken.read.getCurrentSupply(); console.log(`Initial supply of MyToken: ${initialSupply}`); const hash = await myToken.write.increaseSupply([500_000n]); // increaseSupply sends a tx, so we need to wait for it to be mined const publicClient = await hre.viem.getPublicClient(); await publicClient.waitForTransactionReceipt({ hash }); const newSupply = await myToken.read.getCurrentSupply(); console.log(`New supply of MyToken: ${newSupply}`); } main() .then(() => process.exit(0)) .catch((error) => { console.error(error); process.exit(1); }); 4. Open your terminal and run `npx hardhat run scripts/contracts.ts`. This will deploy the `MyToken` contract, call the `increaseSupply()` function, and display the new supply in your terminal. #### [#Contract Type Generation](#contract-type-generation) The proper types for each contract are generated during compilation. These types are used to overload the `hardhat-viem` types and improve type checking and suggestions. For example, if you copy and paste the following code at the end of the `main()` function of `scripts/contracts.ts`, TypeScript would highlight it as an error: // The amount is required as a parameter // TS Error: Expected 1-2 arguments, but got 0. await myToken.write.increaseSupply(); // There is no setSupply function in the MyToken contract // TS Error: Property 'setSupply' does not exist on type... const tokenPrice = await myToken.write.setSupply([5000000n]); // The first argument of the constructor arguments is expected to be a bigint // TS Error: No overload matches this call. const myToken2 = await hre.viem.deployContract("MyToken", ["1000000"]); If you want to learn more about working with contracts, you can visit the [`hardhat-viem` plugin site](/hardhat-runner/plugins/nomicfoundation-hardhat-viem#contracts) and [Viem's official site](https://viem.sh/docs/contract/getContract.html) . ### [#Testing](#testing) In this example, we’ll test the `MyToken` contract, covering scenarios like supply increase and expected operation reverts. 1. Create a `test/my-token.ts` file: import hre from "hardhat"; import { assert, expect } from "chai"; import { loadFixture } from "@nomicfoundation/hardhat-toolbox-viem/network-helpers"; // A deployment function to set up the initial state const deploy = async () => { const myToken = await hre.viem.deployContract("MyToken", [1_000_000n]); return { myToken }; }; describe("MyToken Contract Tests", function () { it("should increase supply correctly", async function () { // Load the contract instance using the deployment function const { myToken } = await loadFixture(deploy); // Get the initial supply const initialSupply = await myToken.read.getCurrentSupply(); // Increase the supply await myToken.write.increaseSupply([500_000n]); // Get the new supply after the increase const newSupply = await myToken.read.getCurrentSupply(); // Assert that the supply increased as expected assert.equal(initialSupply + 500_000n, newSupply); }); it("should revert when increasing supply by less than 1", async function () { // Load the contract instance using the deployment function const { myToken } = await loadFixture(deploy); // Attempt to increase supply by 0 (which should fail) await expect(myToken.write.increaseSupply([0n])).to.be.rejectedWith( "Amount must be greater than 0" ); }); }); 2. Open your terminal and run `npx hardhat test` to run these tests. ### [#Managing Types and Version Stability](#managing-types-and-version-stability) Viem adopts a particular [approach to handling changes in types within their codebase](https://viem.sh/docs/typescript.html#typescript) . They consider these changes as non-breaking and typically release them as patch version updates. This approach has implications for users of both `hardhat-viem` and `hardhat-toolbox-viem`. **Option 1: Pinning Versions (Recommended for Stability)** Viem recommends pinning their package version in your project. However, it's important to note that if you choose to follow this recommendation, you should also pin the versions of `hardhat-viem` and `hardhat-toolbox-viem`. This ensures version compatibility and stability for your project. However, it's worth mentioning that by pinning versions, you may miss out on potential improvements and updates shipped with our plugins. To pin the versions, follow these steps: 1. Explicitly install `hardhat-viem`, `hardhat-toolbox-viem`, and `viem`. This will add these dependencies to your `package.json` file: npm i @nomicfoundation/hardhat-toolbox-viem @nomicfoundation/hardhat-viem viem 2. Open your `package.json` file and remove the caret character (**`^`**) from the versions of the three packages: { "dependencies": { "@nomicfoundation/hardhat-toolbox-viem": "X.Y.Z", "@nomicfoundation/hardhat-viem": "X.Y.Z", "viem": "X.Y.Z" } } **Option 2: Stay Updated (Recommended for Features)** Alternatively, you can choose not to pin versions and remain aware that your project's types may break if a newer version of `viem` is installed. By opting for this approach, you won't miss out on important upgrades and features, but you might need to address type errors occasionally. Both options have their merits, and your choice depends on whether you prioritize stability or staying up-to-date with the latest features and improvements. ---