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

leash-monad

v0.1.9

Published

Spend limits for AI agents on Monad. One call tells a seller whose agent it is, what it may spend today, and whether a payment will go through.

Readme

leash-monad

Spend limits for AI agents, enforced on Monad. This package is the seller and agent side of Leash: one call tells you whose agent is knocking, what it may still spend today, and whether a payment will go through, before you do any work.

npm i leash-monad viem

Check an agent (seller)

import { checkAgent } from "leash-monad";

const v = await checkAgent(agentAddress, myAddress, "2.00");   // Monad mainnet by default
if (!v.ok) return res.status(403).json(v);
// v = { status: "OK", ok: true, remainingToday: "3.0", expiry: 1791887540,
//       erc8004Id: "10299", account: "0xB1C6…", reason: "This agent is leashed and this payment fits its budget." }

| status | Meaning | |---|---| | OK | Leashed, and this payment fits today's budget | | UNKNOWN_AGENT | No leash: nobody has capped this agent | | REVOKED | The owner revoked it | | EXPIRED | The leash ran out | | SELLER_NOT_ALLOWED | The owner didn't allow this agent to pay you | | OVER_CAP | This payment would break the daily limit |

It's one eth_call to the LeashHub contract. No API key, no Leash server in the path.

Charge agents (x402-style gate)

leashGate is framework-agnostic. First request: 402 with your price and a payment reference. The agent pays inside its leash (one Monad transaction) and retries with the tx hash. The gate checks the Paid event on-chain (right agent, right seller, enough money, right reference) and lets it through.

import { leashGate } from "leash-monad";

app.get("/api/forecast", async (req, res) => {
  const g = await leashGate(req, { seller: MY_ADDRESS, priceUsd: "1" });
  if (!g.allow) return res.status(g.status).json(g.body);
  res.json({ paid: g.paid, tx: g.tx, data: await forecast() });
});

A revoked, expired or over-cap agent gets a 403 with the reason before you've done any work.

One payment, one response. Pass claim so a payment can't be replayed: it receives the payment's tx hash and returns false if you've seen it before (a unique row in your database is enough). Payments older than maxPaymentAgeSeconds (default 300) are refused either way, and so are payments in any token outside acceptTokens (default: USDC only), because a leash can name any ERC-20. The Leash test dollar is free to mint (it powers the demo), so add it to acceptTokens only if you want to take demo payments.

The resource is the path. The agent signs leash:<path>:<nonce> (for https://api.example.com/v1/quote that is leash:/v1/quote:<nonce>), and the payment ref is derived from the same path. If you write your own gate, verify against the path, not the full URL, or every honest request will fail with bad_proof.

const g = await leashGate(req, { seller: MY_ADDRESS, priceUsd: "1", claim: (tx) => db.insertIfNew("payments", tx) });

Leave a review in ERC-8004. Pass your seller key as review and the gate writes each agent it serves to Monad's ERC-8004 Reputation Registry (tag1 = "leash", tag2 = "paid", linked to the payment). With reviewRefusals it also records refusals (over_cap, revoked, expired, …); return true only when you want one, because anyone can replay a refused agent's headers. Reviews are broadcast, not awaited, so they add little to the response.

const g = await leashGate(req, { seller: me.address, priceUsd: "1", review: me, reviewRefusals: oncePerAgentPerDay });

// before serving an unfamiliar agent, read what other sellers said about it
import { agentReputation } from "leash-monad";
const rep = await agentReputation(verdict.erc8004Id);            // { reviews, reviewers, paid, refused }
const trusted = await agentReputation(id, { reviewers: [a, b] });  // count only sellers you trust

Full examples, each runnable: Express, Next.js route, check only, agent side.

Pay (agent)

import { fetchWithLeash } from "leash-monad";
import { privateKeyToAccount } from "viem/accounts";

const agent = privateKeyToAccount(AGENT_KEY);           // the session key its owner leashed
const res = await fetchWithLeash("https://leash-monad.vercel.app/api/forecast", agent);

On a 402 it pays inside the leash and retries once. If the leash says no, the payment reverts on-chain and nothing leaves the account.

Pay only bonded sellers (optional)

A leash limits how much an agent spends and, with an allow-list, who it pays by address. sellerPolicy adds an allow-list by stake: the agent pays only a seller whose ERC-8004 identity has a live bond on Sclera, where an agent's owner locks USDC against a floor on its own claim-truth rate. Off unless you pass it.

const res = await fetchWithLeash(url, agent, { sellerPolicy: { requireBond: true, minBondUsd: "0.05", minFloorBps: 8000 } });
// a seller that fails it: 402 { error: "seller_policy", reason: "no_bond", detail: "...", payTo } and nothing is paid

The agent checks all of this on chain before it pays, from the seller's sellerAgentId in the 402:

| check | refused as | |---|---| | the seller named an ERC-8004 id | no_agent_id | | that id's owner or agent wallet is the address being paid, so a seller can't borrow another agent's bond | not_the_payee | | a bond in state Active on Sclera v2, else v1 | no_bond | | its window has not ended, because a matured bond can be withdrawn at any time | bond_matured | | at least minBondUsd in USDC, a floor of at least minFloorBps (both optional) | bond_too_small, floor_too_low | | the chain answered at all: an unreadable chain refuses rather than pays | unreadable |

A seller advertises its id with leashGate(req, { seller, priceUsd, agentId: "10256" }). To check a seller without paying, call checkSeller(payTo, sellerAgentId, { requireBond: true }).

Getting a leashed agent

  1. npx leash-monad-mcp --new-key prints a fresh agent address and key (or use any key your agent already has).
  2. Open leash-monad.vercel.app/own.html, sign in with a passkey and leash that address: daily cap, sellers, expiry, demo dollars or USDC.
  3. Use the key with fetchWithLeash / payWithLeash, or give it to an MCP client through leash-monad-mcp.

Verify Leash yourself

npx leash-monad verify

Checks Leash's claims against Monad mainnet in about ten seconds. It needs no keys and only reads. It covers the deployed and source-verified contracts, one allowed payment, and four refused payments with their on-chain revert reasons (over cap, wrong seller, revoked, expired). It also checks the P256 precompile, the agents' ERC-8004 identities, the live paid API and the Envio indexer.

Networks

| | Chain | LeashHub | |---|---|---| | mainnet (default) | Monad, 143 | 0x64a489074dd6a4b3b977e5f635a178366a8c12c3 | | testnet | Monad Testnet, 10143 | 0x8b427106c04e66dfc6e8d58fa4de0478a54f510a |

Pass { network: "testnet" } as the last argument to any call.

MIT