Ethereum-specific Chai assertion matchers for smart contract testing in Hardhat development environment.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Hardhat Chai Matchers extends the Chai assertion library with Ethereum-specific capabilities for smart contract testing. It provides specialized matchers for testing transaction reverts, event emissions, balance changes, and Ethereum-specific data validation, making smart contract tests more readable and comprehensive.
npm install --save-dev @nomicfoundation/hardhat-chai-matchers// Import the plugin in your Hardhat configuration
require("@nomicfoundation/hardhat-chai-matchers");
// Import utilities for argument matching
import { anyValue, anyUint } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
// Import panic codes for revert testing
import { PANIC_CODES } from "@nomicfoundation/hardhat-chai-matchers/panic";import { expect } from "chai";
import { ethers } from "hardhat";
// After importing the plugin, new matchers are available on Chai expectations
describe("Token Contract", function () {
it("should transfer tokens", async function () {
const [owner, recipient] = await ethers.getSigners();
const Token = await ethers.getContractFactory("Token");
const token = await Token.deploy(1000000);
// Test successful transfer and event emission
await expect(token.transfer(recipient.address, 1000))
.to.emit(token, "Transfer")
.withArgs(owner.address, recipient.address, 1000);
// Test balance changes
await expect(token.transfer(recipient.address, 500))
.to.changeTokenBalance(token, recipient, 500);
});
it("should handle reverts", async function () {
// Test transaction reverts with specific reasons
await expect(token.transfer(ethers.ZeroAddress, 1000))
.to.be.revertedWith("Cannot transfer to zero address");
// Test custom error reverts
await expect(token.transferFrom(owner.address, recipient.address, 1000))
.to.be.revertedWithCustomError(token, "InsufficientAllowance");
});
});Hardhat Chai Matchers is built around extending Chai's assertion interface with Ethereum-specific matchers:
.emit() and .revertedWithCustomError() support chaining with .withArgs()Comprehensive matchers for testing different types of transaction failures including generic reverts, reason strings, custom errors, and panic conditions.
interface Assertion {
reverted: AsyncAssertion;
revertedWith(reason: string | RegExp): AsyncAssertion;
revertedWithoutReason(): AsyncAssertion;
revertedWithPanic(code?: any): AsyncAssertion;
revertedWithCustomError(contract: { interface: any }, customErrorName: string): CustomErrorAssertion;
}Matchers for verifying that transactions emit specific events with expected arguments, supporting complex event validation scenarios.
interface Assertion {
emit(contract: any, eventName: string): EmitAssertion;
}
interface EmitAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}Matchers for testing ETH and ERC-20 token balance changes during transaction execution, supporting both single and multiple account scenarios.
interface Assertion {
changeEtherBalance(account: any, balance: any, options?: any): AsyncAssertion;
changeEtherBalances(accounts: any[], balances: any[] | ((changes: bigint[]) => boolean), options?: any): AsyncAssertion;
changeTokenBalance(token: any, account: any, balance: any): AsyncAssertion;
changeTokenBalances(token: any, accounts: any[], balances: any[] | ((changes: bigint[]) => boolean)): AsyncAssertion;
}Matchers for validating Ethereum-specific data formats including addresses, private keys, and hex strings.
interface Assertion {
hexEqual(other: string): void;
properPrivateKey: void;
properAddress: void;
properHex(length: number): void;
}Helper functions for flexible argument matching in event and error testing scenarios.
function anyValue(): boolean;
function anyUint(i: any): boolean;Enhanced comparison operators that support ethers BigInt and other BigNumber types alongside regular JavaScript numbers.
interface NumericComparison {
within(start: any, finish: any, message?: string): Assertion;
}
// Enhanced operators: equal, above, below, least, most, closeTo
// All support BigInt/BigNumber comparisons automaticallyConstants and utilities for testing Solidity panic conditions and arithmetic errors.
const PANIC_CODES: {
ASSERTION_ERROR: 0x1;
ARITHMETIC_OVERFLOW: 0x11;
DIVISION_BY_ZERO: 0x12;
ENUM_CONVERSION_OUT_OF_BOUNDS: 0x21;
INCORRECTLY_ENCODED_STORAGE_BYTE_ARRAY: 0x22;
POP_ON_EMPTY_ARRAY: 0x31;
ARRAY_ACCESS_OUT_OF_BOUNDS: 0x32;
TOO_MUCH_MEMORY_ALLOCATED: 0x41;
ZERO_INITIALIZED_VARIABLE: 0x51;
};interface AsyncAssertion extends Assertion, Promise<void> {}
interface EmitAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}
interface CustomErrorAssertion extends AsyncAssertion {
withArgs(...args: any[]): AsyncAssertion;
}