从Ethers.js到Viem的平滑迁移:在Hardhat 3中玩转现代以太坊测试

1. 为什么需要迁移到Viem?

如果你最近打开过Hardhat 3的初始化向导,可能会注意到一个明显的变化:官方现在默认推荐使用Viem而非Ethers.js作为以太坊交互库。这不是一个随意的选择,而是反映了以太坊开发工具链的进化方向。

Viem带来了几个关键优势:

  • 更轻量级的架构:相比Ethers.js,Viem的包体积减少了约40%
  • 更好的TypeScript支持:完整的类型推导和更严格的类型检查
  • 更现代的API设计:简化了常见操作,减少了样板代码
  • 原生EIP-1193兼容:与钱包连接更加无缝
// Viem的API设计示例
const client = createPublicClient({
  chain: mainnet,
  transport: http()
})

const blockNumber = await client.getBlockNumber()

2. 迁移前的准备工作

在开始迁移前,建议采取以下步骤确保平稳过渡:

  1. 备份现有项目:确保所有代码都已提交到版本控制系统
  2. 创建迁移分支:git checkout -b migrate-to-viem
  3. 记录现有测试覆盖率:运行npx hardhat coverage保存基准数据
  4. 安装必要依赖:
npm install viem @nomicfoundation/hardhat-viem
npm uninstall ethers @nomicfoundation/hardhat-ethers

3. 核心差异对照表

功能点Ethers.js实现方式Viem等效实现注意事项
合约实例化ContractFactory + deploydeployContractViem简化了部署流程
交易等待waitForDeployment自动处理无需显式等待
事件过滤contract.filters.EventNamegetContractEvents查询语法更直观
数值转换ethers.parseEtherparseEther (直接从viem导入)功能相同但来源不同

4. 逐步迁移指南

4.1 更新Hardhat配置

首先修改hardhat.config.ts:

import "@nomicfoundation/hardhat-viem";

const config: HardhatUserConfig = {
  // 其他配置保持不变...
  networks: {
    localhost: {
      url: "http://127.0.0.1:8545"
    }
  }
};

4.2 重写部署脚本

对比两种写法的差异:

// Ethers.js版本
import { ethers } from "hardhat";

async function main() {
  const contract = await ethers.deployContract("MyContract", [arg1, arg2]);
  await contract.waitForDeployment();
  console.log(`Deployed to ${await contract.getAddress()}`);
}
// Viem版本
import { viem } from "hardhat";

async function main() {
  const contract = await viem.deployContract("MyContract", [arg1, arg2]);
  console.log(`Deployed to ${contract.address}`);
}

4.3 重构测试用例

测试文件的结构变化较大:

// 之前(Mocha + Ethers.js)
import { expect } from "chai";
import { ethers } from "hardhat";

describe("MyContract", function() {
  it("should work", async function() {
    const contract = await ethers.deployContract("MyContract");
    await contract.doSomething();
    expect(await contract.getValue()).to.equal(42);
  });
});
// 现在(Node Test Runner + Viem)
import { describe, it } from "node:test";
import { expect } from "chai";
import { viem } from "hardhat";

describe("MyContract", () => {
  it("should work", async () => {
    const contract = await viem.deployContract("MyContract");
    await contract.write.doSomething();
    expect(await contract.read.getValue()).to.equal(42);
  });
});

5. 常见问题解决方案

5.1 类型不匹配错误

Viem有更严格的类型检查,可能会暴露之前隐藏的类型问题。解决方案:

// 明确指定参数类型
const result = await contract.read.getValue<[bigint], bigint>([arg]);

5.2 事件处理差异

Viem的事件查询API更强大但语法不同:

const events = await publicClient.getContractEvents({
  address: contract.address,
  abi: contract.abi,
  eventName: "ValueChanged",
  fromBlock: 0n
});

5.3 钱包交互模式

连接钱包的代码需要调整:

// 之前
const signer = await ethers.provider.getSigner();
await contract.connect(signer).doSomething();

// 现在
const [client, walletClient] = await Promise.all([
  viem.getPublicClient(),
  viem.getWalletClient()
]);
await walletClient.writeContract({
  address: contract.address,
  abi: contract.abi,
  functionName: "doSomething"
});

6. 性能优化技巧

迁移完成后,可以进一步优化测试性能:

  1. 并行测试:Node Test Runner原生支持并行测试
  2. 智能合约缓存:利用Hardhat的缓存机制加速重复部署
  3. 类型预生成:使用hardhat-typechain生成类型定义
# 并行运行测试
npx hardhat test --parallel

7. 迁移后的验证步骤

为确保迁移没有引入回归问题:

  1. 运行完整的测试套件:npx hardhat test
  2. 比较测试覆盖率:npx hardhat coverage
  3. 执行端到端测试:部署到测试网验证实际交互
  4. 性能基准测试:比较测试执行时间

提示:可以使用git diff对比迁移前后的测试输出,确保行为一致

8. 高级用法探索

Viem提供了许多Ethers.js没有的高级功能:

多链交互:

const clients = {
  mainnet: createPublicClient({ chain: mainnet, transport: http() }),
  polygon: createPublicClient({ chain: polygon, transport: http() })
};

批量交易:

const hash = await walletClient.sendTransactions({
  requests: [
    { to: "0x...", value: parseEther("1") },
    { to: contract.address, data: encodeFunctionData(...) }
  ]
});

实时订阅:

const unwatch = publicClient.watchBlockNumber({
  onBlockNumber: (blockNumber) => {
    console.log(`New block: ${blockNumber}`);
  }
});

// 取消订阅
unwatch();

迁移到Viem和Node Test Runner不仅是技术栈的更新,更是开发体验的升级。虽然初期需要适应新的API,但长期来看,这将带来更高效、更类型安全的开发流程。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐