Skip to content

fix: remove the 20% slippage cap from the quote schema - #1410

Closed
codyborn wants to merge 1 commit into
mainfrom
codyborn/remove-slippage-20-cap
Closed

codyborn wants to merge 1 commit into
mainfrom
codyborn/remove-slippage-20-cap

Conversation

@codyborn

@codyborn codyborn commented Aug 18, 2026 •

Copy link
Copy Markdown

What

Removes .max(20) from slippageTolerance in the quote schema.

Companion PR in the backend monorepo (uniroute carries the same bound): https://github.com/Uniswap/backend/pull/12251

Why

This bound arrived in bc187beb (2021-06-29, "New responses") as one line in a bulk pass that converted the quote schema to typed Joi and put defensive limits on every field at once — tokenIn/Out .max(40), amount .max(20), deadline .max(600), a recipient regex. The deadline line right below it still carries // 180 mins, same as interface max, which is the tell: these mirrored the interface's caps, and the interface bounded slippage at 20% then.

The interface has since moved to a 100% max with a warning at 20%, and the Trading API's copy of the bound was removed in January 2025 with product sign-off (CX-877) — but only in that one layer, leaving routing as the only place still enforcing it.

Effect today: slippage above 20% returns no quote and the app shows a generic "no quotes available" with no explanation. FOT and thin-liquidity tokens routinely need more headroom. Reported four separate times since 2021, and generating routing alert noise since Feb 2025.

No execution-safety argument supports the specific value. minimumAmountOut is amountOut / (1 + slippage), which asymptotes toward zero without reaching it — 100% slippage still floors the trade at half the quote. The ceiling belongs to the client, which already has one and already warns.

Why min(0) stays

The SDK asserts slippage >= 0 in minimumAmountOut, so a negative value would throw downstream rather than degrade. Joi.number() already rejects NaN and Infinity by default — verified:

20 accept · 21 accept · 50 accept · 1000 accept
-1 REJECT "must be greater than or equal to 0"
NaN REJECT "must be a number"
±Infinity REJECT "cannot be infinity"

So dropping .max(20) alone is sufficient here. (The uniroute validator needed an explicit finite/non-negative check instead, since it hand-rolls validation on a proto double rather than going through Joi.)

Rollout note

uniroute and routing-api both serve and both carry this bound. Requests over 20% keep failing on whichever path lands second.

🤖 Generated with Claude Code

The bound arrived in bc187be (2021-06-29) as one line in a bulk pass that
put defensive limits on every field of the then-new v1 quote schema. It
mirrored the interface's cap at the time — the neighboring deadline bound
still says "same as interface max". The interface has since moved to a 100%
max with a warning at 20%, and the Trading API's copy was removed in January
2025 with product sign-off, leaving routing as the only layer enforcing it.

Users who set slippage above 20% get no quote and a generic "no quotes
available" with no indication why. FOT and thin-liquidity tokens routinely
need more headroom.

There is no execution-safety argument for the value: minimumAmountOut is
amountOut/(1+slippage), which asymptotes toward zero without reaching it, so
even 100% slippage floors the trade at half the quote. The ceiling belongs to
the client, which already has one and already warns.

min(0) stays — the SDK asserts slippage >= 0 — and Joi.number() already
rejects NaN and Infinity, so no other guard is needed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@graphite-app
graphite-app Bot requested review from a team and jsy1218 August 18, 2026 16:20
@codyborn

Copy link
Copy Markdown
Author

Closing — routing-api is no longer in the serving path, so this bound is dead code and does not need changing.

The live fix is https://github.com/Uniswap/backend/pull/12251, which removes the same 20% cap from uniroute's quote validator.

Leaving the historical note here for anyone who greps this line later: .max(20) originated in bc187be (2021-06-29) as one line in a bulk pass that put defensive limits on every field of the then-new v1 quote schema, mirroring the interface's cap at the time. It was never a deliberate execution-safety decision.

@codyborn codyborn closed this Aug 18, 2026
@graphite-app

graphite-app Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Graphite Automations

"Request reviewers once CI passes on routing-api repo" took an action on this PR • (08/18/26)

3 reviewers were added and 1 assignee was added to this PR based on Siyu Jiang (See-You John)'s automation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant