Hardhat 提供了一个灵活且易于使用的开发环境,可以轻松地编写、测试和部署智能合约。Hardhat还内置了Hardhat 网络(Hardhat Node),它是为开发而设计的本地以太坊网络。
下面是hardhat的官方文档
https://hardhat.org/hardhat-runner/docs/getting-started
一、创建及配置Hardhat项目
Hardhat 构建在 Node.js 之上, 使用 Hardhat 要求我们在电脑先安装好Node.js (>= 16.0),创建hardhat-tutorial文件夹。
1、初始化Node项目
2、安装Hardhat
3、运行hardhat
用键盘选择create a JavaScript project
生成project后的项目目录
二、编写合约
合约开发推荐使用 VSCode 编辑器 + solidity 插件,在VSCode下添加solidity插件
在contracts
文件夹下新建一个合约文件 Counter.sol
Counter.js代码如下:
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Counter {
uint counter;
constructor() {
counter = 0;
}
function count() public {
counter = counter + 1;
}
function get() public view returns (uint) {
return counter;
}
}
在编写合约时,尽量不要重复造轮子,基于优质开源的第三方库,不仅可以提高效率,还可以让我们的合约代码更安全,例如要开发一个 Token,可以用npm 安装OpenZepplin 库:
npm install @openzeppelin/contracts --save-dev
然后在合约中 import
相应库中的合约文件及可。
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract Token is ERC20 {
constructor(uint256 initialSupply) ERC20("Token Name", "Token Symbol") {
_mint(msg.sender, initialSupply);
}
}
三、编译合约
hardhat.config.js
有默认的Solidity 编译器配置,因此我们直接编译合约即可,在终端中运行 npx hardhat compile。
成功编译后,会在 artifacts/contracts/
目录下生成Counter.json
和 build-info, Counter.json
包含了智能合约的 ABI 、字节码(Bytecode)等
智能合约的ABI信息,包括了合约的函数、事件等接口信息。这个文件通常会与其他合约交互时使用,因为它可以被其他合约和DApp使用。
Bytecode是部署合约所需的字节码,部署合约时候就是把该字节码作为交易的输入数据发送链上。
四、编写测试用例
为智能合约编写自动化测试至关重要,因为事关用户资金。
使用 Harhdat 内置的网络,使用ethers.js与前面的合约进行交互,并使用 Mocha 作为测试运行器。在test文件夹下创建Counter.js文件代码如下:
// 引入 Hardhat 提供的 ethers 库,用于部署和交互智能合约
const { ethers } = require("hardhat");
// 引入 chai 的断言函数 expect,用于编写测试判断条件
const { expect } = require("chai");
// 定义一个全局变量,用于存储部署后的合约实例
let counter;
// 定义测试套件,描述被测试的合约模块为 "Counter"
describe("Counter", function () {
// 初始化函数:部署 Counter 合约并获取实例
async function init() {
// 获取测试账户数组,其中 owner 是部署者,otherAccount 可用于后续扩展测试权限等
const [owner, otherAccount] = await ethers.getSigners();
// 获取 Counter 合约工厂(ContractFactory),可以用来部署合约
const Counter = await ethers.getContractFactory("Counter");
// 部署合约并返回实例(此时合约已经部署完成,不需要调用 .deployed())
counter = await Counter.deploy();
// 打印部署后合约的地址(ethers v6 中使用 .target 属性获取地址)
console.log("counter:" + counter.target);
}
// 所有测试用例运行前执行一次初始化操作(部署合约)
before(async function () {
await init();
});
// 第一个测试用例:测试合约初始值是否为 0
it("init equal 0", async function () {
// 调用 counter 合约的 get() 方法,断言返回值为 0
expect(await counter.get()).to.equal(0);
});
// 第二个测试用例:调用 count() 函数自增,验证是否变为 1
it("add 1 equal 1", async function () {
// 调用 count() 方法进行加 1 操作
let tx = await counter.count();
// 等待交易被打包确认
await tx.wait();
// 调用 get() 方法获取当前计数值,断言为 1
expect(await counter.get()).to.equal(1);
});
});
运行npx hardhat test之后输出全部通过,证明测试通过。
还可以在Solidity代码中调用console.log()
打印日志信息和合约变量,可以方便我们调试代码。
在合约代码中导入Hardhat 的console.log
就可以使用它。
五、部署合约
部署合约我们需要编写一个部署脚本。
在项目下新建scripts
文件夹,新建一个deploy.js
用来写部署脚本,代码如下
const { ethers } = require("hardhat");
async function main() {
// 获取合约工厂
const Counter = await ethers.getContractFactory("Counter");
// 部署合约(v6 会自动等待部署完成)
const counter = await Counter.deploy();
// 输出部署的合约地址(v6 使用 counter.target)
console.log("Counter address:", counter.target);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
运行 npx hardhat run scripts/deploy.js
时,合约会部署到 Hardhat 内置网络上。
为了在运行任何任务时指示Hardhat连接到特定的EVM网络,可以使用--network
参数。
npx hardhat run scripts/deploy.js --network <network-name>
network-name
需要在 hardhat.config.js
文件中进行配置:
require("@nomicfoundation/hardhat-toolbox");
// 填入自己的私钥或助记词,
const PRIVATE_KEY1 = "0x.... YOUR PRIVATE KEY1";
const PRIVATE_KEY2 = "0x.... YOUR PRIVATE KEY1";
const Mnemonic = "YOUR Mnemonic";
module.exports = {
solidity: "0.8.9", // solidity的编译版本
networks: {
goerli: {
url: "https://eth-goerli.api.onfinality.io/public",
accounts: [PRIVATE_KEY1,PRIVATE_KEY2],
chainId: 5,
},
mumbai: {
url: "https://endpoints.omniatech.io/v1/matic/mumbai/public",
accounts: {
mnemonic: Mnemonic,
},
chainId: 80001,
},
}
};
以上配置了两个网络,一个是以太坊测试网 goerli
, 一个是 Polygon 测试网mumbai
, 我们可以在 https://chainlist.org 找到每个网络的节点 URL 及 chainID。
在网络配置中,需要提供提交交易账号, 可以通过私钥或助记词
进行配置,这里配置的账号(需要提前充币进入到账号中),在hardhat 脚本中(测试及部署脚本)调用getSigners
即可获得:
const [owner, otherAccount] = await ethers.getSigners();
六、代码开源验证
智能代码开源会增加了合约的透明度和可靠性,是项目建立信任很重要的一个步骤。
1、安装 hardhat-toolbox
或 hardhat-etherscan
, 这一步我们这里已经完成,因为在初始化项目的时候安装了 hardhat-toolbox
, 如果没有安装,可以使用以下命令安装
npm install --save-dev @nomiclabs/hardhat-etherscan
2、在hardhat.config.js
中配置您的 Etherscan API 密钥和网络设置,例如:
require("@nomicfoundation/hardhat-toolbox");
或
// require("@nomiclabs/hardhat-etherscan");
etherscan: {
apiKey: ""
},
如何获取 Etherscan API 密钥?
1. 访问部署网络对应主网的 Etherscan 网站,并注册一个账号(如果还没有账号的话)。
2. 登录你的账号并进入 Etherscan 的「我的帐户」页面。
3. 点击页面左侧的「API-KEYs」标签页。
4. 在页面上方的「Create New API KEY」部分,输入 API 密钥的名称和描述,然后选择需要访问的 API 权限。
5. 点击「Generate」按钮来生成 API 密钥。
3、执行验证命令:
npx hardhat verify <deployed-contract-address> "参数(若有)" --network <network-name>
该命令会为我们上传合约代码并验证其源代码。如果一切顺利(网络顺畅的话),在 Etherscan 上看到的合约被成功验证。