---
title: "Slippage & Price Impact"
description: "Exact decomposition of oracle mark to taker-received, the deterministic impact term, and the protections against the stochastic remainder"
audience: tech
type: explanation
status: live
lang: en
updated: "2026-09-04"
publish: true
---
# Slippage and price impact

The price a taker receives differs from the oracle mark by four separate quantities, and only one of them is what most traders mean by price impact. This page factors that difference term by term, separates the terms a quote already knows from the stochastic remainder, and gives the bounds a caller can set against that remainder.

---

## 1. The decomposition

Every AIMM quote is a product of four factors applied to the oracle mark, for a single leg with $q$
the trade size:

$$\frac{\text{exec}}{\text{mark}} = \underbrace{P_{\text{skew}}}_{\text{inventory level}} \cdot \underbrace{\Gamma(q)}_{\text{curve traversal}} \cdot \underbrace{(1 - t(q))}_{\text{coverage toll}} \cdot \underbrace{\left(1 - \tfrac{s}{2}\right)}_{\text{half path spread}}$$

| Term | Definition | Depends on size | Owned by |
|------|------------|-----------------|----------|
| $P_{\text{skew}} = r/m$, mid over mark | Inventory skew offset, evaluated at zero volume | No | [Inventory Management §3](/docs/1-1-1-inventory-management#3-inventory-skew-coverage--skew), [Liquidity Shaping §5](/docs/1-1-2-liquidity-shaping#5-inventory-skew-mapping-skew---depth) |
| $\Gamma(q) = \bar{p}/\text{mid}$ | Curve traversal, the VWAP over the interval the trade sweeps | Yes | [Liquidity Shaping §8](/docs/1-1-2-liquidity-shaping#8-traversal) |
| $t(q) = \text{covToll}/\text{gross}$ | Convex coverage toll on the drained output leg | Yes | [Inventory Management §6](/docs/1-1-1-inventory-management#6-convex-coverage-wall) |
| $s$ = `SwapQuote.spreadPbps` | Path spread; the realized fee is $s/2$ of the pre-fee output | No | [Spread & Fees](/docs/1-1-4-spread-fees) |

**Price impact** in the AIMM sense is $\Gamma(q)$ alone, together with $t(q)$ when the output leg is
under-covered. Everything else is a level or a fee and is present at zero size.

The pool publishes both the mark and the mid (`SwapQuote.markPrice`, `midPrice`, both exact WAD
(1e18), `tokenOut` per `tokenIn`, chained across every leg). Deliberate: it lets an indexer split
$(\text{exec} - \text{mid})$, the genuinely extractable value, from $(\text{mid} - \text{mark})$,
the inventory skew, instead of conflating them into one execution-versus-oracle number. See
`IPool.sol`.

### 1.1. What each term is, and what it is not

Canonical vocabulary. Each word names exactly one object; none is a synonym for another.

| Term | Is | Kind | Symmetric in direction? | Site |
|---|---|---|---|---|
| **mark** | the oracle price, as attested by the keeper in the child's anchor unit | level | yes | `FeedMathLib.mark`, consumed at `Pricing.sol` |
| **skew** | the signed dimensionless inventory **index**, `int8` in $[-100, +100]$, a function of coverage alone. An input, never a price | index | n/a | `computeInventorySkew`, `Pricing.sol` |
| **skew offset** | the price displacement that index produces, $(\text{mid} - \text{mark})/\text{mark}$ in bps | **level** | yes: one number, both directions quote off it, and it cancels on a round trip | `_legMid`, `Pricing.sol`; surfaced at `IPool.sol` and by `@btr-protocol/sdk` |
| **mid** | the mark carrying that offset, evaluated at **zero** volume | level | yes | `_legMid`, `Pricing.sol` |
| **price impact** (= curve traversal) | the cost of traversing the liquidity shape from the skew anchor, $\Gamma(q)$ | one-directional cost | **no**, see §1.2 | `_traverseCurve`, `Pricing.sol` |
| **spread** | the round-trip fee **width**, `SwapQuote.spreadPbps`, symmetric about the mid | width | yes, by construction ([Spread & Fees §4](/docs/1-1-4-spread-fees#4-theorem-1-the-spread-is-direction-invariant)) | `_pathSpread`, `Pricing.sol` |
| **fee** | what a swap actually pays: **half** the spread, once, on the output | charge | yes | `Pricing.sol` |
| **coverage toll** | the convex charge on a drained output leg | one-directional, charge-only | **no** | `_covToll`, `Pricing.sol` |
| **slippage** | the *stochastic* gap between the quote and the fill (§3), not a pool term at all | risk | n/a | `minAmountOut`, §4.1 |

Four usages to reject on sight:

- **"spread" for total cost.** The spread is one of four terms and is usually not the largest. Total
  cost is the whole product above.
- **"fee" for the spread.** `minFeePbps` is a floor on the **spread**, not on the fee; the fee is half
  the spread. Nothing caps the spread from above
  ([Spread & Fees §3.1](/docs/1-1-4-spread-fees#31-definition)).
- **"premium", for anything.** The word carries three objects at once: the mid displacement, a generic
  price-versus-mark ratio, and a component of the spread - the level-versus-width collision this table
  exists to stop. The mid displacement is the **skew offset** (a level); the spread's parts are
  **bands** and **surcharges** (widths). "Premium" and "discount" are admissible only as informal words
  for the *sign* of a skew offset, never as a quantity and never as a parameter.
- **"skew" for a price.** `skew` is the dimensionless index; the price effect is the skew offset.
  One map, two objects, two names.

> Naming, settled: the Avellaneda-Stoikov **reservation price** is this codebase's **mid**, and "mid"
> is the only name used for it. AIMM carries no absolute price band on an asset;
> the depeg gate is the feed-relative `refFeedId` / `refBandBps` pair plus the base parity halt
> ([Anchor Path Pricing §7.1](/docs/1-1-3-anchor-path-pricing#71-what-reffeedid-is-and-what-it-is-not)).

### 1.2. Total cost is direction-asymmetric; the width and the level are not

The spread is direction-invariant: both sides quote the same width about the same mid
([Spread & Fees §4](/docs/1-1-4-spread-fees#4-theorem-1-the-spread-is-direction-invariant)).
The skew offset is a level: the same number for both directions, and it cancels on a round trip.
**Price impact is neither**, so total cost is not.

Measured on an exact integer port of `Pricing.sol` + `NUQuartic.sol`, bit-verified against `forge`
on shipped preset 5. WETH: `dispRefPbps` 500, $\sigma = 0$ so dispersion is the
`minDispersionPbps` of 2034 PBPS — still WETH's live floor — spread 1032 PBPS (half-spread 5.16 bps),
mark 1. The leg's `minFeePbps` has since been raised, so the absolute spread column reads low against
the chain today; the impact and skew columns, which is what the table is for, do not depend on it. Notional is a fixed
percentage of **liabilities**, held constant across coverage states, so the rows are comparable.
`slip` is $|\overline{p} - \text{mid}|$ in bps. The skew column is the shipped fixed law,
$+200(1-c)$ draining and $-100(c-1)$ filling, saturating at $c \le 0.5$ and $c \ge 2$; $50\%$ and
$200\%$ are where the law clamps, not a configurable band, and no per-asset dial enters these rows.

> Measurement note: the $c = 1.15$ row reads $-14$ / $x_0 = 4300$ from the fixture. The shipped law
> gives exactly $-15$ and $x_0 = 4250$ at $c = 1.15$. One skew unit of fixture drift, worth 50 bps of
> the spline domain; the slippage figures either side of it are unaffected at this resolution.

| $c$ | skew | $x_0$ | skew offset | notional | slip sell | slip buy | gap (buy $-$ sell) |
|---:|---:|---:|---:|---:|---:|---:|---:|
| 0.70 | $+60$ | 8000 | $+10.880$ bps | 1% | 0.290 | 0.280 | $-0.010$ |
| 0.70 | | | | 10% | 2.770 | 3.050 | $+0.280$ |
| 0.70 | | | | 25% | 6.600 | 4.420 | $-2.180$ **(buy clipped)** |
| 0.85 | $+30$ | 6500 | $+5.200$ bps | 1% | 0.210 | 0.210 | $0.000$ |
| 0.85 | | | | 10% | 2.070 | 2.160 | $+0.090$ |
| 0.85 | | | | 25% | 5.100 | 5.710 | $+0.610$ |
| 1.00 | $0$ | 5000 | $0.000$ | 1% | 0.170 | 0.170 | **$0.000$** |
| 1.00 | | | | 10% | 1.710 | 1.710 | **$0.000$** |
| 1.00 | | | | 25% | 4.360 | 4.360 | **$0.000$** |
| 1.15 | $-14$ | 4300 | $-2.390$ bps | 25% | 3.890 | 3.720 | $-0.170$ |
| 1.30 | $-30$ | 3500 | $-5.200$ bps | 25% | 3.610 | 3.350 | $-0.260$ |

- **At $c = 1$ the gap is exactly zero at every size.** The shipped `wQ` vectors are perfectly
  antisymmetric about $x = 5000$, so their density median is $x^* = 5000$, the traverse starts there
  at $\psi = 0$, and a symmetric inventory state gives symmetric slippage by construction. The
  asymmetry is a property of being off par, not of the machine. On an asymmetric preset $x^*$ moves
  and the zero-gap point moves with it, since the anchor is the median and not the domain midpoint
  ([Liquidity Shaping §5.1](/docs/1-1-2-liquidity-shaping#51-the-center)).
- **Off-center and unclipped, it is real and correctly signed.** At $c = 0.85$ and 25% of
  liabilities, the direction that *worsens* inventory pays 5.710 bps against 5.100 bps for the
  direction that *heals* it. The 0.610 bps gap is about 12% of the 5.16 bps half-spread.
- **Above parity the sign flips**, as it must: at $c = 1.15$ and $1.30$ the buy side is now the
  healing direction and pays less.
- **The $-2.180$ row is not a discount**, it is the buy-side traverse hitting the domain clip at
  $x = \text{BPS}$. Past that point marginal impact is zero. See §2.5.
- **The level dominates.** At $c = 0.70$ and 1% of liabilities the skew offset is 10.880 bps against
  0.29 bps of traverse, so the mid, not the curve, is what moves the executed price off the mark.
- **A round trip costs the same whichever way you start**: 10.663, 10.700 and 10.669 bps across the
  inventory states above. That is the proof that the skew offset is a level that cancels, and that
  what remains is the spread plus two traverse terms.

**The mechanism, stated correctly.** The intuitive version ("the depleted side traverses further") is
wrong for a single leg, because depth is per-**asset**, not per-side: `profileAsset = isUpward ? from
: to` (`Pricing.sol`), so both directions of one edge use the same child, the same curve and the
same depth. Single-leg asymmetry comes from three things instead:

1. the **off-center start** $x_0 = \mathrm{clamp}(x^* + 50\psi,\ 0,\ \text{BPS})$, where
   $x^*$ is the curve's density median from the header and equals 5000 on every shipped preset
   (`_skewToDepth`, `Pricing.sol`);
2. the **convexity** of the shape either side of that start, since a sell integrates
   $[x_0 - v, x_0]$ and a buy integrates $[x_0, x_0 + v]$ over a curve that is not locally linear;
3. **domain clipping** at $x = 0$ and $x = \text{BPS}$ (`Pricing.sol`).

The "depleted side traverses further" intuition *does* hold one level up, on a two-leg spoke-to-spoke
path, where the two directions traverse **different assets'** curves at different depths.

So a round trip is not two halves of one number: it pays the full spread $S$ once
([Spread & Fees §5.5](/docs/1-1-4-spread-fees#55-there-is-exactly-one-charge)) plus two
traverse terms that differ off par, plus the toll on whichever direction drains a walled leg.

### 1.3. Worked, verified on chain

A shipped stable pool (addresses: [2. Deployments](/docs/2-1-contract-addresses)), USDT to USDC, one leg. Read from
`Pool.getSwapQuote` at capture time. `spreadPbps = 177`, `covToll = 0` on all three, because the USDC
output leg read $\kappa_{\text{cov}} = 0$ at that block. That is not the shipped state: every Arc leg
carries $\kappa_{\text{cov}} > 0$ (600 stables / 1,500 FX / 1,800 metals / 2,000 crypto / 2,500
equities, hub at the maximum of its own spokes), so the toll column of a quote taken today is
non-zero the moment the output leg sits below parity — [Parametrization §6.2](/docs/1-1-7-parametrization#62-coverage-wall).

> **Historical capture, before the 2026-08-21 adaptive-dispersion change.** $P_{\text{skew}}$ of
> $-54.00$ pbps is the old $\kappa = 161$ / $x_0 = 3050$ state. At HEAD the same live inputs give
> $\kappa = 237$, $x_0 = 4050$ and a mid offset near $-38$ pbps
> ([Liquidity Shaping §8.6](/docs/1-1-2-liquidity-shaping#86-worked-example-verified-on-chain)). The
> rows are kept because they are the measured verification of the decomposition, not today's quote.

| `amountIn` (USDT) | $P_{\text{skew}} - 1$ | $\Gamma - 1$ | $t$ | $-s/2$ | Total exec/mark $- 1$ |
|-------------------|-----------------------|--------------|-----|--------|------------------------|
| 1 | $-54.00$ pbps | $0.0$ pbps | 0 | $-88.5$ pbps | $-142.50$ pbps |
| 1,000 | $-54.00$ pbps | $-2.0$ pbps | 0 | $-88.5$ pbps | $-144.50$ pbps |
| 10,000 | $-54.00$ pbps | $-25.0$ pbps | 0 | $-88.5$ pbps | $-167.49$ pbps |

Read off: the fee is 62% of the total cost at 1 USDT and 53% at 10,000 USDT. The skew offset is 38%
and 32%. The curve, the term most people mean by "price impact", is **0% to 15%**: on a tight stable
leg it is the smallest of the four terms.

---

## 2. Price impact: deterministic

Impact is knowable before execution: a pure function of on-chain state the quote already reads.

### 2.1. AIMM

$$\Gamma(q) = \frac{\text{PBPS} + \bar{y}}{\text{PBPS} + y(x_0)},
\qquad
\bar{y} = \frac{1}{x_1 - x_0}\int_{x_0}^{x_1} y_{\text{scaled}}(x)\,dx$$

with $x_0 = \mathrm{clamp}(x^* + 50\psi,\ 0,\ \text{BPS})$ ($x^* = 5000$ on every shipped preset),
$x_1 = x_0 \mp v_f$, and
$v_f = \min(\text{BPS},\ \lfloor q \cdot \text{BPS}/D \rfloor)$, all as defined in
[Liquidity Shaping §8](/docs/1-1-2-liquidity-shaping#8-traversal).

**$D$ is the leg's raw reserves.** `uint256 depth = reserves == 0 ? 1 : uint256(reserves)` in
`Pricing.quoteSwap` and `_priceEdgeHop`: the zero-guard exists only because the traverse divides by
it. There is no coverage-dependent adjustment on top, and no "effective" or "virtual" depth
anywhere in the decomposition. Impact therefore scales with $1/R$ and nothing else: at a given size, a
thinner leg is a deeper traverse, with no state-dependent discount in either direction. A denominator
that grew as coverage fell would shorten the traverse on exactly the leg an informed flow is
draining, which is how a two-block round trip becomes trader-positive: an LP leak, not a depth
benefit.

Three structural consequences:

- **Impact is bounded.** The whole book spans $\pm H\kappa/\text{dispRef}$, with $H$ the preset's
  half-swing at its reference dispersion. No trade of any size can move the price beyond that edge,
  because $x$ clamps at the domain edge and $v_f$ clamps at BPS.
- **Impact is zero below the quantum.** $v_f$ is an integer count of bps, so any trade smaller than
  $D/\text{BPS}$ executes exactly at the mid. Live USDT: 6.0036 USDT.
- **Impact is asymmetric.** $x_0 \ne x^*$ on every live leg, so the sell side and the buy side of the
  same leg have different remaining room. See
  [Liquidity Shaping §5.2](/docs/1-1-2-liquidity-shaping#52-the-book-is-asymmetric-before-anything-else-acts).

### 2.2. Against a constant-product pool

For $x\cdot y = k$, executing $q$ against reserve $R$ gives $\text{exec}/\text{spot} = 1/(1 + q/R)$, so
impact is $q/(R+q)$ and grows without bound. AIMM's impact is a traversal of a bounded offset curve.
Measured on the USDT leg at preset 2, selling. These rows are a **pre-adaptive-dispersion capture**
($\kappa = 161$ pbps, $x_0 = 3050$): the band sat at the bare floor and the skew read the old
symmetric slope. Under the current law the same live inputs give $\kappa = 237$ and $x_0 = 4050$
(§2.6, and [Liquidity Shaping §8.6](/docs/1-1-2-liquidity-shaping#86-worked-example-verified-on-chain)).
The ratio the table is making, bounded traversal against unbounded curvature, is unchanged by that:

| Size as % of depth | $v_f$ (bps) | AIMM $\Gamma - 1$ | Constant-product impact |
|--------------------|-------------|--------------------|--------------------------|
| 0.1% | 10 | $-0.15$ pbps | $-10.0$ bp |
| 0.5% | 50 | $-0.73$ pbps | $-49.8$ bp |
| 1% | 100 | $-1.46$ pbps | $-99.0$ bp |
| 5% | 500 | $-7.39$ pbps | $-476.2$ bp |
| 10% | 1000 | $-14.99$ pbps | $-909.1$ bp |
| 20% | 2000 | $-30.98$ pbps | $-1666.7$ bp |

At 10% of depth AIMM charges 0.15 bp of curve impact where a constant-product pool charges 909 bp, a
factor of about 6,000. That is not a free lunch: USDT's half-swing at this capture is 1.61 bp, so the
whole book spans 3.22 bp end to end and it **cannot** charge more. The defense against adverse
selection sits in the spread, the coverage toll and the oracle push policy rather than in curvature.
A constant-product pool prices size; AIMM prices information, and lets size run cheap until the
reserve itself binds.

### 2.3. When the reserve binds

Beyond the curve, two hard limits apply and neither is a smooth impact term:

- `Pricing._legScaleOut` (`Pricing.sol`) clamps a leg's output to the destination asset's
  reserves and sets a `clamped` flag. When it fires, `SwapQuote.amountOut` reports the clamped number
  and the per-hop execution price is suppressed. This is visible live: a 100,000 USDT quote returns
  `hopAmounts` equal exactly to the USDC reserve balance (66,369.84), so the quoted rate silently
  degrades to a partial fill at full price rather than reverting. **Read `hopAmounts` against reserves
  before trusting a large quote.**
- `PoolIOLib.settle` (`PoolIOLib.sol`) reverts `InsufficientAmount` when
  $R_{\mathrm{liq}} = R - \text{invested}$ cannot cover `amountOut + protoFee + minLiquidity`. This is the
  failure that governs at settlement.

### 2.4. The coverage toll

When the output leg is coverage-walled ($\kappa_{\text{cov}} > 0$; on the [reference roster](/docs/2-overview) that is every spoke) a
drain below parity pays

$$t \cdot \text{gross} = \min\!\left(\text{gross},\ \frac{(Q(c_0) - Q(c_1))\,\kappa_{\text{cov}}\,L}{\text{BPS}\cdot\text{WAD}}\right), \qquad Q(c) = \ln c - c + 1$$

evaluated at $c$ clamped to $\le 1$. It is convex and it diverges as $c_1 \to 0$, so the marginal cost
of the last of a reserve is unbounded even though the curve impact is bounded. This, not the spline, is
what stops a drain. Full statement:
[Inventory Management §6](/docs/1-1-1-inventory-management#6-convex-coverage-wall).

### 2.5. The buy-side traverse saturates, and depth cannot stop a drain

A consequence of the bounded book, not a defect, and not to be fixed inside the traverse.

`Pricing._traverseCurve` clamps the volume fraction at `BPS` and the buy-side end depth at `BPS`.
Once $x_1$ reaches `BPS` the averaged offset over $[x_0, \text{BPS}]$ stops changing with size, so
**marginal price impact past that clip is exactly zero**, and the saturated value *falls* as the pool
depletes, because a higher $x_0$ leaves a shorter interval to average over. The clip is on the spline
domain, not on liquidity, so the clip percentages below are percentages of **raw reserves** (§2.1),
the only depth quantity there is.

| Coverage | Clips at (% of reserves) | Saturated slippage |
|---:|---:|---:|
| $c = 1.00$ | 50% | 9.29 bps |
| $c = 0.85$ | 35% | 6.96 bps |
| $c = 0.70$ | 20% | 4.42 bps |

Draining the **entire** WETH reserve costs about 14.45 bps at $c = 1.0$ and 20.46 bps at $c = 0.7$ in
**traverse plus half-spread**, and those two terms alone can never exceed $+\,20.46$ bps at any size.
That is a bound on the bounded terms, not on the price. The coverage toll sits on top of it and is
unbounded: `Pricing._covToll` charges $\Delta Q \cdot \kappa_{\text{cov}} \cdot L / (\text{BPS} \cdot
\text{WAD})$ on the drained output leg once $c_1 < 1$, and $Q(c) = \ln c - c + 1 \to -\infty$ as
$c \to 0$, so at the shipped $\kappa_{\text{cov}} = 300$ the marginal cost of the last of the reserve
diverges (§2.4). A drain that stays above parity pays the 20.46 bps ceiling; one that crosses the peg
does not. Same numbers as the $-2.180$ row in §1.2, which is that clip and not a discount.

**The ceiling is correct for an oracle AMM.** A pool that quotes the external mark must not
price-discover; if size could move its quote without bound, the quote would stop being the mark. The
consequence:

> **Depth cannot stop a drain.** The curve is a bounded offset book, so no amount of size exhausts it.
> The only two mechanisms that stop one are the convex coverage toll (§2.4) and the hard reserve floor
> `minLiquidity` (§2.3), which `initAsset` writes as 0 and no deploy script raises
> (`PoolConfig.sol`).

A leg left with the wall off is a config defect, not a design choice:

- any leg carrying `kappaCovBps = 0` has only `minLiquidity` and the reserve clip as its whole outflow defense. Operator rule: every listed asset including the hub must have κ>0 ([Invariants §I-9](/docs/1-1-8-invariants#i-9-coverage-toll-is-charge-only-and-terminal-only)).
- Where the wall is on it dominates everything else by orders of magnitude: USDT at $c = 0.80$ charged
  **43.84 bps** of toll against a 0.61 bps spread on a pre-Arc reference-roster capture at
  $\kappa_{\text{cov}} = 100$. The toll is linear in $\kappa_{\text{cov}}$, so at the live stable
  value of 600 the same drain costs **263 bps**, and 1,053 bps on an equity leg at 2,500.

The saturation offers no atomic profit: what bounds a drain is the coverage toll of §2.4 and the
reserve clamp of §2.3, plus `minLiquidity` wherever a deploy config raises it above the `initAsset`
zero.

### 2.6. Dispersion

Dispersion $\kappa$ sets the vertical scale of the curve and therefore the magnitude of $\Gamma$:

$\kappa = \min\!\left(\texttt{MAX\_DISPERSION\_PBPS},\ \kappa_{\min} + \left\lfloor \frac{\sigma\nu}{\text{BPS}} \right\rfloor\right)$

`Pricing._calculateDispersion` (`Pricing.sol`; adaptive dispersion since the 2026-08-21 adaptive-dispersion change).
$\kappa_{\min}$ = `minDispersionPbps` is the **additive base**, not a post-hoc clamp; only the
protocol-wide `MAX_DISPERSION_PBPS` = 900000 ceiling clamps - there is no per-asset ceiling field.

At $\nu = 10000$ — the live value on stable legs and on every hub — this reduces to
$\kappa = \kappa_{\min} + \lfloor \sigma \rfloor$ pbps: impact IS volatility-adaptive, one-for-one
with the feed's σ above the floor (live stable $\sigma = 76$ PBPS widens USDT from 161 to 237 pbps).
The volatile classes run $\nu$ below 1.0x (0.30x FX, 0.40x crypto, 0.45x metals, 0.35x equities), so
there the slope is that fraction of σ, deliberately: it is what keeps their book inside the interior
swing cap ([Parametrization §4.2](/docs/1-1-7-parametrization#42-vega-volatility-sensitivity)). Full argument with numbers:
[Liquidity Shaping §6.4](/docs/1-1-2-liquidity-shaping#64-sigma-is-the-live-width-driver-at-shipped-vega).

---

## 3. Slippage: stochastic

Slippage is the difference between the quote a taker saw and the price they got: the part that is
**not** a function of the state the quote read.

### 3.1. Sources

| Source | Mechanism | Direction | AIMM-specific note |
|--------|-----------|-----------|--------------------|
| Mark update | A keeper push lands between quote and inclusion | Either | The pool quotes off the keeper mark (`FeedMathLib.mark`), so a push moves the whole quote, not just the tail |
| Inventory drift | Another swap changes $R$, hence $\psi$ and $x_0$ | Either | Discrete: $x_0$ moves in steps of 50 bps of the domain |
| Coverage drift | Another swap changes $c$ on the output leg | Negative if worsened | Changes $t(q)$ convexly |
| Staleness ramp | Feed ages past the keeper grace, widening $s$ | Negative | Deterministic given the age; see §3.2 |
| Front-running | Searcher trades ahead | Negative | Bounded by the book: they cannot push you past $\pm H\kappa/\text{dispRef}$ |
| Sandwich | Bot trades both sides | Negative | Round trips lose (Liquidity Shaping §8.3), so the sandwicher pays too |
| Reserve clamp | Output reserve drained by an earlier tx | Negative | §2.3 |
| Halt | Feed goes stale, confident, or depegged | Revert | Fails closed, never degrades silently |

### 3.2. The staleness ramp is not random

The spread carries a keeper-lag term (`Pricing._staleTerm`, `Pricing.sol`):

$$U_{\text{stale}} = \frac{z\,\sigma\sqrt{\tau}}{\text{BPS}},
\qquad z = 100, \qquad \tau = \max\!\big(0,\ a - \min(T/2,\ 30)\big)$$

with $a$ the feed's age in seconds, $T$ its `ttl`, and $z$ = `STALE_Z` (`Pricing.sol`). $\tau$ is 0
inside the grace and the surcharge grows as $\sqrt{\tau}$ beyond it. The
observed live USDT spread of 177 pbps decomposes as 61 (path floor) + 0 (volatility term, $\sigma$
truncates to zero at $\nu = 10000$) + 100 (1 bp of feed confidence) + 16 (staleness, about 470 s of
age against a 30 s grace). USDT anchors to the base, so this is a **one-leg** path and the floor is
USDT's own 61 alone; a two-leg cross sums both spokes' floors
([Spread & Fees §9](/docs/1-1-4-spread-fees#9-why-the-path-fee-floor-sums-over-legs)). A taker who
quotes and then waits sees the spread widen, predictably.

Past the hard TTL the feed does not widen further: `FeedMathLib.gate` reverts, and the leg does not
quote at all.

### 3.3. Positive slippage

Slippage can be favorable if the market moves your way between quote and inclusion. On a public
mempool it rarely reaches the trader: searchers monitor pending transactions, favorable movements are
captured by backrunners, and the unfavorable ones pass through. That asymmetry is the whole argument
for private order flow.

---

## 4. Protections

### 4.1. `minAmountOut`

```solidity
function swap(
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    uint256 minAmountOut,   // slippage bound
    address recipient,
    uint256 deadline        // staleness bound; type(uint256).max opts out
) external payable returns (uint256 out);
```

`Pool.sol`. The single state-mutating swap entry is `Pricing.swap`, and
the check is the last thing it does before pushing the output:

```solidity
if (out < minAmountOut) revert Err.ThresholdViolation(out, minAmountOut);
```

Two ordering facts:

- The threshold check runs **after** `PoolIOLib.settle`. That is state-identical in an all-or-nothing
  transaction, but it means a violated threshold burns the full settlement gas.
- A zero-delivery swap reverts first (`Pricing.swap`, `Err.ZeroValue`), before the threshold. A
  fully-tolled coverage-wall drain therefore reverts as `ZeroValue`, not as `ThresholdViolation`.

Sizing the bound, given §1.1: for a stable leg the fee and skew are already about 145 pbps (1.45 bp) at
zero size and are visible in the quote, so a bound set from the quote rather than from the mark can be
tight.

| Tolerance below quote | Use |
|-----------------------|-----|
| 0.05% to 0.1% | Stable legs, fresh feed, private order flow |
| 0.1% to 0.5% | Stable legs, public mempool |
| 0.5% to 1% | Volatile legs, normal conditions |
| 1% to 3% | Volatile legs, stressed tape; expect the spread term to move, not the curve |

### 4.2. `deadline`

`Pool.beforeDeadline` (`Pool.sol`) reverts `Err.Expired` when `block.timestamp > deadline`. The
deadline is **inclusive** (equality succeeds), there is no zero sentinel, and the opt-out is
`type(uint256).max`. Every value-moving entry point carries it: `swap`, `withdraw`, `withdrawTo`,
`swapLiability`. `deposit` and `donate` do not, because they mint at the current index against no
minimum output.

### 4.3. MEV-protected RPCs

Hide the transaction from the public mempool. The endpoints below are examples of widely used public
providers, not a complete or endorsed list; verify any endpoint before routing value through it.

**Ethereum L1**

| Provider | Endpoint | Notes |
|----------|----------|-------|
| MEV Blocker | `https://rpc.mevblocker.io` | CoW Protocol |
| Flashbots Protect | `https://rpc.flashbots.net/fast` | Fast mode trades some protection for inclusion |
| Merkle | `https://eth.merkle.io` | Free tier |
| Llama Nodes | `https://eth.llamarpc.com` | Free tier |
| BlockRazor | `https://eth.blockrazor.xyz` | Protection on by default |

**BNB Chain**: `https://rpc.48.club`, `https://bsc.merkle.io`, `https://binance.llamarpc.com`,
`https://bsc.blockrazor.xyz`.
**Base**: `https://base.llamarpc.com`.

**Multi-chain private networks**

| Provider | Coverage | MEV protection |
|----------|----------|----------------|
| Alchemy | Ethereum, Polygon, Arbitrum, Optimism, Base | Always on |
| BlockPI | Multi-chain | Enable in dashboard |
| dRPC | Multi-chain | Enable in dashboard |
| Helius | Solana | Optional Jito integration |

### 4.4. Timing and sizing

| Strategy | Effect | Trade-off |
|----------|--------|-----------|
| Trade shortly after a keeper push | Minimizes $U_{\text{stale}}$ and mark drift | Requires watching the feed |
| Keep size below $D/\text{BPS}$ | Exactly zero curve impact | Only useful for small orders |
| Split across blocks | Lets $\psi$ and $c$ recover between clips | Higher gas; each clip pays $s/2$ again |
| Trade the coverage-restoring direction | Favorable side of $P_{\text{skew}}$, near-zero $t$ | Direction is dictated by pool state, not preference |
| Avoid draining a walled leg below parity | Avoids the convex toll entirely | Check $c$ on the output asset first |

Splitting is **not** a free win: the spread $s$ is charged per swap and is
size-independent, while the curve impact is the small term. On a stable leg, splitting a trade into $n$
clips multiplies the dominant cost by $n$ and only saves the minor one.

---

## 5. Chain-specific ordering

### 5.1. Ethereum L1

Public mempool: every pending transaction is visible. Ordering is a gas auction. Protection is a
private RPC to a trusted builder.

### 5.2. Arbitrum and OP Stack

Transactions go to a centralized sequencer with full visibility, expected to order fairly. Original
ordering was FCFS; Arbitrum now runs a Timeboost auction for the priority lane, Base and OP run FCFS
with priority-fee escalation. Third-party MEV is limited by the sequencer's control of ordering.

### 5.3. Solana

No public mempool; transactions go directly to slot leaders, who control ordering. Jito provides
bundle auctions at the validator level. Helius offers optional Jito integration.

### 5.4. Sui

DAG mempool with object-based execution. MEV concentrates on shared objects such as AMM pools. Parallel
execution of independent transactions removes ordering MEV for simple transfers but not for contended
pool state.

---

## 6. Practical guidance

### 6.1. Takers

1. Set `minAmountOut` from the **quote**, not from the mark. The gap between them is the skew plus the
   fee and is legitimate, not slippage.
2. Set a real `deadline`. `type(uint256).max` opts out of the only staleness bound the caller controls.
3. Check the output leg's coverage before a large trade. The convex toll is the term that grows without
   bound.
4. Compare `hopAmounts` to the destination reserves on large quotes (§2.3).
5. Use a private RPC on L1 and BNB Chain.

### 6.2. Integrators

1. Quote at display time with `Pool.getSwapQuote`; it is a `view` and takes no cache writes.
2. Show the decomposition, not one number: skew, curve, toll and fee are four different things with
   four different risk profiles. `SwapQuote` exposes `markPrice`, `midPrice`, `covToll`,
   `spreadPbps`, `protoFee` and `lpFee` precisely so this is possible without re-deriving anything.
3. Credit 100% of the fee to `tokenOut`. There is no input-leg fee (`IPool.sol`).
4. The realized fee is `spreadPbps/2` of the pre-fee output, not `spreadPbps`.
5. Handle `Err.Expired`, `Err.ThresholdViolation`, `Err.ZeroValue`, `Err.InsufficientAmount`,
   `Err.BaseDepegged` and `Err.FeatureDisabled` distinctly. They mean different things and only two of
   them are worth retrying.

### 6.3. Large traders

1. Intent-based systems (CoW Protocol, UniswapX) for execution above the reserve scale.
2. Private mempools or direct builder connections.
3. Time-weight across blocks only if the spread cost of extra clips is smaller than the impact saved,
   which on a stable leg it usually is not (§4.4).
4. Monitor markout against `midPrice`, not against `markPrice`. The mid is where the book was.

---

## 7. Research and further reading

- [Flashbots: MEV in Eth2](https://arxiv.org/abs/2101.05511): MEV taxonomy and measurement
- [Private MEV Protection RPCs](https://arxiv.org/pdf/2505.19708v1): effectiveness analysis
- [MEV on Polygon](https://arxiv.org/pdf/2508.21473v1)
- [Cross-chain Sandwich Attacks](https://arxiv.org/pdf/2511.15245v1)
- [High-Frequency Trading on DEXes](https://arxiv.org/abs/2009.14021)
- [UniswapX Price Improvement](https://blog.uniswap.org/UniswapX_PI.pdf)
- [Protected Order Flow Relay](https://arxiv.org/pdf/2408.02303)
- [Flashbots Docs](https://docs.flashbots.net/), [Jito Documentation](https://jito.wtf/)

---

## 8. Related documentation

- [1.1.1. Inventory Management](/docs/1-1-1-inventory-management): $P_{\text{skew}}$ and the coverage toll
- [1.1.2. Liquidity Shaping](/docs/1-1-2-liquidity-shaping): $\Gamma$, the curve and dispersion
- [1.1.3. Anchor Path Pricing](/docs/1-1-3-anchor-path-pricing): how the terms compose over multiple legs
- [1.1.4. Spread & Fees](/docs/1-1-4-spread-fees): $s$ and its components
- [1.1.6. Toxic Flow Mitigation](/docs/1-1-6-toxic-flow-mitigation)
- [1.1.7. Parametrization](/docs/1-1-7-parametrization)
- [3.3. Flow Guards](/docs/3-3-flow-guards)
- [Glossary: Slippage](/docs/glossary#slippage), [Price Impact](/docs/glossary#price-impact), [MEV-Protected RPC](/docs/glossary#mev-protected-rpc)
