rob0 robpaper
ROB0 is a fixed-supply token on Robinhood Chain. Every mint payment buys and burns PONS immediately, so ROB0 is a receipt for burned PONS, not a treasury claim. At the end of the mint a TOKEN/PONS pool opens with liquidity locked forever, a redeemable PONS vault backs every ROB0, and an autonomous reserve keeps buying PONS or ROB0 for as long as it holds funds, harder the further either sits below its own 7-day average. No address holds an owner key, a pause switch, an upgrade path, or a way to move the vault or the liquidity outside the rules below.
PONS, not ROB0, is the target because a self-buy only recycles capital, while buying an outside asset removes supply this project cannot re-inflate. The counter-cyclical rule makes the reserve a buyer of weakness, not a chaser of strength.
1. Parameters
Every figure below is a constant or immutable in the deployed contracts.
Where a payment goes. Each mint payment is split four ways: 55 percent buys PONS (BUY_BPS), 20 percent funds the reserve (RESERVE_BPS), 15 percent funds the liquidity position opened at finalisation (LP_BPS), and 10 percent is paid to the deployer's address (MintCurve.DEV_BPS), which the project will use to fund staking. That use is a commitment by the project. The contracts do not enforce it: the payee is an ordinary address and nothing on chain constrains what it does with what it receives. Of the PONS bought, 60 percent is burned and 40 percent enters the redeemable vault (BURN_SHARE_BPS). Paying in PONS directly earns 25 percent more points than the same value paid in anything else (PONS_BONUS_BPS), because that route buys nothing and so costs the pool nothing.
Limits on the sale. A single transaction may contribute at most 20 WETH-equivalent (MintSale.MAX_PER_MINT). The sale as a whole accepts at most 3,200 WETH-equivalent (CAP_WETH, an immutable fixed at deployment) and runs for at most 15 days (MINT_WINDOW), whichever comes first. A plain ETH transfer to the contract, which mints without going through the interface, is protected only by a fixed 5 percent slippage floor (RECEIVE_SLIPPAGE_BPS).
Supply. One billion ROB0 is minted once, at finalisation, and never again (MintCurve.TOTAL_SUPPLY). Minters share 600,000,000 of it, 60 percent (MINTER_SUPPLY). The liquidity position takes at most 150,000,000, 15 percent (LP_MAX). Whatever remains, never less than 25 percent, becomes the twin-burn pocket described in section 4.
The reserve. Each call spends a base rate of 0.008 percent of the reserve's balance per elapsed hour (Reserve.RATE_PER_HOUR_WAD), multiplied by the square of the ratio between the 7-day and 1-hour averages and clamped between 0.25x and 4x (TickQuote.multiplierX96). No single call may spend more than 0.5 percent of the balance (MAX_SPEND_BPS), calls are at least an hour apart (MIN_INTERVAL), purchases must execute within 2 percent of the 1-hour average (SLIPPAGE_BPS), and whoever pays the gas to call it keeps 0.1 percent of what was spent (BOUNTY_BPS).
The hook. Swaps in the official TOKEN/PONS pool pay 1 percent (BurnHook.BASE_FEE_BPS), rising to 2 percent when the side being sold trades roughly 5 percent, 488 ticks, below the 1-hour average (DUMP_FEE_BPS, TickQuote.DUMP_TICKS).
2. Point curve
Points are granted as points = P × (1 − 2E/(3×CAP)), where P is the PONS this mint bought and E the WETH-equivalent raised before it. The first point is worth three times the last.
In practice the rate falls in a straight line as the sale fills: 100 percent of the opening rate at the start, 83.3 percent a quarter of the way through the cap, 66.7 percent at the halfway mark, 50 percent at three quarters, and 33.3 percent at the cap.
If PONS's price rises mid-mint, a WETH buys less PONS, so points fall faster than the curve alone implies. A mint that would push past the cap is truncated and the excess refunded in the same transaction. mint() and mintETH() take a caller-set minimum PONS out. A plain receive() applies the fixed 5 percent floor instead, or no protection at all if no price history exists yet.
3. Routing, finalisation, redemption, reserve
A route is a list of hops ending in WETH, or no swap at all on the direct-PONS route, with each hop on either Uniswap v4 or V3. V3 hops go through the immutable SwapRouter02 and never call a pool directly, so nothing here exposes a callback a forged pool could exploit. There is no token allowlist. Slippage protection covers the whole route's output rather than each hop.
finalize() is permissionless, runs once, and becomes callable on whichever comes first of the cap being reached or the 15-day deadline passing. It mints the fixed supply, opens the pool at the last point's price so that no minter opens underwater, and deposits the liquidity fund. Uniswap v4 issues no LP token; MintSale holds the position directly and never calls modifyLiquidity with a negative delta, so the liquidity cannot be withdrawn.
redeem(amount) burns amount ROB0 and pays amount / circulatingSupply × vaultPONS, excluding the locked pocket. Because it is exactly proportional, redeeming never changes the floor for anyone else. The floor only rises: PONS enters the vault as 40 percent of every purchase and leaves only pro-rata.
At each hourly poke(), the reserve buys whichever of PONS or ROB0 sits furthest below its 7-day average, using the same 1-hour and 7-day basis to choose as it does to size. It never reads the spot tick, so a same-block push cannot redirect a poke. Everything bought is burned immediately.
4. Twin burn and hook fee currency
Every PONS burn, whether it comes from a mint, the reserve, or hook fees, calls twinBurn(ponsBurned, ponsCirculating) and burns pocket × ponsBurned / ponsCirculating ROB0 from the pocket fixed at finalisation. It stops for good once the pocket empties.
On an exact-input swap the hook's fee is taken from the currency the swapper receives. On an exact-output swap, Uniswap v4 only allows afterSwap to take a fee from the unspecified currency, which in that case is the input. Both charge 1 to 2 percent of trade value; which token is actually debited depends on which side the caller fixed.
5. What does not exist
There is no owner, no pause, no upgrade path, no blacklist, no maximum wallet, and no function that can change any fee, rate, or cap. The only exit from the vault is redeem()'s pro-rata formula. There is no way to withdraw the pool liquidity, ever.
6. Threat model
Price manipulation. An attacker who moves the TWAP to make the reserve buy expensively is bounded by the 0.25x to 4x multiplier clamp and the 0.5 percent per-call spending ceiling. Sandwiching poke() is bounded by a minOut derived from the 1-hour average with 2 percent tolerance. Redirecting a poke by pushing the price within a single block does not work, because the target is chosen from the 1-hour and 7-day averages and never from the spot tick. A tick manipulated through the permissionless record() is time-weighted until the next record, and the hook records on every swap.
Funds. The vault's only exit is the pro-rata redeem(), under nonReentrant. finalize() cannot run twice, guarded by a one-shot flag. Fee-on-transfer and callback tokens at mint are handled by nonReentrant and balance-difference accounting. A malicious hook inside a caller-supplied route risks only that caller's own input. Points are computed at 1e18 precision with division performed last. A residual V3 approval is reset to zero in the same call.
Deployment. The PONS burn address was verified on chain before deployment. wire() rejects a zero address on every side. A short TWAP history on the V3 venue is handled by consult(), which clamps the request to the buffer's actual depth.
The sale. No single address can take the early curve alone, because of the 20 WETH per-transaction cap. A mint that would exceed the overall cap is truncated and the excess refunded in the same call.
Not preventable. A second ROB0/PONS pool opened without the hook cannot be stopped. See the limitations below.
7. Limitations and accepted risks
A plain ETH send carries only the fixed 5 percent default slippage floor, with no route-specific or caller-chosen protection.
A multi-hop route is protected only on its total output, so one hop can be sandwiched within the aggregate tolerance.
The PONS burn address is immutable. A future second PONS burn sink would make ponsCirculating() overcount, which makes the twin burn under-fire, never over-fire.
The PONS price window on the V3 venue reaches back about 5.2 days, not the requested 7, because that pool's buffer is full and it trades too fast to hold more. Measured live at 448,494 seconds, 124.5 hours, on 2026-09-07 by test/fork/ForkPreDeploy.t.sol. The buffer is a fixed 20,000 entries, so its depth in time shrinks as the pool trades more: at the chain's 0.101-second blocks, a pool with a tick-moving swap in every single block would hold only about 34 minutes, below the 1-hour short window, at which point the reserve's counter-cyclical signal degenerates, both deviations going to roughly zero and the multiplier pinning at 1x. The pool currently writes one observation every 22 seconds, leaving roughly two orders of magnitude of headroom, and the reserve's 0.5 percent per-poke and 2 percent slippage bounds hold regardless. Re-measure before deploying.
The per-transaction cap is not a hard bound on the direct-PONS route. MAX_PER_MINT is checked against a quoted WETH-equivalence, so a PONS/WETH 1-hour average pushed down admits more PONS per mint and understates how much that mint moves raised, keeping the point curve favourable for it. This was priced on the live pool by test/fork/ForkTwapCost.t.sol. Holding the price displaced for a full hour costs the round-trip fee of roughly 2 percent on the size sold, and the size needed is large next to an entire raise: selling 1,000,000 PONS moves the average 15.7 percent and costs 19,108 PONS, while 5,000,000 moves it 80 percent and costs 77,481 PONS, a substantial fraction of a whole sale's value. Selling 50,000 PONS moved the average not at all. The manipulation costs more than the edge it buys, and every fix for it, whether bounding the average against spot or imposing a minimum PONS mint size, would let the same manipulator block PONS mints outright instead: a denial of service traded for a bounded edge, on a system with no admin to unblock it. Accepted, not fixed. The assumption is pool depth, so re-price this if the PONS/WETH pool's liquidity falls materially from the 3.15e23 measured here.
Stock-token launchpad pools are shallow. One sampled TSLA/WETH pool held about 711 TSLA against 58.9 WETH, so routes through them can carry real price impact.
Nothing prevents ROB0's market price from falling. The vault is a redemption floor denominated in PONS, not a price guarantee.
A fee-free shadow pool can exist. Uniswap v4 keys a pool on its pair, fee tier and hook, and BurnHook governs only pools that name it. Anyone may open a second ROB0/PONS pool at another fee tier with no hook. Swaps there pay the reserve nothing, and their price is never read by the reserve's oracle. This is inherent to permissionless markets and no hook design avoids it; an admin allowlist would, and this project refuses one. The official pool's advantage is its permanently locked liquidity, which a shadow pool has to match from zero. Nothing is stolen and nothing breaks: the vault, the redemption floor, the locked liquidity and the twin burn are all unaffected. What can be avoided is part of the reserve's perpetual funding. Demonstrated in test/audit/ShadowPool.t.sol.
8. Addresses
Deployed on Robinhood Chain, chain id 4663, on 2026-09-07.
- MintSale
0x07cC15e103377756A178665a96097A0c509F2b34 - BurnToken (ROB0)
0xEd20C0aFF69b9BAd6C3f7841823571fF8E49Cf7C - Reserve
0xD2da340b0E728bFb970933A3d524774A8d33Dbeb - BurnHook
0x6c783f81149214C2943683403182E8BeF5C860c4 - TwapOracle
0x4143236ca852866e70493786257Ed359095A454e - HookDeployer
0xF841A0d503785B11c95aeb31686D93Cf0D5e3D37, which created the hook at a mined address and is inert now that it has
The venue and asset addresses these were wired to, verified on chain before deployment and readable from MintSale itself: PoolManager 0x8366a39CC670B4001A1121B8F6A443A643e40951, WETH 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73, PONS 0x39dBED3a2bd333467115dE45665cC57F813C4571, and the PONS burn address 0x000000000000000000000000000000000000dEaD.
BurnHook's address ends in 0x20c4. Uniswap v4 reads a hook's permissions from the low 14 bits of its address, and those are exactly BEFORE_INITIALIZE | BEFORE_SWAP | AFTER_SWAP | AFTER_SWAP_RETURNS_DELTA and no other flag.