Skip to content

js-legacy: Round pool token amounts in withdrawSol and withdrawStake - #946

Open
ara-stock wants to merge 1 commit into
solana-program:mainfrom
ara-stock:js-legacy-sol-to-lamports-rounding
Open

ara-stock wants to merge 1 commit into
solana-program:mainfrom
ara-stock:js-legacy-sol-to-lamports-rounding

Conversation

@ara-stock

Copy link
Copy Markdown

solToLamports in clients/js-legacy multiplies the UI amount by LAMPORTS_PER_SOL but never rounds the result to an integer. For amounts that aren't exactly representable in binary floating point, the product is fractional, e.g. 1.005 * 1e9 === 1004999999.9999999. That breaks both callers:

  • withdrawSol(..., 1.005) throws RangeError: The number 1004999999.9999999 cannot be converted to a BigInt because it is not an integer from createApproveInstruction, so the withdrawal can't be built at all.
  • withdrawStake(..., 1.005) passes the value through new BN(...), which silently truncates it. The approve and WithdrawStake instructions then use 1004999999 pool tokens, one fewer than requested.

This change rounds the product with Math.round. For inputs with at most 9 decimals the float error is far below 0.5, so rounding always gives the intended base-unit amount.

Tests: I added one test each for withdrawSol and withdrawStake that call them with 1.005 and check the approve amount and the decoded poolTokens. Both tests fail on main (RangeError / 1004999999n) and pass with the fix. pnpm test (28 passing), pnpm lint and pnpm format are clean.

I used an AI assistant (Claude) while preparing this. I reproduced the issue and checked the fix and tests myself.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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