一、框架定位与设计哲学
1.1 Hardhat的设计理念
Hardhat的核心设计理念是开发者体验优先。作为一个Node.js项目,它天然融入Web开发者的技术栈,降低了区块链开发的入门门槛。
Hardhat采用模块化的插件架构,开发者可以根据项目需求自由组合功能。Hardhat Runtime Environment(HRE)提供了统一的上下文注入机制,使得测试、部署和脚本编写都遵循一致的接口规范。
笔者第一次使用Hardhat时,最直观的感受是”熟悉”。对于有JavaScript背景的开发者来说,几乎不需要额外学习成本就能上手。

1.2 Foundry的设计理念
Foundry代表了执行效率优先的思路。它由Rust编写,直接与EVM交互,消除了中间层的抽象开销。Forge、Cast和Anvil三个核心工具覆盖了从开发到部署的完整流程。
Foundry最具革命性的特性是Solidity原生测试。开发者可以用Solidity编写测试合约,与生产代码使用同一语言,这带来了更好的类型安全和执行效率。
plaintext
Foundry工具链:
├── Forge - 编译、测试和部署
├── Cast - 链上交互命令行工具
└── Anvil - 本地以太坊节点
二、核心架构对比
2.1 编译机制差异
Hardhat的增量编译
Hardhat使用基于文件哈希的缓存机制,仅重新编译修改过的文件及其依赖。这在中等规模项目中效果良好,但随着项目复杂度增加,Node.js运行时带来的开销逐渐明显。
typescript
// hardhat.config.ts
export default {
solidity: {
version: "0.8.26",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
// Hardhat的编译器配置
solidity: {
compilers: [
{
version: "0.8.26",
settings: { ... }
}
]
}
};
Foundry的并行编译
Foundry利用Rust的Rayon库实现并行任务池,能够充分利用多核CPU进行并行编译。对于包含数百个合约的大型项目,这一特性带来了数量级的速度提升。
toml
# foundry.toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.26"
optimizer = true
optimizer_runs = 200
# 启用并行编译(默认启用)
via_ir = false
2.2 执行引擎对比
| 指标 | Hardhat | Foundry |
|---|---|---|
| 实现语言 | TypeScript/Node.js | Rust |
| 编译速度 | 较慢(分钟级) | 极快(秒级) |
| 测试执行 | 秒级 | 毫秒级 |
| 内存占用 | 较高(GB级) | 较低(MB级) |
| 本地节点 | Hardhat Network | Anvil |
三、测试能力深度对比
3.1 Hardhat测试架构
Hardhat基于Mocha和Chai测试框架,开发者使用JavaScript/TypeScript编写测试。这种方式的优点是学习曲线平缓,测试代码可读性强。
typescript
// Hardhat测试示例
import { expect } from "chai";
import { ethers } from "hardhat";
describe("Token Contract", function () {
let token: Contract;
beforeEach(async function () {
const Token = await ethers.getContractFactory("MyToken");
token = await Token.deploy(1000000);
await token.deployed();
});
it("should have correct total supply", async function () {
const totalSupply = await token.totalSupply();
expect(totalSupply).to.equal(1000000);
});
it("should transfer tokens correctly", async function () {
const [owner, addr1] = await ethers.getSigners();
await token.transfer(addr1.address, 100);
expect(await token.balanceOf(addr1.address)).to.equal(100);
});
});
3.2 Foundry测试架构
Foundry的测试直接在Solidity中编写,测试合约继承Test合约并使用内置的Test风格断言函数。
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "forge-std/Test.sol";
import "../src/MyToken.sol";
contract MyTokenTest is Test {
MyToken token;
function setUp() public {
token = new MyToken(1000000);
}
function testTotalSupply() public {
assertEq(token.totalSupply(), 1000000);
}
function testTransfer() public {
vm.prank(address(1));
token.transfer(address(2), 100);
assertEq(token.balanceOf(address(2)), 100);
}
// Foundry原生Fuzz测试
function testTransferFuzz(uint256 amount, address to) public {
vm.assume(amount > 0 && amount <= token.totalSupply());
vm.assume(to != address(0));
uint256 senderBalance = token.balanceOf(address(this));
token.transfer(to, amount);
assertEq(token.balanceOf(to), amount);
assertEq(token.balanceOf(address(this)), senderBalance - amount);
}
}
3.3 关键差异分析
类型安全:Foundry的Solidity测试在编译时进行类型检查,能在开发早期发现错误。Hardhat的JavaScript测试依赖运行时断言,类型问题可能直到执行时才暴露。
Gas追踪:Foundry内置--gas-report功能,每次测试自动生成详细Gas报告。Hardhat需要额外配置hardhat-gas-reporter插件。
bash
# Foundry直接生成Gas报告
forge test --gas-report
# 输出示例
┌─────────────────┬──────────┬─────────┬─────────┐
│ Token::transfer │ 51,413 │ - │ - │
│ Token::approve │ 46,423 │ - │ - │
└─────────────────┴──────────┴─────────┴─────────┘
模糊测试:Foundry内置强大的模糊测试引擎,能自动生成随机输入发现边界条件漏洞。这是Hardhat生态难以匹敌的优势。
四、部署与脚本能力
4.1 Hardhat部署脚本
typescript
// scripts/deploy.ts
import { ethers } from "hardhat";
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with account:", deployer.address);
console.log("Account balance:", (await deployer.getBalance()).toString());
const Token = await ethers.getContractFactory("MyToken");
const token = await Token.deploy(1000000);
await token.deployed();
console.log("Token deployed to:", token.address);
// 保存部署信息
saveDeployments(token.address);
}
function saveDeployments(tokenAddress: string) {
const fs = require("fs");
const deployments = {
network: network.name,
token: tokenAddress,
timestamp: new Date().toISOString()
};
fs.writeFileSync(
`deployments/${network.name}.json`,
JSON.stringify(deployments, null, 2)
);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
4.2 Foundry部署脚本
Foundry的脚本使用Solidity编写,与合约代码风格一致:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "forge-std/Script.sol";
import "../src/MyToken.sol";
contract DeployScript is Script {
function run() external {
vm.startBroadcast();
MyToken token = new MyToken(1000000);
console.log("Token deployed to:", address(token));
vm.stopBroadcast();
}
}
bash
# 执行部署
forge script scripts/Deploy.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
五、调试与日志
5.1 Hardhat调试能力
typescript
// Hardhat console
import "hardhat/console.sol";
function complexOperation(uint256 amount) public {
console.log("Starting operation with amount:", amount);
// ...
console.log("Operation completed");
}
5.2 Foundry调试能力
solidity
// Foundry内置日志和断点
function testComplexOperation() public {
uint256 result = complexOperation(1000);
console.log("Result:", result);
// 触发断点,进入调试模式
debugger;
assertEq(result, expectedValue);
}
bash
# 使用--debug标志进入交互式调试
forge test --debug --match-test testComplexOperation
六、生态与插件
6.1 Hardhat插件生态
Hardhat拥有丰富的插件生态,覆盖了从代码验证到Gas优化的各类需求:
| 插件 | 功能 |
|---|---|
| @nomiclabs/hardhat-ethers | ethers.js集成 |
| hardhat-deploy | 部署脚本管理 |
| hardhat-gas-reporter | Gas消耗报告 |
| @nomiclabs/hardhat-waffle | Waffle测试框架 |
| hardhat-contract-sizer | 合约大小分析 |
| solidity-coverage | 代码覆盖率 |
6.2 Foundry内置功能
Foundry将许多Hardhat需要插件实现的功能作为内置能力:
bash
# 内置功能一览
forge build # 编译(内置优化)
forge test # 测试(内置Gas报告)
forge coverage # 覆盖率分析(无需插件)
forge snapshot # Gas快照对比
forge fmt # 代码格式化
forge verify-contract # Etherscan验证
七、性能实测对比
7.1 编译性能
| 项目规模 | Hardhat | Foundry | 性能提升 |
|---|---|---|---|
| 10个合约 | 15秒 | 2秒 | 7.5x |
| 100个合约 | 2分钟 | 8秒 | 15x |
| 500个合约 | 10分钟 | 30秒 | 20x |
7.2 测试性能
| 测试数量 | Hardhat | Foundry | 性能提升 |
|---|---|---|---|
| 100个测试 | 30秒 | 3秒 | 10x |
| 1000个测试 | 5分钟 | 20秒 | 15x |
| 10000个测试 | 1小时 | 2分钟 | 30x |
八、选型建议
8.1 选择Hardhat的场景
- 团队以JavaScript/TypeScript为主:无需额外学习曲线
- 需要丰富的前端集成:ethers.js、viem等工具链完善
- 项目复杂度适中:编译性能尚可接受
- 依赖现有插件:某些特定功能只有Hardhat插件支持
8.2 选择Foundry的场景
- 追求极致性能:大型项目编译可节省数小时
- 需要高级测试能力:模糊测试、Invariant测试等
- 纯合约开发:不涉及复杂前端交互
- Gas优化导向:精确的Gas追踪至关重要
8.3 两者并存的策略
实际上,两个框架完全可以共存:
plaintext
项目结构/
├── contracts/ # Solidity合约(两框架共用)
├── foundry.toml # Foundry配置
├── hardhat.config.ts # Hardhat配置
├── test/
│ ├── foundry/ # Foundry测试
│ └── hardhat/ # Hardhat测试
├── script/
│ ├── forge/ # Foundry脚本
│ └── hardhat/ # Hardhat脚本
└── frontend/ # 前端集成
使用策略:
- Foundry处理合约开发、测试和Gas优化
- Hardhat处理前端集成和复杂脚本编排
九、迁移与过渡
9.1 从Hardhat迁移到Foundry
bash
# 1. 安装Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# 2. 初始化项目
forge init --force .
# 3. 复制现有合约
cp -r ../hardhat-project/contracts ./src
# 4. 迁移测试(需要重写为Solidity)
9.2 共享测试套件
可以同时维护两套测试,运行相同的合约测试:
solidity
// test/Token.behavior.t.sol
// 行为测试可以跨框架使用
function testBehavior_Transfer() public {
token.transfer(recipient, amount);
assertEq(token.balanceOf(recipient), amount);
}
十、总结
Hardhat和Foundry代表了两种不同的技术路线:前者强调生态和集成,后者追求性能和精确。选择哪个框架,应当基于团队技术背景、项目规模和具体需求综合判断。
对于新启动的纯合约项目,笔者强烈建议优先考虑Foundry。其性能优势和原生测试能力在复杂项目中会持续带来回报。对于需要深度前端集成的全栈项目,Hardhat的生态优势仍然不可忽视。
无论选择哪个框架,关键在于建立完善的测试流程和安全审计机制。工具只是手段,代码质量和安全意识才是根本。
常见问题
Q: Foundry可以替代Hardhat的所有功能吗?
A: 大部分可以,但涉及Node.js生态的功能(如复杂的构建流水线)仍需Hardhat。
Q: 两个框架可以同时用于同一个项目吗?
A: 可以。建议将合约源码放在共享目录,分别配置测试和部署流程。
Q: Foundry的测试比Hardhat更难写吗?
A: 对于有Solidity背景的开发者,Foundry测试更直观;对于JavaScript背景的开发者,Hardhat测试更容易上手。
Q: Foundry适合团队协作吗?
A: 非常适合。Forge的确定性构建确保跨环境一致性,fuzz测试能自动发现边界情况。

发表回复