fix: reclamm getMaxSwapAmount return raw instead of scaled - #165
Merged
Conversation
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.
Summary
ReClamm.getMaxSwapAmount and ReClammV2.getMaxSwapAmount returned values in scaled18 units instead of raw token amounts, inconsistent with every other pool type (Stable, Weighted, Gyro2CLP, GyroECLP, LiquidityBootstrapping). For rate-bearing tokens, this caused the returned limit to be off by roughly the token's rate (e.g. ~1.4x too large), which can lead consumers (like the SOR) to take the wrong routing branch or attempt impossible exact-out swap amounts, sometimes reverting with AmountOutGreaterThanBalance.
Changes
typescript/src/reClamm/reClammPool.ts / typescript/src/reClammV2/reClammV2Pool.ts:
getMaxSwapAmount now converts its result back to raw token units via toRawUndoRateRoundDown(amount, scalingFactor, tokenRate) before returning, matching the convention used by Stable and other pool types.
Replaced the previous balance - 10n rounding-tolerance hack with a 99% safety margin on the token-out balance (_MAX_TOKEN_OUT_RATIO), applied to both GivenIn and GivenOut, to guard against edge-case reverts when swapping near the theoretical max (matching Stable's existing 99% margin convention, but now applied to both swap kinds since both are bounded by the token-out balance in this pool).
For GivenIn, the curve computation (computeInGivenOut) now targets the 99%-reduced output amount directly, rather than computing against the full balance and then subtracting a fixed wei tolerance.
typescript/test/reClammPool.test.ts:
Updated existing tests to scale the (now raw) getMaxSwapAmount result back up via toScaled18ApplyRateRoundDown before feeding it into onSwap's amountGivenScaled18, since previously the raw output was fed in directly (only valid under the old buggy scaled18-return behavior).
Added a new with rate test suite covering rate-bearing tokens, asserting the returned amount is raw (strictly less than balancesLiveScaled18[indexOut]), matches the exact expected value, and round-trips cleanly through onSwap.
Test plan
npx vitest run — all 171 tests pass across the TS test suite.
npx eslint src/reClamm/reClammPool.ts src/reClammV2/reClammV2Pool.ts — no lint errors.
Note: Python and Rust implementations don't define get_max_swap_amount for any pool type, so no changes were needed there.