Cohort Order Book: an O(1) fully on-chain limit order book via generational fungible liquidity
Draft for Ethereum Magicians. Looking for critique, especially on the one-sided-add justification in §4 and the FIFO concerns in §6.
TL;DR
A fully on-chain limit order book where orders at each price point are fungibilized into time-ordered “cohorts.” Fills touch ≤2 cohorts per price point → O(1) (no per-order loop), partial fills are exact, and cancellation is just “withdraw your own position.” The design’s real justification isn’t gas — it’s that it’s the clean way to accept one-sided liquidity adds to a partially-filled price level, which pro-rata AMMs cannot do without either two-sided adds or subtle rebasing math. The cost is a coarse, tunable batch-FIFO. I want to pressure-test whether that price is acceptable — and whether this is worth building at all.
1. Motivation
On-chain order books are gas-hostile: filling loops over resting orders, O(n) in the number of orders. That’s why on-chain trading converged on AMMs, which fungibilize liquidity per price level (O(1) fills) — but in doing so give up clean limit-order semantics.
The specific semantic that breaks is one-sided adds to a partially-filled level (§4). This post proposes a structure that keeps O(1) fills and clean one-sided adds, and is honest that the price is a coarse FIFO.
2. Core idea — cohorts
At each price point (tick), resting liquidity lives in cohorts — fungible batches (one fungible token per cohort). At most two are live at any time:
Staging — where new orders land; not yet being filled.
Open — the batch currently being filled; frozen (no new orders join it).
3. Mechanism
Place → mint a share of the current staging cohort.
Promote → on the first fill at this price, staging is frozen → open, and a fresh staging opens.
Fill → consume open, tracked by a single fill fraction (filled / frozen total).
Settle → when open is fully consumed it settles (redeemable), and the next staging promotes.
Because only one open + one staging are ever live, a fill touches ≤2 cohorts per price point → O(1) (settled cohorts just await redemption, O(1) per LP). A trade sweeping multiple ticks is O(ticks crossed), same as any tick-based AMM.
Freeze-on-fill is what gives exact partial-fill accounting: each cohort has a single clean fill fraction, and new orders never inherit someone else’s partial fill.
Worked example (one tick): Alice 100 + Bob 50 → Staging C1=150. Fill 90 → C1 freezes (60% filled), new Staging C2. Carol 30 → C2=30. Fill 60 → C1 fully settles. Fill 20 → C2 promotes, consumed 67%.
4. Why generations at all? — the one-sided-add problem
This is the actual justification, and it’s easy to miss.
A limit order is one-sided (you post a single token at a price). In a pro-rata AMM (Uniswap V3 range order), once a tick is partially crossed (price inside the range), you can only add liquidity in the current two-token ratio — you cannot cleanly top up one-sided. In practice, V3 range-order users open a new position per add during a partial fill — i.e. they manually create generations.
You can pool one-sided adds with a per-LP accumulator, but consuming fills rebase the remaining one-sided balance while accruing the counter-asset — a rebasing-token-plus-rewards accounting that is doable but subtle and error-prone.
Cohorts automate the “new position per add” workaround: freeze the partially-filled batch, route fresh one-sided liquidity to a clean 0%-filled batch. That’s the real value.
The same structure that enables this — draining the open batch before promoting the next — is also what imposes a batch-FIFO ordering across cohorts. That’s the main tradeoff, discussed in §6.
5. Prior art (this is not novel in isolation)
Ambient (CrocSwap) “knockout liquidity” is essentially this: on-chain limit orders as concentrated liquidity that fully converts when crossed, using pivots/epochs — which are cohorts by another name — precisely to handle one-sided adds + partial fills. This post is largely a generalization/formalization of that pattern as a standalone order book.
Trader Joe Liquidity Book — fungible per-bin liquidity (the recurring, two-sided endpoint).
Uniswap V3/V4 range orders + feeGrowth — the pro-rata accumulator alternative in production.
If there’s prior art that handles one-sided adds more cleanly, I’d love pointers.
6. Known concerns / where I expect pushback
Being upfront, because these are real:
FIFO on-chain is arguably not real FIFO. Intra-block ordering is set by builders (MEV), so “time priority” is partly auctioned, not earned. The promotion boundary (“first fill freezes the cohort”) is itself a potential griefing/MEV surface (dust-fill to freeze a rival cohort; snipe into staging before a known large fill). Mitigation: coarsen cohorts (promote on a volume/time threshold, not every first fill) so it’s pro-rata within large batches and FIFO only at rare boundaries — but does that fully address it?
Front-of-queue adverse selection. The oldest cohort fills first, i.e. gets picked off first by toxic flow. “Priority” may be a poisoned chalice.
Fresh-liquidity discouragement. Back cohorts fill last, so why add depth right before a move? Pro-rata welcomes liquidity anytime.
Capital + adverse selection. A one-shot resting order earns nothing while waiting and is a free option to takers (the classic reason on-chain order books lost to AMMs). This is independent of the cohort structure.
Is one-sided limit UX even worth building given off-chain intents (CoW/1inch/UniswapX: gasless, no lockup, free cancel) and AMM range orders already serve most limit-order demand?
7. Discussion questions
Does keeping O(1) fills + clean one-sided adds necessarily force batch-FIFO, or is there a pro-rata construction that avoids it?
Does coarsening cohorts (threshold-based promotion) reduce the FIFO/MEV concerns to de minimis, or just move them?
Is there a cleaner accounting for one-sided adds under a pro-rata accumulator that I’m underrating (rebase index done right)?
Given Ambient already ships the pattern — is there value in a standalone, generalized order-book form, or is “limit orders as a layer inside an AMM” the only version worth having?
For a term-structure / maturity-bucketed market, a far-dated limit is a composite of per-period orders that must fill atomically — does the cohort model extend, or does that push you back to intent/solver execution?
Thanks in advance for tearing into it.
3 posts - 2 participants
Read full topic
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | ERC-XXXX: NFT-Bound Prediction Markets (LMSR pricing, on-chain state) | 0 | 15.86 | 21-07-2026 |
| 2 | [Idea/Draft] Protocol-Level Smart Contract Invariant Protection via Pre-Mempool Validation (Security Manifests) | 0 | 10.76 | 22-07-2026 |
| 3 | ERC-8349: Index-Based Multi-Facet Proxy | 0 | 10.21 | 21-07-2026 |
| 4 | ERC-8343: Contract Deactivation | 0 | 15.62 | 21-07-2026 |
| 5 | ERC-TBA: Prediction Market CTF Wrapper | 0 | 11.4 | 27-07-2026 |
| 6 | ERC-8354: Confidential Agent Policy Verdicts | 0 | 12.87 | 24-07-2026 |
| 7 | EIP-8146: Block Access List Sidecars | 0 | 6 | 10-07-2026 |
| 8 | Timelock Account recovery: A trust minimized recovery system for Smart Accounts | 0 | 6.22 | 14-07-2026 |
| 9 | ERC-8335: Account-Level Transfer With Authorization | 0 | 7 | 10-07-2026 |
| 10 | EIP-8334: Bundled Attestation Propagation | 0 | 13.2 | 14-07-2026 |