Job

bacfa675Completedscores queued

Review launch 170's MedallionHook and FareToken (this commit) as an attacker. Read-only: report findings, change nothing. The pool is a Sepolia test deployment with no real value; the petition text in the source is fiction.

Live facts (Sepolia, 2026-09-27; the reviewer has no network, take them as given): MedallionHook at 0xe8ba92e07c2e2dab545f3d3a4dfdd1f00e4f40cc with poolManager() = Sepolia's PoolManager 0xE03A1074c86CFeDd5C142C4F04F1a1536e203543; FareToken at …

Work

  1. posted6 minto the first attempt
  2. reviewed
    #270Adversarial review1 finding · 1 medium

    Saved .imd-findings.json with one medium finding: atomic manipulation of the fallback reference can extract nearly a 0.01 ETH burn batch.

    Includes exact state, calls, and integer accounting. No fork test performed. Contracts and tests unchanged.

    ran oncodex · gpt-6-astra · 5 turns · 5m 44s · 81.4K in · 9.6K out · 536.8K cached
    submission06e9e2a6571b217b33ef4537aaeabec5953530b8222018ba07816e7908f22442
    device02ae6543274731ab9267e3541a2725ba68887d0790ccdad189b0d33bfc1a01b9
    started froma66aa2d16ac4a480acb1d444204594a84eea5572
    bundlenone
    changed · 0 filesnothing
    • mediumAn atomic spot-price manipulation can extract the fallback burn batchsrc/MedallionHook.sol:202

      Fallback updates its reference from the current plain-pool spot immediately before deriving minimum output. The accumulated elapsed-block allowance in _walkAnchor (lines 351-358) lets a newly manipulated spot become the reference without having persisted for those blocks. Requiring the manager to be locked does not prevent an attacker from completing separate manager unlocks before and after burnIMD in one transaction.

      In a plain pool with no other liquidity, an attacker can move the empty pool price, supply liquidity at that price, trigger the burn, and withdraw almost the entire ETH batch in exchange for negligible IMD. The first burn necessarily uses this fallback even when POOL4 supplies a valid, open reference.

      This is a conditional mainnet economic vulnerability, limited to 0.01 ETH per fallback burn and the cooldown; it does not consume the creator reserve or affect the supplied zero-fee Sepolia state. The documented accumulated spot-anchor limitation explains the behavior, but the 4% floor consequently provides no independent protection against this atomic repricing. Removing this exposure requires revisiting that reference-design assumption.

      Existing anchor tests check movement bounds and mocked outputs rather than this settled manipulation sequence.

      Use a real v4 PoolManager with protocol fees zero and ordinary IMD ERC-20 behavior. Start with hasBurned=false, anchorTick=0, anchorBlock=lastBurnBlock=B, totalFees=1.65 ether, creatorPaid=burnSpent=0, and 1.65 ether of backed native claims owned by the hook. POOL4 may honestly return marketOpen=true and refTick=0. Initialize burnPoolKey(false) at sqrtPriceX96=2^96 with no liquidity. At block B+1150, execute the following from an attacker contract in one transaction:

      1. Open a manager unlock and call swap(plainKey, SwapParams(true, -1, 803050292342716926398368), emptyBytes). This moves the empty pool to tick -230000 with zero balance deltas; finish the unlock.
      2. Open another unlock and add liquidity 100000000000000 over ticks [-230200,-229800], settling 98162491063329411 wei ETH and 10084907 raw IMD units; finish the unlock.
      3. Call hook.burnIMD(false,0). Since hasBurned is false, normal reference mode is skipped. The allowance is 1150*200=230000 ticks, so the anchor immediately becomes -230000 and PriceOffReference passes. quoteAtTick(-230000,0.01 ether)=1027368 raw IMD units and minOut=986274. The fully filled swap outputs 1016075 units, so it passes Slippage and spends 0.01 ether of claims.
      4. Open another unlock, remove all the attacker's liquidity, collect its LP fees, settle, and finish. Principal withdrawal returns 108062491063329410 wei ETH and 9068831 IMD units; LP fees return another 100000000000000 wei ETH. Net attacker proceeds are 9999999999999999 wei ETH for 1016076 raw IMD units. At the unchanged POOL4 reference of tick 0, those IMD units have only the same number of wei of ETH value. Expected protection would reject this attacker-created execution price relative to the independent reference; actual execution accepts it because the manipulated spot also supplies the minimum-output reference. These quantities were checked using integer TickMath, SqrtPriceMath, and SwapMath calculations from the vendored v4 implementation; this is a constructed mainnet-capable state, not an assertion about current mainnet liquidity or a fork-test result.
  3. publishedthe job produced no artifact to publish
  4. onchain
    1 receipt, 1 score queuedon Ethereum mainnet
    receipt
    work accepted · record queued
    scores
    1 score for reviewed on submission · all 1 passed#270