Toxic flow mitigation

AIMM prices toxicity rather than banning it. Each defense below is stated as 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 exactly three channels, each with a different clock and defense:

ChannelClockBoundDefensePriced by
Push-latency LVRbetween pushesθ (the deviation trigger)keeper cadence + minFee floorfmin,p2iθi
OEVaround the push txmempool visibility of batchPushSignedminFee, 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 wanders. The deviation trigger bounds that wander: 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 sees 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

S2θ(bps)fmin200θ(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 evaporate in exactly 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 three points, all off chain - the keeper’s startup gate, the pre-submit coupling gate and parameter generation - enumerated in Parametrization §11.2.

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

2.4. Live values

The θ requirement, on the pre-Arc reference roster (per-parameter tables in Parametrization):

Classθ (bps)2θ (PBPS)heartbeat
Stables (per-leg range)0.25 - 0.8750 - 1731800 s
Majors and EURC (WETH, WBTC, cbBTC, BNB, XAUT, PAXG, EURC)5.01000300 s
FX (QCAD, AUDF, BRLA, JPYC, KRW1)5.01000240 - 300 s

The shipped minFeePbps column is deliberately not reproduced here: the floors are mid-change, a tighter σ-derived floor is being applied leg by leg and is only partly on chain, so a number quoted on this page would be stale within the week (Parametrization §11.3). Read getAsset(token).minFeePbps. Every live leg clears the 2θ fence above either way; that is what the startup gate checks. 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(XbaseY)=θX+θYfmin,p2(θX+θY)

Over the reference roster’s stable crosses a max rule under-fences most pairs; the shipped sum rule under-fences none. The measurement, the worst pair and the per-row arithmetic are at Spread & Fees §9.

What matters here is the shape of the residual. 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 small against a live quote, but it is guaranteed, and it bites hardest exactly when the rest of the spread is at its thinnest: the surcharge terms that make up three quarters of a live stable quote all vanish when the keeper is healthy (Spread & Fees §8).

The shipped rule sums, and the three aggregation rules are one mechanism rather than three choices. Nothing caps the composed spread from above, so the summed floor cannot be clamped away on the tape where it is needed; trader protection is minAmountOut (Spread & Fees §3.1).


4. Staleness: what happens when the keeper misses

2θ funds the pool only while the keeper honors its contract. Past the grace it has not, and the θ guarantee is void; the premium then ramps with the unobserved drift:

Ustale=izσiτiBPSPBPS,z=100,τi=max(0,ai-min(Ti2,30))

with ai the leg’s feed age in seconds and Ti its ttl.

Pricing._staleTerm, _staleExcessOf, summed per leg in _walkLegs. Per leg, not one coupled term at (maxiτi,σp): one keeper feeds several spokes, so an outage staleses them together and the coupled form charged two equally stale legs 2/2=70.7% of what they each owe. Worked: σ=1%, 100 s past grace 10 bp; 1800 s past grace 42 bp. The hard revert sits above it at age > ttl (FeedMathLib.gate).

Three properties, in order of importance:

  1. Zero inside the grace. A flat tape produces no pushes and owes none; penalizing an old-but-accurate mark quotes the pool out of the market for nothing. _staleTerm short-circuits before the sqrt when τi=0, so a fresh leg beside a stale one pays nothing.
  2. The grace is capped at 30 s regardless of ttl (Pricing.STALE_GRACE_CAP_SECS). It was sized to V1’s per-instance maxRelayLagSecs, which the live V4 does not have — V4’s only past bound is the constant MAX_RECON_AGE = 6 h — so the cap now stands on its own and nothing on chain couples the two. Without it a ttl = 600 feed bought a 300 s premium-free window.
  3. It is defense-in-depth, not the defense. Under a per-block keeper (Base ~2 s, BNB ~1 s) 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.

The trade: during a stale window the pool quotes wider and wins less flow. That is correct (better to sit out than be picked off), and 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 by construction (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 returns coverage where it found it, 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 degrades into a toll nobody ever pays back. 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, exactly. The skew slope is not one of them. Pricing.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; “tidying” them into one slope reopens a ping-pong extraction. Holding the law in constants is what makes it safe: no write can move it. Formula and derivation: Inventory Management §3.

Tunable per asset is the magnitude that fixed skew index buys: 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 preset the asset points at, and κcov for the coverage wall.

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

T(y)=κcovBPS[Q(min(c0,1))-Q(min(c1,1))]L,Q(c)=lnc-c+1

charged once, on the terminal output asset, before the fee (Pricing._settleQuote, _covToll). Charge-only: ΔQ00, never rebated.

Its marginal rate at zero size is

κcovBPS(1c-1)forc<1,0exactlyforc1

Measured on a pre-Arc reference roster with RLUSD at c=0.9575 and κcov=100 bps: 4.44 bp, and dust pays the same 4.44 bp. The live stable κcov is 600, so the same coverage is 26.6 bp today (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 κ when κ>0. Same-pool spoke→spoke terminals the destination spoke, so the toll asymmetry is still TY-TX. Old P3 “base κ=0 ⇒ sell-into-base is free” is void. Proof: Spread & Fees §6.4.

Operator rule: every listed asset including the hub must have κ>0 (Invariants §I-9); live per-leg values belong to 2. Deployments.


6. Mark integrity

The mark is the single input everything above trusts. Four independent bounds sit on it:

BoundMechanismConstant
Per-push movevolatility-adaptive deviation band: maxDeviation+6σdt/1800, the σ term capped at 9×maxDeviation (so any push is bounded at 10×maxDeviation)ExternalOracle.sol
Uncertaintyrevert past a 1σ CI of 1000 bpsMAX_CONFIDENCE_HALT_BPS, PoolConstantsLib.sol
Agerevert past ttl; priced below itFeedMathLib.gate
Depegfeed-relative band only (refFeedId/refBandBps): the asset’s mark must sit within refBandBps of an independent reference feed’s price for the same pair, checked on both endpoints and every interior node. The base additionally halts past 500 bps from parity. An absolute per-asset price band would need a unit to be denominated in, which multi-anchor does not supply; that policy call is the guardian’sBASE_DEPEG_HALT_BPS, PoolConstantsLib.sol; 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 (ExternalOracle.sol).
  • The observation clock is min(sourceTs/1000,updatedAt) (FeedMathLib.observedAt), so a relay cannot stamp a withheld signed quote fresh and buy back the staleness surcharge.

Authority is a k-of-n signer quorum with immediate revokeSigner, not a single feed’s uptime. A mark landed this block is deliberately not age-gated: withholding it would hand any address a pool-wide outage switch, since batchPushSigned takes authority from signatures rather than msg.sender.


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 between deposit-withdraw and stake-unstake on the same account, making the atomic version impossible. Default 15 s (DEFAULT_FLOW_COOLDOWN, PoolConstantsLib.sol), hard ceiling 300 s (MAX_FLOW_COOLDOWN, PoolConstantsLib.sol). The ceiling exists because the receipt is transferable and the setter is untimelocked: it bounds the worst-case unavailability one compromised admin key can impose. 0 remains permitted as an explicit disable.

Detail: Flow Guards, Layer 2.

Second reason JIT is unattractive here: the LP fee is credited as a liability via liquidityIndexWad (PoolLiquidity.accrueLpFee), 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θby design: the fence makes it unprofitable, it does not make it 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 once multi-anchor ships; the mitigation is a pinned synthetic feed with its own σ and its own trigger
Interior hop clamped against a hub balance0Pricing._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, by decision. Residual OEV measures $0.05 to $0.46 per push, about $80/day gross on a $10M pool at ~1,400 pushes/day, below the level at which an auction clears: Arbitrum Timeboost decayed to $5.65/round over 494,608 rounds, with 3 entities taking 99.74% of them. Ordering rent accrues to whoever owns the ordering rule, not to the venue whose flow creates it: Timeboost paid $2.44M to the DAO and $69,806 to searchers, nothing to the applications involved. A pool that does not control sequencing has no ordering right to sell. The lever that measurably works is the adverse-selection fee already in the curve: on BTC at θ=2 bp, moving the fee floor from 10 bp to 40 bp takes LVR from 10.15% to 1.14% APR with organic fill rising.

The reopen threshold is chain-neutral, measuring LP harm rather than BTR’s ability to monetize it: a sustained residual above $5/push (~100x the measured residual above) or 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. The push-concentrated share is 1.1% to 28% of LVR depending on θ; the remaining 72% to 99% is between-push latency loss, which no mempool policy, auction or ordering rule touches.

Arc disposition. If the threshold trips on Arc, the response is not a capture mechanism. Block production is a permissioned validator set with Circle-gated membership and a single block assembler, the intra-block ordering rule is undocumented, maxPriorityFeePerGas = 0 is the documented recommendation so no priority-fee auction runs, no third-party ordering privilege exists, and the only announced MEV path routes proceeds to validator and staker rewards and to burn rather than to applications. That is a statement about BTR’s rights, not a claim that Arc has no MEV: an opaque assembler holds an unpriced ordering option and latency races persist. BTR has no ordering right to sell. Permitted responses on Arc: lower CADENCE_CAP_PER_H / MIN_BATCH_PUSH_GAP_S (keeper push-cadence config), raise the fee floor or the staleness premium, or escalate to Circle. Revisit only if Arc ships an application-addressable ordering primitive.


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. Clean and 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 cleanly to a multi-asset pool.
  • am-AMM auctions a manager lease; the winner pays continuous rent and captures internal arb. Economically elegant and 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 precisely 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 (Oracles §8.4).


10. Monitoring

Three quarters of a live stable quote 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