npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

x402-bench

v0.1.1

Published

The x402 test bench: a local, honest mock facilitator. Real @x402 signature verification, faked chain — it won't teach you a false green.

Readme

x402-bench

The x402 test bench — a local, honest mock facilitator. Build and test an x402 payer or resource server on your laptop, offline, with no testnet faucet, no funded wallet, and no live facilitator. Real signature verification, faked chain.

Honesty is the whole point. x402-bench runs the real @x402 signature + authorization checks — a broken signature is rejected, exactly as production would. It fakes only the chain (balance, nonce, settlement). And it tells you which is which on every result, so a green here never means more than it should.

Why another mock?

Local x402 mocks already exist. The pure-mock ones take a shortcut that quietly hurts you: they rubber-stamp. Their verify checks that a signature field is present, not that the signature is valid — so a payload signed with a broken EIP-712 domain, a wrong nonce, or garbage bytes passes green locally and then fails on mainnet. The mock taught you a false green.

x402-bench can't do that, by construction. It does not implement verify at all. It injects a chain-faking signer into the real @x402 ExactEvmScheme, and the real library recovers the EIP-712 signer itself (in-library ECDSA). The faked signer is never in the signature path — it cannot make a bad signature pass. The differentiator isn't "we promise to verify"; it's "we can't not verify."

Fidelity — stated up front, not buried

| Aspect | x402-bench | Meaning | | --- | --- | --- | | Signature + authorization | ✅ real | Verified by @x402 (real ECDSA recovery). A bad signature is rejected. | | Chain state (balance, nonce, deployment) | ~ simulated | Faked, not read from any chain. | | Settlement | ~ synthetic | Returns a well-formed but fabricated tx hash. Nothing is submitted; nothing moves. | | Fault reasons | ✅ precise (injected) | Inject a specific cause and the facilitator's own diagnosis surfaces the precise reason (insufficient_balance / nonce_used); an unspecified revert yields generic simulation_failed. |

A green result proves the payment is protocol-valid (its shape is right), NOT that a real chain would accept it. For chain-acceptance you still need a testnet run. Every verify/settle result carries a fidelity field saying exactly this, and BenchFacilitator.BANNER is a ready-to-print notice for CLIs/servers.

Quick start

As a local facilitator server (npx x402-bench)

Start it, then point your real @x402 client's facilitator URL at it — no chain, no faucet, no funds:

npx x402-bench --port 3402 --asset 0x036cbd53842c5426634e7929541ec2318f3dcf7e
#  POST /verify   POST /settle   GET /supported
#  every response carries an `x-bench-fidelity` header stating what was real vs. simulated
import { HTTPFacilitatorClient } from "@x402/core/http";

const facilitator = new HTTPFacilitatorClient({ url: "http://127.0.0.1:3402" });
// verify/settle exactly as against a production facilitator — a bad signature is rejected,
// settlement returns a synthetic tx hash. Nothing is submitted to any chain.

Flags: --port (3402) · --network (eip155:84532) · --asset · --token-name/--token-version · --fault transferReverts|insufficient_balance|nonce_used|settleReverts · --quiet (silence the live inspector).

As a library

The one thing every library example needs is a signed payment payload. That's what a real @x402 client produces when it pays a 402 — so here is the whole loop, end to end, with a throwaway account and no funds. (In your own app, steps 1–2 are just your client paying; you already have the payload.)

import { BenchFacilitator, startX402Server } from "x402-bench";
import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const CHAIN = "eip155:84532";
const USDC = "0x036cbd53842c5426634e7929541ec2318f3dcf7e";
const requirement = {
  scheme: "exact", network: CHAIN, asset: USDC, amount: "10000",   // 0.01 USDC (6 decimals)
  payTo: "0x1111111111111111111111111111111111111111",
  maxTimeoutSeconds: 600, extra: { name: "USDC", version: "2" },   // `extra` is the EIP-712 domain
};

// 1. A real @x402 client with a throwaway signer (real key, no funds).
const account = privateKeyToAccount(generatePrivateKey());
const client = new x402Client();
registerExactEvmScheme(client, { signer: account as never });      // viem account -> SDK signer type
const http = new x402HTTPClient(client);

// 2. Get a genuine 402 (x402-bench's own resource server stands in) and sign it -> the payload.
const server = await startX402Server({ x402Version: 2, resource: { url: "http://resource.local/x" }, accepts: [requirement] });
const res = await fetch(server.url);
const header = res.headers.get("PAYMENT-REQUIRED");
const body = header ? undefined : await res.json();
const payload = await client.createPaymentPayload(http.getPaymentRequiredResponse((n) => res.headers.get(n), body));
await server.close();

// 3. Verify it — REAL signature check, faked chain. `fidelity` says which is which, on every result.
const bench = new BenchFacilitator({ networks: CHAIN, chain: { deployedContracts: [USDC], token: { name: "USDC", version: "2" } } });
const { result, fidelity } = await bench.verify(payload, requirement);
console.log(result.isValid, fidelity.signature); // true "verified" — a TAMPERED signature would be false

const settled = await bench.settle(payload, requirement);
console.log(settled.result.transaction);          // 0x… a synthetic tx hash; nothing was submitted

This exact flow — including the tamper-is-rejected check — runs in test/documented-example.test.ts, so the example can't quietly rot.

Fault injection

Model the chain-state failures a real facilitator would hit, so you can test your error paths offline:

new BenchFacilitator({ networks: "eip155:84532", chain: {
  deployedContracts: ["0x036cbd…"],
  faults: { transferReverts: "insufficient_balance" }, // verify rejects with the PRECISE reason
  // faults: { transferReverts: "nonce_used" },        // precise: nonce_already_used
  // faults: { transferReverts: true },                // generic: simulation_failed
  // faults: { settleReverts: true },                  // mined-but-reverted receipt -> settle fails
}});

The precise reason isn't invented — you answer the facilitator's own diagnostic reads with the state you inject, and it diagnoses. So your error-handling is tested against the same reason string production would emit.

Status

0.1.1 — the honest core, complete: exact/EIP-3009 EVM verify + settle over a faked chain, with fidelity labeling on every result — as a library, a runnable npx x402-bench HTTP facilitator server (fidelity header on every response), and a live inspector (each handshake printed as it happens; --quiet to silence). Injected chain-state faults surface the facilitator's own precise reason (insufficient_balance / nonce_used). 0.1.1 made it stranger-ready: a complete, runnable library quick-start (the README now shows how to produce a signed payload end to end, exercised by a test so it can't rot), a --help/-h flag that prints usage and exits, and CI. Not yet built:

  • an offline load/throughput harness — because the facilitator is free and instant, you can hammer your integration with thousands of simulated payments to test concurrency/error-handling. Guardrail: it would measure your integration's off-chain behavior only, labeled as such — never chain/settlement performance, which is faked.

Contributions and issues welcome.

License

MIT © 2026 Kevin Brown