Skip to main content

Session — stage 3, graduation — closed 15 Sep 2026

Graduation must actually happen inline for a normal wallet. Every stage 3 line was ✔ bar the permissioned pool; checking the first one against a real gas estimate found it does not hold.

What we found — 15 Sep 2026

  • A crossing buy sent at its gas estimate defers graduation. Local anvil, make dev-deploy: cast estimate of a crossing buy = 192,308; sent at that limit it succeeded, locked true, graduated false. graduate() alone estimates 452,747; the floor is 500,000.
  • Why: below the floor the curve locks and returns success, and estimation looks for the least gas that succeeds. RHUB hid it with an interface that doubled the gas (TradePanel.tsx). Doubling would not reach the floor here.
  • The permissioned-pool line was never needed for anything we pair against.

Decided (D23)

  • A crossing buy short of the floor reverts. Deferral stays for a migrator that really fails.
  • Proved by a fuzz over gas limits: never success + crossed + not graduated.
  • Permissioned-pool graduation: out of v1, into Future updates.

Build plan

  1. Done. Curve: a failed graduation is believed only with ≥ 2M gas; below, the buy reverts. Gas sweeps (real PoolManager, a dearer mock migrator, the live singleton) all revert-or-graduate; both sweeps failed on the old code at 250k.
  2. Done. On anvil the same crossing buy now estimates 566,419 and, sent at exactly that, graduates (was 192,308 and deferred). make dev-smoke sends the crossing buy at the node's estimate from now on; its hard-coded 4M limit was what hid the bug.
  3. Nothing to build. The fix lives in the curve, so every caller inherits it. A gas sweep through the router still passed with the router capping the curve's gas to 700k — it caught nothing the curve's own sweep does not, so it was deleted.

Tried and rejected

  • Revert under a 500k floor before the try. Holds for today's migrator, but one costing more than the floor passes the check, runs out inside the try, and is deferred again.
  • Telling out-of-gas apart in the catch by gas left (< 1/63). A migrator that runs out two calls deep hands gas back as each frame unwinds; failed at 760k. Nothing in a catch can tell.
  • So the floor moved into the catch and rose to 2M, above any graduation: a crossing buy that graduates needs 660k locally and 670k on the live singleton. A hooked migrator must be added to GraduationGas.t.sol before it ships.

Not this session

Pool fees (O17), hooks, the interface, anti-snipe, security, dividends (O18).

Next

Closed. STATUS.md updated; the next thread is the developer's call.