前言
本文详细介绍如何使用 Hardhat V3 框架从零开始构建智能合约项目,涵盖合约的开发、测试、部署全流程,以及开发过程中常见问题的解决方法。
项目构建
bash
# 创建项目文件夹
mkdir hardhat-example
# 进入项目文件夹
cd hardhat-example
# hardhat初始化
npx hardhat --init
# 按照提示进行模板选择和项目构建
# 构建成功
项目目录
arduino
hardhat-example/
├── contracts/
│ └── Counter.sol // 示例智能合约
├── test/
│ └── Counter.test.ts // 测试文件
├── ignition/
│ └── modules/
│ └── Counter.ts // Ignition部署模块
├── scripts/
│ └── interact.ts // 交互脚本
├── hardhat.config.ts // Hardhat配置文件
├── package.json // 项目依赖
└── .env // 环境变量(需gitignore)
常用指令
bash
# 获取所有指令
npx hardhat
# 在 Hardhat Network 上启动 JSON-RPC 服务器
npx hardhat node
# 编译合约(两种等价方式)
npx hardhat build
npx hardhat compile
# 清空缓存并删除所有编译产物
npx hardhat clean
# 测试合约
npx hardhat test //测试所有的合约
npx hardhat test ./test/xxx.ts//测试指定的合约
# 编译项目后运行用户自定义脚本快速部署不止是部署(快速验证)
npx hardhat run
npx hardhat run ./scripts/xxx.ts
# 部署(Hardhat 2.0+ 的现代部署标准)
npx hardhat ignition deploy ignition/modules/xxx.ts --network sepolia
# 然后使用公共网络验证
npx hardhat verify <已部署地址> --network sepolia//验证sepolia链
# 扁平化并打印合约及其依赖项 =>展平并保存到文件
npx hardhat flatten contracts/YourContract.sol > flattened.sol
常见问题解决
问题描述:项目构建后执行指令时卡在 "Downloading solc 0.8.28",通常是由于网络问题导致 Solidity 编译器下载失败。
解决方法:手动下载 solc 并指定路径
-
手动下载安装solc :根据操作系统下载对应二进制文件solc releases安装包并安装
-
找到安装路径
通过命令提示符(CMD)
sql按 Win + R,输入 cmd,回车 输入指令:start %LOCALAPPDATA%\hardhat-nodejs\Cache\compilers-v3\windows-amd64\ -
配置 Hardhat 使用本地 solc:
- 在
hardhat.config.js中指定本地 solc 路径:
phpexport default defineConfig({ plugins: [hardhatToolboxViemPlugin], solidity: { profiles: { default: { version: "0.8.28", }, production: { version: "0.8.28", settings: { solc:{ //绝对路径 path: "C:/Users/用户名/AppData/Local/hardhat-nodejs/Cache/compilers-v3/windows-amd64/tmp-solc-windows-amd64-v0.8.28+commit.7893614a.exe", }, optimizer: { enabled: true, runs: 200, }, }, }, }, }, 其他配置 }特殊说明:
关于以上hardhat.config.js配置或导致执行npx hardhat ignition deploy --network localhost ignition/modules/Counter.ts 执行失败部署问题修复:
css// 注释掉solc路径配置 把以上配置 production: { version: "0.8.28", settings: { // solc:{ // path: "xxx.exe", // }, optimizer: { enabled: true, runs: 200, }, }, }, - 在
实操案例
合约开发:ERC20 代币合约
基于 OpenZeppelin 实现一个带 mint 和 burn 功能的 ERC20 代币:
javascript
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.5.0
pragma solidity ^0.8.27;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
contract BoykaYuriToken is ERC20, ERC20Burnable, Ownable, ERC20Permit {
constructor(address recipient, address initialOwner)
ERC20("BoykaYuriToken", "BTK")
Ownable(initialOwner)
ERC20Permit("BoykaYuriToken")
{
_mint(recipient, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
# 编译指令
# npx hardhat compile
合约测试
javascript
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { network } from "hardhat";
describe("MyToken", async function () {
it("Should deploy the contract", async function () {
const { viem } = await network.connect();
const publicClient = await viem.getPublicClient();
const [owner] = await viem.getWalletClients();//获取第一个钱包客户端
const deployerAddress = owner.account.address;//钱包地址
const contract = await viem.deployContract("BoykaYuriToken", [deployerAddress, deployerAddress]);//部署合约
assert.ok(contract.address); //断言合约地址存在
console.log("Contract deployed at:", contract.address);
console.log("合约所有者:", deployerAddress);
console.log("代币名:", await publicClient.readContract({
address: contract.address,
abi: contract.abi,
functionName: "name",
}));
console.log("代币符号:", await publicClient.readContract({
address: contract?.address,
abi: contract?.abi,
functionName: "symbol",
}));
console.log("合约总供应量:", await publicClient.readContract({
address: contract.address,
abi: contract.abi,
functionName: "totalSupply",
}));
})
})
# 测试指令
# npx gardhat test test/xx.ts
合约部署
csharp
// scripts/deploy.js
import { network, artifacts } from "hardhat";
async function main() {
// 连接网络
const { viem } = await network.connect({ network: network.name });
// 获取客户端
const [deployer] = await viem.getWalletClients();
const publicClient = await viem.getPublicClient();
// 加载合约
const artifact = await artifacts.readArtifact("BoykaYuriToken");
// 部署(构造函数参数:recipient, initialOwner)
const hash = await deployer.deployContract({
abi: artifact.abi,
bytecode: artifact.bytecode,
args: [process.env.RECIPIENT, process.env.OWNER],//参数1,参数2
});
// 等待确认并打印地址
const receipt = await publicClient.waitForTransactionReceipt({ hash });
console.log("TOKEN合约地址",receipt.contractAddress);
}
main().catch(console.error);
# 部署指令
# npx hardhat run scripts/xxx.ts
总结
本文完整介绍了使用 Hardhat V3 框架从项目初始化到合约开发、测试、部署的全流程,并提供了常见问题的解决方案。通过本文的指导,你可以快速搭建起一个可靠的智能合约开发环境并完成基础的合约开发工作。