Hardhat vs Foundry: Choosing the Right Ethereum Development Tool

Here are some of the things to consider when choosing between Hardhat and Foundry.

by MetaMask DeveloperMay 30, 2024
Hardhat vs Foundry

Choosing the right tools for your dapp development does not only affect productivity but also impacts the effectiveness of testing, deployment, and maintenance of smart contracts. In this blog, we compare two popular choice amongst Ethereum dapp developers: Foundry and Hardhat, focusing on their installation requirements, testing and deployment workflows, and specific technical aspects and limitations.

About Hardhat


Hardhat is a well-established development environment designed to help developers manage and automate tasks involved in smart contract development. It is known for its flexible and adaptable nature. Hardhat features the Hardhat Network, a local Ethereum network designed for development which also allows for easy testing, deployment, and debugging.

Developers can interact directly with smart contracts deployed on the Hardhat Network via an interactive console, providing a comprehensive local environment tailored for development tasks. Hardhat also supports a robust plugin ecosystem, allowing developers to extend its capabilities easily. However, some users might find the initial setup and configuration of Hardhat to be complex.

About Foundry


On the other hand, Foundry is a relatively new development toolkit that emphasizes speed and reliability. It is built on Forge, a powerful testing framework that enables developers to write, compile, and test smart contracts efficiently. One of the key features of Foundry is its fast testing capabilities as the Forge testing framework dramatically speeds up test execution times, allowing developers to iterate more quickly.

Additionally, Foundry includes native debugging tools that help developers diagnose and fix issues directly within the environment. Foundry also integrates seamlessly with other tools in the Ethereum ecosystem, facilitating a more streamlined development process. However, being relatively new, Foundry might lack the extensive community support available to more established tools.

Technical comparison of Hardhat and Foundry


For this section, we’ll use a basic random sum smart contract. This smart contract will remain the same for Hardhat and Foundry, however, the project setup will differ slightly between the two frameworks.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract RandomSum {
    // Function to generate a pseudo-random number based on input
    function random(uint seed) private view returns (uint) {
        return uint(keccak256(abi.encodePacked(block.timestamp, msg.sender, seed))) % 100;
    }

    // Function to generate two random numbers and return their sum
    function generateSum() public view returns (uint sum) {
        uint num1 = random(1);
        uint num2 = random(2);
        sum = num1 + num2;
    }
}

Installation:

Hardhat:


To begin using Hardhat, you need to have Node.js installed on your machine. Once that’s set up, you can create a new Hardhat project by following these steps:

  1. Initialize a new Node.js project:
mkdir randomsum
cd randomsum
npm init -y
  1. Install Hardhat:
npm install --save-dev hardhat
  1. Create a Hardhat project:
npx hardhat
  1. Follow the prompts to create a basic project. Select "Create an empty hardhat.config.js" for a bare setup. Choose to create a sample project. This sets up a Hardhat environment with all necessary configurations.

Contract: Place your RandomSum contract in the contracts folder.

Foundry


Foundry uses Rust, so you’ll need Rust installed on your system. With Rust ready, you can install Foundry by running:

  1. Install Foundry:
curl -L <https://foundry.paradigm.xyz> | bash
foundryup
  1. Initialize a new Foundry project:
forge init randomsum-foundry
cd randomsum-foundry

Contract: Place your RandomSum contract in the src directory.

Local blockchain deployment

Hardhat


  • Local blockchain: Use Hardhat Network, which runs automatically when you perform tasks like testing or deploying contracts.

  • Deployment script: Create a script under scripts/deploy.js:

async function main() {
    const RandomSum = await ethers.getContractFactory("RandomSum");
    const randomSum = await RandomSum.deploy();
    await randomSum.deployed();
    console.log("RandomSum deployed successfully:");
}

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

  • Run deployment: Execute the deployment using:
npx hardhat run scripts/deploy.js --network localhost

Foundry


  • Local blockchain: Foundry uses anvil, a local Ethereum node. Run this in a separate terminal to start your local node.
anvil
  • Deployment script: Use the forge create command directly:
forge create RandomSum --private-key YOUR_PRIVATE_KEY --rpc-url <http://localhost:8545>

Live testnet deployment

Hardhat


  • Network configuration: Configure the desired network in hardhat.config.js, adding a section for the network settings (e.g., Sepolia).
module.exports = {
  solidity: "0.8.0",
  networks: {
    sepolia: {
      url: "https://linea-sepolia.infura.io/v3/YOUR_INFURA_KEY",
      accounts: [`0x${process.env.PRIVATE_KEY}`]
    }
  }
};
  • Deployment: Run the same deployment script with the network option changed to Sepolia.

Foundry


  • Network configuration: No additional configuration file is needed; specify the network in the command.

  • Deployment: use:

forge create RandomSum --private-key YOUR_PRIVATE_KEY --rpc-url <https://linea-sepolia.infura.io/v3/YOUR_INFURA_KEY>

Smart Contract Testing

Hardhat


  • Write tests: Create a test file in test/randomSum.js using JavaScript:
const { expect } = require("chai");

describe("RandomSum", function() {
  it("Should return the sum of two random numbers", async function() {
    const RandomSum = await ethers.getContractFactory("RandomSum");
    const randomSum = await RandomSum.deploy();
    await randomSum.deployed();

    const sum = await randomSum.generateSum();
    expect(sum).to.be.a('number');
  });
});
  • Run tests: Execute using:
npx hardhat test

If you face problems with testing, simply add The loadFixture function from @nomicfoundation/hardhat-toolbox/network-helpers.

The key benefits of using loadFixture are:

  • It sets up a clean environment for each test by reverting to a snapshot.
  • It's more efficient than redeploying contracts for each test.
  • It allows you to share setup code across multiple tests.

Foundry


  • Write tests: Add a test file in test/RandomSum.t.sol using Solidity:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "ds-test/test.sol";
import "../src/RandomSum.sol";

contract RandomSumTest is DSTest {
  RandomSum randomSum;

  function setUp() public {
    randomSum = new RandomSum();
  }

  function testGenerateSum() public {
    uint sum = randomSum.generateSum();
    assertTrue(sum >= 0 && sum <= 198); // since each random number is <100
  }
}
  • Run tests: Use:
forge test

Conclusion


Choosing between Hardhat and Foundry often comes down to the team's skill set and the specific needs of the project. If the team is proficient in JavaScript and requires extensive integration with web technologies, Hardhat could be the better choice. Its robust plugin ecosystem and flexible environment makes it ideal for projects that demand a high degree of customization and interaction with various web technologies.

On the other hand, if the project demands rapid development cycles with a focus purely on smart contracts, Foundry offers an appealing and efficient option that keeps everything within the Solidity ecosystem. Its speed and native support for Solidity can significantly enhance productivity for teams dedicated to smart contract development.

Ultimately, both tools have their strengths, and the right choice depends on your project's unique requirements and your team's expertise.

Receive our Newsletter