Hardhat vs Foundry:2026年智能合约开发框架选型指南

左右分屏VS对决风格,蓝绿色Hardhat与橙红色Foundry框架对比

两个框架的基因差异

Hardhat:JavaScript生态的产物

Hardhat出身于JavaScript/TypeScript生态,它的核心理念是让Web2开发者能平滑过渡到Web3

typescript

// Hardhat配置文件(TypeScript)
import { task } from "hardhat/config";

task("deploy", "Deploy the contract", async (taskArgs, hre) => {
    const Greeter = await hre.ethers.getContractFactory("Greeter");
    const greeter = await Greeter.deploy("Hello, World!");
    await greeter.deployed();
    console.log(`Greeter deployed to: ${greeter.address}`);
});

Hardhat的本质是一个插件化的任务调度系统。它没有内置Solidity编译器,而是通过插件(如@nomiclabs/hardhat-solc)调用solc-js。这个设计让Hardhat可以灵活集成各种工具,但同时也引入了Node.js的运行时开销。

Foundry:Rust极客的杰作

Foundry则是另一个极端——用Rust重写一切,追求极致性能

solidity

// Foundry测试文件(Solidity)
// test/Greeter.t.sol
contract GreeterTest {
    function testCanDeploy() public {
        Greeter greeter = new Greeter("Hello, World!");
        assertEq(greeter.greet(), "Hello, World!");
    }
}

Foundry的核心是forge命令,它集编译、测试、部署于一身。因为底层直接使用solc编译器和revm(Rust EVM),所以能实现毫秒级的测试执行。

编译速度对比柱状图,展示四个场景下Hardhat与Foundry的5-12倍性能差距

编译速度对比:这是最直观的差距

我用一个包含100个合约的项目做了实测:

指标HardhatFoundry差距
首次全量编译45秒8秒5.6x
修改单文件增量编译12秒1秒12x
50并发编译20秒3秒6.7x
冷启动(无缓存)50秒9秒5.5x

这个差距在大型项目中会更加明显。Hardhat每次全量编译都需要重新处理所有合约,而Foundry的增量编译机制非常高效——它会分析合约间的依赖关系,只重新编译受影响的部分。

背后的原因:

Hardhat使用solc-js(JavaScript实现的编译器),而Foundry调用原生solc二进制文件,配合Rust的并行处理能力。另外,Foundry使用文件哈希做缓存,比Hardhat的时间戳缓存更准确。

测试框架:谁更强大?

Hardhat的JavaScript测试

typescript

// test/sample-test.ts
import { expect } from "chai";
import { ethers } from "hardhat";

describe("Token", function () {
    it("should have the correct name", async function () {
        const Token = await ethers.getContractFactory("Token");
        const token = await Token.deploy("MyToken", "MTK", 1000000);
        await token.deployed();
        
        expect(await token.name()).to.equal("MyToken");
    });
    
    it("should transfer tokens correctly", async function () {
        const [owner, addr1] = await ethers.getSigners();
        const Token = await ethers.getContractFactory("Token");
        const token = await Token.deploy("MyToken", "MTK", 1000000);
        await token.deployed();
        
        await token.transfer(addr1.address, 100);
        expect(await token.balanceOf(addr1.address)).to.equal(100);
    });
});

Hardhat测试使用Mocha + Chai,这是前端开发者非常熟悉的组合。它的优点是断言语法丰富,可以写出非常可读的测试代码。

Foundry的Solidity原生测试

solidity

// test/Token.t.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import "../src/Token.sol";

contract TokenTest is Test {
    Token public token;
    
    function setUp() public {
        token = new Token("MyToken", "MTK", 1000000);
    }
    
    function testName() public {
        assertEq(token.name(), "MyToken");
    }
    
    function testTransfer() public {
        token.transfer(address(1), 100);
        assertEq(token.balanceOf(address(1)), 100);
    }
    
    // Fuzz测试
    function testTransferFuzz(uint256 amount) public {
        amount = bound(amount, 0, 1000000);
        token.transfer(address(1), amount);
        assertEq(token.balanceOf(address(1)), amount);
    }
}

Foundry测试用Solidity编写,这意味着测试代码和被测合约运行在同一个EVM环境——不存在JavaScript到Solidity的类型转换问题。

更强大的是Fuzzing测试testTransferFuzz会用随机生成的amount值执行多次测试,发现边界条件下的漏洞。这是传统JavaScript测试框架很难实现的。

Gas追踪:谁更精准?

Gas追踪是合约优化的重要工具。

Hardhat方案:

typescript

// 使用 hardhat-gas-reporter 插件
import gasReporter from "hardhat-gas-reporter";

export default {
    gasReporter: {
        currency: "USD",
        coinmarketcap: process.env.COINMARKETCAP_API_KEY
    }
};

Foundry方案:

bash

forge test --gas-report

text

╔═══════════════════════════════════════════════════════════════════╗
║                        Gas Report                                  ║
╠═══════════════════════════════════════════════════════════════════╣
║  Token::transfer                          51,382    51,382    51,382  ║
║  Token::transferFrom                      62,481    62,481    62,481  ║
║  Token::approve                           46,134    46,134    46,134  ║
╚═══════════════════════════════════════════════════════════════════╝

Foundry内置的Gas报告更加精准,因为它直接测量EVM执行成本。而Hardhat的插件需要额外的集成层,可能存在偏差。

调试体验:各有千秋

Hardhat的console.log

solidity

import "hardhat/console.sol";

function complexOperation(uint256 value) public view {
    console.log("Processing value:", value);
    // ...
}

Hardhat的console直接集成在Solidity标准库中,用起来非常顺手。输出会显示在终端的Hardhat日志中。

Foundry的更多调试工具

solidity

import "forge-std/console.sol";

function testFailTransfer() public {
    vm.expectRevert("Insufficient balance");
    token.transfer(address(0), type(uint256).max);
}

Foundry的vm作弊码提供了更强大的调试能力:vm.expectRevert()vm.prank()(模拟调用者)、vm.warp()(时间操控)等。

部署流程对比

Hardhat的部署脚本

typescript

// scripts/deploy.ts
import { ethers } from "hardhat";

async function main() {
    const [deployer] = await ethers.getSigners();
    console.log("Deploying with account:", deployer.address);
    
    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy("MyToken", "MTK", 1000000);
    await token.deployed();
    
    console.log("Token deployed to:", token.address);
    
    // 验证合约
    await token.deployTransaction.wait(5);
    await hre.run("verify:verify", {
        address: token.address,
        constructorArguments: ["MyToken", "MTK", 1000000]
    });
}

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

bash

npx hardhat run scripts/deploy.ts --network mainnet

Foundry的部署脚本

solidity

// script/Deploy.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Script.sol";

contract DeployScript is Script {
    function run() external {
        vm.startBroadcast();
        
        Token token = new Token("MyToken", "MTK", 1000000);
        console.log("Token deployed to:", address(token));
        
        vm.stopBroadcast();
    }
}

bash

forge script script/Deploy.s.sol:DeployScript --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast

Foundry的部署脚本更优雅——全链路都是Solidity,部署逻辑和测试逻辑使用同一套工具链,减少了心智负担。

项目结构推荐

Hardhat项目结构

plaintext

project/
├── contracts/
│   ├── Token.sol
│   └── Greeter.sol
├── test/
│   ├── token.test.ts
│   └── greeter.test.ts
├── scripts/
│   └── deploy.ts
├── hardhat.config.ts
├── package.json
└── tsconfig.json

Foundry项目结构

plaintext

project/
├── src/
│   ├── Token.sol
│   └── Greeter.sol
├── test/
│   ├── Token.t.sol
│   └── Greeter.t.sol
├── script/
│   └── Deploy.s.sol
├── lib/
│   └── forge-std/
├── foundry.toml
└── remappings.txt

Foundry通过lib/目录管理依赖(通常是git submodule),而Hardhat使用npm/yarn。

2026年的生态现状

到2026年,两个框架的生态都有很大发展:

Hardhat的优势:

  • 更完善的官方文档和社区资源
  • 与ethers.js、TypeScript生态的无缝集成
  • 丰富的插件生态(如OpenZeppelin的升级插件)
  • 更适合前端团队主导的Web3项目

Foundry的优势:

  • 官方的Anvil(本地测试网)、Cast(交互工具)、Chisel(Solidity REPL)
  • 更活跃的GitHub社区,issue响应更快
  • 内置的Invariant测试(状态测试)
  • Forge Std库功能强大

选型建议

基于我的经验,给出几个实际场景的推荐:

选择Hardhat的场景

  1. 团队以JavaScript/TypeScript为主——学习曲线最低
  2. 项目需要复杂的前端集成——ethers.js + Hardhat是成熟方案
  3. 需要使用特定的Hardhat插件——如升级合约、自动化部署等
  4. 项目刚起步,需要快速原型——npm生态更友好

选择Foundry的场景

  1. 大型复杂合约项目——编译和测试速度优势明显
  2. 对安全性要求极高——Fuzzing和Invariant测试是安全审计的标准配置
  3. 团队有Rust背景——可以深入定制工具链
  4. Gas优化密集型项目——内置的Gas报告更精准

两者结合使用

实际上,很多项目现在采用混合方案

  • 用Foundry做测试和Gas优化
  • 用Hardhat做前端集成和脚本任务

bash

# 两个框架可以共存于一个项目
/project-root
  /foundry    # 合约代码和测试
  /frontend   # Next.js前端

迁移成本评估

如果你现在用Hardhat想迁移到Foundry:

维度复杂度说明
测试代码中等需要重写为Solidity测试
部署脚本较低语法相近,迁移较简单
配置文件较低foundry.toml vs hardhat.config.ts
CI/CD两个工具都支持主流CI

建议从小项目开始尝试Foundry,熟悉后再决定是否全面迁移。

总结

Hardhat和Foundry代表了两种不同的设计哲学:

  • Hardhat:”开发者体验优先”,通过分层抽象降低认知负担
  • Foundry:”执行效率优先”,最小化抽象层以逼近硬件极限

两者都是成熟的生产级工具,选择哪个都不会错。关键是理解团队的技术背景和项目需求

对于大多数新项目,我的建议是:如果团队对JavaScript更熟悉,从Hardhat开始;如果追求极致性能和安全性,优先考虑Foundry。无论选择哪个,测试都是最重要的——花多少时间都不为过。

相关推荐阅读:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注