The Hardhat Runtime Environment (HRE) is a powerful feature of the Hardhat development framework that provides developers with a set of tools and functionalities to interact with the Ethereum blockchain, smart contracts, and various Hardhat plugins. It is essentially a context in which your scripts and tests are executed, allowing you to access the entire Hardhat ecosystem seamlessly.

What is HRE?

The HRE acts as a bridge between your scripts and the underlying Ethereum network. It includes various modules that help you manage tasks such as:

  • Contract Deployment: Easily deploy smart contracts to any network.
  • Contract Interaction: Read and write data to your deployed contracts.
  • Testing: Run tests against your contracts using the built-in testing framework.
  • Configuration Management: Access and modify Hardhat configurations.
  • Plugins: Integrate with Hardhat plugins to extend functionality.

How to Use HRE

The HRE is automatically available in your scripts and tests when you run them using Hardhat. You can access it by simply using the hre variable. Below are some examples of how to use the HRE effectively.

1. Accessing the HRE in a Script

Let’s create a script that deploys a smart contract using the HRE. For this example, we will use the same MyToken contract from previous examples.

const hre = require("hardhat");

async function main() {
const Token = await hre.ethers.getContractFactory("MyToken");
const token = await Token.deploy("MyToken", "MTK", 1000000);
await token.deployed();
console.log(`Token deployed to: ${token.address}`);
}

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

In this script, we use hre.ethers to access the Ethers.js library for contract interactions, enabling us to deploy the MyToken contract.

2. Interacting with a Deployed Contract

Now, let’s create another script that interacts with the deployed contract. This script will read the total supply of the token and transfer some tokens to another account:

const hre = require("hardhat");

async function main() {
const tokenAddress = "YOUR_DEPLOYED_TOKEN_ADDRESS"; // Replace with your deployed token address
const Token = await hre.ethers.getContractFactory("MyToken");
const token = Token.attach(tokenAddress);

// Read total supply
const totalSupply = await token.totalSupply();
console.log(`Total Supply: ${totalSupply.toString()}`);

// Transfer tokens
const [owner, addr1] = await hre.ethers.getSigners();
const amount = hre.ethers.utils.parseUnits("100", 18); // 100 tokens

console.log(`Transferring ${amount.toString()} tokens from ${owner.address} to ${addr1.address}`);
const transferTx = await token.transfer(addr1.address, amount);
await transferTx.wait();

console.log(`Transfer successful!`);
}

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

In this script, we again use hre.ethers to interact with the deployed contract. We read the total supply and perform a token transfer.

3. Using HRE in Tests

The HRE is also available in your test files, making it easy to write tests for your contracts. Here’s an example of a simple test for the MyToken contract:

const { expect } = require("chai");
const hre = require("hardhat");

describe("MyToken", function () {
let token;
let owner;
let addr1;

beforeEach(async function () {
const Token = await hre.ethers.getContractFactory("MyToken");
[owner, addr1] = await hre.ethers.getSigners();
token = await Token.deploy("MyToken", "MTK", 1000000);
await token.deployed();
});

it("should have the correct name and symbol", async function () {
expect(await token.name()).to.equal("MyToken");
expect(await token.symbol()).to.equal("MTK");
});

it("should transfer tokens correctly", async function () {
const amount = hre.ethers.utils.parseUnits("100", 18);
await token.transfer(addr1.address, amount);
const addr1Balance = await token.balanceOf(addr1.address);
expect(addr1Balance).to.equal(amount);
});
});

In this test, we use the HRE to deploy the contract and perform assertions to verify that the contract behaves as expected. The beforeEach hook ensures that a fresh instance of the contract is deployed before each test.

Conclusion

The Hardhat Runtime Environment (HRE) is an essential part of the Hardhat framework that simplifies the process of developing, testing, and deploying smart contracts. By providing a unified interface to interact with the Ethereum blockchain and manage your development environment, the HRE allows developers to focus on building robust decentralized applications without worrying about the underlying complexities. Whether you are deploying contracts, interacting with them, or writing tests, the HRE is a powerful tool that enhances your development workflow.