The coin
Every Garner coin is a clone (EIP-1167) of one small contract, GarnerCoin. It is an ordinary ERC-20 with 18 decimals and a fixed supply of 1,000,000,000, all of which starts inside the coin itself. The coin is also its own market: a constant-product curve between the coins it holds and a reserve of ETH that starts with a virtual 1 ETH. So a new coin has a price from its first block (a market cap of 1 ETH), and there is no other pool to route around its fee.
Buying sends ETH in; the fee is taken first, the rest goes to the curve, and you receive coinReserve × net ÷ (ethReserve + net) coins, rounded down. Selling is the mirror image, and the fee is taken from the ETH that comes out. The page computes both with the contract’s own integer formulas and sends a minimum 1% below its quote.
The fee
Chosen at launch, from 0.25% to 10% in steps of 0.25%, and stored in the coin. No function changes it: there is no owner and no admin, in the coin or in the factory. Every buy and every sell pays it, in ETH. None of it goes to the creator or to Garner: all of it becomes stock in the coin’s store.
The store
Each fee is swapped into the coin’s stock (below) and put in the coin’s store. The store pays itself out continuously: between any two moments it releases what is in the store × time passed ÷ time left until its end, and every purchase first brings the store up to that second at the old pace, adds the new stock, and sets the end to seven days from now. So a single purchase is paid out evenly over the next seven days, and a coin that trades all the time keeps a store that is always about a week of its fees deep.
What is released goes to the locks that are live at that moment, each in proportion to its weight, through a running total: stockPerWeight grows by released ÷ live weight, and what a lock is owed is its weight times how much that total has grown while it was live. Coins that are not locked weigh nothing and earn nothing; the coins inside the coin’s own curve are never locked.
While no lock is live, nothing is released and the store stands still: its end moves on by exactly the time that passed, so the first lockers find all of it waiting and it pays out over the same seven days it would have.
Rounding never lets the coin owe more than it holds. The share per unit of weight is rounded down; the amount taken out of the store for it is rounded up, and whatever a release cannot place exactly stays in the store and is paid out with the rest.
Locks and weights
lock(coins, term) locks coins in your own wallet for one of four terms. The coins never move: the coin simply refuses any transfer, sale or transferFrom that would take a wallet below the coins it has locked, with the error CoinsLocked.
| Term | Weight per coin |
|---|---|
| 7 days | ×1 |
| 30 days | ×1.5 |
| 90 days | ×2.5 |
| 365 days | ×5 |
A lock ends at 00:00 UTC on the first day at least the term’s length away, so it is never shorter than the term and never more than a day longer. At that moment its weight stops counting (the contract keeps, for every day on which locks end, the running total at the start of that day) and its coins are free again, with nothing to press. Each wallet holds one lock per coin. Locking more coins, or choosing a term again, moves the whole lock to the new end and the new term’s weight; a choice that would end it sooner than it already ends is refused (ShorterThanCurrent). There is no early exit.
buyAndLock(minCoins, term) buys and locks what was bought (with any lock already held) in one transaction. Because the store pays out over seven days and the shortest lock is seven days, locking just before a large trade earns a slice of that trade’s stock at the same pace as every other lock, not a lump of it.
Claiming
claim(to) sends everything the caller has earned to to, in the stock, and touches nothing else: the coins and the lock stay as they are, and the store keeps paying. There is no deadline and nothing expires. A lock that has ended, and a wallet that has sold every coin, can still claim what was earned. Your locks reads every coin at once and shows what is waiting; the coin page shows it rising by the second.
Anyone can call poke() to bring a store up to the present (every lock, claim and purchase does it anyway), and convert(maxEth) to swap fees that are waiting for a fair price.
The fair-price guard
Each fee is swapped inside the same transaction: ETH → USDG in Uniswap’s WETH/USDG 0.01% pool, then USDG → the coin’s stock in its pool (the fee tier chosen at launch; the launch page picks the deepest). Before swapping, the coin reads both pools’ time-weighted average price (30 minutes; if a very busy pool has overwritten that much history, 10 minutes, then 2) and sets the swap’s minimum to what the averages say the ETH is worth, less both pools’ fees and 2%.
A price pushed inside the current block carries no weight in an average, so an attacker who moves a pool and then triggers a purchase gets nothing: the swap fails its minimum, the ETH stays in the coin as pendingEth, and the next trade (or anyone calling convert) tries again. The trade itself always goes through.
One refusal is deliberate: a transaction with too little gas left for the swap reverts with NeedsMoreGas instead of quietly deferring the fee. Wallets estimate the smallest gas at which a transaction does not revert; without that refusal, estimates would starve every purchase.
The picture and links
The picture (cropped square and shrunk to under 16 KB in your browser), the description and up to three links are ABI-encoded and stored as the code of a tiny contract (SSTORE2) when the coin launches: 24 KB at most. meta() returns them byte for byte. Nothing depends on a server.
The contracts
| What | Address |
|---|---|
| GarnerFactory | 0x64A815E050694431f1908c171946f1a06f3D342e |
| GarnerCoin implementation | 0xE2e81A3DeDECd0F412AA4308Be85D79cf00b7398 |
| CREATE2 deployer (Arachnid’s, deterministic) | 0x4e59b44847b379578588920ca78fbf26c0b4956c |
| Uniswap SwapRouter02 | 0xCaf681a66D020601342297493863E78C959E5cb2 |
| WETH / USDG 0.01% pool | 0x52e65B17fB6E5BA00Ed806f37Afcd2DaA50271Ca |
The factory’s address is keccak256(0xff ++ deployer ++ salt ++ keccak256(initCode)), with salt 0x54d771750562d664893589f77f3d8b3a6b931e427a567d94e7ec6c1b3f2f7254 and init-code hash 0xb6e33f7da814fa9935515a9022be4c93a32d561d66d6adcee58724230f0c92b3. So the address is the code: anyone can deploy it, and whoever does puts exactly this code there. The launch page does it for you: if the factory is not there yet, your wallet first sends that one deployment, then your launch. Source: GarnerFactory.sol, GarnerCoin.sol, and Uniswap’s TickMath.sol; solc 0.8.26, optimizer 1000 runs, via-IR, Cancun. Status right now: checking…
How it was tested
Every property below runs on a private fork of live Robinhood Chain (anvil, started fresh at the newest block for each property): the real CREATE2 deployer deploys the factory, coins launch on real stock tokens, and every purchase swaps through the real Uniswap pools, in the state they are in right now. Nothing is broadcast and nothing is mocked. Expected numbers are computed in the test from the formulas written out there, never by asking the contract; the store’s payout is checked against a model that knows nothing of the contract’s running total or its day-by-day bookkeeping: a continuous seven-day payout, divided by weight among the locks the test itself believes are live.
The last run: 11/11 properties and 1,487 checks passed against live state (01 Oct 2026), for the factory at 0x64A815E050694431f1908c171946f1a06f3D342e.
| # | Property | Checks |
|---|---|---|
| P1 | The factory lands at the address its code fixes, with the implementation beside it | 7 |
| P2 | Launch refuses every bad input with the error named for it, and accepts a good one | 21 |
| P3 | Buys and sells pay exactly the curve and the fee, and every fee becomes stock in the store or waits | 66 |
| P4 | A round trip never makes money in ETH, and everyone can always sell back | 21 |
| P5 | Stock is only bought near the average price; a pushed pool defers the buy until it is not | 16 |
| P6 | The price read is Uniswap's, in both token orders and every fee tier, and the swap matches the quoter NVDA through its 0.05% pool: 0.005 ETH bought 0.058341 NVDA, 5 bp above the 30-minute average (the floor allows 206 bp below) SPCX through its 0.05% pool: 0.005 ETH bought 0.090778 SPCX, 1 bp above the 30-minute average (the floor allows 206 bp below) TSLA through its 0.3% pool: 0.005 ETH bought 0.037964 TSLA, 21 bp below the 30-minute average (the floor allows 231 bp below) MSTR through its 1% pool: 0.005 ETH bought 0.083682 MSTR, 90 bp below the 30-minute average (the floor allows 301 bp below) | 17 |
| P7 | The store pays out over seven days, only to live locks, by weight — and claims pay it exactly store paid out in 6 segments; of 833186006420616754 units bought, 2 belong to nobody (rounding) | 308 |
| P8 | Too little gas is refused outright rather than silently deferring the fee | 12 |
| P9 | A coin keeps its picture and links on chain, byte for byte | 6 |
| P10 | The coin is an ordinary ERC-20 apart from locked coins, refuses stray ETH, and cannot be re-initialised | 14 |
| P11 | Under random trading, locking and waiting, every holder is owed what the model says and the coin can pay everyone 30 random steps + coda; landed 16 buy, 4 sell, 3 transfer, 2 lock, 4 buyAndLock, 6 claim, 24 stockBuy, 2 refusedLocked, 4 warp, 4 endedLocks; 8 payout segments | 999 |
Then a sabotage sweep plants 30 bugs, one at a time, in copies of the contracts: the fair-price guard removed, the 30-minute average swapped for the spot price, a store that runs down while nobody is locked, a store paid out all at once, an ended lock that keeps earning or keeps its weight, locked coins that can be sold, a lock that never ends or can be shortened, a month weighed like a year, a new lock paid for time before it existed, a claim that can be taken twice. It requires the property named for each one to fail. 30/30 were caught by the property named for them.
And in a real browser: headless Chrome drove these pages with a test wallet against a private copy of the live chain. One click on the launch page deployed the factory and launched a coin with a picture whose store fills with NVDA; the launcher locked everything for a month from the Lock tab; a second wallet bought and a day passed, and the launcher’s share appeared on the coin page and rose by the second; the Claim button paid exactly what the coin said; the trade box refused to sell locked coins and bought-and-locked in one transaction; the locks page showed the lock and claimed; the board showed the store; and once the month was over the coins sold. 8/8 journeys, 44 checks, each outcome read back from the chain by the harness itself (01 Oct 2026).
Risks
- Unaudited. The contracts are small and tested, not audited.
- Coins can go to zero, and a locked coin cannot be sold while it does. A Garner coin has no floor: its store is paid out, not kept as backing. What you have been paid is yours; what the coin is worth is up to the market.
- Payouts depend on trading. No trades, no fees, no stock: a store runs dry seven days after its last purchase. The calculator on the front page is arithmetic, not a forecast.
- Stocks fall, and Robinhood controls its stock tokens. Robinhood can pause, block or burn its tokenized stocks. A paused stock cannot be bought (fees wait as ETH) or claimed (claims revert until it resumes).
- Thin pools make fees wait. If the stock’s pool is too thin for a fair fill, the fee waits as ETH until a trade or
convertcan buy at a fair price.