Rate limitsthat keep no record
Agents lock a deposit and prove they are within quota without saying who they are. Cheat, and the deposit is forfeit.
Stake once, with a tap.An operator locks a deposit with a passkey. Allowance scales with it, so splitting it gains nothing.
Every request, unlinkable.Each call carries a zero-knowledge proof: a staked member, request k of N. Never which member.
One deposit.
No record of who called.
Four stops. One deposit.
The whole journey of a request, from the stake that backs it to the slash that punishes a repeat.
Stake
Lock a deposit with a passkey. The agent joins a public list of staked members.
- Custody
- Passkey, checked on-chain
- Allowance
- Linear in stake
Prove
Each request carries a zero-knowledge proof: a member, request k of N. Never which one.
- Circuit
- RLN-v2, audited and reused
- Scope
- Quotas are per server
Check
The service verifies off-chain and learns nothing about who sent it.
- Check
- Off-chain, milliseconds
- Memory
- One line per nullifier
Slash
A reused number leaks the key. Anyone holding it can claim the stake.
- Claim path
- Commit, then reveal
- Payout
- Slasher paid, rest burned
Every fix so far keeps a record or picks a gatekeeper.
Anyone running a free or cheap endpoint has to stop one agent sending millions of calls. This is what is on the board today.
Breaking the rule exposes the cheater.
Each request carries one point on a secret line. One point is noise. Two points on the same line are the secret itself.
Every line through it is equally likely. The service learns neither the key nor who is calling, and cannot link this request to another.
Four roles. No one in charge.
Operator
The person or team that owns agents. Taps a passkey to lock, change or withdraw a deposit. Public at enrollment, never again.
Privy agent wallet, policy-limitedAgent
The program making requests. It holds a secret key derived from a wallet signature, so it is recoverable and never stored in plain text.
@quota/clientService
An API, MCP tool server or site. It sets requests per epoch, chooses which trust lists to accept, and keeps one line per nullifier.
@quota/server middlewareSlasher
Runs beside the service. When a number repeats it recovers the secret and claims the deposit through a commit then reveal.
@quota/slasher, Dynamic server walletWhat QUOTA does not do.
We would rather you hear it here than find it in production.
- Not proof of being human.A passkey is not a person. The deposit is what makes abuse expensive.
- Limits are per service.Each service sets its own N, so total exposure is N for every server you call.
- The deposit must outweigh the abuse.Services choose a minimum tier. We publish guidance on sizing it.
- Proofs take time.Built for tool servers, APIs and scraping targets, not for public RPC.
- The operator is public at enrollment.Anonymity is among everyone staked in the accepted trees at that moment.
- No sealed mempool yet.BTX is not live on Monad testnet, so claims use commit then reveal. We say so plainly.
A middleware, not an accounts system.
Set how many requests per epoch and which trust lists you accept. Slash rewards go to your wallet.
import { quota } from "@quota/server";
app.use(
quota({
serverId: "lantern-search",
perEpoch: 100,
trees: ["open"],
onViolation: slasher.submit,
})
);API sketch of the target interface. The packages are under construction; see the integration status in the docs.