Skip to main content
skill Claude Code CX Codex Cursor

web3-testing — Claude Code skill: tests and install

This skill guides Solidity contract testing with Hardhat and Foundry, from unit checks to mainnet forks. Use it for test suites and DeFi protocol validation.

Install into Claude Code · Plugin marketplace All methods and platforms ↓
/plugin marketplace add wshobson/agents
/plugin install blockchain-web3@claude-code-workflows
Open on GitHub

What web3-testing does

web3-testing provides patterns for testing Solidity contracts with Hardhat and Foundry. The examples cover deployment, transfers, events, reverted transactions, and time-dependent behavior. It also includes integration tests, fuzzing for edge cases, gas checks, coverage reporting, and contract verification on Etherscan.

The Hardhat setup uses @nomicfoundation/hardhat-toolbox, @nomiclabs/hardhat-etherscan, hardhat-gas-reporter, and solidity-coverage. Foundry examples use forge-std/Test.sol plus cheatcodes such as vm.prank, vm.deal, and vm.createSelectFork. Mainnet fork tests need an RPC value in MAINNET_RPC_URL; the shown configuration also uses GOERLI_RPC_URL, PRIVATE_KEY, COINMARKETCAP_API_KEY, and ETHERSCAN_API_KEY.

Install it when your project contains Solidity contracts and you need a testing structure for Hardhat or Foundry. It is unnecessary for projects that do not test smart contracts.

What it helps with

  • check contract deployment and initial state
  • cover transfers, events, and reverted transactions
  • exercise edge cases with fuzzing
  • measure gas used by contract operations
  • run DeFi checks against a mainnet fork

Example prompts for the agent

  • “Write Hardhat unit tests for `Token` covering owner, total supply, transfers, and the Transfer event.”
  • “Create a Foundry fuzz test for token transfers and cover insufficient balance.”
  • “Set up a mainnet fork with `MAINNET_RPC_URL` and test interaction with DAI.”

How to install web3-testing

1Plugin marketplace

/plugin marketplace add wshobson/agents
/plugin install blockchain-web3@claude-code-workflows

This installs the whole blockchain-web3 plugin with all its skills

2Skills CLI (Vercel)

npx skills add wshobson/agents --skill web3-testing -a claude-code

3Manually: put the files in place

~/.claude/skills/web3-testing/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/web3-testing/

From the same set213

The whole set →
typescript-advanced-types Seth Hobson Guides an agent through advanced TypeScript types, from generics to conditional and mapped types. Use it for typed libraries, API clients, or strict configuration objects. Claude Code CX Codex Cursor 92,169installs tailwind-design-system Seth Hobson Helps build design systems with Tailwind CSS v4, from theme tokens to component variants. Use it when a project needs shared UI patterns. Claude Code CX Codex Cursor 70,180installs brand-landingpage Travis D. Elliott This skill interviews you about the product and its visual direction, then builds a landing page through Stitch. Use it when there’s no established design yet. Claude Code CX Codex Cursor 39,476installs python-testing-patterns Seth Hobson This skill guides Python testing with pytest, fixtures and mocks. Use it when building a test suite or tracking down failing checks. Claude Code CX Codex Cursor 36,943installs python-performance-optimization Seth Hobson This skill profiles Python code to locate CPU and memory bottlenecks. Use it when an application responds slowly or consumes too many resources. Claude Code CX Codex Cursor 35,675installs nextjs-app-router-patterns Seth Hobson This skill covers Next.js App Router patterns for rendering, routing, and data fetching. Use it when starting an App Router project or moving from Pages Router. Claude Code CX Codex Cursor 32,529installs api-design-principles Seth Hobson Use this skill to plan or review REST and GraphQL APIs. It helps when writing a specification or setting API conventions for a team. Claude Code CX Codex Cursor 30,348installs code-review-excellence Seth Hobson This skill guides pull request reviews, catches logic and security issues, and helps teams give specific feedback. Use it for review standards or developer mentoring. Claude Code CX Codex Cursor 30,193installs

Similar

google-mobile-ads-validate official google Audits Google Mobile Ads SDK integrations in iOS, Android, and Unity projects. Run a full pre-launch check or ask it to inspect one specific area. Claude Code Gemini CLI CX Codex 3,300installs eval-driven-dev official github Builds end-to-end evaluations for Python applications that call an LLM, from criteria and test data to scored runs. Use it for QA, benchmarks, and investigating wrong responses. GitHub Copilot 3,900installs improve-codebase-architecture Matt Pocock This skill scans a codebase for architectural friction, then builds a visual HTML report with refactoring candidates. Use it before a deeper architecture review. Claude Code 1,163,035installs design-taste-frontend Leonxlnx This skill directs the design of public pages and work screens, then checks the result in a browser through screenshots. Use it when an interface feels generic or unfinished. Claude Code CX Codex Cursor +1 673,100installs tdd Matt Pocock Guides the red-green TDD loop: ensures tests are written first, keep them at public interfaces, and avoid coupling to implementation details. Claude Code 1,141,062installs skill-creator official anthropics Creates and refines skills, then tests them with prompts, evaluations, and performance checks. Claude Code Claude.ai 414,180installs agent-browser vercel-labs A CLI skill for browser control: it opens pages, fills forms, clicks buttons, and tests web apps. Use it when an agent needs to act inside a website. Claude Code CX Codex Cursor +1 1,200,000installs prototype Matt Pocock Creates throwaway prototypes for checking state logic or exploring UI before committing the decision to the main codebase. Claude Code 986,201installs

Questions about web3-testing

How do I install web3-testing in Claude Code?

Run npx skills add wshobson/agents --skill web3-testing -a claude-code. The skill file is placed at ~/.claude/skills/web3-testing/SKILL.md.

What does web3-testing do?

It guides unit and integration testing for Solidity contracts with Hardhat and Foundry. It also covers fuzzing, gas checks, coverage, and mainnet fork tests.

What is required for mainnet fork testing?

You need an RPC value in MAINNET_RPC_URL. The examples use a selected mainnet block for the fork.

Source text

SKILL.md · MIT
---
name: web3-testing
description: Test smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or validating DeFi protocols.
---

# Web3 Smart Contract Testing

Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.

## When to Use This Skill

- Writing unit tests for smart contracts
- Setting up integration test suites
- Performing gas optimization testing
- Fuzzing for edge cases
- Forking mainnet for realistic testing
- Automating test coverage reporting
- Verifying contracts on Etherscan

## Hardhat Testing Setup

```javascript
// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-etherscan");
require("hardhat-gas-reporter");
require("solidity-coverage");

module.exports = {
  solidity: {
    version: "0.8.19",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    hardhat: {
      forking: {
        url: process.env.MAINNET_RPC_URL,
        blockNumber: 15000000,
      },
    },
    goerli: {
      url: process.env.GOERLI_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
    },
  },
  gasReporter: {
    enabled: true,
    currency: "USD",
    coinmarketcap: process.env.COINMARKETCAP_API_KEY,
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};
```

## Unit Testing Patterns

```javascript
const { expect } = require("chai");
const { ethers } = require("hardhat");
const {
  loadFixture,
  time,
} = require("@nomicfoundation/hardhat-network-helpers");

describe("Token Contract", function () {
  // Fixture for test setup
  async function deployTokenFixture() {
    const [owner, addr1, addr2] = await ethers.getSigners();

    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy();

    return { token, owner, addr1, addr2 };
  }

  describe("Deployment", function () {
    it("Should set the right owner", async function () {
      const { token, owner } = await loadFixture(deployTokenFixture);
      expect(await token.owner()).to.equal(owner.address);
    });

    it("Should assign total supply to owner", async function () {
      const { token, owner } = await loadFixture(deployTokenFixture);
      const ownerBalance = await token.balanceOf(owner.address);
      expect(await token.totalSupply()).to.equal(ownerBalance);
    });
  });

  describe("Transactions", function () {
    it("Should transfer tokens between accounts", async function () {
      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);

      await expect(token.transfer(addr1.address, 50)).to.changeTokenBalances(
        token,
        [owner, addr1],
        [-50, 50],
      );
    });

    it("Should fail if sender doesn't have enough tokens", async function () {
      const { token, addr1 } = await loadFixture(deployTokenFixture);
      const initialBalance = await token.balanceOf(addr1.address);

      await expect(
        token.connect(addr1).transfer(owner.address, 1),
      ).to.be.revertedWith("Insufficient balance");
    });

    it("Should emit Transfer event", async function () {
      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);

      await expect(token.transfer(addr1.address, 50))
        .to.emit(token, "Transfer")
        .withArgs(owner.address, addr1.address, 50);
    });
  });

  describe("Time-based tests", function () {
    it("Should handle time-locked operations", async function () {
      const { token } = await loadFixture(deployTokenFixture);

      // Increase time by 1 day
      await time.increase(86400);

      // Test time-dependent functionality
    });
  });

  describe("Gas optimization", function () {
    it("Should use gas efficiently", async function () {
      const { token } = await loadFixture(deployTokenFixture);

      const tx = await token.transfer(addr1.address, 100);
      const receipt = await tx.wait();

      expect(receipt.gasUsed).to.be.lessThan(50000);
    });
  });
});
```

## Foundry Testing (Forge)

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../src/Token.sol";

contract TokenTest is Test {
    Token token;
    address owner = address(1);
    address user1 = address(2);
    address user2 = address(3);

    function setUp() public {
        vm.prank(owner);
        token = new Token();
    }

    function testInitialSupply() public {
        assertEq(token.totalSupply(), 1000000 * 10**18);
    }

    function testTransfer() public {
        vm.prank(owner);
        token.transfer(user1, 100);

        assertEq(token.balanceOf(user1), 100);
        assertEq(token.balanceOf(owner), token.totalSupply() - 100);
    }

    function testFailTransferInsufficientBalance() public {
        vm.prank(user1);
        token.transfer(user2, 100); // Should fail
    }

    function testCannotTransferToZeroAddress() public {
        vm.prank(owner);
        vm.expectRevert("Invalid recipient");
        token.transfer(address(0), 100);
    }

    // Fuzzing test
    function testFuzzTransfer(uint256 amount) public {
        vm.assume(amount > 0 && amount <= token.totalSupply());

        vm.prank(owner);
        token.transfer(user1, amount);

        assertEq(token.balanceOf(user1), amount);
    }

    // Test with cheatcodes
    function testDealAndPrank() public {
        // Give ETH to address
        vm.deal(user1, 10 ether);

        // Impersonate address
        vm.prank(user1);

        // Test functionality
        assertEq(user1.balance, 10 ether);
    }

    // Mainnet fork test
    function testForkMainnet() public {
        vm.createSelectFork("https://eth-mainnet.alchemyapi.io/v2/...");

        // Interact with mainnet contracts
        address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
        assertEq(IERC20(dai).symbol(), "DAI");
    }
}
```

## Advanced Testing Patterns

### Snapshot and Revert

```javascript
describe("Complex State Changes", function () {
  let snapshotId;

  beforeEach(async function () {
    snapshotId = await network.provider.send("evm_snapshot");
  });

  afterEach(async function () {
    await network.provider.send("evm_revert", [snapshotId]);
  });

  it("Test 1", async function () {
    // Make state changes
  });

  it("Test 2", async function () {
    // State reverted, clean slate
  });
});
```

### Mainnet Forking

```javascript
describe("Mainnet Fork Tests", function () {
  let uniswapRouter, dai, usdc;

  before(async function () {
    await network.provider.request({
      method: "hardhat_reset",
      params: [
        {
          forking: {
            jsonRpcUrl: process.env.MAINNET_RPC_URL,
            blockNumber: 15000000,
          },
        },
      ],
    });

    // Connect to existing mainnet contracts
    uniswapRouter = await ethers.getContractAt(
      "IUniswapV2Router",
      "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
    );

    dai = await ethers.getContractAt(
      "IERC20",
      "0x6B175474E89094C44Da98b954EedeAC495271d0F",
    );
  });

  it("Should swap on Uniswap", async function () {
    // Test with real Uniswap contracts
  });
});
```

### Impersonating Accounts

```javascript
it("Should impersonate whale account", async function () {
  const whaleAddress = "0x...";

  await network.provider.request({
    method: "hardhat_impersonateAccount",
    params: [whaleAddress],
  });

  const whale = await ethers.getSigner(whaleAddress);

  // Use whale's tokens
  await dai
    .connect(whale)
    .transfer(addr1.address, ethers.utils.parseEther("1000"));
});
```

## Additional patterns and templates

More detailed templates and worked examples live in `references/details.md`. Read that file for the full pattern library.

© Seth Hobson · MIT · wshobson/agents

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor