新闻详情

新闻详情

首页 / 资讯中心 / 详情

Solidity工程化开发入门:用Hardhat搭建智能合约编译、部署与测试全流程

发布时间:2026/9/28 6:33:55来源:尧图网络
Solidity工程化开发入门:用Hardhat搭建智能合约编译、部署与测试全流程
说个很多Solidity新手都会掉进去的坑在Remix里写完一个合约觉得万事大吉等到真要上手项目才发现根本不知道代码怎么组织、怎么自动化测试、怎么批量部署。我第一次接真实项目时就是这个状态翻文档翻了整整一个周末才搞明白Hardhat这套工程化工具链的玩法。如果你也准备认真学Solidity我建议直接跳过在网页里写合约的阶段从Hardhat开始。这篇是Solidity入门系列的第一篇聚焦Hardhat框架本身。我们会从环境搭建、项目结构、配置解析、合约编写、编译部署到测试调试把一套完整的开发流程跑通。内容面向零基础读者但即使你已经写过几个简单合约这篇文章里关于配置文件解析、部署脚本演进、常见报错排除的部分也值得你花几分钟扫一遍——毕竟很多坑不是新手才踩老手一样会翻车。1. 先把框架选对Hardhat凭什么成为Solidity开发者默认选择以太坊智能合约的开发流程本质上是一条流水线写Solidity代码、编译成字节码、部署到链上、调用合约验证逻辑、测试各种边界情况。问题是这条流水线上每一环都有独立的工具新手很容易迷失在工具选择里。目前主流的开发框架主要有三个Hardhat、Truffle和Foundry。我用一张表格带你快速比较它们的定位差异框架核心定位语言生态调试能力适合场景Hardhat工程化开发环境JavaScript/TypeScript内置console.log、堆栈追踪绝大多数项目资料最全Truffle老牌一体化框架JavaScript较弱依赖外部工具遗留项目维护已停止维护Foundry快速测试与链上交互Solidity原生基于Rust速度快对性能要求高的测试场景很多人会问既然Foundry那么快为什么不直接用它答案很简单生态成熟度差距太大。Hardhat背后有Nomic Foundation在维护插件生态覆盖了部署、验证、覆盖率、Gas报告、升级等几乎所有需求而且以太坊官方文档、OpenZeppelin的大量示例都基于Hardhat。对入门者来说跟着一个生态最完整的框架走能少踩无数坑。再说说Hardhat名字的来历它和硬帽这个词有关系官方寓意是让开发者在本地拥有一顶安全的头盔——同样一个Solidity合约在本地跑和在真实链上跑成本天差地别。真实主网上每笔交易都要付Gas费测试网虽然免费但有速率限制而Hardhat内置的Hardhat Network直接在本地模拟了一个完整的以太坊节点交易秒级确认、无费用、可随时重置状态这就相当于给合约开发装了一台本地练习机等逻辑全部验证通过再花钱上真实赛场。Hardhat Network的核心价值就是让快速迭代成为可能。我调试一个合约逻辑时最频繁的操作就是改一行代码、跑一次测试、看一眼输出、再改这个循环如果放到真实链上光是等待区块确认就足以让人崩溃。还有一个被很多人忽略的点Hardhat的优秀栈追踪能力。当合约revert时Hardhat会直接从Solidity源码层面告诉你出错的行号和调用栈而不再是一堆让人头大的字节码。这一点在复杂合约联调时几乎是救命级别的功能。2. 从空目录到Hello WorldHardhat环境搭建与项目初始化2.1 确认环境Node.js版本是第一个坑Hardhat运行在Node.js环境上所以第一步是装Node.js。这里有一个很多新手会踩的坑版本太老或太新的Node.js都可能让Hardhat安装失败。我建议使用Node.js 16.14及以上版本18.x和20.x的LTS版本都测试过没问题。检查当前版本node -v如果你机器上有多个Node版本推荐用nvmNode Version Manager管理切版本就一行命令省去很多环境层面的混乱。2.2 初始化项目并安装Hardhat新建一个项目目录并进入mkdir hello-hardhat cd hello-hardhat npm init -y先执行npm init初始化package.json文件再通过npm把Hardhat作为开发依赖安装npm install --save-dev hardhat这里强调一个原则永远使用本地安装不要全局安装。全局安装看似方便但不同项目对Hardhat版本要求不同全局版本一旦升级可能直接拖垮旧项目。本地安装之后用npx hardhat调用的一定是当前项目里的那个版本可靠得多。安装完成后执行初始化命令npx hardhat init这会进入一个交互式引导界面问你几个问题是否创建示例项目建议选Yes里面有一个现成的合约和测试跑通它你就知道整个流程长什么样了使用JavaScript还是TypeScript第一次建议选JavaScript少一层类型配置专注理解核心概念初始化完成后项目里会自动装好下面这些依赖hardhat框架本体nomicfoundation/hardhat-toolbox全家桶插件集成了ethers.js、测试工具、覆盖率等常用能力chai和mocha测试框架2.3 验证安装跑一次示例流程项目初始化完成后先别急着改代码直接按顺序执行三个命令验证环境npx hardhat compile npx hardhat test npx hardhat nodecompile编译合约、test跑测试、node启动本地节点三关都过了说明你的Hardhat环境是健康的。后面每遇到诡异问题我都建议先跑一遍这三关快速判断问题出在环境还是代码。3. hardhat.config.js拆解网络、编译器与插件到底在配置什么初始化完成后项目根目录会出现一个hardhat.config.js或hardhat.config.ts文件这是整个项目的总开关。先看一个最小可用的配置require(nomicfoundation/hardhat-toolbox); module.exports { solidity: 0.8.24, networks: { hardhat: { chainId: 31337 } } };就这么几行背后牵涉了三个层面的配置逻辑。3.1 compiler配置用什么版本的solcsolidity: 0.8.24指定了Solidity编译器版本。为什么要单独指定因为Solidity编译器每个版本之间可能存在细微行为差异同一个合约在不同版本下编译出的字节码可能不同。为了保证在本地编译和测试的结果和CI服务器、队友电脑上一致项目里必须锁定一个版本。一个常见问题是如果项目里引用了不同版本的库合约怎么办Hardhat支持按目录指定编译器版本module.exports { solidity: { compilers: [ { version: 0.8.24 }, { version: 0.7.6 } ], overrides: { openzeppelin/contracts/: { version: 0.8.24 } } } };不过这个属于进阶用法新手知道有这回事就行见到版本冲突报错时知道来改这个配置。3.2 networks配置本地、测试网和主网的接线图networks配置块定义了你的合约可以部署到哪里。默认配置中只有一个hardhat网络也就是Hardhat内置的本地网络。除了它之外最常见的还有两类一是本地独立节点使用npx hardhat node启动一个持续运行的本地网络配置起来就是指定url地址networks: { localhost: { url: http://127.0.0.1:8545 } }二是公开测试网比如Sepolia。真实部署需要两类信息RPC节点地址和部署账户私钥。RPC地址可以从Infura、Alchemy等节点服务商免费申请私钥是你在测试网部署时用来签交易的账户密钥。注意这里的私钥是测试网私钥即使泄露理论上损失也有限但依然不建议直接写在配置文件里。我习惯用dotenv管理环境变量具体做法在第5章部署部分详细说。3.3 插件系统什么功能都可以往里加第3行的require(nomicfoundation/hardhat-toolbox)加载了toolbox插件。这个插件是Hardhat官方推荐的实用工具集合内部打包了ethers.js集成提供hre.ethers对象用于部署和交互chai匹配器让测试断言更贴合合约语义Hardhat Network的vendor功能支持模拟任意链的账户和状态合约大小检查防止合约体积超出以太坊限制24KB插件的意义在于解耦核心框架只负责编译、部署、任务调度等基础设施具体功能比如覆盖率、Gas报告、合约验证通过插件按需加载。这种设计让Hardhat的生态越滚越大新功能出现时不需要等框架更新。4. 合约编写与编译从Solidity源码到ABI和Bytecode4.1 第一个合约一个带增减功能的计数器初始化的示例项目里已经有一个Lock合约但结构对入门者来说偏复杂。我们在contracts目录下新建一个Counter.sol写一个最简单的合约// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; contract Counter { uint256 public count; function increment() public { count 1; } function decrement() public { require(count 0, Counter: count cannot be negative); count - 1; } function getCount() external view returns (uint256) { return count; } }逐行拆解一下核心结构SPDX-License-Identifier是许可证声明以太坊社区要求开源合约标注许可证类型MIT是最宽松的常见选择不写会编译警告pragma solidity ^0.8.24;声明了编译器版本范围。^0.8.24意味着大于等于0.8.24且小于0.9.0这样可以兼容不会破坏现有代码的更新uint256 public count;是状态变量public会自动生成一个同名的getter函数方便外部读取increment和decrement是修改合约状态的函数会消耗GasgetCount是view函数只读取状态、不修改链上数据不消耗Gas在外部调用时require是Solidity的断言函数条件不满足时回滚整个交易并抛出错误信息4.2 编译npx hardhat compile到底做了什么执行编译npx hardhat compile第一次编译会慢一点因为需要下载对应的solc编译器。后续再编译Hardhat会做增量编译只重新编译有变更的文件速度很快——这个缓存机制是默认开启的不需要额外配置。编译完成后项目里会多出一个artifacts目录。这个目录里有每个合约的JSON文件重点关注两个字段abi一个描述合约接口的JSON数组包含函数名、参数类型、返回类型、是否为view/payable等信息。外部程序依赖ABI来编码调用数据、解析返回结果可以理解成合约的函数接口说明书bytecodeSolidity编译生成的字节码也就是最终要部署到链上的机器码包含合约完整的逻辑和代码还有一个细节artifacts目录之外还有个cache目录里面是Hardhat对编译信息做的索引。这两个目录都应该加入.gitignore因为它们是从源码重新生成的产物存在版本库里只会制造噪音。4.3 编译期常见报错速查我整理了几个高频编译错误你看一眼心里有数报错信息常见原因解决办法Source file requires different compiler version项目锁定的solc版本和合约的pragma声明的版本范围没有交集在config中调整solidity版本Contract has not been fully specified有抽象函数未实现或引用了未导入的合约检查继承关系和import语句DeclarationError: Identifier not found变量或函数名写错到对应行检查拼写TypeError: Function override specified but did not override anything标了override但父合约并没有这个函数检查继承合约函数签名ParserError: Expected token语法错误多半是缺括号或分号到报错行附近检查编译报错时Hardhat会直接给出Compilation failed加上具体文件路径和行号定位成本很低。5. 部署脚本实战把合约送上本地网络和Sepolia测试网5.1 为什么部署要单独写脚本在Remix里部署就是点个按钮在Hardhat里部署则要写脚本很多新手在这里不习惯。但脚本化恰恰是工程化的价值同一份部署逻辑可以原样跑到本地网络、测试网、主网只是切换网络配置而已无需人工重复点击而且过程可审计、可版本管理、可被CI集成。在scripts目录下新建deploy.jsconst hre require(hardhat); async function main() { const [deployer] await hre.ethers.getSigners(); console.log(Deploying contracts with the account:, deployer.address); const Counter await hre.ethers.getContractFactory(Counter); const counter await Counter.deploy(); await counter.waitForDeployment(); console.log(Counter deployed to:, await counter.getAddress()); } main().catch((error) { console.error(error); process.exitCode 1; });这段脚本做四件事获取部署账户签名者、从合约工厂获取Counter的部署对象、部署合约、打印合约地址。注意waitForDeployment()是新版API旧版常见写法是deployed()如果你在别人的老教程里看到后者记得换成新API否则在最新版Hardhat里会报错。执行部署npx hardhat run scripts/deploy.js默认部署到内置Hardhat Network每次运行后合约地址都会变这是正常的——内置网络每次是全新状态。如果想要一个持续运行的网络可以另开一个终端执行npx hardhat node然后部署时指定网络名npx hardhat run scripts/deploy.js --network localhost5.2 部署测试网RPC、私钥和.env的最佳实践部署到Sepolia测试网的流程和本地几乎一样只是网络配置不同。首先申请一个RPC地址以Alchemy为例创建应用后会得到一个形如https://eth-sepolia.g.alchemy.com/v2/XXXX的URL。接着准备一个带有Sepolia测试币的钱包账户私钥。我的做法是引入dotenv管理敏感信息npm install --save-dev dotenv然后在hardhat.config.js最顶部加上require(dotenv).config();再让配置引用环境变量require(nomicfoundation/hardhat-toolbox); require(dotenv).config(); module.exports { solidity: 0.8.24, networks: { hardhat: {}, sepolia: { url: process.env.SEPOLIA_RPC_URL || , accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [] } } };项目根目录新建.env文件SEPOLIA_RPC_URLhttps://eth-sepolia.g.alchemy.com/v2/你的key PRIVATE_KEY你的账户私钥同时把.env加入.gitignore这个文件绝对不应该出现在Git仓库里。私钥一旦泄露别人就能控制你的账户、转走测试币极端情况下如果用了主网账户后果是资产直接丢失。配置完成后执行npx hardhat run scripts/deploy.js --network sepolia脚本不用改一行代码网络切换完全靠配置驱动。这条配置与逻辑分离的思路在真实项目中几乎天天用到。测试网上列出的合约还可以通过npx hardhat verify --network sepolia 合约地址验证源码这用到了socrates/hardhat-verify插件toolbox里已包含验证后合约就能在区块浏览器里看到源码方便别人信任和审计。5.3 Gas费用是个绕不开的话题说到部署Gas是无法回避的概念。在以太坊上每笔交易耗费的Gas乘以Gas价格就是交易费用。部署合约是链上计算密集型操作代价通常不小。在主网部署时代码越复杂的合约Gas费越高所以Hardhat才会提供合约大小检查插件——如果字节码超过24KB上限合约就无法部署。这里是Hardhat在帮你在上链之前就把问题暴露出来而不是等部署失败才着急。6. 测试与调试console.log之外的排错手段6.1 为什么合约必须有自动化测试Solidity合约部署后不可篡改一旦上线Bug就是永久的。这意味着测试不是可有可无而是上线之前的最后一道防线。在test目录下新建Counter.test.js跑一次完整的测试流程const { expect } require(chai); const { ethers } require(hardhat); describe(Counter, function () { let counter; beforeEach(async function () { const Counter await ethers.getContractFactory(Counter); counter await Counter.deploy(); await counter.waitForDeployment(); }); it(初始值应该为0, async function () { expect(await counter.getCount()).to.equal(0); }); it(increment后count应该变为1, async function () { await counter.increment(); expect(await counter.getCount()).to.equal(1); }); it(decrement不能把count减到负数, async function () { await expect(counter.decrement()).to.be.revertedWith( Counter: count cannot be negative ); }); });测试代码读起来像自然语言初始值应该为0、increment后count应该变为1。这就是chai匹配器的功劳配合hardhat-toolbox内置的ethers.js测试里可以用真实账户签名发起交易完整模拟链上行为。执行测试npx hardhat test输出中每个it都是一个测试用例绿色对勾表示通过。如果在某条用例中合约报了错Hardhat会把错误信息、回放栈和Gas使用情况一并打在终端里这比测试失败四个大字有用得多。6.2 console.log合约里的临时调试窗口Hardhat最受欢迎的功能之一就是在合约中使用JavaScript风格的console.log。使用方式很简单合约里直接调用// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import hardhat/console.sol; contract Counter { uint256 public count; function increment() public { count 1; console.log(count is now:, count); } }编译后用任意方式调用increment函数终端就会打印出count is now: 1。这个功能只对Hardhat Network生效不会污染正式链上的逻辑因为正式环境不会运行在Hardhat里。这里要强调一点console.log是调试工具不是日志系统。调试完后记得移除import否则合约代码里残留调试信息既不专业也可能引入意想不到的Gas开销console的字节码在正式链上没什么意义但会占据合约体积。6.3 测试覆盖率的查看toolbox里还集成了Solidity覆盖率工具执行npx hardhat coverage它会跑一遍测试并生成覆盖率报告显示每个合约的函数、行、分支覆盖情况。覆盖率不是越高越好但一个核心逻辑覆盖率低于70%的项目上线前我都会打个问号——不是所有的路径都被测试到就意味着有些边界情况还等着在真实链上爆出来。7. 写在最后给新手的几个实战建议整个流程跑通之后你已经具备了用Hardhat开发Solidity合约的基本能力。最后分享几个我认为最值得记住的实战建议。第一不要跳过测试直接部署。在Hardhat里写测试的成本其实很低几行断言就能覆盖一个函数的核心路径。但一旦合约上链任何Bug的修复代价都是一次新的部署、一次新地址分发、所有使用者位置的迁移。测试不是给框架看的是给你自己上一份保险。第二写合约前先看看OpenZeppelin的模板。Counter这种玩具合约可以自己写但真实项目里涉及Token、权限管理、升级机制直接用经过审计的OpenZeppelin合约比自己造轮子安全得多。Hardhat项目里引入OpenZeppelin就是一条npm install的事npm install --save-dev openzeppelin/contracts第三遇到报错先读原文再复制去搜。Hardhat的报错信息通常已经精确到文件和行号很多问题读一遍报错自己就明白了。直接复制报错去搜索引擎反而会把你引到过时教程里去。这个系列的下一篇文章我会带你基于Hardhat实现一个完整的ERC-20代币合约并把它部署到测试网讲清楚合约构造函数参数、事件日志和合约交互这些进阶内容。在你动手把这篇文章里的Counter合约部署出去之前建议先把Hardhat的编译、测试、部署三个循环多跑几遍让肌肉记忆先形成——后面所有更复杂的东西都是在这条循环里逐步叠加的。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

嘉立创EDA专业版原理图绘制全攻略:从建工程到编译检查 2026/9/28 7:29:53

嘉立创EDA专业版原理图绘制全攻略:从建工程到编译检查

做硬件这几年,我见过太多新手在原理图上栽跟头:元件密密麻麻堆在一起、网络标签乱飞、封装和符号对不上,最后画 PCB 的时候一个个改到崩溃。我自己最开始用 Altium Designer 也确实卡在这上面,后来换到嘉立创EDA专业版&#xff0c…

阅读更多 →
从零搭建AI工程能力:环境、数据、训练与部署全链路实战 2026/9/28 7:29:53

从零搭建AI工程能力:环境、数据、训练与部署全链路实战

1. 从零搭建AI工程能力,为什么大多数人卡在第一步就放弃了聊到AI工程,很多人第一反应是“我得先学Python”“我得先搞懂Transformer”“我得先买块显卡”。这些想法本身没错,但顺序全反了。我见过太多人抱着《深度学习》花书啃了三个月&#…

阅读更多 →
STM32直流电机PWM控制实战:Proteus仿真与L293D驱动全解析 2026/9/28 7:29:53

STM32直流电机PWM控制实战:Proteus仿真与L293D驱动全解析

带过不少做嵌入式课设的同学之后,我发现一个特别普遍的现象:点灯、按键、串口这些实验都能顺利跑通,一旦进入"用STM32控制直流电机"这个项目,很快就卡住了。有人调了一下午,最后发现是L293D的使能引脚悬空&a…

阅读更多 →
光伏板航拍鸟粪缺陷检测:VOC+YOLO数据集与YOLOv8训练实战 2026/9/28 7:29:53

光伏板航拍鸟粪缺陷检测:VOC+YOLO数据集与YOLOv8训练实战

简介:本数据集面向光伏电站智能巡检与航拍图像缺陷检测方向,提供367张光伏板航拍图片,聚焦鸟粪这一单一类别的目标检测任务,适合从事无人机巡检、新能源运维及计算机视觉算法验证的开发者与研究人员使用。包内共1103个文件&#x…

阅读更多 →
ClawX Computer Use CLI 验证全记录:CUA 0.25.0 升级、遥测抑制与原生驱动边界 2026/9/28 7:29:53

ClawX Computer Use CLI 验证全记录:CUA 0.25.0 升级、遥测抑制与原生驱动边界

人工智能AI 应用桌面应用交互助手 【免费下载链接】ClawX ClawX is a desktop app that provides a graphical interface for OpenClaw AI agents. It turns CLI-based AI orchestration into a desktop experience without using the terminal. China website is https://claw…

阅读更多 →
Woodpecker 官方分发包(DEB/RPM)安装与 systemd 部署实战:从软件包安装到 NixOS 声明式配置 2026/9/28 7:29:47

Woodpecker 官方分发包(DEB/RPM)安装与 systemd 部署实战:从软件包安装到 NixOS 声明式配置

CI/CDDevOps 【免费下载链接】woodpecker Woodpecker is a simple, yet powerful CI/CD engine with great extensibility. 项目地址: https://gitcode.com/gh_mirrors/wo/woodpecker 点击查看 免费下载 本文聚焦 Woodpecker 的 Linux 分发安装路径:先介…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉