Skip to content

fix: reclamm getMaxSwapAmount return raw instead of scaled - #165

Merged
johngrantuk merged 2 commits into
mainfrom
fix-reclamm-maxswapamount-return-raw
Jun 30, 2026
Merged

fix: reclamm getMaxSwapAmount return raw instead of scaled#165
johngrantuk merged 2 commits into
mainfrom
fix-reclamm-maxswapamount-return-raw

Conversation

@johngrantuk

@johngrantuk johngrantuk commented Jun 30, 2026

Copy link
Copy Markdown
Member

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.

@johngrantuk
johngrantuk merged commit 9f91ab3 into main Jun 30, 2026
@johngrantuk
johngrantuk deleted the fix-reclamm-maxswapamount-return-raw branch June 30, 2026 21:08
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