hardhat安装、测试、部署

环境

hardhat3.1.8、nodejs22.22、win11

安装初始化

安装

npx hardhat –init

有三种初始化方式,先选择了minimal Hardhat project,minimal只包含 Hardhat 核心功能,无测试框架:不预装 Mocha/Chai 或 Node Test Runner,无 Web3 库:不包含 Ethers.js、Viem 等

生成项目结构:

基础命令

  • 编译,编译后会生成artifacts目录

    npx hardhat build

  • 测试所有test

    npx hardhat test

  • 仅测试solidity test

    npx hardhat test solidity

  • 仅测试typescript test

    npx hardhat test nodejs

  • 安装forge插件,可以进行更复杂的测试

    forge install foundry-rs/forge-std@v1.11.0

TypeScript 测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Node.js 内置的严格断言模块
import assert from 'node:assert/strict';

// Node.js 20+ 内置的测试框架
import { describe, it } from 'node:test';

// 用于连接 Hardhat 网络并获取 Viem 客户端
import { network } from 'hardhat';

// 使用 describe 定义一个名为 "Counter" 的测试套件
describe('Counter', async function () {
	// Viem 是 TypeScript-first 的 Web3 库,比 Ethers.js 更类型安全、模块化。
	const { viem } = await network.connect();

	// 返回一个 只读客户端,用于查询链上数据(如区块、余额),监听合约事件
	const publicClient = await viem.getPublicClient();

	it('The sum of the Increment events should match the current value', async function () {
		//自动查找 artifacts/contracts/Counter.sol/Counter.json,使用默认 signer 部署合约,返回一个 Viem 合约实例,包含 .write(写)、.read(读)、.abi 等属性
		const counter = await viem.deployContract('Counter');

		//获取部署时的最新区块号,后续用它作为 fromBlock,确保只监听部署之后的事件,避免抓到历史噪音事件
		const deploymentBlockNumber = await publicClient.getBlockNumber();

		// run a series of increments
		for (let i = 1n; i <= 10n; i++) {
			await counter.write.incBy([i]);
		}

		// events 是一个 类型化的数组,每个 event.args.by 是 bigint
		const events = await publicClient.getContractEvents({
			address: counter.address, //合约地址(必填)
			abi: counter.abi, //ABI(必填,用于解析事件)
			eventName: 'Increment', //事件名(可选,不填则返回所有事件)
			fromBlock: deploymentBlockNumber, //起始区块(默认:0n)
			strict: true, //严格模式(ABI 必须完全匹配)
			/**
            toBlock: 456n,  不必填,结束区块(默认:'latest')
			args: {
                by是Counter.sol中定义的event的参数名
				by: 5n,
				或范围:by: { gt: 3n, lt: 10n }
                或地址:to: aliceAddress (from: aliceAddress)
			},
             */
		});

		// 0n 是 JavaScript/TypeScript 中表示 BigInt 类型字面量的原生语法,精度整数仅受内存限制,理论上无上限
		let total = 0n;
		// 遍历所有事件,累加 by 字段
		for (const event of events) {
			total += event.args.by;
		}

		assert.equal(total, await counter.read.x());
	});
});

solidity覆盖测试

npx hardhat test solidity –coverage

执行后生成coverage目录

打开html

终端输出

nodejs覆盖测试

npx hardhat test nodejs –coverage

全部覆盖测试

npx hardhat test –coverage

部署

部署脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// ignition\modules\Counter.ts
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";

export default buildModule("CounterModule", (m) => {
  const counter = m.contract("Counter");

  m.call(counter, "incBy", [5n]);

  return { counter };
});

部署到默认网络(通常是 hardhat),可以在hardhat.config.ts 中 defaultNetwork 指定的网络

npx hardhat ignition deploy ignition/modules/Counter.ts

显式指定 localhost 网络,要求已启动一个节点。可以连接到已运行的本地节点(如 anvil的8545端口 或 hardhat node内置节点)

启动hardhat内置节点

npx hardhat node

npx hardhat ignition deploy ignition/modules/Counter.ts –network localhost

配置hardhat.config.ts后部署到sepolia网络

npx hardhat ignition deploy ignition/modules/Counter.ts –network sepolia

测试网查看部署的合约:

sepolia.etherscan

1
2
3
4
5
6
7
8
sepolia: {
			type: 'http',
			url: 'https://ethereum-sepolia-rpc.publicnode.com',
			// 或 https://sepolia.infura.io
			// configVariable('SEPOLIA_RPC_URL'),
			//钱包导出的私钥
			accounts: [configVariable('SEPOLIA_PRIVATE_KEY')],
		},

修改配置,将私钥添加到加密密钥库(keystore),不直接配置在文件中(有泄露风险),添加时,前两个密码是用来加密私钥的。以后每次部署,你只需要输入这个简短的密码,而不需要接触那串长长的私钥。第三个才是私钥:

npx hardhat keystore set SEPOLIA_PRIVATE_KEY

修改配置后再次部署:

验证合约

配置ETHERSCAN_API_KEY

1
2
3
4
5
verify: {
    etherscan: {
      apiKey: configVariable("ETHERSCAN_API_KEY"),
    },
  },

npx hardhat keystore set ETHERSCAN_API_KEY

npx hardhat ignition deploy ignition/modules/Counter.ts –network sepolia –verify

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计