Conversation
A discount leg prices off the backend's advertised `maxRate`, which is the adapter oracle price with the discount already applied *and floored*. The adapter rounds down in the opposite order: `getAmountOut` floors `amountIn * price * 10^outDec / (1e18 * 10^inDec)` first, then `swap(DiscountSwap, ...)` applies the discount and floors again. The two nested roundings differ by at most one unit, and the difference falls our way often -- roughly a fifth to a half of amounts at any non-zero discount. So pricing at the raw `maxRate` predicts one unit more output than the adapter delivers. That is not an adapter revert: the adapter computes `amountOut` itself and `InvalidSwapRate` cannot trigger because `discount >= minDiscount`. It reverts in `Reactor._fill`, which pulls the order's *signed* outputs out of the Executor after `execute()` returns. RFQ has no `priceBufferBps` and `Finalize` distributes the full achievable output, so the slack is exactly zero whenever the price has not moved since the quote. The fill then fails gas estimation (no tx is broadcast, no gas burned) and the order is re-armed by the next poll, retrying until it expires -- we win the auction and never fill it. `NormalizeOracleInventory` now re-derives every discount candidate's rate through the new `liquidlane.ConservativeAdvertisedRate`, which shaves one unit off the predicted output and converts it back to a rate. That round trip through `RateForAmountOut` floors, so every downstream `AmountOutForRate` call site stays at or below the on-chain value without knowing about the shave -- which is why the fix lands on the rate rather than on each output site. Direct legs are unaffected: they already re-derive from a live `getAmountOut` read. `NormalizeOracleInventory` is RFQ-only, so LI.FI and UniswapX are untouched. Value given up is usually zero: when `amountIn * 10^outDec <= 1e18 * 10^inDec` the rate round trip is lossless and the candidate lands exactly on the adapter's number. The exact alternative -- clamp against `AmountOutAfterDiscount(GrossAmountOut, discount)`, as `discounts.AdvertisedFillQuotes` already does -- needs the discount ppm, which the `/quote` request's `adapters[]` entries do not carry. Left as a follow-up noted in the plan rather than a backend contract change. Tests: a regression case pinning the concrete one-unit overprediction, and a 12,500-case sweep (5 decimal pairs x 5 discounts x 500 sizes) asserting the invariant. The sweep was verified to have teeth -- 2,351 of those cases violate it at the raw rate. Two existing tests that asserted the raw rate passing through verbatim were updated to the conservative expectation. Docs: the rate-rounding rule is recorded in LIQUIDLANE-CONVENTIONS.md (it is a LiquidLane-wide fact, not an RFQ quirk) and the full mechanics plus the follow-up in RFQ-PLAN.md Section 5. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fix(rfq): price discount legs below the adapter's nested rounding
…-lifecycle fix: lifi/uniswapx correct capacity and fill lifecycle
chore(deps): update dependencies
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.