DApp开发 ✅ 验证通过
Hardhat = 以太坊开发的专业框架,提供编译、测试、部署、调试一体化工具链。基于JavaScript/TypeScript,是Truffle的继任者,也是目前最主流的以太坊开发框架。Hardhat Network内置本地EVM,支持mainnet forking,开发者可以在本地模拟真实链上环境进行测试。
# 安装与初始化
npm init -y
npm install --save-dev hardhat
npx hardhat init # 选择 JavaScript project
# 项目结构
├── contracts/ ← Solidity源码
│ └── Lock.sol
├── scripts/ ← 部署脚本
│ └── deploy.js
├── test/ ← 测试文件
│ └── Lock.test.js
├── hardhat.config.js ← 配置文件
└── artifacts/ ← 编译输出
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: {
version: "0.8.19",
settings: {
optimizer: { enabled: true, runs: 200 },
viaIR: true,
},
},
networks: {
hardhat: {
forking: {
url: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
enabled: false,
},
},
sepolia: {
url: process.env.SEPOLIA_RPC_URL,
accounts: [process.env.PRIVATE_KEY],
},
},
etherscan: { apiKey: process.env.ETHERSCAN_API_KEY },
};
const { expect } = require("chai");
const { loadFixture } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
describe("Counter", function () {
async function deployFixture() {
const [owner, other] = await ethers.getSigners();
const Factory = await ethers.getContractFactory("Counter");
const counter = await Factory.deploy();
return { counter, owner, other };
}
it("should start at 0", async function () {
const { counter } = await loadFixture(deployFixture);
expect(await counter.getCount()).to.equal(0);
});
it("should increment", async function () {
const { counter } = await loadFixture(deployFixture);
await counter.increment();
expect(await counter.getCount()).to.equal(1);
});
it("should emit event", async function () {
const { counter, owner } = await loadFixture(deployFixture);
await expect(counter.increment())
.to.emit(counter, "CountIncremented")
.withArgs(1, owner.address);
});
it("should revert for non-owner", async function () {
const { counter, other } = await loadFixture(deployFixture);
await expect(counter.connect(other).reset())
.to.be.revertedWithCustomError(counter, "Unauthorized");
});
});
const hre = require("hardhat");
async function main() {
const Factory = await hre.ethers.getContractFactory("Counter");
console.log("Deploying Counter...");
const counter = await Factory.deploy();
await counter.waitForDeployment();
console.log("Deployed to:", await counter.getAddress());
if (hre.network.name !== "hardhat") {
await counter.deploymentTransaction().wait(5);
await hre.run("verify:verify", {
address: await counter.getAddress()
});
}
}
main().catch(console.error);
| 命令 | 说明 |
|---|---|
| npx hardhat compile | 编译合约 |
| npx hardhat test | 运行测试 |
| npx hardhat coverage | 测试覆盖率 |
| npx hardhat node | 启动本地节点 |
| npx hardhat run scripts/deploy.js --network sepolia | 部署到测试网 |
| npx hardhat verify ADDR --network sepolia | 验证源码 |
| npx hardhat console | 交互式控制台 |
Hardhat测试框架?
optimizer.runs?
mainnet forking?
loadFixture?
waitForDeployment?
// hardhat.config.js - 高级网络配置
module.exports = {
networks: {
hardhat: {
// 主网Fork: 本地模拟真实链上状态
forking: {
url: "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
blockNumber: 18000000, // 固定区块(可重复测试)
enabled: true,
},
// 自定义账户余额
accounts: [{ balance: "10000000000000000000000" }],
// 挖矿模式
mining: { auto: true, interval: 5000 },
},
},
};
| 插件 | 用途 |
|---|---|
| hardhat-toolbox | 一站式工具包(推荐) |
| hardhat-gas-reporter | Gas消耗报告 |
| solidity-coverage | 测试覆盖率 |
| hardhat-watcher | 文件变化自动测试 |
| hardhat-deploy | 高级部署管理 |
| hardhat-verify | Etherscan源码验证 |
const hre = require("hardhat");
// 多合约部署脚本
async function main() {
// 1. 部署代币
const Token = await hre.ethers.getContractFactory("SimpleERC20");
const token = await Token.deploy("MyToken", "MTK", 1000000);
await token.waitForDeployment();
console.log("Token:", await token.getAddress());
// 2. 部署DEX(依赖代币地址)
const DEX = await hre.ethers.getContractFactory("SimpleDEX");
const dex = await DEX.deploy(await token.getAddress(), "0xOtherToken");
await dex.waitForDeployment();
console.log("DEX:", await dex.getAddress());
// 3. 验证源码(仅非本地网络)
if (hre.network.name !== "hardhat") {
console.log("Waiting for confirmations...");
await token.deploymentTransaction().wait(5);
await hre.run("verify:verify", {
address: await token.getAddress(),
constructorArguments: ["MyToken", "MTK", 1000000],
});
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
// .env文件(不要提交到Git!)
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
PRIVATE_KEY=your_private_key_here
ETHERSCAN_API_KEY=your_api_key_here
// hardhat.config.js
require("dotenv").config();
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.19",
networks: {
sepolia: {
url: process.env.SEPOLIA_RPC_URL,
accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
},
},
etherscan: { apiKey: process.env.ETHERSCAN_API_KEY },
};
// Hardhat + TypeScript配置
// npm install --save-dev typescript ts-node @types/node @types/chai @types/mocha
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"outDir": "./dist"
},
"include": ["./scripts", "./test", "./deploy"],
"files": ["./hardhat.config.ts"]
}
// test/Token.test.ts
import { expect } from "chai";
import { ethers } from "hardhat";
import { Token } from "../typechain-types";
describe("Token", function () {
let token: Token;
beforeEach(async () => {
const Factory = await ethers.getContractFactory("Token");
token = await Factory.deploy("Test", "TST", 1000000);
});
it("should have correct name", async () => {
expect(await token.name()).to.equal("Test");
});
});
// hardhat.config.js - 性能优化配置
module.exports = {
solidity: {
version: "0.8.19",
settings: {
optimizer: {
enabled: true,
runs: 200, // 调用次数预估,影响优化方向
// runs=1: 最小部署大小(部署便宜,调用贵)
// runs=999999: 最小运行Gas(部署贵,调用便宜)
},
viaIR: true, // ✅ IR pipeline: 更好的优化
evmVersion: "paris", // Shanghai后包括PUSH0
},
},
mocha: { timeout: 60000 }, // 增加超时
};
| Hardhat | Foundry | |
|---|---|---|
| 语言 | JavaScript/TypeScript | Solidity |
| 测试速度 | 较慢(EVM模拟) | 极快(原生编译) |
| Fuzz测试 | 手动JS循环 | 原生支持 |
| 学习曲线 | 低(前端友好) | 中等(需学Solidity) |
| 生态 | 成熟(更多插件) | 快速增长 |
| 适合 | 全栈开发者 | Solidity专家 |
你已掌握Hardhat全流程——编译/测试/部署/验证!
✅ 项目初始化 ✅ 配置优化 ✅ Chai测试 ✅ 部署脚本