hardhat-toolbox-viem について
viem を使う Hardhat プロジェクト向けのスキルです。TypeScript でコントラクトテストを書く開発者を対象に、型付きの操作と Ethereum 固有のアサーションを扱います。
主な機能
- 01型付き viem クライアント
- 02型付きコントラクトのデプロイと取得
- 03フィクスチャを使ったデプロイ
- 04Ethereum のリバートとイベント検証
活用シーン
- 01Hardhat テストでのコントラクトデプロイ
- 02リバートとイベントの検証
- 03型安全なコントラクト操作の作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nomicfoundation/ hardhat-skills --skill hardhat-toolbox-viemインストール後、Claude Code で/hardhat-toolbox-viemを入力して読み込まれたか確認します。
詳細
Hardhat toolbox:viem
このスキルは、コアの hardhat スキルを基盤としています。テストの構成、network.create() の形式、networkHelpers、フィクスチャ、型チェックのワークフローについては、まずそちらを読み込んでください。以下の内容はすべて、network.create() が返す接続を基準としています。
import { network } from "hardhat";
import { describe, it } from "node:test";
import assert from "node:assert/strict";
describe("Counter", async function () {
const { viem, networkHelpers } = await network.create();
// ...
});
viem:クライアントとコントラクトとのやり取り
// Clients
const publicClient = await viem.getPublicClient();
const [owner, alice, bob] = await viem.getWalletClients(); // default accounts
const testClient = await viem.getTestClient(); // dev-only operations
// Deploy a contract, returns a fully typed instance
const counter = await viem.deployContract("Counter");
// Read state (return type inferred from ABI)
const value = await counter.read.x();
// Write transactions. Args and options are type-checked against the ABI at
// compile time; passing wrong types, wrong argument counts, or `value` on a
// non-payable function is a TypeScript error
await counter.write.inc();
await counter.write.inc({ account: alice.account }); // different sender
await counter.write.incBy([3n]); // with args
await counter.write.deposit({ value: 10n ** 18n }); // no parameters and payable
// Attach to an already-deployed contract
const existing = await viem.getContractAt("Counter", "0xabc...");
コントラクトとのやり取りに walletClient.writeContract を使うのは避けてください。ABI による型付けがなく、誤った引数がそのまま通ってしまいます。代わりに、viem.deployContract または viem.getContractAt が返す型付きのインスタンスを使ってください。
loadFixture のセットアップ関数内では(周辺のパターンについては hardhat スキルを参照)、viem.deployContract が標準的なデプロイ手順です。
async function deployCounter() {
const counter = await viem.deployContract("Counter");
return { counter };
}
const { counter } = await networkHelpers.loadFixture(deployCounter);
viem.assertions:Ethereum 固有のアサーション
コントラクト固有のチェックには viem.assertions を使ってください。最初の引数には、await していないトランザクションの Promise を渡します。
// Reverts
await viem.assertions.revert(counter.write.inc({ account: banned }));
await viem.assertions.revertWith(
counter.write.inc({ account: banned }),
"Not authorized",
);
await viem.assertions.revertWithCustomError(
counter.write.inc({ account: banned }),
counter,
"Unauthorized",
);
await viem.assertions.revertWithCustomErrorWithArgs(
counter.write.inc({ account: banned }),
counter,
"Unauthorized",
[banned],
);
// Events
await viem.assertions.emit(counter.write.inc(), counter, "Increment");
await viem.assertions.emitWithArgs(counter.write.inc(), counter, "Increment", [
1n,
]);
// ETH balance changes (positive = received, negative = spent, before gas)
await viem.assertions.balancesHaveChanged(game.write.claim(), {
[winner]: PRIZE,
[loser]: -STAKE,
});
*WithArgs マッチャー(revertWithCustomErrorWithArgs と emitWithArgs)では、具体的な値とともに、任意の引数位置で (value) => boolean の述語を指定できます。また、気にしない引数位置に使える anyValue ヘルパーもプラグインに含まれています。
import { anyValue } from "@nomicfoundation/hardhat-toolbox-viem/predicates";
// Inline predicate at any arg position. Useful for ranges or computed conditions.
await viem.assertions.revertWithCustomErrorWithArgs(
contract.write.failing(),
contract,
"BadValue",
[(n: bigint) => n > 100n, "another error arg"],
);
await viem.assertions.emitWithArgs(
counter.write.incBy([3n]),
counter,
"Increment",
[(by: bigint) => by >= 1n],
);
// `anyValue` matches anything — handy for fields you don't care about.
await viem.assertions.revertWithCustomErrorWithArgs(
contract.write.failing(),
contract,
"BadValue",
[anyValue, "another error arg"],
);
通常の TypeScript のアサーション(等価性、配列、型)には node:assert/strict を使ってください。