Toxic flow mitigation

AIMM prices toxic flow rather than banning it. Each defense below is a quantity: what it bounds, what it costs, and where the shipped parameters do not yet cover the bound.


1. The framing

An external-mark AMM leaks value through three channels, each with a different clock and defense:

ChannelClockBoundDefensePriced by
Push-latency LVRbetween pushesθ (the deviation trigger)keeper cadence + minFee floorfmin,p≥2∑iθi
OEVaround the push txmempool visibility of the push txminFee, private relayfmin,p
Keeper delinquencypast the graceστstaleness surchargeUstale

Classical curve LVR (the reserve-ratio kind, where the pool’s own invariant is the stale price) does not apply: the quote center is a fresh external mark, never a reserve- or trade-derived accumulator. That does not remove all LVR.

A fourth channel is not oracle-timing at all: inventory-direction toxicity, flow that persistently moves coverage one way. It is priced by the mid skew and the coverage toll, not by the spread. See §5.

Coverage ratio definition: Inventory Management §2. Spread and fee mechanics: Spread & Fees.


2. The 2\theta fence: the one number that matters

2.1. The mechanism

The keeper pushes a new mark when either trigger fires (deviation trigger evaluated in the keeper’s push loop):

  • deviation: |ptrue-mark|/mark·104>θ bps
  • heartbeat: heartbeat_s elapsed

Between pushes the mark is frozen and the true price moves. The deviation trigger bounds that move: while the keeper is live, the gap never exceeds θ before a push fires. This is the primary LVR defense, and the only one independent of volatility and elapsed time.

2.2. The derivation

An informed trader observing ptrue has an edge of at most θ bps in whichever direction the mark is wrong. Extracting it requires a round trip: buy at the stale mark, sell back at truth. That crosses the quoted width twice and pays S in total (S/2 per swap, on the output, Spread & Fees §5.1). The pick-off is unprofitable when

S≥2θ(bps)⟺fmin≥200θ(PBPS)

The floor must satisfy it, not the runtime spread: σ, confidence and staleness all add to the quote, so a fence built on them would vanish in the calm conditions where the arb is cheapest to run.

2.3. The enforcement

The floor predicate is one comparison:

minfee_covers_theta(minfee_pbps, theta_bps) = minfee_pbps >= 200 * theta_bps

It is checked at four points, all off chain - the keeper’s startup gate, the pre-submit coupling gate, parameter generation and the deploy manifest - enumerated in Parametrization §11.2.

θ exists only in the keeper: not an on-chain parameter, not in Asset, not in OracleConfig. The chain carries maxDevBps and ttl, the acceptance band: maxDevBps bounds what a signer may push, θ bounds when the keeper chooses to push.

Every leg must clear the 2θ fence, which is what the startup gate checks; read getAsset(token).minFeePbps for a leg’s floor. A cross needs more, hence the summed path floor (§3).


3. The path floor sums over legs, it does not reduce by max

The pick-off edge on a cross is the sum of the per-leg thetas. Both marks are independently allowed to sit θ from truth, and an adversary selects the joint worst realization, so a max would fund one leg and leave the other unfunded.

edge(X→base→Y)=θX+θY⟹fmin,p≥2(θX+θY)

Under a max rule the extraction is repeatable and size-unbounded: a per-swap rate, not a one-off, with nothing in the pool capping how often it runs. It is guaranteed, and it is largest when the rest of the spread is thinnest: the surcharge terms all vanish when the keeper is healthy (Spread & Fees §8).

The shipped rule sums, and nothing caps the composed spread from above (Spread & Fees §3.1).


4. Staleness: what happens when the keeper misses

2θ funds the pool only while the keeper meets its push contract. Past the grace it has not, and the ≤θ guarantee is void; the premium then ramps with the unobserved drift στ, per leg and summed (Spread & Fees §3.4: formula, constants, worked values). The hard revert sits above it at age > ttl (FeedMathLib.gate).

Two properties:

  1. The grace is capped at 30 s regardless of ttl (PricingLib.MAX_STALE_GRACE_SECS). The push side separately refuses a source second more than 120 s old (MarkStoreP8). Without the cap a ttl = 600 feed bought a 300 s premium-free window.
  2. It is defense-in-depth, not the defense. Under a per-block keeper (block times of a few seconds or less) every τi is zero and the term never engages. It exists so a late or censored keeper degrades gracefully instead of being picked off at the frozen mark.

During a stale window the pool quotes wider and receives less flow. That is the intended trade-off; it is not a substitute for a fresh keeper.

Operational requirement: the keeper heartbeat must be strictly below ttl/2 on every feed (heartbeat_le_half_ttl, reported per feed at GET /thresholds on the keeper’s status endpoint).


5. Inventory toxicity: skew and the coverage toll

5.1. Skew is a Glosten-Milgrom soft fee

Coverage imbalance shifts the mid, not the spread. The spread is direction-invariant (Spread & Fees §4), so a coverage-worsening trade pays a worse price at the same width.

Inventory-moving (informed) flow walks up the skew and pays the displacement on top of the floor; that slippage stays in reserves. Round-trip (noise) flow restores coverage, the displacement nets to zero, and it pays only the floor. Because the mark is frozen between pushes, the quote moves only through realized inventory. The construction, its formula and the flash-loan guardrail are at Spread & Fees §7.2.

Which of the two dominates is a composition property rather than a pricing one. Inside a core of correlated legs, flow that drains one leg tends to arrive against another, so inventory mean-reverts and one-sided accumulation is the exception; an uncorrelated roster makes it the default and the skew becomes a one-way charge with no offsetting flow. It is a tendency, not a guarantee: correlated legs can move together and leave every leg in the core displaced the same way at once (Pool Composition).

Consequence: defensiveness is tuned with the shape, not with fmin. A pool can quote a tight floor for the benign majority and still charge the toxic minority, because the charge is a slope on inventory rather than a level on volume.

The levers. The skew slope is not one of them. PricingLib.computeInventorySkew is a fixed protocol law with no per-asset field behind it, and its two arms are asymmetric because the filling arm’s slope is the round-trip impact-conservation bound read from its other side; merging them into one slope reopens a ping-pong extraction. The law is held in constants, so no write can move it. Formula and derivation: Inventory Management §3.

Tunable per asset is the magnitude that fixed skew index produces: the dispersion κ (per-asset fitted floor minDispersionPbps and sensitivity vegaBps; σ scales κ 1:1 above the floor at the shipped ν=10000, capped only by the protocol-wide MAX_DISPERSION_PBPS), the curve the asset points at, and κcov for the coverage wall.

5.2. The coverage toll is a level shift, and it is asymmetric

The toll is charged once, on the terminal output asset, before the fee (PricingLib._settleQuote, _covToll), and is charge-only. Definition: Spread & Fees §6.1.

Its marginal rate at zero size is strictly positive whenever the leg is under-covered (§6.3), with κcov sized in Parametrization §6.2. That is the correct anti-drain shape: it charges the first unit that worsens an already-deficient leg, not only the block trade.

_covToll is output-only: a sell into the hub pays hub κ, and a same-pool spoke→spoke trade ends on the destination spoke, so the toll asymmetry is TY-TX. Proof: Spread & Fees §6.4.

Every listed asset, the hub included, carries 50≤κcov≤BPS (requireNeverDepletable, Invariants §I-9).


6. Mark integrity

Every defense above reads the mark. Four independent bounds sit on it:

BoundMechanismConstant
Per-push movevolatility-adaptive deviation band: maxDevBps+min(6σdt/1800/100,9·maxDevBps) bps, σ in PBPS, so any push is bounded at 10×maxDevBpsMarkStoreP8._lane
Uncertaintyrevert past a 1σ CI of 1000 bpsMAX_CONFIDENCE_HALT_BPS, PoolConstantsLib.sol
Agerevert past ttl; priced below itFeedMathLib.gate
Depegreference band (refBandBps): the asset’s primary mark must sit within refBandBps of the same lane’s reference (R) tier, checked on both endpoints and every interior node. A USD-attested mark also carries a per-asset depeg code (band = code x 250 bps) against 1.0, and the base halts past its own band (2,500 bps at code 0). An anchor-attested mark has no fixed unit to test against; that policy call is the guardian’sPoolConstantsLib.DEPEG_STEP_BPS; PoolIOLib.priceBandGuard / priceBandGuardPath

Two details that matter for toxicity:

  • The σ in the deviation band is the stored prior σ, never the incoming push’s own. Using the incoming value would let a signer inflate its own band (MarkStoreP8._lane).
  • The observation clock is the segment’s signed source second: a segment more than 120 s old or 5 s in the future reverts, and a lane moves only on an advancing source second (MarkStoreP8._segment), so a relay cannot stamp a withheld signed quote fresh and avoid the staleness surcharge.

Authority is a k-of-n signer quorum on a committed roster, not a single feed’s uptime. A mark landed this block is not age-gated: that would hand every allowlisted relayer a pool-wide outage switch (Mark Relayer §5.3).


7. JIT liquidity

Attack: add liquidity immediately before a large swap, remove immediately after, capturing fee share without carrying inventory risk.

flowCooldownSecs enforces a mandatory delay on freshly minted receipt shares, against transfer and burn alike, making the atomic version impossible. Default 15 s (DEFAULT_FLOW_COOLDOWN_SECS, PoolConstantsLib.sol), hard ceiling 300 s (MAX_FLOW_COOLDOWN_SECS, PoolConstantsLib.sol). The ceiling exists because the receipt is transferable and the raise lane is untimelocked: it bounds the worst-case unavailability one compromised admin key can impose. There is no disable: MIN_FLOW_COOLDOWN_SECS = 1 and both writers reject 0.

Detail: Flow Guards.

Second reason JIT is unattractive here: the LP fee is credited as a liability via liquidityIndexWad (PoolLiquidityLib._raiseIndex), pro rata across the whole leg. A JIT depositor’s share of one swap’s fee is its share of the leg, so capture is proportional to real capital committed, not to timing.


8. What is not defended

ResidualSizeWhy it is accepted
OEV at the pushdeterministic once the push is pendingneeds a private relay or a jump auction; neither is shipped. minFee is the only shipped lever
Push-latency LVR inside θ≤θ per event, funded by 2θthe fence makes it unprofitable, not impossible
Cross-leg basis on an anchored pairunmeasuredif a leg’s ratio is not its own push trigger, both legs can sit inside their own θ bands while the ratio drifts to the sum, and no push fires. Applies to multi-anchor paths; the mitigation is a pinned synthetic feed with its own σ and its own trigger
Interior hop clamped against a hub balance0PricingLib._legScaleOut caps against destination reserves only on the delivering leg (if (!delivering) return), so an interior hop is never clamped against a balance the swap does not spend. The decimal rescale runs per leg regardless. Listed so a regression is recognizable

Auction-shaped recapture of the push OEV is out of scope. Ordering rent accrues to whoever owns the ordering rule, not to the venue whose flow creates it, and a pool that does not control sequencing has no ordering right to sell. The lever is the adverse-selection fee already in the curve: the 2θ floor.

The reopen threshold measures LP harm, not the ability to monetize it: a sustained residual above 1% APR of pool TVL under a healthy oracle. Value leaks from LPs whether the taker is a searcher, a block assembler or a latency racer, and whether or not anyone auctions the right to be it. Most of the LVR is between-push latency loss, which no mempool policy, auction or ordering rule touches. If the threshold trips, the response is chain-specific, bounded by the ordering primitives that chain exposes and whether the venue controls sequencing at all.


9. Why not the alternatives

ApproachPortabilityCentralizationOracle dependencyPermissionless
McAMM (first-trade auction)low (needs PBS)medium (pro MEV shops)noneyes
am-AMM (Harberger manager lease)highhigh (single manager)practical (manager needs CEX)yes
UAMM / DODO / Swaap (oracle-first)highvery high (oracle control)totalyes
AIMM (external mark + adverse-selection fee)highmedium (k-of-n signer quorum)external mark, hardenedyes
  • McAMM auctions the right to trade first in each block, sending the bid to LPs. Strongly LVR-reducing, but requires PBS and builders who respect the auction, realistically Ethereum mainnet only. It also concentrates capture in builder-integrated shops, and “first trade of block” does not translate to a multi-asset pool.
  • am-AMM auctions a manager lease; the winner pays continuous rent and captures internal arb. Chain-agnostic, but a single manager controls all fees and trading revenue at any time, and a competitive manager needs off-chain CEX feeds anyway.
  • UAMM and the oracle-first family quote at oracle price and add slippage only for inventory. The strongest LVR answer if the oracle is perfect, which is the failure mode: a wrong, manipulated or lagging oracle produces unbounded LP loss, and AMM safety collapses to oracle safety.

AIMM is external-mark-primary, so it inherits the oracle-first LVR result. The difference: the fragile parts are fenced individually.

  • A volatility-adaptive per-push band bounds a compromised key.
  • A confidence halt rejects an uncertain mark.
  • A staleness surcharge degrades on keeper lag.
  • Per-asset depeg bands gate tail risk.
  • Trust rests on a k-of-n quorum with immediate revocation rather than one feed’s uptime.

Residual push-latency LVR and OEV remain (Mark Relayer).


10. Monitoring

On a stressed feed most of the quoted spread is oracle health rather than pricing (Spread & Fees §8), so the spread decomposition is the monitoring dashboard:

MetricSourceAlarm
Uconf/Sconfidence per feedrising share means the source, not the market, is degrading
Ustale/Smark age vs gracenon-zero at all means a push was missed
fmin,p vs 2∑θiper crossany negative value is a live pick-off exposure
covToll / amountOutSwapQuote.covTollrising means a leg is draining
(exec - mid)/mid vs (mid - mark)/markSwapQuote.midPrice, markPricesplits extractable value from skew premium exactly

That last row makes OEV measurable rather than inferred: the book is centered on the mid, not the mark, so the two components sum to the naive exec-vs-mark number and can be attributed separately (IPool.sol). Both are exact WAD, so the split carries no encoding error into the attribution.

Off-chain: LP-versus-arbitrageur PnL segregation, adverse-selection cost estimation, CEX-DEX price correlation.


https://ethresear.ch/t/mev-capturing-amm-mcamm/13336

https://www.gate.com/learn/articles/-introduction-to-mev-mitigation/5121

https://www.pyth.network/blog/beyond-the-dark-forest-experiments-in-mitigating-mev

https://arxiv.org/html/2403.03367v1

https://fc25.ifca.ai/preproceedings/183.pdf

https://arxiv.org/abs/2403.03367

https://fenbushi.vc/2024/01/20/ending-lps-losing-game-exploring-the-loss-versus-rebalancing-lvr-problem-and-its-solutions/

https://arxiv.org/html/2308.06375v2

https://arxiv.org/abs/2308.06375