Skip to main content
slippageBps and maxImpactBps are both basis points, both make a trade safer, and both appear on the same request. They are not variants of one idea, and setting one does not do the other’s job. The short version: slippage protects you from other people, impact protects you from yourself. Written against swap-router at d88da91. Every figure below was measured on a Base fork at blocks 50,807,273 to 50,807,275, minutes apart: the pool moves between them, which is exactly why each measurement names its block.

Slippage never changes the trade

The same 50,000 USDC into WETH, quoted twice, at 10 bps and at 50 bps of slippage: Five times the slippage, and the trade is identical: same input, same output, same impact. The only number that moved is the floor. That is the whole of it. slippageBps is a statement about what you will still accept, not an instruction about what to trade. It becomes minAmountOut, which the aggregation router enforces on chain, and if the market has moved past it by the time your transaction mines the swap reverts.
The floor is a haircut on amountOutAfterFee: the output after the protocol fee, not before it. A floor computed from the gross figure is one the router cannot meet, and it would revert every swap for a reason that reads like slippage.

Impact is the cost you cause

Price impact is what your own size does to the pool as it walks the book. It is already in the quote above: that 50,000 USDC trade moves the price 0.87 bps, and no slippage setting changes that number: slippage is applied after impact has been paid. maxImpactBps is the bound on it. The service quotes your amount, and if the impact it reports exceeds the cap it bisects the offer down until it fits, then answers with the smaller trade. You are not refused; you are given less than you asked for, at a better average price, and told so. Measured at block 50,807,274 and 50,807,275, offering 450,000 USDC both times: The cap cut the offer to 82.29% of itself and landed the impact at exactly 500 pips, the boundary, found by search rather than by scaling. The answer says so:
sizedDown is deliberately not folded into fill. A limit fill stops at a price and carries a sqrtPriceLimitX96 to execute it; this is an ordinary swap of a smaller amount, and reusing that shape would hand back a price limit nothing solved for. amountIn is already the reduced figure, so the quote can be built and sent as it stands: the block only explains why it is smaller than what you asked for. It searches for the largest size that fits rather than accepting the first one that does. Impact is convex: depth is concentrated, so scaling by cap / impact overshoots downward hard. Measured on Base: 3,000,000 USDC capped at 5 bps came back as 237,675 by that ratio, while the true 5 bps maximum on that pair was 2,317,948. A tenth of the volume, every step defensible.

Neither one substitutes for the other

Slippage does not stop you causing impact. A trade with 12 bps of impact and 50 bps of slippage sails through. The impact is inside the quote, so the floor is computed from the already-worsened price. You paid it, and nothing complained. A cap does not protect you from time. maxImpactBps is measured at quote time, on a snapshot. If somebody else moves the market between your quote and your transaction mining, the cap has nothing to say about it: only minAmountOut stands between you and the new price.

Sending both

They compose, and the order is what makes them coherent:
  1. maxImpactBps acts first, on the offer. The bisection settles on a smaller amount.
  2. slippageBps then prices that amount. minAmountOut is derived from the quote of the reduced trade, not of the one you asked for.
So the floor always belongs to the amount that will actually be sent. A floor derived from a larger offer is one a smaller trade can never clear; that is InsufficientOutput, and it is the failure this ordering exists to prevent. The same 450,000 USDC offer, capped at 5 bps, priced at two tolerances: block 50,807,275 for both: Identical trades. The cap decided the size and slippage decided nothing but the floor, which is the whole page in one pair of rows.
slippageBps: 5 beside maxImpactBps: 5 is legal and usually wrong. The two fives mean unrelated things; one bounds the size you may trade, the other how far the price may move afterwards, and they do not add up to anything. Five bps of slippage is a floor five hundredths of a percent below the quote, so almost any adverse movement reverts you.There is an irony in the pairing, too: the cap makes each trade smaller, so filling the size you wanted takes more transactions, each with its own window in which a 5 bps move can revert. If you are capping impact because you are trading big, maxImpactBps: 5, slippageBps: 50 is the pairing that expresses “do not let me move the market, but do actually land”.
limitRate with slippageBps is a different story and is refused: with a limit the floor is the caller’s own rate, so a tolerance would be a second and conflicting guarantee. slippageBps with maxImpactBps has no such conflict, which is exactly why it is allowed.

Read impact in pips, not bps

priceImpactBps is truncated. On the trade above it reads 0 while priceImpactPips reads 87: 0.87 bps. Comparing a cap against the truncated figure is wrong by up to a whole basis point, which is 2% of a 50 bps cap and 100% of a 1 bps cap, and maxImpactBps: 1 is precisely the request “fill me at near-zero impact”. The service enforces the cap in pips for that reason. Show pips to anybody who has to act on the number.
The confusion is not only conceptual. In the service, max_price_impact_bps and max_slippage_bps were adjacent u32 parameters until they were bundled into a struct, because a caller could transpose them and no compiler would notice.

Where costBps fits

A third bound, and a third question, see Bounded execution. costBps also bounds the size, like maxImpactBps, but on a different basis: it is the marginal rate the book is walked to, over direct pools, rather than the average the quote reports over any route. Because a trade stopped at a marginal rate delivers an average about half as far from spot, costBps: 25 is roughly maxImpactBps: 10, not 25.

Does capping mean trading in pieces?

Capping impact makes each trade smaller, which raises the obvious next question: if you then send the rest, have you saved anything? Sent immediately, no, and the per-slice impact figures make it look as though you have. That question has its own page: Does splitting cost less?.

In a plan

A swap.router step names them as max_slippage and max_impact_bps, both in basis points:
max_slippage is required when the step states no price of its own: the minimum has to come from what the venue would pay, and deriving it from the input amount is meaningless across two tokens with different decimals. State a limit_price instead and it becomes the floor, at which point max_slippage has nothing left to do.