Skip to content

fix(ripple): represent XRPL issued-currency amounts exactly (no float scaling)#19

Merged
runninyeti merged 1 commit into
mainfrom
fix/xrpl-issued-currency-amount-scaling
Jun 18, 2026
Merged

fix(ripple): represent XRPL issued-currency amounts exactly (no float scaling)#19
runninyeti merged 1 commit into
mainfrom
fix/xrpl-issued-currency-amount-scaling

Conversation

@runninyeti

Copy link
Copy Markdown
Contributor

Problem

Reported by Mesh (Mircea) while validating XRPL. The Ripple token-transfer extractor scaled issued-currency (IOU) amounts with:

const floatVal = parseFloat(deliveredOrAmount.value);
const smallestUnit = Math.round(floatVal * 1_000_000);
parsedAmount = BigInt(smallestUnit);

Two compounding errors:

  1. Hardcoded * 1e6 — that's XRP's drops scaling. IOUs aren't denominated in drops; their value is an arbitrary-precision decimal (up to 15 significant digits, wide exponent) with no fixed integer unit and no universal decimals.
  2. parseFloat + Math.round — lossy on large / scientific-notation values.

Observed on live ledger 105011630:

token real value old amount correct
BITx 0.00026764546195073 268 0.00026764546195073
USDV 7979.002624671 7979002625 (rounded) 7979.002624671
MAG 0.00001 10 0.00001

Native XRP (integer drops) was already correct.

Fix

  • Parse the IOU value losslessly into (mantissa: bigint, decimals: number) using string/BigInt math — never parseFloat. Handles plain and scientific-notation values; trims trailing fractional zeros to a minimal scale.
  • Add an optional NetworkTransfer.decimals field (additive, non-breaking), populated only for IOUs. human = amount / 10 ** decimals. This mirrors how EVM token amounts already work (raw integer + decimals applied out-of-band). Native XRP / EVM / all other paths are unchanged — no decimals emitted, so existing consumers and tests are unaffected.
  • Decode 40-hex XRPL currency codes to their ASCII symbol (e.g. BITx) instead of emitting the raw hex blob; non-printable codes (LP tokens, etc.) keep the hex.

Verification

  • New inline tests cover the fractional (the 268 regression), large-whole, and scientific-notation cases, plus hex-currency decode.
  • Existing native-XRP and failed-payment (fee-only) tests pass unchanged.
  • Spot-checked against live ledger 105011630 — BITx / USDV / MAG now reconstruct to their exact on-ledger values.

Note on token identity

token is set to the (decoded) currency code, preserving prior semantics. XRPL IOUs are uniquely identified by currency + issuer, so same-symbol tokens from different issuers still collide on token alone — out of scope here, worth a follow-up if we need issuer-level disambiguation.

🤖 Generated with Claude Code

… scaling)

XRPL issued currencies (IOUs) carry an arbitrary-precision decimal value with
no fixed on-chain integer unit. The extractor scaled them with
round(parseFloat(value) * 1e6), which both hardcoded XRP's 6-decimal drops
scaling onto IOUs and lost precision via float math. Example: BITX value
0.00026764546195073 was reported as amount '268'; 7979.002624671 was rounded;
large whole values like 1000000000000000 became nonsense 1e21.

Parse the value losslessly into (mantissa bigint, decimals) using string/BigInt
math (handles plain + scientific notation), mirroring how EVM token amounts
work (raw integer + decimals). Adds an optional NetworkTransfer.decimals field,
populated only for IOUs; native XRP (integer drops) is unchanged. Also decode
40-hex XRPL currency codes to their ASCII symbol (e.g. 'BITx') instead of
emitting the raw hex blob.

Verified against live ledger 105011630 (BITx/USDV/MAG now exact) plus inline
tests for the fractional, whole, and scientific-notation cases.
@runninyeti runninyeti merged commit e98abcb into main Jun 18, 2026
1 check passed
@runninyeti runninyeti deleted the fix/xrpl-issued-currency-amount-scaling branch June 18, 2026 16:37
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