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

walletcap-crash-test

v0.4.0

Published

Crash-test AI agent spend limits offline: puts Coinbase CDP x402 spend controls, Spend Permissions and (opt-in) AgentKit through ordinary events such as a restart, 10 replicas or a second permission, then walletcap through the same, and counts the dollars

Readme

walletcap crash test

This puts Coinbase's agent spend controls through the events that hand an AI agent a fresh budget, runs walletcap through the same events, and counts what gets past the cap.

| Control | Events | | ---------------------------------------------------------- | ---------------------------------------------------------------- | | CDP's x402 controls, on their own store and on walletcap's | a restart, replicas, a shared store, a payee who switches assets | | Spend Permissions | a second permission, a period boundary | | AgentKit (--agentkit) | a merchant who lists a bigger offer first |

It runs offline in under fifteen seconds and sends nothing.

$ npx walletcap-crash-test

walletcap crash test: Coinbase's agent spend controls
@coinbase/cdp-sdk 1.61.0 · @x402/core 2.30.0 · SpendPermissionManager 1.0.0 · walletcap 0.2.3
Every agent is held to $50 a payment and $150 in any 24 hours, in USDC on Base.

CDP x402 spend controls                      CDP's controls                     walletcap guard          walletcap cdpStore
  restart, then pay again                    $300 signed · $150 over            $150 signed · $0 over    $150 signed · $0 over
  10 replicas                                $1,500 signed · $1,350 over        $150 signed · $0 over    $150 signed · $0 over
  10 replicas, shared store 1 ms away        $350 signed · $200 over            $150 signed · $0 over    $150 signed · $0 over
  payee asks for EURC, not USDC              1,000 EURC signed, counted as $0   refused before signing   refused before signing

Spend Permissions                            SpendPermissionManager             AccountCapSpender
  a second permission                        $300 pulled · $150 over            $150 pulled · $0 over
  across a period boundary, 1 second apart   $300 pulled · $150 over            $150 pulled · $0 over

Past the $150 cap: $1,700 and 1,000 EURC with CDP's controls, $300 with Spend Permissions;
$0 with walletcap's guard and AccountCapSpender; $0 with CDP's controls on walletcap's cdpStore.

It needs Node 22.13 or later. Add --json for machine-readable results; each event's cdp, walletcap and cdpStore hold the three columns. The process exits 1 if walletcap's guard, CDP's controls on walletcap's cdpStore, or any other walletcap control lets anything past the cap.

To run it from this repository instead: cd crash-test && npm install && npm start.

What runs

Every agent is a separate Node process with its own throwaway key. It builds an @x402/core client with the exact EVM scheme and tries its payments.

The three controls:

  • CDP's controls: applySpendControls from @coinbase/cdp-sdk/x402, the same guardrails CdpX402Client uses. The settings follow Coinbase's README example: per-payment and cumulative caps in USDC, Base only, and no asset allowlist. Like CdpX402Client, the agent turns off x402's own default cap.
  • walletcap guard: guard(client, budget) from walletcap/x402 on the same client. The owner sets the budget once, and every agent opens the same file.
  • walletcap cdpStore: CDP's own applySpendControls again, set exactly as walletcap's README shows: the same caps, allowedAssets: [USDC], and store: cdpStore(budget, { asset: USDC }) from walletcap/cdp. The owner sets the budget once, and every agent, replica or restart opens the same file, so CDP's ledger is that file.

The events, each from a fresh start, once per control:

| Event | What happens | | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Restart | One process pays until it is refused. A second process, the restart, pays again. | | 10 replicas | Ten processes start together and pay. | | 10 replicas, shared store | The same, with CDP's ledger in one shared store built to its SpendStore interface. In the cdpStore column, walletcap's store answers each call after the same 1 ms. | | EURC instead of USDC | The payee asks for 1,000 EURC. |

The shared store is what Coinbase's docs advise for replicas: "implement this interface against a shared durable backend (Redis, Postgres, DynamoDB, etc.)". The store in spend-store.mjs does exactly what the interface says, and answers each call after 1 ms, as a network database does.

The interface has no single step that both checks the cap and records the payment. CDP reads the total, decides, then appends, and its lock covers one process. Replicas can read the same total before any of them appends. How many overlap varies from run to run.

walletcap's cdpStore sits behind the same interface, so CDP still reads, decides, then appends. Its append re-checks the cap inside one SQLite write transaction and throws if the payment would go past it. CDP appends before it signs, so a payment the store refuses is never signed. In the replica rows, the re-check usually refuses a few payments that CDP's own check had passed (budget in --json); how many varies from run to run. In the EURC row, CDP's allowedAssets, which walletcap's README sets, refuses before the store is asked.

Coinbase Spend Permissions

Coinbase's SpendPermissionManager v1.0.0 and Smart Wallet run on an in-process EVM. Their code is the exact runtime code deployed on Base mainnet, read once with eth_getCode and shipped in contracts/coinbase-base-mainnet.json with each code hash, so the crash test needs no network.

A Smart Wallet holds $1,000 of a test token that stands in for USDC, and grants the agent permissions of $150 a day.

| Event | What happens | | ------------------- | -------------------------------------------------------------------------------------------- | | A second permission | The wallet grants two permissions with different salts, and the agent pulls $150 from each. | | A period boundary | The agent pulls $150 in the last second of one day and $150 in the first second of the next. |

The manager counts each permission, and each period, on its own, so both events pull $300. Within one permission and one period it holds: the test suite checks that a fourth $50 is refused with ExceededSpendPermission.

walletcap's side: the wallet grants the same permissions to AccountCapSpender, walletcap's on-chain spender. It counts every permission against one rolling $150 cap and refuses the second $150 with OverBudget. AccountCapSpender is unaudited.

node contracts/build.mjs --check checks two things: that each piece of Coinbase code still matches its recorded hash, and that the shipped AccountCapSpender still compiles from its Solidity source in the repository's contracts/src. --fetch re-reads Coinbase's code from Base mainnet.

Coinbase AgentKit (--agentkit)

$ npx -p walletcap-crash-test -p @coinbase/[email protected] walletcap-crash-test --agentkit

Coinbase AgentKit 0.10.4: the agent approves the merchant's 1¢ offer on Base Sepolia; the merchant
lists $1.00 on Base mainnet, to another address, first.

AgentKit                         signed $1.00 on Base mainnet to the first-listed address, valid 4 days; reported $0.01 on Base Sepolia
walletcap, 2¢ a payment          signed $0.01 on Base Sepolia, the offer the agent approved

The AgentKit row runs AgentKit's own retry_http_request_with_x402 action against a merchant on 127.0.0.1. The agent hands it the 1¢ offer it approved, which is how AgentKit's flow works.

What AgentKit does with it:

  • It checks only that the approved offer's network is one the wallet supports.
  • It then builds a fresh x402 client, which pays whatever the merchant listed first.
  • Its answer reports the approved offer, not the one it signed.

walletcap's guardAgentKit(provider, budget), at 2¢ a payment, limits how much AgentKit pays, not which offer it pays. Here it passes over the $1.00, which the merchant asks to be valid 4 days (walletcap signs only terms valid an hour or less, and at most 2¢), and the offer left is the 1¢ one the agent approved. Had the merchant listed the approved offer valid two hours, and a 2¢ one valid five minutes, walletcap would have let AgentKit sign the 2¢ one. The row passes only if walletcap signs the approved offer or nothing.

AgentKit is opt-in because it installs about 1.3 GB. Its wallet providers also send an analytics event with the wallet's address when they start. The crash test turns that off and blocks every request except the one to the local merchant.

What "signed" means

Nothing is sent. Each payment is an x402 authorization (EIP-3009) signed with a key that holds nothing. A payee holding one could settle it on Base until it expires, so signing is the moment the money is committed. The crash test counts what each control lets the agent sign.

What it doesn't cover

  • Settlement of x402 payments. For x402 it measures what the client-side control lets the agent sign, not what lands on chain. The Spend Permissions rows do move tokens on the local EVM.
  • More than one machine. The replicas share one machine, and walletcap's budget file, behind both its guard and its cdpStore, is single-host.
  • A revoke in the same block. A revoke that lands after the agent's payment in the same block doesn't stop that payment, with either control. Neither control can make a revoke retroactive.
  • Other vendors' controls. Coinbase's CDP x402 controls, Spend Permissions and AgentKit are covered so far. The Agentic Wallet, Safe, MetaMask, Tempo and AP2 come next.

Coinbase's contract code in contracts/coinbase-base-mainnet.json comes from coinbase/spend-permissions and coinbase/smart-wallet, both under the MIT license.

Releasing

To release a new version:

  1. Bump version in crash-test/package.json and merge the change.
  2. Publish a GitHub Release tagged crash-test-v<version>. Untick "Set as the latest release", so walletcap's own release stays the latest.

The Publish workflow then runs the crash test against the walletcap on npm and publishes with provenance. Releases tagged v<version> publish walletcap only.

To have the same measurement run against your own agent, inside your walls, with every control on and a signed result, ask for a ShadowPath report.