Skip to content

Conversation

@Patel-Raj11
Copy link
Collaborator

@Patel-Raj11 Patel-Raj11 commented Jan 23, 2026

High Level Overview of Change

Recent Number type refactor in rippled changed the following:

  1. mantissa range from [10^15, 10^16-1] to [10^18, 10^19-1].
  2. Shrinking mantissa if it goes beyond max signed 64-bit integer (2^63 - 1). Occurs due to increased mantissa range.

This PR implements above two changes and fixes toJSON (string representation) to match with rippled's behaviour.

Additional changes in PR:

  1. Adds helper functions signLoanSetByCounterparty and combineLoanSetCounterpartySigners helper functions.
  2. Adds temporary fix to docker container so that rippled node runs. This can be reverted once Michael confirms the root cause and provides a permanent fix.

Context of Change

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (non-breaking change that only restructures code)
  • Tests (You added tests for code that already exists, or your new feature included in this PR)
  • Documentation Updates
  • Release

Did you update HISTORY.md?

  • Yes
  • No, this change does not impact library users

Test Plan

Added unit tests that takes expected value from standalone rippled instance.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

Walkthrough

STNumber normalization and rendering updated with 64-bit mantissa bounds and stricter overflow/underflow checks; Loan model field renamed; many TRANSACTION_RESULTS codes added; Wallet gained counterparty LoanSet signing/combining helpers and multisign-aware signing utilities; tests, fixtures, CI docker command, and HISTORY entries updated.

Changes

Cohort / File(s) Summary
STNumber implementation & tests
packages/ripple-binary-codec/src/types/st-number.ts, packages/ripple-binary-codec/test/st-number.test.ts
Reworked STNumber: added MAX_INT64, raised mantissa bounds to 10^18–(10^19−1), enhanced normalization, rounding, overflow/underflow checks, and updated rendering; expanded test coverage for rounding, limits, and canonical rendering.
Definitions & model rename
packages/ripple-binary-codec/src/enums/definitions.json, packages/xrpl/src/models/ledger/Loan.ts
Renamed PreviousPaymentDatePreviousPaymentDueDate in Loan model and updated definitions JSON; added many TRANSACTION_RESULTS entries (new te*/tef*/tel*/tem*/ter*/tes* codes).
Wallet: counterparty signing & utils
packages/xrpl/src/Wallet/counterpartySigner.ts, packages/xrpl/src/Wallet/utils.ts, packages/xrpl/src/Wallet/index.ts
Added signLoanSetByCounterparty and combineLoanSetCounterpartySigners; introduced computeSignature(tx, privateKey, signAs?) supporting multisign/XAddress handling; replaced local computeSignature with utility import and exported new helpers.
Counterparty signer tests
packages/xrpl/test/wallet/counterpartySigner.test.ts
New unit tests covering single- and multi-counterparty LoanSet signing, validation/error paths, and combining signers.
Fixtures & signing-data test
packages/ripple-binary-codec/test/fixtures/codec-fixtures.json, packages/ripple-binary-codec/test/signing-data-encoding.test.ts
Added two VaultCreate fixtures; updated expected multi-signing blob bytes in signing-data encoding test.
Integration tests (lending/vaults/amm)
packages/xrpl/test/integration/transactions/lendingProtocol.test.ts, packages/xrpl/test/integration/transactions/singleAssetVault.test.ts, packages/xrpl/test/integration/transactions/ammBid.test.ts
Added single-signer LoanSet scenario, replaced multi-sign encode flow with signer helpers, adjusted numeric literals in vault tests to much larger values, and refined a precision literal in AMMBid test.
Wallet exports & history
packages/xrpl/src/Wallet/index.ts, packages/xrpl/HISTORY.md, packages/ripple-binary-codec/HISTORY.md
Exported counterparty signer helpers and added HISTORY entries documenting STNumber fix and Wallet counterparty signer additions.
CI / docs
.github/workflows/nodejs.yml, CONTRIBUTING.md
Docker-run commands now create the rippled DB directory before starting rippled; minor YAML quoting adjustments.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • achowdhry-ripple
  • pdp2121
  • khancode

Poem

🐇 I hopped through mantissas, large and small,
Pushed LoanSet signatures — one signer, then all.
Vaults grew tall with digits bold and bright,
Blobs stitched tidy by moonlit rabbit light.
A rabbit cheers these ledger bytes tonight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes both main changes: STNumber serialization fixes and new counterparty signing helper functions.
Description check ✅ Passed The description provides clear context on the STNumber bug fix with specific technical details, explains the counterparty signing additions, mentions HISTORY.md updates, includes test plan information, and checks relevant change type boxes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-number-serialization

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ripple-binary-codec/src/enums/definitions.json (1)

733-742: Update Loan.ts to use PreviousPaymentDueDate instead of PreviousPaymentDate.

The field was renamed in definitions.json (line 734) but the TypeScript model at packages/xrpl/src/models/ledger/Loan.ts (line 108) still references the old name. Update the field name and consider whether the JSDoc comment should also be clarified to match the new semantic meaning ("when the previous payment was due" vs. "when it was made").

🤖 Fix all issues with AI agents
In `@packages/ripple-binary-codec/src/enums/definitions.json`:
- Around line 3645-3660: Update the failing test that still expects the removed
terNO_DELEGATE_PERMISSION code: in delegateSet.test.ts replace any
assertion/expectation using the string 'terNO_DELEGATE_PERMISSION' (or its
numeric -85) with the new error code 'tecNO_DELEGATE_PERMISSION' (value 198) so
the test checks for the updated code name/value returned by the transaction;
search for references in the test (the expect/assert block around the
delegateSet result) and swap the identifier accordingly.

In `@packages/ripple-binary-codec/src/types/st-number.ts`:
- Around line 98-125: The normalize() flow can still produce an exponent >
MAX_EXPONENT for huge inputs (e.g. "1e40000"); after the existing
normalization/shrink/grow loops (but before returning or doing int64-specific
shrinking), add an explicit upper-bound check that if exponent > MAX_EXPONENT
the function throws an Error (similar to the existing 'Mantissa and exponent are
too large' case). Ensure you reference the MAX_EXPONENT constant and perform
this guard in normalize() so no out-of-range exponent is returned or serialized.
🧹 Nitpick comments (1)
packages/ripple-binary-codec/test/st-number.test.ts (1)

27-31: Rename the duplicate test title for clearer output.
Two tests share the exact name “-ve normal value”, which makes failures harder to attribute. Consider a more specific label for one of them.

Also applies to: 87-91

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/xrpl/src/Wallet/counterpartySigner.ts`:
- Around line 1-3: The import list includes an unused symbol `decode` which
causes a TS6133 CI failure; remove `decode` from the import statement (leaving
`encode` and `stringify`) in the top of counterpartySigner.ts so the module only
imports used symbols and the TypeScript build error is resolved.

@Patel-Raj11 Patel-Raj11 marked this pull request as draft January 26, 2026 15:18
@Patel-Raj11 Patel-Raj11 changed the title Fix STNumber serialization Fix STNumber serialization and add counterparty signing helper functions Jan 26, 2026
@Patel-Raj11 Patel-Raj11 marked this pull request as ready for review January 27, 2026 17:59
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
CONTRIBUTING.md (2)

80-80: Documentation inconsistency with the updated command.

Line 80 still describes -c 'rippled -a' as the bash command, but the actual command on line 67 now includes mkdir -p /var/lib/rippled/db/ && before rippled -a. Update the documentation to match.

📝 Suggested fix
-*  `-c 'rippled -a'` provides the bash command to start `rippled` in standalone mode from the manual entrypoint
+*  `-c 'mkdir -p /var/lib/rippled/db/ && rippled -a'` creates the database directory and starts `rippled` in standalone mode from the manual entrypoint

109-109: Browser Tests Docker command missing the mkdir fix.

The Browser Tests section still uses -c 'rippled -a' without the mkdir -p /var/lib/rippled/db/ workaround that was added to the Integration Tests command on line 67 and in the CI workflow.

📝 Suggested fix
-docker run  -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'rippled -a'
+docker run  -p 6006:6006 --rm -it --name rippled_standalone --volume $PWD/.ci-config:/etc/opt/ripple/ --entrypoint bash rippleci/rippled:develop -c 'mkdir -p /var/lib/rippled/db/ && rippled -a'
🤖 Fix all issues with AI agents
In `@packages/ripple-binary-codec/test/st-number.test.ts`:
- Around line 168-173: The test description is misleading: the it(...) currently
says "underflow returns zero (value too small)" but the code asserts that
STNumber.from throws an Error('Underflow: value too small to represent'); update
the it(...) title to reflect that it expects an underflow error (for example
"underflow throws error (value too small to represent)") so the test name
matches the asserted behavior; keep the assertion using STNumber.from and the
exact error message 'Underflow: value too small to represent'.

In `@packages/xrpl/src/models/ledger/Loan.ts`:
- Around line 105-108: Update the JSDoc for the PreviousPaymentDueDate field to
reflect the new semantics: change the description from "when the previous
payment was made" to indicate it is the Ripple Epoch timestamp when the previous
payment was due; ensure the comment still mentions the numeric Ripple Epoch
format and optional status to match the field declaration
PreviousPaymentDueDate?: number.
🧹 Nitpick comments (3)
packages/xrpl/src/Wallet/counterpartySigner.ts (1)

176-199: Consider edge case: duplicate signers across transactions.

The validateLoanSetTransactionEquivalence function ensures all transactions are equivalent except for their CounterpartySignature.Signers. However, getTransactionWithAllLoanSetCounterpartySigners uses flatMap to combine all signers without checking for duplicates.

If the same signer account signs multiple input transactions, the combined result would contain duplicate entries, which could cause issues during submission.

♻️ Consider deduplicating signers by Account
 function getTransactionWithAllLoanSetCounterpartySigners(
   transactions: LoanSet[],
 ): LoanSet {
   // Signers must be sorted in the combined transaction - See compareSigners' documentation for more details
-  const sortedSigners: Signer[] = transactions
+  const allSigners = transactions
     .flatMap((tx) => tx.CounterpartySignature?.Signers ?? [])
+
+  // Deduplicate by Account
+  const uniqueSigners = Array.from(
+    new Map(allSigners.map((s) => [s.Signer.Account, s])).values(),
+  )
+
+  const sortedSigners: Signer[] = uniqueSigners
     .sort((signer1, signer2) => compareSigners(signer1.Signer, signer2.Signer))
packages/xrpl/test/wallet/counterpartySigner.test.ts (2)

1-1: Remove outdated TODO comment.

This comment appears to be a development note that is no longer needed since both tests are now implemented.

Suggested fix
-// Add one test for single signing and one test for multi-signing
-
 import { assert } from 'chai'

14-14: Typo: singedLoanSet should be signedLoanSet.

This typo appears in both test cases (lines 14 and 88).

Suggested fix for the single sign test
-    const singedLoanSet = {
+    const signedLoanSet = {

And update all references in this test case accordingly.

shawnxie999
shawnxie999 previously approved these changes Jan 30, 2026
Copy link
Collaborator

@shawnxie999 shawnxie999 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Number serialization looks good

ckeshava
ckeshava previously approved these changes Jan 30, 2026
@Patel-Raj11 Patel-Raj11 dismissed stale reviews from ckeshava and shawnxie999 via fe16a34 January 30, 2026 23:11
Copy link
Collaborator

@achowdhry-ripple achowdhry-ripple left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code+syntax lgtm, approving to not block release -- am less familiar with the context on the serialization changes but did not see an issue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/ripple-binary-codec/test/st-number.test.ts`:
- Around line 87-97: Two test cases use duplicate names ('-ve normal value' and
'+ve normal value') which duplicate earlier tests; update the it(...)
descriptions to unique, descriptive names to disambiguate failures. Locate the
it blocks that call STNumber.from(...) and sn.toJSON() and rename their first
argument strings (for example include "string input" or "large value" context)
so each it(...) label is unique and clearly references STNumber.from and toJSON
behavior.
🧹 Nitpick comments (1)
packages/ripple-binary-codec/src/types/st-number.ts (1)

114-121: Shrink loop appears to be unreachable dead code.

The initial mantissa overflow check at lines 98-101 rejects any m > MAX_MANTISSA before reaching this loop. The growth loop (lines 108-112) cannot produce m > MAX_MANTISSA since it stops when m >= MIN_MANTISSA, and the maximum value after growth is MIN_MANTISSA * 9 < MAX_MANTISSA.

This code appears to be defensive but will never execute. Consider removing it or adding a comment explaining its purpose.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/ripple-binary-codec/src/types/st-number.ts`:
- Around line 141-143: Rounding can push m past MAX_INT64 (e.g., m == MAX_INT64
and lastDigit >= 5); after the current increment (m += BigInt(1)) add a
post-rounding shrink check that mirrors the pre-rounding MAX_INT64 handling: if
m > MAX_INT64 then repeatedly shrink the mantissa (divide/round as your existing
shrink logic does) and increment the exponent until m <= MAX_INT64, updating any
flags used for writeInt64BE serialization; ensure this uses the same shrink
routine used earlier so writeInt64BE never receives a value > MAX_INT64.
🧹 Nitpick comments (1)
packages/ripple-binary-codec/test/st-number.test.ts (1)

177-181: Consider adding a test for rounding overflow at MAX_INT64 boundary.

The test suite covers rounding behavior but doesn't include a case where rounding could push the mantissa exactly to MAX_INT64 + 1. Given the potential bug in normalize() where rounding can exceed MAX_INT64, adding a targeted test would help catch regressions.

🧪 Suggested test case
it('handles rounding at MAX_INT64 boundary', () => {
  // Value that after shrinking lands exactly at MAX_INT64, with lastDigit >= 5
  // This tests that rounding doesn't cause int64 overflow
  const value = '92233720368547758075' // 9223372036854775807.5 * 10
  const sn = STNumber.from(value)
  // Verify it doesn't throw and produces valid output
  expect(sn.toJSON()).toBeDefined()
})

@Patel-Raj11 Patel-Raj11 merged commit b449a31 into main Feb 4, 2026
12 checks passed
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.

4 participants