Weight
A parcel of tokens arrives weighing nothing. Its weight climbs linearly with time held and reaches the full token amount after the ramp, which is three hours. In basis points:
ripeness(since, t) = min(10000, (t − since) × 10000 / RAMP) weight(parcel, t) = parcel.tokens × ripeness(parcel.since, t) / 10000
Integer arithmetic throughout, evaluated in BigInt. Nothing in
the path from a transfer log to a payment amount has ever been a float.
Weight only ever grows with time, which is the property the page relies on: a wallet's weight at a future moment is exactly computable now, as long as nothing leaves the wallet. That is why the standing can say what a wallet will weigh at the close rather than asking it to wait and find out.
The worked example
| Held for | Weight of a 1,000,000 bag |
|---|---|
| 0 min | 0 |
| 45 min | 250,000 |
| 90 min | 500,000 |
| 3 h | 1,000,000 |
| 3 weeks | 1,000,000 |
There is no cliff anywhere in that. A gate at three hours would make the minute before it worth nothing and the minute after it worth everything, and a moment like that is a moment to plan around. A ramp has no such moment.
Parcels and LIFO
A wallet is not one number. It is a stack of dated parcels, each on its own clock, because one number cannot describe a bag bought at five different times without being wrong about four of them.
When tokens leave a wallet — sold, sent, anything — they come out of the newest parcels first. Trimming a tenth off the top takes the parcel bought this morning, which weighs least, and leaves the one held since launch, which weighs everything.
The cost of that, stated plainly: it means the top of a position can be churned without touching the old part of it. Each round trip costs a swap fee and earns nothing, so it is expensive noise rather than an exploit — but it is possible, and you should know it is possible. Under the other order, selling anything at all would destroy the heaviest holding, and people would end up frightened to touch their own bag.
The round
The clock starts with the token, not with a timezone somebody has to look
up. Round n closes at launch + (n + 1) × 3h, so there
are eight closes a day.
Weight is evaluated at the close, not at the moment somebody loads the page — that is when the money is actually split, so a parcel that reaches full weight between now and then is counted at what it will be worth then.
The round is the same three hours as the ramp, and that is deliberate rather than tidy. A parcel that arrives at the start of a round reaches full weight exactly as that round closes, so within any one round the weight really is the share of it you were present for. Make the round longer than the ramp — a day, say — and almost everything is at full weight by the close, and the ramp stops distinguishing anybody from anybody.
The split
The round's pot is divided strictly in proportion to weight. No tiers, no multipliers, no bonus for a streak, no second term.
Linearity is the whole anti-splitting argument: two wallets each holding half a parcel weigh exactly what one wallet holding the parcel weighs. So splitting across addresses gains nothing, there is no reason to go looking for people who have, and nobody honest gets caught by a clustering heuristic that guessed wrong. Square-root weighting sounds fairer and is farmed by precisely that split.
Integer division leaves a remainder, and it is handed out by largest remainder with a deterministic tiebreak on the address — so two people running the settlement produce byte-identical files.
Payments that land under the cost of sending them are not kept and not lost: they are named in the ledger and roll into the next round, so small holders accumulate rather than getting nothing indefinitely.
Where the pot comes from
Pons charges 1% on the pool 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 since the last close.
Every claim counted is a transaction that was looked up and checked to land at the configured treasury. A claim that lands anywhere else is not counted. Money leaving is never counted — only money arriving.
It is not money from new buyers. There is nothing to stake, nothing to lock, nothing to bond, and no contract holding anyone's tokens. If volume is zero the pot is zero; it is not a yield.
What the reader sees
Balances are rebuilt from Transfer logs, which are
deltas rather than balances. Miss one and the number is
wrong permanently, and nothing inside the reconstruction would notice.
So every wallet is checked against a live balanceOf before
anyone is paid. A wallet that disagrees is held back —
named in the ledger, paid nothing that round — rather than paid on a number
nobody can defend.
Weight does not care why a balance moved, which turns out to matter a lot: no swap decoding, no venue-specific event shape, nothing to break when a venue changes its ABI. It only needs to know when a balance changed, which is the one thing a transfer log actually says.
Two limits, plainly. The pool and treasury addresses are configured, not detected — get them wrong and they show up in the standing as enormous holders. And circulating supply is inferred from mints, burns and excluded balances, so supply parked in an unlisted address counts as circulating.
Arithmetic
Integers in wei throughout, no floats anywhere. At eighteen decimals a float64 stops being able to count single units somewhere above 0.009 of a token.
paid + rollover === pot, exactly. It is asserted before
publication and across four hundred randomly generated rounds in the tests.
A round that does not balance to the wei does not publish.
The ledger goes up before the money moves; the payment transactions go up after. The two can be held against each other by anyone who kept a copy.
The API
Read-only, GET only. A POST gets a 405 and nothing else. Nothing is written to disk and no request can choose what the server fetches.
| Route | What it returns |
|---|---|
| /api/day | the whole open round: pot, source claims, the standing, the scale, and every closed round behind it |
| /api/weight?addr=0x… | one wallet: every parcel, what each weighs now and at the close, and what it has been paid |
| /api/token | the token, the market read off a public venue, and the fee totals |
| /api/ledger.csv | the open round's ledger as it stands, with every wallet considered and the reason beside it |
Running it
npm run dev # the engine over invented history, on :8100 npm test # the engine, the settlement and the server npm start # the deployment; see the settings below npm run close r328 # write the round's ledger and payment file
| Setting | What it is |
|---|---|
| RPC_URL | a JSON-RPC endpoint for Robinhood Chain |
| TOKEN | the coin |
| POOL | the Pons pair |
| TREASURY | the address the creator fee is claimed to |
| FROM_BLOCK | the block the token was created in |
| FEE_ASSET | the asset fees arrive in, or native |
| RAMP_HOURS | time to full weight. Default 3 |
| ROUND_HOURS | how often the pot pays. Default 3 |
| LAUNCH | unix seconds the token launched — the round clock starts there |
| LEDGER_DIR | where closed rounds live. Default ./ledgers |
RAMP_HOURS is a stated setting, not something read off
the chain. Whatever it is set to is printed on the front page,
written into the header of every ledger, and served by the API — so the
number the site claims and the number the money was divided by are the same
number, or the mismatch is visible.
What it can't do
There is no custody here. No keys, no signing, no connect-wallet button, no account, and no record of who looked up what. No route in the codebase can spend anything, and the tests grep the source for private keys, seed phrases and signing calls and fail the build if they find one. They also check that neither page loads a font or a script from anyone else.
Payments are sent by a person, from their own wallet, using a file the closing tool writes. Every custody failure in this category began with something that held funds briefly on somebody's behalf.
Rewards depend on fees earned. Nothing here is financial advice.