hardhat-toolbox-mocha-ethers

star 1

Use alongside the `hardhat` skill when the project depends on `@nomicfoundation/hardhat-toolbox-mocha-ethers`. Covers the ethers helpers exposed on `network.create()`, contract interaction (`ethers.deployContract`, calling functions, `connect`), TypeChain-typed contract instances, and the chai matchers from `@nomicfoundation/hardhat-ethers-chai-matchers` (`.to.emit`, `.to.be.revertedWith*`, `.to.changeEtherBalance(s)`).

NomicFoundation By NomicFoundation schedule Updated 5/19/2026

name: hardhat-toolbox-mocha-ethers description: Use alongside the hardhat skill when the project depends on @nomicfoundation/hardhat-toolbox-mocha-ethers. Covers the ethers helpers exposed on network.create(), contract interaction (ethers.deployContract, calling functions, connect), TypeChain-typed contract instances, and the chai matchers from @nomicfoundation/hardhat-ethers-chai-matchers (.to.emit, .to.be.revertedWith*, .to.changeEtherBalance(s)). metadata: package: "@nomicfoundation/hardhat-toolbox-mocha-ethers"

Hardhat toolbox: ethers + Mocha

This skill builds on the core hardhat skill. Load that first for test organization, the network.create() shape, networkHelpers, fixtures, and the typechecking workflow. Everything below hangs off the connection returned by network.create().

This stack runs tests under Mocha (global describe / it) and asserts with chai. Mocha doesn't await describe callbacks, so the connection is set up at the top of the file with top-level await:

import { expect } from "chai";
import { network } from "hardhat";

const { ethers, networkHelpers } = await network.create();

describe("Counter", function () {
  // ...
});

One connection per file is the norm. State isolation between tests comes from loadFixture (see the hardhat skill), not from creating a fresh connection per describe.

ethers: signers and contract interaction

Contract types are generated by TypeChain from the compiled ABI. Run hardhat build before typechecking so the types reflect the latest contracts.

// Provider (read-only chain data)
const blockNumber = await ethers.provider.getBlockNumber();
const balance = await ethers.provider.getBalance("0xabc...");

// Signers (for sending transactions)
const [owner, alice, bob] = await ethers.getSigners(); // default funded accounts

// Utilities
const oneEth = ethers.parseEther("1.0");

// Deploy a contract, returns a fully typed instance.
// Pass constructor args as the second argument, and (optionally) a signer
// other than the default as the third.
const counter = await ethers.deployContract("Counter");
const counterWithArgs = await ethers.deployContract("Counter", [42n]);
const counterFromAlice = await ethers.deployContract("Counter", [], alice);

// Read state and call functions. Args and return types are type-checked
// against the ABI at compile time; passing wrong types or wrong argument
// counts is a TypeScript error.
const value = await counter.x();
await counter.inc();
await counter.incBy(3n);

// Send from a different signer
await counter.connect(alice).inc();

// Send ETH along with a payable call
await counter.deposit({ value: oneEth });

// Attach to an already-deployed contract
const existing = await ethers.getContractAt("Counter", "0xabc...");

Inside a loadFixture setup function (see the hardhat skill for the surrounding pattern), ethers.deployContract is the canonical deploy step:

async function deployCounterFixture() {
  const counter = await ethers.deployContract("Counter");
  return { counter };
}

const { counter } = await networkHelpers.loadFixture(deployCounterFixture);

To send a transaction from an arbitrary address (not one of the default-funded accounts), fund it for gas and pull an impersonating signer with ethers.getImpersonatedSigner — it handles the impersonation internally, no separate networkHelpers.impersonateAccount call needed:

const addr = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
await networkHelpers.setBalance(addr, ethers.parseEther("1.0"));
const signer = await ethers.getImpersonatedSigner(addr);
await counter.connect(signer).inc();

Chai matchers: Ethereum-specific assertions

The hardhat-ethers-chai-matchers plugin extends chai's expect with matchers for transactions, events, and balance changes. Pass the transaction promise (the result of a write call, unawaited) into expect:

import { expect } from "chai";

// Reverts
await expect(counter.connect(banned).inc()).to.revert(ethers);
await expect(counter.connect(banned).inc()).to.be.revertedWith(
  "only the owner can increment the counter",
);
await expect(counter.connect(banned).inc()).to.be.revertedWithCustomError(
  counter,
  "Unauthorized",
);
await expect(counter.connect(banned).inc())
  .to.be.revertedWithCustomError(counter, "Unauthorized")
  .withArgs(banned.address);

// Events
await expect(counter.inc()).to.emit(counter, "Increment");
await expect(counter.inc()).to.emit(counter, "Increment").withArgs(1n);

// ETH balance changes (positive = received, negative = spent, before gas)
await expect(game.claim()).to.changeEtherBalance(ethers, winner, PRIZE);
await expect(game.claim()).to.changeEtherBalances(
  ethers,
  [winner, loser],
  [PRIZE, -STAKE],
);

For plain assertions (equality, arrays, types), use expect from chai directly without the Ethereum matchers.

Install via CLI
npx skills add https://github.com/NomicFoundation/hardhat-skills --skill hardhat-toolbox-mocha-ethers
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
NomicFoundation
NomicFoundation Explore all skills →