目录
Truffle + Hardhat 双框架实战指南
1. 双框架集成概述
在现代以太坊开发中,Truffle 和 Hardhat 都是主流开发框架,各有优势:
- Truffle:成熟生态,内置合约编译、测试、部署功能
- Hardhat:强大灵活性,支持 TypeScript,插件系统丰富
2. 环境配置与初始化
2.1 项目初始化
mkdir dual-framework-demo
cd dual-framework-demo
npm init -y
# 安装 Truffle
npm install -g truffle
truffle init
# 安装 Hardhat
npm install --save-dev hardhat
npx hardhat init
2.2 目录结构调整
dual-framework-demo/
├── contracts/ # 共享合约目录
├── migrations/ # Truffle 迁移脚本
├── scripts/ # Hardhat 部署脚本
├── test/ # 共享测试目录
│ ├── truffle/ # Truffle 测试
│ └── hardhat/ # Hardhat 测试
├── hardhat.config.js # Hardhat 配置
└── truffle-config.js # Truffle 配置
2.3 安装依赖
npm install --save-dev \
@nomicfoundation/hardhat-toolbox \
@truffle/hdwallet-provider \
dotenv \
chai \
@types/chai \
ts-node \
typescript
3. 配置双框架环境
3.1 Hardhat 配置 (hardhat.config.js
)
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
module.exports = {
solidity: "0.8.19",
networks: {
hardhat: {
chainId: 1337,
},
goerli: {
url: process.env.GOERLI_RPC_URL,
accounts: [process.env.PRIVATE_KEY],
}
},
paths: {
sources: "./contracts",
tests: "./test/hardhat",
cache: "./cache_hardhat",
artifacts: "./artifacts_hardhat"
}
};
3.2 Truffle 配置 (truffle-config.js
)
require("dotenv").config();
const HDWalletProvider = require("@truffle/hdwallet-provider");
module.exports = {
contracts_build_directory: "./build_truffle",
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
},
goerli: {
provider: () => new HDWalletProvider({
privateKeys: [process.env.PRIVATE_KEY],
providerOrUrl: process.env.GOERLI_RPC_URL
}),
network_id: 5,
}
},
compilers: {
solc: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
}
}
};
4. 智能合约开发
4.1 创建示例合约 (contracts/SimpleStorage.sol
)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract SimpleStorage {
uint256 private storedValue;
event ValueChanged(uint256 newValue);
function setValue(uint256 _value) public {
storedValue = _value;
emit ValueChanged(_value);
}
function getValue() public view returns (uint256) {
return storedValue;
}
}
5. 迁移与部署脚本
5.1 Truffle 迁移脚本 (migrations/1_deploy_contracts.js
)
const SimpleStorage = artifacts.require("SimpleStorage");
module.exports = function (deployer) {
deployer.deploy(SimpleStorage);
};
5.2 Hardhat 部署脚本 (scripts/deploy.ts
)
import { ethers } from "hardhat";
async function main() {
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
const simpleStorage = await SimpleStorage.deploy();
await simpleStorage.deployed();
console.log(`SimpleStorage deployed to: ${simpleStorage.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
6. 双框架测试集成
6.1 Truffle 测试 (test/truffle/simpleStorage.test.js
)
const SimpleStorage = artifacts.require("SimpleStorage");
contract("SimpleStorage (Truffle)", (accounts) => {
let simpleStorage;
before(async () => {
simpleStorage = await SimpleStorage.deployed();
});
it("should store a value", async () => {
const newValue = 42;
await simpleStorage.setValue(newValue);
const storedValue = await simpleStorage.getValue();
assert.equal(storedValue, newValue, "Value not stored correctly");
});
it("should emit ValueChanged event", async () => {
const newValue = 100;
const tx = await simpleStorage.setValue(newValue);
assert.equal(tx.logs[0].event, "ValueChanged", "Event not emitted");
assert.equal(tx.logs[0].args.newValue, newValue, "Event value incorrect");
});
});
6.2 Hardhat 测试 (test/hardhat/simpleStorage.test.ts
)
import { expect } from "chai";
import { ethers } from "hardhat";
import { SimpleStorage } from "../typechain-types";
describe("SimpleStorage (Hardhat)", function () {
let simpleStorage: SimpleStorage;
before(async () => {
const SimpleStorageFactory = await ethers.getContractFactory("SimpleStorage");
simpleStorage = await SimpleStorageFactory.deploy();
await simpleStorage.deployed();
});
it("Should store a value", async () => {
const newValue = 42;
await simpleStorage.setValue(newValue);
expect(await simpleStorage.getValue()).to.equal(newValue);
});
it("Should emit ValueChanged event", async () => {
const newValue = 100;
await expect(simpleStorage.setValue(newValue))
.to.emit(simpleStorage, "ValueChanged")
.withArgs(newValue);
});
});
7. 双框架编译与测试
7.1 使用 Truffle
# 编译合约
truffle compile
# 启动开发链
truffle develop
# 在Truffle控制台内执行
migrate
test ./test/truffle/simpleStorage.test.js
7.2 使用 Hardhat
# 编译合约
npx hardhat compile
# 运行测试
npx hardhat test
8. 高级功能集成
8.1 TypeScript 支持配置 (tsconfig.json
)
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"outDir": "dist",
"rootDir": ".",
"types": ["hardhat", "chai"]
},
"include": ["./scripts", "./test"]
}
8.2 集成 Hardhat 插件
npm install --save-dev \
@nomiclabs/hardhat-etherscan \
hardhat-gas-reporter \
solidity-coverage
更新 hardhat.config.js
:
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
require("hardhat-gas-reporter");
require("solidity-coverage");
module.exports = {
solidity: "0.8.19",
networks: {
// ...网络配置
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY,
},
gasReporter: {
enabled: process.env.REPORT_GAS ? true : false,
currency: "USD",
coinmarketcap: process.env.COINMARKETCAP_API_KEY,
},
paths: {
// ...路径配置
}
};
9. 双框架部署策略
9.1 Truffle 部署到 Goerli 测试网
truffle migrate --network goerli
9.2 Hardhat 部署到 Goerli 测试网
npx hardhat run scripts/deploy.ts --network goerli
9.3 验证合约 (Hardhat)
// scripts/verify.ts
import { run } from "hardhat";
async function verify() {
const address = "0x..."; // 部署后的合约地址
await run("verify:verify", {
address: address,
constructorArguments: [],
});
}
verify().catch(console.error);
运行验证:
npx hardhat run scripts/verify.ts --network goerli
10. 实战工作流程示例
10.1 完整开发流程
10.2 自动化脚本 (package.json
)
{
"scripts": {
"truffle:compile": "truffle compile",
"truffle:test": "truffle test ./test/truffle",
"truffle:migrate": "truffle migrate",
"truffle:migrate-goerli": "truffle migrate --network goerli",
"hardhat:compile": "hardhat compile",
"hardhat:test": "hardhat test ./test/hardhat",
"hardhat:coverage": "hardhat coverage",
"hardhat:gas": "REPORT_GAS=true hardhat test",
"hardhat:deploy": "hardhat run scripts/deploy.ts",
"hardhat:deploy-goerli": "hardhat run scripts/deploy.ts --network goerli",
"hardhat:verify": "hardhat run scripts/verify.ts --network goerli",
"dev": "npm run truffle:compile && npm run truffle:migrate && npm run truffle:test",
"test": "npm run truffle:test && npm run hardhat:test",
"deploy": "npm run hardhat:deploy-goerli && npm run hardhat:verify"
}
}
11. 双框架优势整合
11.1 Truffle 核心优势
- 成熟迁移系统:结构化部署流程
- 内置开发控制台:交互式调试
- Ganache 集成:可视化区块链管理
- 广泛文档支持:初学者友好
11.2 Hardhat 核心优势
- TypeScript 支持:强类型开发体验
- 插件生态系统:丰富扩展功能
- 高级调试功能:
console.log
在 Solidity - 任务系统:自定义工作流
11.3 最佳整合策略
开发阶段 | 推荐框架 | 原因 |
---|---|---|
本地开发环境 | Truffle | 快速启动,内置控制台 |
合约编译 | 双框架 | 确保兼容性 |
基础测试 | Truffle | 简单快速 |
复杂测试 | Hardhat | TypeScript支持,高级断言 |
本地部署 | Truffle | 迁移脚本简单 |
测试网部署 | Hardhat | 更好的错误处理,插件支持 |
合约验证 | Hardhat | 集成化验证流程 |
性能分析 | Hardhat | Gas报告,代码覆盖率 |
12. 常见问题解决方案
12.1 编译冲突问题
当两个框架同时编译时,解决方案:
# truffle-config.js
module.exports = {
+ contracts_build_directory: "./build_truffle",
// ...
}
# hardhat.config.js
module.exports = {
paths: {
+ artifacts: "./artifacts_hardhat"
}
}
12.2 TypeScript 类型生成
安装类型生成工具:
npm install --save-dev typechain @typechain/hardhat @typechain/truffle-v5
配置 Hardhat:
// hardhat.config.js
require("@typechain/hardhat");
require("@nomiclabs/hardhat-ethers");
module.exports = {
// ...
typechain: {
outDir: "typechain",
target: "ethers-v5",
},
};
配置 Truffle:
// truffle-config.js
require("@typechain/truffle-v5");
module.exports = {
// ...
plugins: ["@typechain/truffle-v5"],
typechain: {
outDir: "typechain-truffle",
},
};
12.3 共享合约目录技巧
在 hardhat.config.js
和 truffle-config.js
中设置相同的合约目录:
// 两个配置文件中
{
// ...
paths: {
sources: "./contracts"
}
}
13. 生产环境最佳实践
13.1 安全加固措施
- 合约验证:部署后立即验证源码
- 多签名部署:关键操作使用 Gnosis Safe
- 自动化测试:CI/CD 集成测试流程
- 依赖锁定:使用
package-lock.json
或yarn.lock
13.2 性能优化
// 在两个框架的配置中启用优化器
compilers: {
solc: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200 // 优化程度,值越大Gas越少但字节码越大
}
}
}
}
13.3 持续集成配置 (GitHub Actions)
name: CI Pipeline
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Run Truffle tests
run: npm run truffle:test
- name: Run Hardhat tests
run: npm run hardhat:test
- name: Run Hardhat coverage
run: npm run hardhat:coverage
- name: Run Hardhat gas report
run: npm run hardhat:gas
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Deploy to Goerli
run: npm run deploy
env:
PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }}
GOERLI_RPC_URL: ${{ secrets.GOERLI_RPC_URL }}
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
结论:双框架工作流优势
通过整合 Truffle 和 Hardhat,开发者可以创建强大的混合开发环境:
- 本地开发:使用 Truffle + Ganache 快速原型开发
- 测试阶段:
- Truffle 用于基础功能测试
- Hardhat 用于复杂场景和 TypeScript 测试
- 部署流程:
- Truffle 用于简单本地部署
- Hardhat 用于生产环境部署和验证
- 维护阶段:
- Hardhat 插件用于监控和优化
- 双框架确保兼容性和灵活性
关键建议:
- 统一合约目录,分离编译输出
- 使用 TypeScript 增强代码质量
- 自动化测试和部署流程
- 定期同步两个框架的 Solidity 版本
- 利用 Hardhat 插件扩展功能
Truffle 和 Hardhat 双框架策略为以太坊开发者提供了从初学者到高级项目的完整工具链,平衡了易用性和灵活性,是现代 DApp 开发的最佳实践。