fix(xrpl): return string from dropsToXrp to preserve precision (#3316)#3341
fix(xrpl): return string from dropsToXrp to preserve precision (#3316)#3341achowdhry-ripple wants to merge 2 commits into
Conversation
`dropsToXrp` previously returned a JavaScript `number` via `.toNumber()`,
which silently lost precision for amounts approaching the XRP supply
(~10^17 drops). `xrpToDrops(dropsToXrp('9999999999999999'))` returned
`'9999999999999998'`, dropping one drop on the round-trip.
Return a base-10 decimal string from `dropsToXrp` (and from
`Client.getXrpBalance`, which forwards the value) so the full precision
of the input is preserved. Callers that need a JS number can wrap the
result in `Number(...)`.
BREAKING CHANGE: `dropsToXrp()` now returns `string` instead of `number`;
`Client.getXrpBalance()` now returns `Promise<string>`.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (1)
WalkthroughThis PR changes ChangesXRP Conversion BigNumber Return Type
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
packages/xrpl/src/Wallet/fundWallet.tsParsing error: The keyword 'import' is reserved packages/xrpl/src/client/index.tsParsing error: The keyword 'import' is reserved packages/xrpl/src/utils/xrpConversion.tsParsing error: The keyword 'import' is reserved
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Address PR #3341 review feedback (kuan121): returning BigNumber is symmetric with the BigNumber.Value input type and avoids the silent string-concat foot-gun where `dropsToXrp(a) + dropsToXrp(b)` would have concatenated rather than added. - `dropsToXrp()` returns `BigNumber` (was `string`, originally `number`). - `Client.getXrpBalance()` returns `Promise<BigNumber>` (was `Promise<string>`). - `Client.getBalances()` initialises `xrpPromise` with `new BigNumber(0)`, uses `.isZero()` for the sentinel check, and `.toString()` when pushing the XRP balance. - `getBalanceChanges()` calls `.toString()` on the result of `dropsToXrp` to populate the string-typed `Balance.value`. - `fundWallet`/`Client.fundWallet` convert via `.toNumber()` (replacing `Number(...)` coercion on the previous string return). - Tests updated to assert via `BigNumber.isEqualTo` / `.isZero()`. - `HISTORY.md` breaking-change entry updated to describe BigNumber. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| formatBalances(response.result.lines), | ||
| ) | ||
| if (xrpBalance !== 0) { | ||
| if (!xrpBalance.isZero()) { |
There was a problem hiding this comment.
We should add test coverage for this change as well to be thorough
| @@ -1,6 +1,7 @@ | |||
| /* eslint-disable jsdoc/require-jsdoc -- Request has many aliases, but they don't need unique docs */ | |||
There was a problem hiding this comment.
Can you update the PR title and description?
|
Browser tests are still failing. |
High Level Overview of Change
Fixes xrpl.js#3316.
dropsToXrp()now returns a base-10 decimalstringinstead of a JavaScriptnumber. The internal.toNumber()call is replaced with.toString(BASE_TEN).Client.getXrpBalance()(which forwards the value) now returnsPromise<string>instead ofPromise<number>.Client.getBalances()is updated for the new return type (the branch that pushes the XRP balance no longer needs a redundant.toString(), and the!== 0sentinel check becomes!== '0').getBalanceChanges()drops a now-redundant.toString()on the already-string XRP value.Existing
dropsToXrptests updated for the new return type; new regression test added per the issue:HISTORY.mdupdated underUnreleased > BREAKING CHANGES.Context of Change
dropsToXrpconverts a drops integer (≤ ~10^17 for the XRP total supply) into an XRP amount by dividing by 1,000,000. The old implementation called.toNumber()on the BigNumber result, coercing to IEEE-754 double. For amounts above ~9 billion XRP, the double cannot represent every drop exactly, so the conversion silently loses precision.Repro from the issue:
The fix is to return the BigNumber's exact base-10 string representation. Drops are at most 6 fractional digits of XRP, so the division terminates exactly within BigNumber's default precision and never produces exponential notation.
This is a breaking API change (return type
number→string), which is why it is grouped with the otherUnreleasedbreaking changes inHISTORY.md. Callers that rely on a JS number can wrap the result inNumber(...)— this is already done at the two internal call sites inWallet/fundWallet.ts.Type of Change
Did you update HISTORY.md?
Test Plan
dropsToXrp > round-trips large amounts without precision loss (issue #3316)directly exercises the regression case from the issue.dropsToXrptests were updated to assert against the new string return type (mechanical change — same values, now quoted).getXrpBalancemock test updated to assert the string return.getBalanceChangesfixture-driven tests are unchanged (the fixture already expected string values; the new code path produces the same strings).npm installis currently hitting the npm "Exit handler never called!" bug on my machine. Relying on CI; happy to push fixups if anything fails.