coupons

documentation

One coupon a day.
It matures in a day.

That's the whole mechanism. Everything here is the arithmetic for it, what the reader can and cannot see, and every number that can be changed. If something on the site isn't explained here, that's a bug in this page.

The idea

A holder-rewards distribution usually reads everyone's balance at some moment and splits a pot by what it saw. That asks a person to be holding at an instant, which makes the optimal play buy-just-before and sell-just-after, and the reader cannot tell a month of holding from forty seconds of it.

A coupon is what a bond pays whoever is holding it, and that is the idea borrowed intact: the payment belongs to the holder, and it has to be held to be earned.

A day is a low bar on purpose. This isn't trying to punish people who trade. It is trying to stop the fee paying a wallet that was in the token for under a minute. On this chain, on this chain, is most of them. Everything above that bar is treated the same.

Maturity

matured = tokens acquired at least 24 hours ago and still held

Nothing arrives already matured. This applies to a buy, a transfer in, an airdrop, or a rebuy after a sale. Maturity cannot be bought, borrowed or sent, only waited for.

The moment each parcel matures is fixed the instant it arrives, so the whole thing is computable now. Rather than asking anyone to trust that their tokens start earning, the page gives the hour.

Parcels and LIFO

A wallet is not a balance, it is a stack of dated parcels. One number cannot stand for a bag bought at five different times without being wrong about four of them.

When you sell, it comes out of the newest parcels first. Trimming a tenth off the top takes the parcel you bought this morning, not the one you have held since launch.

This is the decision that makes it liveable. Under first-in-first-out, selling anything at all would destroy your oldest and most valuable holding, and people would become frightened to touch their own position. Last-in-first-out means managing a bag and keeping your coupons are not in conflict.

The day

The day runs from the launch, not from a timezone anybody has to look up. Day zero opens the moment the token exists; day n closes exactly n+1 days later.

The pot for a day is whatever creator fee arrived at the treasury during it, plus whatever rolled over from the day before.

Splitting the pot

Strictly in proportion to matured tokens. No multiplier, no tier, no bonus, no streak bonus and no second term. One number decides everything.

Integer wei throughout; no float anywhere in the path. Integer division leaves a remainder, handed out by largest remainder with the address as a deterministic tiebreak, so two people running this produce byte-identical files.

Payments smaller than the gas to send them are not paid and not kept: they are named in the ledger and roll into tomorrow, so a small holder accumulates rather than receiving nothing indefinitely.

paid + rollover === pot

Asserted before publication and across four hundred randomly generated days in the tests. A day that doesn't balance to the wei doesn't publish.

What it survives

buying before the closeEarns nothing at that close because the tokens haven't been held a day. They join tomorrow's split, at an hour the page has already given.
selling after a closeWorks once, for the day actually held. Buying back starts green again. No penalty, no blacklist; you simply pay the day back.
splitting across walletsWeight is linear in matured tokens, so two wallets holding half a parcel each weigh what one wallet holding the parcel weighs. Nothing gained, so nothing policed, and nobody honest flagged by a clustering guess.
shuffling to a second addressStrictly worse than doing nothing. Tokens leave one wallet and arrive green in the other, so the pair earns nothing at the next close where one wallet would have earned in full.
airdrops inArrive green and wait a day like everything else.
trimmingTakes the newest parcels first, so an old position is untouched. This is the one thing here that is deliberately generous.
What it does not stop: somebody who buys, holds for a day, takes one close and sells. That is not an attack. It is exactly what the mechanism advertises, and they held for a day to get it. The bar is honest rather than secretly higher than stated.

Supply that survived the night

The same arithmetic, summed over circulating supply: the share of every token that has sat in the same wallet for a full day.

It cannot be staged for a screenshot. A wallet that buys this morning to inflate it contributes nothing until tomorrow, by which time the screenshot is old.

Circulating supply is minted, less burned, and less anything sitting in an excluded address: the pool and the treasury, which are configured rather than detected. A distributor that tries to work out what a contract is will eventually decide a real holder is one.

Stubs and streaks

A wallet's stubs, including how many days it has been paid and its current streak, are read back out of the published ledgers rather than kept in memory. A streak here is a fact about files anyone can download, not a counter this process is holding.

Streaks pay nothing. They are a record, not a multiplier, because a multiplier would be a second rule and the whole point is that there is one.

What it reads, and what it can't

Balances are rebuilt from Transfer logs, which are deltas, not balances. Miss one and the number is wrong forever and nothing inside the reconstruction would ever notice.

So every wallet is checked against a live balanceOf before anyone is paid. A wallet whose reconstruction disagrees is held back. It is named in the ledger and paid nothing that day rather than being paid on a number nobody can stand behind.

A coupon doesn't care why a balance moved, so this needs no swap decoding and no venue-specific event shape. It only needs to know when a balance changed, which is the one thing a transfer log actually says. That makes this reader considerably harder to break than one that has to understand a DEX.

Events are folded in strict time order; a read that arrives out of order stops rather than being sorted over, because a reconstruction that has quietly reordered itself is wrong somewhere else too.

Where the pot comes from

Pons takes 1% of every swap and splits it 70/30 with the creator. The creator's side is claimed in ETH to one address, and the pot is whatever has actually arrived there.

fee asset transfersFees paid in a token: Transfer logs into the treasury. Exact, cheap and complete.
native transfersA block scan for transactions paying the treasury. Value forwarded inside a contract call doesn't appear in a block's transaction list, so this mode reports itself incomplete rather than quietly under-counting.
claim listCurated claim hashes, each verified on chain: exists, didn't revert, pays the treasury, moves value. The fallback that always works.

Money leaving is never counted, only money arriving. It is not money from new buyers. nothing to stake, nothing to lock, no contract holding anyone's tokens.

The ledger

State is not a database. It is the stack of published days, and everything carried between them is recomputed from those files on every boot. A day is published once; a correction is a new day with a note, never a quiet edit to an old one.

It goes up before the money moves, so anyone who saved a copy can hold it against the payment transactions afterwards. Every wallet holding the token is in it, with a reason:

whole bag maturedevery token has been held a full day
part of the bag is still maturingwith the hour the rest joins
nothing matured, bought inside the dayearns at the next close
under the send floor, rolled forwardsmaller than the gas to send it
held backreconstruction disagreed with the chain

Settings

RPC_URLJSON-RPC endpoint, read from the environment at boot. No request can influence it. An endpoint that fetches a URL somebody handed it is an SSRF with better manners, and there is no flag to turn the guard off.
TOKENthe coin
POOLthe Pons pair. Excluded from the standing.
TREASURYwhere the creator fee is claimed to. Also excluded.
FROM_BLOCKthe block the token was created in
LAUNCHunix seconds the token launched. The day clock starts there; if it is not given, the first transfer the reader saw is used.
FEE_ASSETthe asset fees arrive in, or native
CLAIM_TXSoptional claim hashes, each verified on chain
EXCLUDEoptional extra addresses to leave out of the standing
RIPEN_HOURShow long a parcel takes to mature. Default 24. The only real parameter there is.
DAY_HOURShow long a day is, for the close. Default 24.
MIN_PAYthe send floor in wei
LEDGER_DIRwhere closed days live. Default ./ledgers

The API

GET only. A POST gets a 405 and nothing else. Amounts travel as exact decimal strings alongside their raw wei, never as JSON numbers.

/api/daythe open day: pot, source, every claim transaction, supply that survived the night, the full standing, when it closes, and whether it balances
/api/book?addr=one wallet: every parcel, which have matured, what is still ripening and when, its stubs, and what this close pays it
/api/tokenmarket figures labelled as read from a public venue; fees claimed, distributed and rolling
/api/ledger.csvthe ledger as a file
/healthzok

No lookup is written to disk. There is no route that takes free text and returns generated text, and none that can be made to fetch something on a caller's behalf.

Running it

node test-book.mjs     # the book, the maturity and the split
node test-http.mjs     # the routes, and the promises the source has to keep
node dev.js            # local preview, invented history, real engine

RPC_URL=… TOKEN=… POOL=… TREASURY=… FROM_BLOCK=… node live.js

node close.js d41
  → ledgers/d41.json     replayed by the next day
  → out/d41-ledger.csv   the human-readable record
  → out/d41-pay.csv      address, amount, for your own wallet

Zero dependencies. Node's standard library and nothing else. The pages load no font and no script from anybody else, because a page that says it isn't tracking you and then calls a CDN has broken that promise before it finishes rendering.

What it holds

Nothing.

No keys. No signing. No connect-wallet button, no account, no record of who looked up what. There is no route in this codebase that can spend anything, and the test suite greps its own source for private keys, seed phrases and signing calls and fails the build if it finds one.

close.js writes a file. A person sends the payments from their own wallet, on their own machine. Every custody failure in this category began with something that held funds briefly on someone's behalf.

Known edges

Rewards depend on fees earned. Nothing here is financial advice.