Skip to content

Release v10.4 to main#7

Merged
Platonenkov merged 6 commits into
mainfrom
dev
May 13, 2026
Merged

Release v10.4 to main#7
Platonenkov merged 6 commits into
mainfrom
dev

Conversation

@Platonenkov
Copy link
Copy Markdown
Collaborator

@Platonenkov Platonenkov commented May 13, 2026

Summary

  • feat: add 25 new XRPL transaction types (Vault, Loan, LoanBroker, Delegate, XChain), 7 ledger objects, and docs
  • Enhance enums and update Visual Studio solution with GenerateEnums tool
  • Enhance JSON validation and error handling in Amount and Uint64 types
  • NuGet CI fix
  • Bump package versions to 10.4.0.0 (Xrpl, Xrpl.BinaryCodec)
  • Add Claude AI instructions

Packages updated

  • Xrpl 10.3.0.0 → 10.4.0.0
  • Xrpl.BinaryCodec 10.3.0.0 → 10.4.0.0
  • Xrpl.AddressCodec and Xrpl.Keypairs unchanged (no changes since v10.3)

Summary by CodeRabbit

Release Notes: Version 10.4.0.0

  • New Features

    • Added Vault (XLS-65d) transaction support: VaultCreate, VaultDeposit, VaultWithdraw, VaultSet, VaultDelete, VaultClawback
    • Added Lending Protocol (XLS-66d) support: LoanBrokerSet, LoanSet, LoanPay, LoanManage, and related operations with multi-party signing helpers
    • Added XChain Bridge support: bridge creation, claim management, attestations, and account creation across chains
    • Added DelegateSet and LedgerStateFix transaction types
    • Added new RPC methods: ServerDefinitions, VaultInfo, TransactionEntry, ChannelAuthorize, ChannelVerify
    • Enhanced stream subscriptions: BookChanges, ServerStatus, ManifestStream, ValidationStream
    • Improved MPT (Multi-Purpose Token) support in asset handling
  • Documentation

    • Added comprehensive guides for Vault, Lending Protocol, and XChain Bridge (English and Russian)

Platonenkov and others added 6 commits May 7, 2026 16:21
- Improved null checks and error handling in Amount.FromJson and Uint64.FromJson methods.
- Strengthened validation for XRP Amount objects and Uint64 JSON tokens.
- Updated Oracle currency converters for better handling of non-standard currency codes.
- Enhanced unit tests for currency encoding and decoding to ensure robust exception handling.
…ol (#5)

* update definition.json file

* Enhance EngineResult, Field, FieldType, LedgerEntryType, and TransactionType enums with new values and improved organization

- Added multiple new EngineResult values for better error handling.
- Introduced new Uint8Field and Uint16Field values in Field.cs for enhanced functionality.
- Expanded FieldType with additional types including Number, Int32, and Int64.
- Updated LedgerEntryType with new entries and deprecated legacy types.
- Added new TransactionType values for XChain and Vault operations, along with loan-related transactions.

* Update Visual Studio solution to version 18 and add GenerateEnums tool

- Updated the solution file to target Visual Studio version 18.
- Added a new project for GenerateEnums tool to generate C# enums from definitions.json.
- Implemented the main functionality for reading definitions and generating enum source files for EngineResult, TransactionType, and LedgerEntryType.

* Refactor enum generation for EngineResult, LedgerEntryType, and TransactionType

- Converted EngineResult, LedgerEntryType, and TransactionType to partial classes for better organization.
- Generated new files for EngineResult.Generated.cs, LedgerEntryType.Generated.cs, and TransactionType.Generated.cs containing only static readonly field declarations.
- Updated the GenerateEnums tool to reflect changes in enum structure and generation process.

* update changes

* Add generated enum files for various field types in Xrpl.BinaryCodec

- Introduced new generated files for AccountIdField, AmountField, BlobField, CurrencyField, Hash128Field, Hash160Field, Hash192Field, Hash256Field, Int32Field, IssueField, NumberField, PathSetField, StArrayField, StObjectField, Uint8Field, Uint16Field, Uint32Field, and Uint64Field.
- Each file contains static readonly field declarations for respective field types, enhancing the enum structure and organization.
- These changes were made to support the updated definitions from definitions.json and improve the overall codebase structure.

* Remove unused folder declaration from Xrpl.BinaryCodec.Test project file

* Refactor and enhance unit tests for binary codec functionality

- Updated TestBinaryParser to improve method assertions and added new tests for reading variable-length data.
- Introduced TestBinarySerializer with methods for writing length-encoded data and validating serialized output.
- Expanded TestUDefinitions with comprehensive tests for field properties and mappings.
- Enhanced TestFieldIDCodec to validate field ID encoding and decoding.
- Improved TestAmount with additional tests for XRP and IOU handling, ensuring robust serialization and deserialization processes.
- Cleaned up TestMain by removing commented-out code and improving test structure.

* Refactor Field and AmountValue classes for improved validation and dispatch handling

- Updated Field class to use private backing fields for FromJson and FromParser properties, enhancing encapsulation and ensuring proper dispatch.
- Introduced a maximum limit for native XRP amounts in AmountValue, with validation to prevent exceeding this limit.
- Enhanced Uint32's FromJson method to handle various JSON value types more robustly.
- Improved unit tests to replace deprecated assertions with more descriptive methods, ensuring clarity in test outcomes.

* Update auto-generated file comments to clarify usage instructions

- Modified comments in multiple auto-generated files to specify that they should not be edited manually and to provide the command for regenerating them using the GenerateEnums tool.
- This change enhances clarity for developers working with generated files, ensuring proper usage and maintenance.

* Refactor Field class and enhance error handling in StObject

- Updated the Field class to use a private backing field for Values, improving encapsulation and lazy initialization.
- Enhanced error handling in StObject by adding an exception for unregistered FromJson/FromParser dispatches.
- Improved Uint32's FromJson method to include range validation for long values and ensure proper parsing with invariant culture.
- Expanded unit tests to cover additional cases and improve assertions for field definitions and transaction types.

* Enhance Field class documentation and improve error handling in GenerateEnums tool

- Added comments in the Field class to clarify the thread-safety and idempotency of the FromJson and FromParser properties.
- Improved error handling in the GenerateEnums tool by adding checks for missing properties in the definitions.json file, ensuring a more robust file structure validation.
* feat: add 25 new XRPL transaction types, 7 ledger objects, and integration tests

Add models, converters, TxFormat, validation, and integration tests for:
- XChain Bridge (XLS-38d): 8 transaction types + 3 ledger objects
- Vault (XLS-65d): 6 transaction types + 1 ledger object
- Loan/LoanBroker (XLS-66d): 9 transaction types + 2 ledger objects
- DelegateSet (XLS-74d) + LedgerStateFix: 2 transaction types + 1 ledger object

* fix: add missing CurrencyConverter attributes to transaction models

Currency properties in XChain and Loan transaction models were missing
[JsonConverter(typeof(CurrencyConverter))] attributes, causing XRP amounts
to serialize as objects instead of strings — leading to invalidTransaction
errors. Also fix VaultClawback test to set asfAllowTrustLineClawback flag.

* fix: VL-encode AccountID in XChainBridgeType and skip unavailable tests

XChainBridge compound type was writing raw 20-byte AccountID fields
without VL length prefix, causing rippled to reject blobs with
"Invalid STAccount size". Now matches rippled's STXChainBridge::add()
serialization format.

Mark integration tests [Ignore] for amendments not available on
rippled 3.0.0 standalone: Loan, DelegateKeys, LedgerStateFix,
XChainBridge (requires sidechain), VaultCreate_WithAsset2 (Asset2
field unsupported), VaultClawback (XRP vaults not clawback-eligible).

* fix: improve error handling, XChainBridge tests, and add bridge documentation

- Fix error messages to include error_exception from rippled responses
  (RequestManager.cs, XrplErrorClassifier.cs)
- Fix nullable request fields (AccountObjects.Limit, DeletionBlockersOnly,
  AccountOffers.Strict) to prevent invalidParams errors on rippled 3.1.x
- Fix XChainBridge XRP tests: use genesis account as IssuingChainDoor
- Add IOU-IOU bridge tests with DefaultRipple, TrustLine setup, token issuance
- Fix XChainBridgeType binary size assertions after VL-encoding fix
- Update CI rippled config: unveto XChainBridge/SingleAssetVault/LendingProtocol,
  comment out removed Batch amendment
- Add [Ignore] on tests for removed/unavailable amendments (Batch, DelegateSet,
  Loan, LedgerStateFix) with explanatory messages
- Add Cross-Chain Bridge Guide documentation (EN + RU) to DocFx

* chore: add .claude/settings.local.json to .gitignore

* fix: rename DelegateSet.Delegate to Authorize and add LODelegate verification

- Fix DelegateSet model: field "Delegate" → "Authorize" to match rippled protocol
- Update validation to check for "Authorize" field
- Add LODelegate ledger object verification in integration tests via account_objects
- Verify Account, Delegate, Permissions fields and PermissionValue correctness

* feat: add LedgerStateFix to Autofill reserve fee logic

LedgerStateFix requires a special transaction cost >= owner reserve
(0.2 XRP), similar to AccountDelete and AMMCreate. Added it to
IsReserveFeeTxNeed() so Autofill handles the fee automatically.
Updated test to use fail_hard and rely on Autofill for fee.

* fix: rewrite NumberType to 12-byte format and fix Loan integration tests

NumberType was writing 8 bytes (raw ulong) but rippled expects 12 bytes
(8 bytes int64 mantissa + 4 bytes int32 exponent). This caused
`invalid SerialIter geti32` errors on LoanSet submission.

Key changes:
- NumberType: 12-byte serialization with mantissa normalized to [10^18, MaxValue]
- LoanSet: CounterpartySignature co-signing with fee tripling
- LoanBrokerSet/LoanSet/LoanManage/LoanPay: field corrections per XLS-66 spec
- TxFormat: corrected field requirements for Loan transaction types
- Integration tests: all 8 Loan tests passing (broker, loan, pay, delete)

* docs: add Lending Protocol guide and update CHANGES.md

Add comprehensive documentation for the XRPL Lending Protocol (XLS-66d):
- LendingProtocol-Guide.md (English) and LendingProtocol-Guide.ru.md (Russian)
- Covers: broker setup, vault funding, loan creation, CounterpartySignature
  co-signing flow, Number type encoding, common errors, best practices
- Update CHANGES.md with all new transaction types, ledger objects, and fixes
- Add Lending Protocol Guide to DocFx table of contents

* feat: add LoanSigningHelper with V1/V2/V3 multi-party signing patterns

Implement three signing patterns for LoanSet CounterpartySignature
analogous to Batch signing (XLS-66d):
- V1 (automatic): both keys available locally
- V2 (parallel): independent signing + CombineLoanSignatures merge
- V3 (sequential): borrower signs first via SignAsLoanCounterparty,
  broker completes via LoanSigningHelper.BrokerSign

Add SignAsLoanCounterparty() to XrplWallet for borrower partial signing.
Add V2/V3 integration tests (10 total Loan tests passing).
Update documentation with all three signing patterns.

* refactor: move LoanSet fee calculation from LoanSigningHelper to Autofill

Fee for CounterpartySignature overhead is now computed in
CalculateBaseFeeForType (baseFee * 2) alongside EscrowFinish and Batch
fee logic. Removed adjustFee parameter from PrepareForSigning.

* fix: enable VaultCreate_WithIOU and VaultClawback tests

- Replace TestVaultCreate_WithAsset2 with TestVaultCreate_WithIOU
  (Asset2 not supported in VaultCreate on rippled 3.1.3)
- Remove Asset2 from VaultCreate TxFormat
- Rewrite TestVaultClawback_Basic to use IOU vault with proper setup:
  DefaultRipple, AllowTrustLineClawback, TrustLine, Payment, then
  VaultDeposit before clawback
- All 8 Vault tests now pass

* fix: audit Validate methods, fix WasLockingChainSend type, add Vault docs

- Audit all 25 Validate methods against xrpl.org documentation
- VaultClawback: Holder field changed from Optional to Required in TxFormat
- XChainAddAccountCreateAttestation: add missing OtherChainSource field
- XChainAddClaimAttestation: add WasLockingChainSend validation
- WasLockingChainSend changed from int to byte (UInt8, 0/1 values)
- DelegateSet: rename Authorize to Delegate (PascalCase, no keyword conflict)
- LOVault: add VaultDataFormat, VaultCreateFlags, VaultLedgerFlags, DataParsed
- VaultCreate/VaultSet/VaultWithdraw: add Scale, WithdrawalPolicy, Destination fields
- LOLoan/LOLoanBroker: relax STNumber null-field assertions (rippled omits zero defaults)
- Add Vault Guide documentation (EN + RU)

* fix: address CodeRabbitAI review findings on PR #6

- XChainBridgeType: add 20-byte AccountID length validation in FromParser
- NumberType: replace decimal with BigInteger to prevent OverflowException
- RequestManager: include ErrorException in error detection gate
- TestLoanSetEncode: replace Console.WriteLine with proper assertions
- VaultWithdraw/VaultClawback: add missing CurrencyConverter attributes
- XrplWallet: validate SigningPubKey before counterparty signing
- LoanSigningHelper: verify SigningPubKey match and guard against overwrite
- TestILoanBase: isolate mutable dicts in V2 signing, replace delay with polling
- Autofill: use IsReserveFeeTxNeed helper for fee cap bypass
- LendingProtocol docs: remove contradictory fee advice
- TxFormat: add CounterpartySignature as Optional for LoanSet
- LoanManage: add tfLoanImpair/tfLoanUnimpair mutual exclusion validation
- LoanPay: add tfLoanOverpayment/tfLoanFullPayment/tfLoanLatePayment exclusion
- DelegateSet: full Permissions validation (shape, max 10, non-delegable, uniqueness)
- LoanBrokerCoverClawback: at-least-one of LoanBrokerID/Amount validation

* feat: add MPT support in BinaryCodec STIssue and integration tests

Rewrite Issue.cs to support MPT binary format matching rippled's
STIssue serialization: account(20) + noAccount(20) + sequence(4).
Add Hash192 type for 24-byte MPTokenIssuanceID. Add MptIssuanceId
to IssuedCurrency model and IssuedCurrencyConverter.

Integration tests:
- Vault: TestVaultClawback_MPT (MPT-backed vault lifecycle)
- Loan: TestLoanBrokerSet_MPT, TestLoanSet_MPT, TestLoanPay_MPT
- AMM: TestAMMCreate_MptXrpPool_RejectedByProtocol (XLS-62 pending)

Unit tests: TestIssueMpt (encode/decode roundtrip, binary match)

* fix: address code review findings from CodeRabbitAI

NumberType.cs:
- Fix doc comments: mantissa range is [10^18, long.MaxValue], not [10^15, 10^16-1]
- Add exponent/mantissa invariant validation in FromParser
- Replace decimal.Parse with BigInteger-based manual parsing to handle
  full XRPL exponent range (±32768) without overflow

LendingProtocol-Guide.md / .ru.md:
- Add ```text language tag to ASCII diagram blocks (MD040)
- Fix V2 signing example: use separate dicts per signer to avoid
  mutation of shared payload
- Remove contradictory fee statement in RU guide (Autofill handles it)

DelegateSet.cs:
- Add full validation in IList<object> branch matching JsonElement path
  (entry shape, PermissionValue, non-delegable types, duplicates)

LoanManage.cs:
- Require exactly one action flag (tfLoanDefault|tfLoanImpair|tfLoanUnimpair)
- ParseFlags now throws FormatException instead of silently returning 0
- Reject empty/whitespace LoanID strings

VaultWithdraw.cs:
- Validate VaultID as Hash256 (64 hex chars)

* fix: IsMpt empty string check, LoanManage require Flags

- IssuedCurrency.IsMpt()/ToString(): use IsNullOrWhiteSpace instead of
  null check to reject empty/whitespace MptIssuanceId
- LoanManage validation: Flags is now mandatory (exactly one action flag
  required), not just validated when present

* feat: add missing stream subscriptions and RPC methods

Fix validationReceived handler bug (was calling OnManifestReceived).
Add 3 missing streams: manifestReceived, bookChanges, serverStatus.
Add 5 RPC methods: vault_info, channel_authorize, channel_verify,
server_definitions, transaction_entry.
Remove dead code ValidationsStream.cs.

* fix: pass client parameter to TryFillAccounts, init Changes list

TryFillAccounts was using static client field before it was assigned.
Initialize BookChangesStream.Changes to empty list to avoid null.

* fix: null-coalesce Changes setter to prevent NRE from deserialization

System.Text.Json sets null on "changes": null, overriding initializer.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

Refactors and auto-generates XRPL binary codec enums/fields, adds new serialized types and stricter Amount handling, and updates definitions. Introduces models, validation, converters, client APIs/events, and signing helpers for XChain Bridge, Vault, Lending, DelegateSet, and LedgerStateFix. Expands unit/integration tests, adds documentation, CI tweaks, and version bumps.

Changes

Binary Codec Refactor and New Wire Types

Layer / File(s) Summary
Enum infrastructure split and regeneration
Base/Xrpl.BinaryCodec/Enums/Field.cs, .../Enums/EngineResult.cs, .../Enums/TransactionType.cs, .../Enums/LedgerEntryType.cs, .../Enums/*.Generated.cs
Enums switched to partial classes; large static declarations moved into generated files for EngineResult, TransactionType, LedgerEntryType, and Field groups.
Wire type additions and dispatch
.../Enums/FieldType.cs, .../Enums/NumberField.cs, .../Enums/Int32Field.cs, .../Enums/Int64Field.cs, .../Enums/XChainBridgeField.cs, .../Types/StObject.cs
Adds Number, Int32, Int64, XChainBridge field kinds and lazy dispatch via a centralized table in StObject.
New serialized types
.../Types/NumberType.cs, .../Types/Int32Type.cs, .../Types/Int64Type.cs, .../Types/XChainBridgeType.cs
Implements encoding/decoding for Number (mantissa/exponent), signed Int32/Int64, and XChainBridge composite.
Issue and Amount adjustments
.../Types/Issue.cs, .../Types/AmountValue.cs
Adds MPT Issue form (mpt_issuance_id) across binary/JSON; enforces integer and max limit for native XRP amounts.
Definitions and generator tooling
.../Enums/definitions.json, Tools/GenerateEnums/*
Extends XRPL codec definitions (Loan/Vault/XChain fields and types) and adds a generator to produce partial enum/field files with change detection.
Project/package updates
Base/Xrpl.BinaryCodec/Xrpl.BinaryCodec.csproj, Xrpl/Xrpl.csproj
Bumps package versions to 10.4.0.0.

XChain Bridge, Vault, Lending, DelegateSet, and Admin Transactions

Layer / File(s) Summary
Converters and common models
Xrpl/Client/Json/Converters/*, Xrpl/Models/Common/*
CurrencyConverter handles MPT; adds XChain bridge/attestation models and permission wrappers; IssuedCurrency gains MPT helpers.
New ledger-entry DTOs
Xrpl/Models/Ledger/*
Adds LOBridge, LOXChain*ClaimID, LOVault, LOLoanBroker, LOLoan, LODelegate models with JSON bindings.
Transaction DTOs and validation
Xrpl/Models/Transactions/*
Implements request/response/validation for XChain* (bridge/claim/account-create/attest), Vault* (create/set/delete/deposit/withdraw/clawback), Loan* and LoanBroker*, DelegateSet, LedgerStateFix; extends TxFormat and central Validate switch.
Client API surface and streams
Xrpl/Client/IXrplClient.cs, Xrpl/Client/connection.cs, Xrpl/Client/RequestManager.cs, Xrpl/Client/Exceptions/XrplErrorClassifier.cs
Adds methods: ServerDefinitions, VaultInfo, TransactionEntry, ChannelAuthorize/Verify; adds stream events for validation, manifest, bookChanges, serverStatus; improves error message sourcing.
Wallet helpers and autofill
Xrpl/Wallet/LoanSigningHelper.cs, Xrpl/Wallet/XrplWallet.cs, Xrpl/Sugar/Autofill.cs
Introduces LoanSet multi-party signing (V1/V2/V3) and counterparty-signing; adjusts fee rules (LoanSet base fee, reserve-fee for AMMCreate/LedgerStateFix).
Enums in SDK
Xrpl/Models/Enums/*
Extends TransactionType and LedgerEntryType for new features.

Tests Expansion (Unit and Integration)

Layer / File(s) Summary
Codec unit tests
Tests/Xrpl.BinaryCodec.Test/*
Covers parser/serializer VL-length, field ids/dispatch, enum parity, Amount, NumberType, Int32/Int64, Issue MPT, XChainBridgeType, LoanSet encode.
Client JSON tests
Tests/Xrpl.Tests/Client/Json/*
Round-trips transaction requests via interface and verifies request serialization shapes.
Subscription/event tests
Tests/Xrpl.Tests/Client/TestSubscribe.cs, Tests/TestsClients/Test.ClonsoleApp/Program.cs
Adds async tests for validation/manifest/bookChanges/serverStatus streams; console app exercises websocket and bookChanges.
Integration tests: XChain, Vault, Lending, Admin
Tests/Xrpl.Tests/Integration/transactions/*
End-to-end flows for XChain bridges (XRP/IOU), Vault lifecycle + clawback (IOU/MPT), Lending lifecycle with signing modes, LedgerStateFix behavior, AMMCreate with MPT rejection; marks Batch tests ignored.

Docs, CI, and Config

Layer / File(s) Summary
Guides and TOC
DocFx/*Guide*.md, DocFx/toc.yml, CLAUDE.md, CHANGES.md
Adds comprehensive guides for XChain Bridge, Vault, Lending (EN/RU), updates TOC and changelog; repository overview.
CI/config updates
.github/workflows/nuget.release.yml, .ci-config/rippled.cfg, .gitignore, XrplCSharp.sln
Workflow permissions, rippled cfg amendments (remove Batch, add fixCleanup3_1_3), ignore Claude settings, add Tools project.

Sequence Diagram(s)

sequenceDiagram
  actor Borrower as Borrower Wallet
  actor Broker as Broker Wallet
  participant SDK as XrplCSharp (LoanSigningHelper)
  participant Node as rippled

  Note over SDK,Node: LoanSet V3 sequential signing
  Borrower->>SDK: SignAsLoanCounterparty(LoanSet JSON)
  SDK->>SDK: EncodeForSigning(preimage)
  SDK-->>Borrower: Partial blob (CounterpartySignature)
  Broker->>SDK: BrokerSign(partial blob)
  SDK->>SDK: Verify SigningPubKey matches broker
  SDK->>SDK: EncodeForSigning(preimage)
  SDK-->>Broker: Fully signed blob (TxnSignature + CounterpartySignature)
  Broker->>Node: submit(tx_blob)
  Node-->>Broker: submit result (hash)
  Broker->>Node: tx(hash) wait for meta
  Node-->>Broker: meta with Created Loan ID
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Poem

A rabbit taps the ledger’s tree,
New bridges span from chain to sea.
Vaults unlock with silky clicks,
Loans now dance in numbered ticks.
Two pens sign one tiny byte—
Hop! It’s valid. Hash in sight.
Carrots committed. All feels right. 🥕✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

Copy link
Copy Markdown

@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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (2)
Tests/TestsClients/Test.ClonsoleApp/Program.cs (1)

444-449: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Do not silently swallow exceptions in account funding flow.

The empty catch masks why balance fetch failed and makes funding behavior hard to troubleshoot. At minimum, log the exception before fallback funding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/TestsClients/Test.ClonsoleApp/Program.cs` around lines 444 - 449, The
empty catch in Program.Main around the account funding flow swallows exceptions;
update the catch to log the exception before proceeding to the fallback funding
call: inside the catch block that currently catches Exception e, write a
descriptive error using the available logger or Console.Error (e.g., include
xrplWallet.ClassicAddress, e.Message and e.StackTrace), then continue to call
xrplClient.FundWallet(xrplWallet) as before; reference the catch around the
balance fetch and the xrplClient.FundWallet/xrplWallet/funded variables to
locate where to add the logging.
Base/Xrpl.BinaryCodec/Types/Issue.cs (1)

51-56: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject non-native currency without issuer in constructor.

Issue(Currency, AccountId) can create an invalid IOU issue (issuer == null) that later crashes in ToBytes (Line 105-107).

Suggested fix
 public Issue(Currency currency, AccountId issuer)
 {
     Currency = currency ?? Currency.Xrp;
-    Issuer = issuer;
+    if (!Currency.IsNative && issuer is null)
+        throw new ArgumentNullException(nameof(issuer), "Issuer is required for non-native currency issues.");
+    Issuer = issuer;
     MptIssuanceId = null;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Base/Xrpl.BinaryCodec/Types/Issue.cs` around lines 51 - 56, The Issue
constructor allows creating a non-native currency with a null issuer which later
causes ToBytes to crash; update the Issue(Currency currency, AccountId issuer)
constructor to validate inputs and throw a meaningful exception when a non-XRP
currency is provided without an issuer (e.g., if (currency != Currency.Xrp &&
issuer == null) throw new ArgumentNullException(nameof(issuer))), keep existing
behavior for Currency.Xrp (allow null issuer or set to null), and ensure
MptIssuanceId initialization remains unchanged; reference the Issue constructor
and the ToBytes method to locate the related logic.
🟠 Major comments (23)
Tests/Xrpl.BinaryCodec.Test/Types/TestUInt.cs-22-23 (1)

22-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Comparison assertions are reversed and will fail deterministically.

Line 22, Line 23, Line 41, and Line 42 invert operand order relative to the expected values (124, 123, 125), so these checks are always false.

Proposed fix
-            Assert.IsLessThan(v1, v2);
-            Assert.IsGreaterThan(v2, v1);
+            Assert.IsGreaterThan(v1, v2);
+            Assert.IsLessThan(v2, v1);

-            Assert.IsLessThan(125u, v);
-            Assert.IsGreaterThan(123u, v);
+            Assert.IsGreaterThan(125u, v);
+            Assert.IsLessThan(123u, v);

Also applies to: 41-42

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.BinaryCodec.Test/Types/TestUInt.cs` around lines 22 - 23, The
assertions in TestUInt.cs use the wrong operand order: swap the arguments to
Assert.IsLessThan and Assert.IsGreaterThan so they compare the expected smaller
value first and the larger value second (e.g., change Assert.IsLessThan(v1, v2)
to Assert.IsLessThan(v2, v1) and Assert.IsGreaterThan(v2, v1) to
Assert.IsGreaterThan(v1, v2)); apply the same swap for the two assertions around
lines 41–42 that also use Assert.IsLessThan/IsGreaterThan involving v1 and v2.
Base/Xrpl.BinaryCodec/Types/AmountValue.cs-271-279 (1)

271-279: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Cast to ulong can throw unhandled OverflowException before validation.

Line 277 casts Math.Abs(parsed) to ulong before the bounds check on line 278. Inputs larger than ulong.MaxValue (which decimal can represent) will throw OverflowException instead of the intended BinaryCodecException. Move the MaxNativeDrops check before the cast, or use decimal.ToUInt64() with proper overflow handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Base/Xrpl.BinaryCodec/Types/AmountValue.cs` around lines 271 - 279, The cast
of Math.Abs(parsed) to ulong in AmountValue (setting Mantissa) can throw
OverflowException for decimals > ulong.MaxValue; reorder or change the logic so
you validate parsed against MaxNativeDrops and ulong limits before casting:
check Math.Abs(parsed) <= MaxNativeDrops and <= ulong.MaxValue (or use
decimal.ToUInt64 inside a try/catch) and only then assign Mantissa = (ulong)...;
keep setting IsNegative = parsed < 0 and throw BinaryCodecException on
out-of-range values instead of allowing OverflowException.
Base/Xrpl.BinaryCodec/Types/Int64Type.cs-24-39 (1)

24-39: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add culture-invariant parsing and null-safety guard to Int64Type JSON handling.

The FromJson method lacks a null guard and uses culture-sensitive ToString() and long.Parse() calls. When running in locales with different number formatting (e.g., using comma as decimal separator), these operations produce non-deterministic JSON output and parsing failures. Additionally, a null token parameter throws an unhelpful NullReferenceException instead of a clear ArgumentNullException.

Suggested patch
 using System;
+using System.Globalization;
 using System.Text.Json;
 using System.Text.Json.Nodes;
@@
-        public JsonNode ToJson() => JsonValue.Create(Value.ToString());
+        public JsonNode ToJson() => JsonValue.Create(Value.ToString(CultureInfo.InvariantCulture));

-        public override string ToString() => Value.ToString();
+        public override string ToString() => Value.ToString(CultureInfo.InvariantCulture);
@@
         public static Int64Type FromJson(JsonNode token)
         {
+            if (token is null) throw new ArgumentNullException(nameof(token));
             JsonValueKind kind = token.GetValueKind();
@@
             if (kind == JsonValueKind.String)
             {
-                return new Int64Type(long.Parse(token.GetValue<string>()));
+                string raw = token.GetValue<string>();
+                if (!long.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out long parsed))
+                {
+                    throw new FormatException($"Cannot parse Int64 from JSON string '{raw}'.");
+                }
+                return new Int64Type(parsed);
             }

Similar culture-sensitive patterns exist in Uint64.cs, Int32Type.cs, AmountValue.cs, and other numeric types and should be addressed consistently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Base/Xrpl.BinaryCodec/Types/Int64Type.cs` around lines 24 - 39, Add a
null-check and culture-invariant formatting/parsing to Int64Type: in FromJson
add a guard that throws ArgumentNullException if token is null; when handling
JsonValueKind.Number use token.GetValue<long>() as before, and when handling
JsonValueKind.String parse using long.Parse(..., NumberStyles.Integer,
CultureInfo.InvariantCulture) (or TryParse with the same culture) and ensure
ToJson() and ToString() use Value.ToString(CultureInfo.InvariantCulture) instead
of the culture-sensitive overload; apply the same pattern to the analogous
numeric types (Uint64, Int32Type, AmountValue, etc.) so JSON output and parsing
are deterministic and null-safe.
Xrpl/Models/Transactions/LoanBrokerSet.cs-133-139 (1)

133-139: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validation incorrectly requires VaultID for all LoanBrokerSet flows.

The validator contradicts this model’s own contract: modify flow can be identified by LoanBrokerID, but current logic rejects it unless VaultID is present.

Proposed fix
 public static async Task ValidateLoanBrokerSet(Dictionary<string, object> tx)
 {
     await Common.ValidateBaseTransaction(tx);

-    if (!tx.TryGetValue("VaultID", out var vaultId) || vaultId is not string)
-        throw new ValidationException("LoanBrokerSet: missing field VaultID");
+    bool hasVaultId = tx.TryGetValue("VaultID", out var vaultId) &&
+                      vaultId is string vaultIdStr &&
+                      !string.IsNullOrWhiteSpace(vaultIdStr);
+
+    bool hasLoanBrokerId = tx.TryGetValue("LoanBrokerID", out var loanBrokerId) &&
+                           loanBrokerId is string loanBrokerIdStr &&
+                           !string.IsNullOrWhiteSpace(loanBrokerIdStr);
+
+    if (!hasVaultId && !hasLoanBrokerId)
+        throw new ValidationException("LoanBrokerSet: missing field VaultID or LoanBrokerID");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/LoanBrokerSet.cs` around lines 133 - 139, The
ValidateLoanBrokerSet validator incorrectly requires VaultID for all
LoanBrokerSet transactions; update ValidateLoanBrokerSet to allow either a
create flow (require VaultID) or a modify flow (require LoanBrokerID) by
checking tx for LoanBrokerID when VaultID is absent and only throwing
ValidationException if neither is present; reference the ValidateLoanBrokerSet
method and the VaultID and LoanBrokerID keys in the tx dictionary when
implementing the conditional validation.
Tools/GenerateEnums/Program.cs-448-452 (1)

448-452: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast on unknown field types instead of silently skipping.

Skipping unknown types can generate an incomplete codec surface without failing CI, which is risky for release integrity.

Proposed fix
 if (!TypeToFieldClass.ContainsKey(typeName))
 {
-    Console.Error.WriteLine($"  ! Unknown field type '{typeName}' for field '{name}', skipping.");
-    continue;
+    throw new InvalidOperationException(
+        $"Unknown field type '{typeName}' for field '{name}'. Update TypeToFieldClass/TypeToFileName mappings.");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tools/GenerateEnums/Program.cs` around lines 448 - 452, The code currently
silently skips unknown field types by checking
TypeToFieldClass.ContainsKey(typeName) and writing to Console.Error then
continuing; instead fail fast so CI catches missing mappings: replace the
Console.Error.WriteLine + continue with a hard failure (throw a descriptive
exception or call Environment.Exit(1)) that includes typeName and field name, so
the failure occurs immediately when TypeToFieldClass.ContainsKey(typeName) is
false (reference the TypeToFieldClass.ContainsKey check, the typeName and name
variables, and the existing Console.Error.WriteLine/continue location).
Tools/GenerateEnums/Program.cs-301-316 (1)

301-316: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat duplicate nth conflicts as hard errors.

The generator currently reports duplicate nth values but still proceeds, allowing invalid field tables to be emitted.

Proposed fix
 private static void ValidateFields(Dictionary<string, List<FieldEntry>> grouped)
 {
+    bool hasConflicts = false;
     foreach (var (typeName, fields) in grouped)
     {
         var duplicateNths = fields
             .GroupBy(f => f.Nth)
             .Where(g => g.Count() > 1)
             .ToList();

         foreach (var dup in duplicateNths)
         {
             string names = string.Join(", ", dup.Select(f => f.Name));
             Console.Error.WriteLine($"  ! CONFLICT: Duplicate nth={dup.Key} in {typeName}: {names}");
+            hasConflicts = true;
         }
     }
+
+    if (hasConflicts)
+        throw new InvalidOperationException("definitions.json contains duplicate field nth values.");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tools/GenerateEnums/Program.cs` around lines 301 - 316, ValidateFields
currently logs duplicate nth conflicts via Console.Error.WriteLine but
continues; change it to treat duplicates as hard errors by throwing an exception
(e.g., InvalidOperationException) or terminating process after logging so
generation stops. In the ValidateFields method, after detecting duplicateNths
(and after constructing the names/message for each dup), either aggregate
messages and throw a single InvalidOperationException including
typeName/dup.Key/names (so the generator halts) or call Environment.Exit(1)
after writing errors; ensure you reference ValidateFields, the duplicateNths/dup
variable and FieldEntry.Nth/Name when building the error text so the exception
contains the same conflict details that were previously logged.
Tests/Xrpl.BinaryCodec.Test/TestEnumParity.cs-12-149 (1)

12-149: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rename test methods to follow required TestU/TestI prefixes.

Test methods in this file currently use Test... naming, but not the required TestU... (unit) or TestI... (integration) prefixes, which can break test filtering conventions.

As per coding guidelines: "**/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.BinaryCodec.Test/TestEnumParity.cs` around lines 12 - 149, The
test methods in TestEnumParity.cs use the "Test..." prefix but must follow the
repo convention of "TestU..." for unit tests; rename each test method (e.g.,
TestTransactionType_AllNamesResolvable, TestTransactionType_OrdinalLookup,
TestLedgerEntryType_AllNamesResolvable, TestLedgerEntryType_OrdinalLookup,
TestEngineResult_SuccessAndFailureCodes, TestEngineResult_ShouldClaimFee,
TestEngineResult_NewXChainCodes, TestEngineResult_NewAmmCodes) to start with
"TestU" (for example TestUTransactionType_AllNamesResolvable) while keeping the
[TestMethod] attributes and method bodies unchanged so test discovery and
behavior remain the same.
Xrpl/Wallet/XrplWallet.cs-1032-1034 (1)

1032-1034: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject Signers for counterparty single-sign flow.

SignAsLoanCounterparty removes TxnSignature but currently allows Signers to remain. That can produce a mismatched preimage/signature flow for LoanSet co-signing.

Suggested fix
// Remove existing signatures but keep SigningPubKey (broker's)
+if (tx["Signers"] != null)
+    throw new ValidationException("LoanSet for counterparty signing must not include Signers.");
+
tx.Remove("CounterpartySignature");
tx.Remove("TxnSignature");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Wallet/XrplWallet.cs` around lines 1032 - 1034, In
SignAsLoanCounterparty (XrplWallet.cs) the method currently removes
"CounterpartySignature" and "TxnSignature" but leaves "Signers", which allows a
Signers array to produce mismatched preimage/signature flows; update the method
to also reject/remove any existing "Signers" entry from the transaction (call
tx.Remove("Signers") or equivalent) so the counterparty single-sign flow cannot
include co-signatures.
Tests/Xrpl.Tests/Integration/transactions/TestILedgerStateFix.cs-15-55 (1)

15-55: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard this integration test on amendment availability to avoid flaky failures.

This test only accepts tesSUCCESS/tecFAILED_PROCESSING, but it can legitimately fail for environments where the LedgerStateFix amendment is not enabled. Add a pre-check and mark inconclusive/skip when unsupported.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestILedgerStateFix.cs` around
lines 15 - 55, Add a runtime guard in TestLedgerStateFix_Basic that queries the
test XRPL node/client for enabled amendments and skips the test if the
LedgerStateFix amendment is not present: use the existing static client (set up
in ClassInitializeAsync) to retrieve server/amendment info, check for the
"LedgerStateFix" amendment (or whatever exact amendment identifier your node
exposes), and call Assert.Inconclusive (or the MSTest skip mechanism) to mark
the test as skipped when the amendment is unavailable before attempting to fund
the wallet or submit the LedgerStateFix transaction.
Tests/Xrpl.Tests/Integration/transactions/TestIAMMCreateMpt.cs-115-120 (1)

115-120: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid asserting on exception message text for protocol rejection checks.

ex.Message.Contains("MPT") is fragile; prefer asserting structured error/result identifiers when available so tests stay stable across message wording changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestIAMMCreateMpt.cs` around lines
115 - 120, The test currently asserts on the free-form exception message inside
the catch (RippledException ex) block in TestIAMMCreateMpt.cs which is brittle;
change the assertion to check a structured error identifier exposed by
RippledException (for example use ex.ErrorCode or ex.Error /
ex.Result["error_code"] if available) or, if those properties are not present,
add a small accessor on RippledException that returns the protocol error code
and assert against that (e.g., Assert.AreEqual("temMPT", ex.ErrorCode)). Update
the catch block to use the structured field instead of
ex.Message.Contains("MPT") so the test validates the protocol error identifier
rather than message text.
Tests/TestsClients/Test.ClonsoleApp/Program.cs-718-729 (1)

718-729: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout/cancellation path to websocket wait loops.

Both loops can block forever when no event arrives, which can hang this client workflow indefinitely. Add a bounded timeout and fail/exit explicitly.

Also applies to: 772-783

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/TestsClients/Test.ClonsoleApp/Program.cs` around lines 718 - 729, The
waiting loops that spin on the shared isFinished flag inside the Task.Run lambda
(and the similar loop at the other occurrence) need a bounded
timeout/cancellation to avoid hanging; introduce a CancellationTokenSource with
a sensible timeout or accept a CancellationToken, use Task.WhenAny or pass the
token into Task.Delay(token) inside the while(!isFinished) loop so the delay can
be cancelled, and when the timeout triggers set isFinished (or throw/return) and
log/propagate an explicit timeout error so the client workflow fails fast
instead of blocking forever; update both the Task.Run async lambda that
references isFinished and the loop at the other occurrence (lines ~772-783) to
use the same cancellation/timeout pattern.
Xrpl/Models/Transactions/VaultDelete.cs-50-51 (1)

50-51: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject empty VaultID values in ValidateVaultDelete.

The current check accepts empty/whitespace strings, which should fail fast as invalid transaction input.

🔧 Suggested fix
-            if (!tx.TryGetValue("VaultID", out var vaultId) || vaultId is not string)
+            if (!tx.TryGetValue("VaultID", out var vaultId) ||
+                vaultId is not string vaultIdStr ||
+                string.IsNullOrWhiteSpace(vaultIdStr))
                 throw new ValidationException("VaultDelete: missing field VaultID");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/VaultDelete.cs` around lines 50 - 51, The
VaultDelete validation currently only checks presence/type of "VaultID" but
allows empty/whitespace values; update the ValidateVaultDelete logic in class
VaultDelete (the block that reads var vaultId) to cast vaultId to string and
reject empty or whitespace-only values using string.IsNullOrWhiteSpace (or trim
+ length check), throwing the same ValidationException("VaultDelete: missing
field VaultID") when the value is invalid so empty/whitespace VaultID is treated
as missing.
Xrpl/Models/Transactions/VaultSet.cs-90-92 (1)

90-92: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tighten VaultID validation to reject empty values and invalid optional field types.

Current check allows ""/whitespace VaultID, and optional fields can be non-string without early validation.

🔧 Suggested validation hardening
-            if (!tx.TryGetValue("VaultID", out var vaultId) || vaultId is not string)
+            if (!tx.TryGetValue("VaultID", out var vaultId) ||
+                vaultId is not string vaultIdStr ||
+                string.IsNullOrWhiteSpace(vaultIdStr))
                 throw new ValidationException("VaultSet: missing field VaultID");
+
+            if (tx.TryGetValue("Data", out var data) && data is not string)
+                throw new ValidationException("VaultSet: field Data must be a string");
+            if (tx.TryGetValue("AssetsMaximum", out var assetsMaximum) && assetsMaximum is not string)
+                throw new ValidationException("VaultSet: field AssetsMaximum must be a string");
+            if (tx.TryGetValue("DomainID", out var domainId) && domainId is not string)
+                throw new ValidationException("VaultSet: field DomainID must be a string");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/VaultSet.cs` around lines 90 - 92, The VaultSet
validation currently accepts empty/whitespace VaultID and allows optional fields
with wrong types; update the check in the VaultSet validation (the block using
tx.TryGetValue and throwing ValidationException) to require VaultID be a
non-empty, non-whitespace string (e.g., use string.IsNullOrWhiteSpace on the
cast string) and—where optional fields are read from tx—add early type checks
that throw a ValidationException if an optional field exists but is not a string
(use tx.TryGetValue(...) and validate the value is string before using it).
Ensure you reference the existing tx.TryGetValue/VaultID logic and throw
ValidationException with a clear message when validation fails.
Xrpl/Models/Transactions/LedgerStateFix.cs-57-63 (1)

57-63: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate Owner in ValidateLedgerStateFix.

Line 61 validates LedgerFixType, but Owner is never validated. Incomplete transactions can pass local validation unexpectedly.

💡 Suggested patch
 public static async Task ValidateLedgerStateFix(Dictionary<string, object> tx)
 {
     await Common.ValidateBaseTransaction(tx);

     if (!tx.TryGetValue("LedgerFixType", out var fixType) || fixType is null)
         throw new ValidationException("LedgerStateFix: missing field LedgerFixType");
+
+    if (!tx.TryGetValue("Owner", out var owner) || owner is not string)
+        throw new ValidationException("LedgerStateFix: missing field Owner");
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/LedgerStateFix.cs` around lines 57 - 63,
ValidateLedgerStateFix currently checks LedgerFixType but never ensures the
Owner field exists; update ValidateLedgerStateFix to also require "Owner" by
attempting tx.TryGetValue("Owner", out var owner) and throw a
ValidationException like "LedgerStateFix: missing field Owner" if missing or
null/empty, and where available call an existing address/account validator
(e.g., Common.ValidateAccount or other project validation helper) to validate
the Owner format; keep the existing Common.ValidateBaseTransaction call and add
this Owner presence/format validation after the LedgerFixType check.
Xrpl/Models/Transactions/XChainAddClaimAttestation.cs-173-199 (1)

173-199: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Complete attestation validation for Destination and WasLockingChainSend.

Destination is required by the model but not validated, and WasLockingChainSend should be validated as a byte value limited to 0 or 1.

Suggested fix
             if (!tx.TryGetValue("AttestationSignerAccount", out var signerAccount) || signerAccount is not string)
                 throw new ValidationException("XChainAddClaimAttestation: missing field AttestationSignerAccount");

+            if (!tx.TryGetValue("Destination", out var destination) || destination is not string)
+                throw new ValidationException("XChainAddClaimAttestation: missing field Destination");
+
             if (!tx.TryGetValue("OtherChainSource", out var source) || source is not string)
                 throw new ValidationException("XChainAddClaimAttestation: missing field OtherChainSource");
@@
-            if (!tx.TryGetValue("WasLockingChainSend", out var wasLocking) || wasLocking is null)
+            if (!tx.TryGetValue("WasLockingChainSend", out var wasLocking) || wasLocking is not byte flag || (flag != 0 && flag != 1))
                 throw new ValidationException("XChainAddClaimAttestation: missing field WasLockingChainSend");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/XChainAddClaimAttestation.cs` around lines 173 -
199, The validation block in XChainAddClaimAttestation is missing a check for
the required Destination field and does not enforce WasLockingChainSend to be a
byte 0/1; update the validation inside the XChainAddClaimAttestation
parsing/validation routine to (1) verify tx contains "Destination" and that it
is a string (or the expected type) and throw a ValidationException with the same
naming pattern if absent/invalid, and (2) ensure "WasLockingChainSend" exists
and its value is a numeric/byte type and equals 0 or 1 (throw a
ValidationException if out of range or wrong type). Ensure you reference the
same exception messages style used elsewhere in this method.
Xrpl/Models/Transactions/VaultCreate.cs-96-98 (1)

96-98: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add CurrencyConverter to the Amount property in both request and response models.

The Currency type is polymorphic and can represent XRP (as a string), MPT (as an object with mpt_issuance_id), or issued tokens (as an object with currency, issuer, value). Without the converter, serialization/deserialization will fail for non-XRP amounts. Related vault transaction models (VaultClawback, VaultWithdraw) correctly use this converter on their Amount fields.

Suggested fix
         [JsonPropertyName("Amount")]
+        [JsonConverter(typeof(CurrencyConverter))]
         public Currency Amount { get; set; }

Apply to both VaultCreate (lines 96-97) and VaultCreateResponse (lines 133-134).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/VaultCreate.cs` around lines 96 - 98, Add the
JsonConverter attribute to the Amount property in both VaultCreate and
VaultCreateResponse so the polymorphic Currency type is properly (de)serialized:
on the Amount property in class VaultCreate and the Amount property in class
VaultCreateResponse, add [JsonConverter(typeof(CurrencyConverter))] (or the
project's equivalent CurrencyConverter type) so XRP, MPT and issued-token shapes
are handled correctly.
Base/Xrpl.BinaryCodec/Types/NumberType.cs-206-213 (1)

206-213: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Change expValue to long to prevent integer overflow in exponent parsing.

The line expValue = expValue * 10 + (str[pos] - '0') using int can overflow in unchecked arithmetic before the > 100000 cap check evaluates. A malformed exponent string with enough digits will cause the value to wrap, bypassing validation. Use long instead and cast the result to int when assigning to sciExponent:

Suggested fix
-                int expValue = 0;
+                long expValue = 0;
                 bool hasExpDigits = false;
                 while (pos < str.Length && char.IsDigit(str[pos]))
                 {
                     expValue = expValue * 10 + (str[pos] - '0');
                     if (expValue > 100000) // sanity cap
                         throw new FormatException($"NumberType: exponent too large in '{str}'");
                     hasExpDigits = true;
                     pos++;
                 }
@@
-                sciExponent = expNegative ? -expValue : expValue;
+                sciExponent = (int)(expNegative ? -expValue : expValue);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Base/Xrpl.BinaryCodec/Types/NumberType.cs` around lines 206 - 213, The
exponent parsing uses an int variable expValue which can overflow during
expValue = expValue * 10 + (str[pos] - '0') before the > 100000 check; change
expValue's type to long in the loop that accumulates the exponent (where
expValue and hasExpDigits are declared and updated) to prevent wrapping, keep
the existing sanity cap check against 100000, and when assigning the final value
to sciExponent cast or clamp the long to int (e.g., (int)expValue) so
sciExponent remains an int.
Tests/Xrpl.Tests/Integration/transactions/TestIVault.cs-35-625 (1)

35-625: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rename integration test methods to use the TestI prefix.

Current method names don’t follow the required integration-test naming convention for filtering.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestIVault.cs` around lines 35 -
625, The test methods in this file use the TestU/Test... naming instead of the
required integration-test prefix; rename each public async Task method that
starts with TestVault... (e.g., TestVaultCreate_Basic, TestVaultCreate_WithIOU,
TestVaultCreate_WithData, TestVaultCreate_WithOptionalFields,
TestVaultDeposit_Basic, TestVaultWithdraw_Basic,
TestVaultWithdraw_WithDestination, TestVaultSet_UpdateData,
TestVaultSet_UpdateAssetsMaximum, TestVaultDelete_Empty,
TestVaultClawback_Basic, TestVaultLedgerEntry_VerifyFields,
TestVaultClawback_MPT, TestVaultInfo_Basic) to start with TestI (e.g.,
TestIVaultCreate_Basic) so they follow the integration-test naming convention;
update each method identifier consistently (keeping signatures and attributes
unchanged) and run tests to ensure no external references break.
Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridge.cs-31-377 (1)

31-377: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Rename integration test methods to TestI* for filterability.

Current method names (TestXChain...) don’t follow the required integration prefix, which will break naming-based test filters.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridge.cs` around lines
31 - 377, The test methods in this file (e.g., TestXChainCreateBridge_Basic,
TestXChainCreateClaimID_Basic, TestXChainModifyBridge_UpdateSignatureReward,
TestXChainCommit_Basic, TestXChainAccountCreateCommit_Basic,
TestXChainCreateBridge_Iou, TestXChainCreateClaimID_Iou, TestXChainCommit_Iou,
TestXChainModifyBridge_Iou) must be renamed to use the TestI prefix so they
match integration-test filters; rename each method identifier from TestXChain...
to TestI... (preserving the rest of the name and [TestMethod] attributes) and
update any references/calls to those method names if present so the test
discovery/filtering picks them up.
Xrpl/Models/Transactions/XChainAddAccountCreateAttestation.cs-192-193 (1)

192-193: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate numeric/range constraints for XChainAccountCreateCount and WasLockingChainSend.

Line 192 and Line 219 only enforce non-null. Non-numeric values (or WasLockingChainSend outside 0/1) currently pass local validation.

Suggested fix
+using System;
+using System.Text.Json;
-            if (!tx.TryGetValue("XChainAccountCreateCount", out var count) || count is null)
+            if (!tx.TryGetValue("XChainAccountCreateCount", out var count) || !TryGetUInt64(count, out _))
                 throw new ValidationException("XChainAddAccountCreateAttestation: missing field XChainAccountCreateCount");
...
-            if (!tx.TryGetValue("WasLockingChainSend", out var wasLocking) || wasLocking is null)
+            if (!tx.TryGetValue("WasLockingChainSend", out var wasLocking) || !TryGetByte(wasLocking, out var chainFlag) || (chainFlag != 0 && chainFlag != 1))
                 throw new ValidationException("XChainAddAccountCreateAttestation: missing field WasLockingChainSend");
private static bool TryGetUInt64(object value, out ulong parsed)
{
    switch (value)
    {
        case ulong u: parsed = u; return true;
        case long l when l >= 0: parsed = (ulong)l; return true;
        case int i when i >= 0: parsed = (ulong)i; return true;
        case string s when ulong.TryParse(s, out var us): parsed = us; return true;
        case JsonElement je when je.ValueKind == JsonValueKind.Number && je.TryGetUInt64(out var j): parsed = j; return true;
        default: parsed = 0; return false;
    }
}

private static bool TryGetByte(object value, out byte parsed)
{
    switch (value)
    {
        case byte b: parsed = b; return true;
        case int i when i is >= byte.MinValue and <= byte.MaxValue: parsed = (byte)i; return true;
        case JsonElement je when je.ValueKind == JsonValueKind.Number && je.TryGetByte(out var j): parsed = j; return true;
        default: parsed = 0; return false;
    }
}

Also applies to: 219-220

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/XChainAddAccountCreateAttestation.cs` around lines
192 - 193, The checks in XChainAddAccountCreateAttestation currently only ensure
XChainAccountCreateCount and WasLockingChainSend are present but do not validate
numeric type or ranges; add robust parsing helpers (e.g., TryGetUInt64 and
TryGetByte as suggested) and use them when reading
tx["XChainAccountCreateCount"] and tx["WasLockingChainSend"] to reject
non-numeric values, handle JsonElement/string/int/long/ulong cases, and enforce
WasLockingChainSend is either 0 or 1 and XChainAccountCreateCount is a
non-negative ulong before proceeding; throw ValidationException with the same
field-specific message if parsing or range checks fail.
Xrpl/Models/Transactions/DelegateSet.cs-102-107 (1)

102-107: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce PermissionValue string type before normalization.

Line 105 and Line 136 use ToString(), which accepts non-string JSON/token types and can incorrectly pass validation.

Suggested fix
-                    if (!permObj.TryGetProperty("PermissionValue", out JsonElement permVal))
+                    if (!permObj.TryGetProperty("PermissionValue", out JsonElement permVal) || permVal.ValueKind != JsonValueKind.String)
                         throw new ValidationException("DelegateSet: each Permission must contain PermissionValue");

-                    string permValueStr = permVal.ToString();
+                    string permValueStr = permVal.GetString();
                     if (string.IsNullOrWhiteSpace(permValueStr))
                         throw new ValidationException("DelegateSet: PermissionValue must not be empty");
-                    if (!perm.TryGetValue("PermissionValue", out object permVal))
+                    if (!perm.TryGetValue("PermissionValue", out object permVal) || permVal is not string permValueStr)
                         throw new ValidationException("DelegateSet: each Permission must contain PermissionValue");

-                    string permValueStr = permVal?.ToString();
                     if (string.IsNullOrWhiteSpace(permValueStr))
                         throw new ValidationException("DelegateSet: PermissionValue must not be empty");

Also applies to: 133-138

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/DelegateSet.cs` around lines 102 - 107, The code
currently calls JsonElement.ToString() for "PermissionValue" (and the other
occurrence at the second block) which accepts non-string JSON values; change the
checks in DelegateSet deserialization to first assert permVal.ValueKind ==
JsonValueKind.String, then call permVal.GetString() and validate that the
returned string is not null/whitespace, throwing the same ValidationException if
the kind is not String or the value is empty; update both places where
PermissionValue is read so only actual JSON strings are accepted before
normalization.
Xrpl/Models/Transactions/LoanManage.cs-114-115 (1)

114-115: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize flag parse failures to ValidationException.

ParseFlags throws FormatException, so ValidateLoanManage can emit a different exception type than the rest of transaction validators.

Suggested fix
-                uint rawFlags = ParseFlags(flagsObj);
+                uint rawFlags;
+                try
+                {
+                    rawFlags = ParseFlags(flagsObj);
+                }
+                catch (FormatException ex)
+                {
+                    throw new ValidationException($"LoanManage: invalid field Flags ({ex.Message})");
+                }

Also applies to: 124-133

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/LoanManage.cs` around lines 114 - 115,
ValidateLoanManage calls ParseFlags (which throws FormatException) and then uses
LoanManageActionMask; to normalize errors, wrap the ParseFlags calls inside a
try/catch that catches FormatException and rethrows a ValidationException
(preserving the original exception as InnerException and a clear message).
Update both occurrences where ParseFlags is used in ValidateLoanManage so all
flag parse failures produce ValidationException instead of FormatException.
Xrpl/Models/Transactions/XChainModifyBridge.cs-102-108 (1)

102-108: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject no-op XChainModifyBridge transactions.

Current validation allows requests with only XChainBridge and no actual modifications (SignatureReward, MinAccountCreateAmount, or clear flag).

Suggested fix
         public static async Task ValidateXChainModifyBridge(Dictionary<string, object> tx)
         {
             await Common.ValidateBaseTransaction(tx);

             if (!tx.TryGetValue("XChainBridge", out var bridge) || bridge is null)
                 throw new ValidationException("XChainModifyBridge: missing field XChainBridge");
+
+            bool hasSignatureReward = tx.TryGetValue("SignatureReward", out var reward) && reward is not null;
+            bool hasMinAccountCreateAmount = tx.TryGetValue("MinAccountCreateAmount", out var minAmount) && minAmount is not null;
+            bool hasClearFlag = tx.TryGetValue("Flags", out var flagsObj) && flagsObj is uint flags &&
+                                (flags & (uint)XChainModifyBridgeFlags.tfClearAccountCreateAmount) != 0;
+
+            if (!hasSignatureReward && !hasMinAccountCreateAmount && !hasClearFlag)
+                throw new ValidationException("XChainModifyBridge: at least one bridge parameter must be modified");
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Xrpl/Models/Transactions/XChainModifyBridge.cs` around lines 102 - 108,
ValidateXChainModifyBridge currently accepts a transaction that only contains
XChainBridge with no actual changes; update ValidateXChainModifyBridge to cast
the 'bridge' object to a Dictionary<string, object> and check for at least one
modifying field (e.g., "SignatureReward", "MinAccountCreateAmount") or the clear
flag (name used in the diff for clearing the bridge), and if none are present
throw a ValidationException like "XChainModifyBridge: no modifications
specified". Use the existing method name ValidateXChainModifyBridge and the
local variable 'bridge' to locate where to add the extra check.
🧹 Nitpick comments (5)
Tests/Xrpl.BinaryCodec.Test/TestDefinitions.cs (1)

16-107: ⚡ Quick win

Align unit test method names with TestU prefix for filterability.

Consider renaming these test methods to TestU... to keep filtering conventions uniform.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.BinaryCodec.Test/TestDefinitions.cs` around lines 16 - 107, Rename
the unit test methods in TestDefinitions.cs to use the TestU prefix so they
follow the repository filtering convention; specifically rename TestFieldExists,
TestGetFieldTypeName, TestGetFieldTypeCode, TestGetFieldCode,
TestGetFieldHeader, TestGetFieldNameFromHeader, TestInverseTransactionTypeMap,
TestInverseTransactionResultMap, TestFieldTypes_KnownMappings,
TestFieldIsSigningField, and TestFieldIsVlEncoded to TestUFieldExists,
TestUGetFieldTypeName, TestUGetFieldTypeCode, TestUGetFieldCode,
TestUGetFieldHeader, TestUGetFieldNameFromHeader,
TestUInverseTransactionTypeMap, TestUInverseTransactionResultMap,
TestUFieldTypes_KnownMappings, TestUFieldIsSigningField, and
TestUFieldIsVlEncoded respectively so the test runner/filter can consistently
identify unit tests.
Tests/Xrpl.Tests/Integration/transactions/TestILedgerStateFix.cs (1)

32-32: ⚡ Quick win

Use the integration test prefix for method naming consistency.

Rename this method to start with TestI to preserve filtering conventions.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestILedgerStateFix.cs` at line 32,
The test method TestLedgerStateFix_Basic is misnamed for integration tests;
rename the method to start with TestI (e.g., TestILedgerStateFix_Basic) to
follow the TestI prefix convention and update any references or usages of
TestLedgerStateFix_Basic (such as test runners, callers, or reflection-based
filters) so the test continues to run under the integration test filter.
Tests/Xrpl.Tests/Integration/transactions/TestIAMMCreateMpt.cs (1)

50-50: ⚡ Quick win

Use TestI prefix for integration test method naming.

Rename this test method to start with TestI for consistent test filtering.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestIAMMCreateMpt.cs` at line 50,
The integration test method currently named
TestAMMCreate_MptXrpPool_RejectedByProtocol should be renamed to start with the
TestI prefix to satisfy test-filtering conventions; update the method
declaration for TestAMMCreate_MptXrpPool_RejectedByProtocol to
TestI_AMMCreate_MptXrpPool_RejectedByProtocol (or
TestIAMMCreate_MptXrpPool_RejectedByProtocol per your naming pattern) and adjust
any references or attributes (e.g., in
TestAMMCreate_MptXrpPool_RejectedByProtocol usages or test runners) to use the
new method name so integration tests are correctly discovered.
Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridge.cs (1)

132-137: ⚡ Quick win

Avoid hardcoded XChainClaimID = "1" in commit tests.

Use the claim ID produced by XChainCreateClaimID result instead of a fixed literal to reduce flakiness when ledger state or sequencing differs.

Also applies to: 324-325

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridge.cs` around lines
132 - 137, The test currently hardcodes XChainClaimID = "1" in the XChainCommit
construction which can flake; instead obtain the claim ID from the earlier
XChainCreateClaimID result and assign that value to XChainCommit.XChainClaimID.
Locate the code that calls XChainCreateClaimID (the result object from that
call) and replace the literal "1" in the XChainCommit initializer with the claim
ID property from that result; apply the same change at the other occurrence
around lines 324-325 to use the generated claim ID rather than a hardcoded
string.
Tests/Xrpl.Tests/Integration/transactions/TestILoan.cs (1)

35-508: 🏗️ Heavy lift

Rename integration test methods to TestI* for filter compliance.

Methods like TestLoanBrokerSet_Basic and TestLoanPay_Basic should use the TestI prefix to match the repository’s integration-test naming convention.

As per coding guidelines **/Tests/**/*.cs: Name unit tests with TestU prefix and integration tests with TestI prefix for filtering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tests/Xrpl.Tests/Integration/transactions/TestILoan.cs` around lines 35 -
508, Rename the integration test methods that start with "Test" to use the
"TestI" prefix for integration-test filter compliance (e.g., rename
TestLoanBrokerSet_Basic → TestILoanBrokerSet_Basic, TestLoanBrokerSet_WithRates
→ TestILoanBrokerSet_WithRates, TestLoanBrokerCoverDeposit_Basic →
TestILoanBrokerCoverDeposit_Basic, TestLoanSet_Basic → TestILoanSet_Basic,
TestLoanDelete_Basic → TestILoanDelete_Basic, TestLoanBrokerDelete_Basic →
TestILoanBrokerDelete_Basic, TestLoanPay_Basic → TestILoanPay_Basic,
TestLoanSet_V2_ParallelSigning → TestILoanSet_V2_ParallelSigning,
TestLoanSet_V3_SequentialSigning → TestILoanSet_V3_SequentialSigning,
TestLoanBrokerLedgerEntry_VerifyFields →
TestILoanBrokerLedgerEntry_VerifyFields, TestLoanLedgerEntry_VerifyFields →
TestILoanLedgerEntry_VerifyFields, TestLoanBrokerSet_MPT →
TestILoanBrokerSet_MPT, TestLoanSet_MPT → TestILoanSet_MPT, TestLoanPay_MPT →
TestILoanPay_MPT, TestLoanPay_WithOverpaymentFlag_Rejected →
TestILoanPay_WithOverpaymentFlag_Rejected), updating each method declaration
name (e.g., the public async Task TestLoanBrokerSet_Basic() definitions) while
leaving their [TestMethod] attributes and signatures intact; search for any
external references to these method names (rare for tests) and update them
accordingly so the MSTest runner and repository filters pick them up.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5b73eaf8-8512-44a2-bb3f-13369b80a617

📥 Commits

Reviewing files that changed from the base of the PR and between 20ceaa6 and 4aa6e07.

📒 Files selected for processing (153)
  • .ci-config/rippled.cfg
  • .github/workflows/nuget.release.yml
  • .gitignore
  • Base/Xrpl.BinaryCodec/Enums/EngineResult.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/EngineResult.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.AccountId.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Amount.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Blob.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Currency.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Hash128.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Hash160.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Hash192.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Hash256.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Int32.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Issue.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Number.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.PathSet.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.StArray.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.StObject.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Uint16.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Uint32.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Uint64.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Uint8.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.Vector256.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.XChainBridge.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/Field.cs
  • Base/Xrpl.BinaryCodec/Enums/FieldType.cs
  • Base/Xrpl.BinaryCodec/Enums/Int32Field.cs
  • Base/Xrpl.BinaryCodec/Enums/Int64Field.cs
  • Base/Xrpl.BinaryCodec/Enums/LedgerEntryType.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/LedgerEntryType.cs
  • Base/Xrpl.BinaryCodec/Enums/NumberField.cs
  • Base/Xrpl.BinaryCodec/Enums/TransactionType.Generated.cs
  • Base/Xrpl.BinaryCodec/Enums/TransactionType.cs
  • Base/Xrpl.BinaryCodec/Enums/XChainBridgeField.cs
  • Base/Xrpl.BinaryCodec/Enums/definitions.json
  • Base/Xrpl.BinaryCodec/Types/AmountValue.cs
  • Base/Xrpl.BinaryCodec/Types/Int32Type.cs
  • Base/Xrpl.BinaryCodec/Types/Int64Type.cs
  • Base/Xrpl.BinaryCodec/Types/Issue.cs
  • Base/Xrpl.BinaryCodec/Types/NumberType.cs
  • Base/Xrpl.BinaryCodec/Types/StObject.cs
  • Base/Xrpl.BinaryCodec/Types/Uint32.cs
  • Base/Xrpl.BinaryCodec/Types/XChainBridgeType.cs
  • Base/Xrpl.BinaryCodec/Xrpl.BinaryCodec.csproj
  • CHANGES.md
  • CLAUDE.md
  • DocFx/LendingProtocol-Guide.md
  • DocFx/LendingProtocol-Guide.ru.md
  • DocFx/Vault-Guide.md
  • DocFx/Vault-Guide.ru.md
  • DocFx/XChainBridge-Guide.md
  • DocFx/XChainBridge-Guide.ru.md
  • DocFx/toc.yml
  • Tests/TestsClients/Test.ClonsoleApp/Program.cs
  • Tests/Xrpl.BinaryCodec.Test/TestBinaryParser.cs
  • Tests/Xrpl.BinaryCodec.Test/TestBinarySerializer.cs
  • Tests/Xrpl.BinaryCodec.Test/TestDefinitions.cs
  • Tests/Xrpl.BinaryCodec.Test/TestEnumParity.cs
  • Tests/Xrpl.BinaryCodec.Test/TestFieldDispatch.cs
  • Tests/Xrpl.BinaryCodec.Test/TestFieldIDCodec.cs
  • Tests/Xrpl.BinaryCodec.Test/TestMain.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestAmount.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestInt32Type.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestInt64Type.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestIssueMpt.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestLoanSetEncode.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestNumberType.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestUInt.cs
  • Tests/Xrpl.BinaryCodec.Test/Types/TestXChainBridgeType.cs
  • Tests/Xrpl.BinaryCodec.Test/Xrpl.BinaryCodec.Test.csproj
  • Tests/Xrpl.Tests/Client/Json/Converters/TransactionRequestRoundTripTests.cs
  • Tests/Xrpl.Tests/Client/Json/RequestSerializationTests.cs
  • Tests/Xrpl.Tests/Client/TestSubscribe.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIAMMCreateMpt.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIBatch.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIDelegateSet.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestILedgerStateFix.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestILoan.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestILoanBase.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIVault.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIVaultBase.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridge.cs
  • Tests/Xrpl.Tests/Integration/transactions/TestIXChainBridgeBase.cs
  • Tests/Xrpl.Tests/Sugar/TestUAutofillFees.cs
  • Tools/GenerateEnums/GenerateEnums.csproj
  • Tools/GenerateEnums/Program.cs
  • Tools/GenerateEnums/README.md
  • Xrpl/Client/Exceptions/XrplErrorClassifier.cs
  • Xrpl/Client/IXrplClient.cs
  • Xrpl/Client/Json/Converters/CurrencyConverter.cs
  • Xrpl/Client/Json/Converters/LedgerObjectConverter.cs
  • Xrpl/Client/Json/Converters/TransactionRequestConverter.cs
  • Xrpl/Client/Json/Converters/TransactionResponseConverter.cs
  • Xrpl/Client/RequestManager.cs
  • Xrpl/Client/connection.cs
  • Xrpl/Models/Common/Common.cs
  • Xrpl/Models/Common/PermissionModel.cs
  • Xrpl/Models/Common/XChainAttestations.cs
  • Xrpl/Models/Common/XChainBridgeModel.cs
  • Xrpl/Models/Enums/LedgerEntryType.cs
  • Xrpl/Models/Enums/TransactionType.cs
  • Xrpl/Models/Ledger/LOBridge.cs
  • Xrpl/Models/Ledger/LODelegate.cs
  • Xrpl/Models/Ledger/LOLoan.cs
  • Xrpl/Models/Ledger/LOLoanBroker.cs
  • Xrpl/Models/Ledger/LOVault.cs
  • Xrpl/Models/Ledger/LOXChainOwnedClaimID.cs
  • Xrpl/Models/Ledger/LOXChainOwnedCreateAccountClaimID.cs
  • Xrpl/Models/Methods/AccountObjects.cs
  • Xrpl/Models/Methods/AccountOffers.cs
  • Xrpl/Models/Methods/ChannelAuthorize.cs
  • Xrpl/Models/Methods/ChannelVerify.cs
  • Xrpl/Models/Methods/ServerDefinitions.cs
  • Xrpl/Models/Methods/TransactionEntry.cs
  • Xrpl/Models/Methods/VaultInfo.cs
  • Xrpl/Models/Subscriptions/BookChangesStream.cs
  • Xrpl/Models/Subscriptions/ManifestStream.cs
  • Xrpl/Models/Subscriptions/ResponseStreamType.cs
  • Xrpl/Models/Subscriptions/ServerStatusStream.cs
  • Xrpl/Models/Subscriptions/ValidationsStream.cs
  • Xrpl/Models/Transactions/DelegateSet.cs
  • Xrpl/Models/Transactions/LedgerStateFix.cs
  • Xrpl/Models/Transactions/LoanBrokerCoverClawback.cs
  • Xrpl/Models/Transactions/LoanBrokerCoverDeposit.cs
  • Xrpl/Models/Transactions/LoanBrokerCoverWithdraw.cs
  • Xrpl/Models/Transactions/LoanBrokerDelete.cs
  • Xrpl/Models/Transactions/LoanBrokerSet.cs
  • Xrpl/Models/Transactions/LoanDelete.cs
  • Xrpl/Models/Transactions/LoanManage.cs
  • Xrpl/Models/Transactions/LoanPay.cs
  • Xrpl/Models/Transactions/LoanSet.cs
  • Xrpl/Models/Transactions/TxFormat.cs
  • Xrpl/Models/Transactions/Validation.cs
  • Xrpl/Models/Transactions/VaultClawback.cs
  • Xrpl/Models/Transactions/VaultCreate.cs
  • Xrpl/Models/Transactions/VaultDelete.cs
  • Xrpl/Models/Transactions/VaultDeposit.cs
  • Xrpl/Models/Transactions/VaultSet.cs
  • Xrpl/Models/Transactions/VaultWithdraw.cs
  • Xrpl/Models/Transactions/XChainAccountCreateCommit.cs
  • Xrpl/Models/Transactions/XChainAddAccountCreateAttestation.cs
  • Xrpl/Models/Transactions/XChainAddClaimAttestation.cs
  • Xrpl/Models/Transactions/XChainClaim.cs
  • Xrpl/Models/Transactions/XChainCommit.cs
  • Xrpl/Models/Transactions/XChainCreateBridge.cs
  • Xrpl/Models/Transactions/XChainCreateClaimID.cs
  • Xrpl/Models/Transactions/XChainModifyBridge.cs
  • Xrpl/Sugar/Autofill.cs
  • Xrpl/Wallet/LoanSigningHelper.cs
  • Xrpl/Wallet/XrplWallet.cs
  • Xrpl/Xrpl.csproj
  • XrplCSharp.sln
💤 Files with no reviewable changes (2)
  • Tests/Xrpl.BinaryCodec.Test/Xrpl.BinaryCodec.Test.csproj
  • Xrpl/Models/Subscriptions/ValidationsStream.cs

Comment on lines +57 to +60
if (mantissa != 0 && exponent != ZeroExponent &&
(exponent < MinExponent || exponent > MaxExponent))
throw new FormatException(
$"NumberType: exponent {exponent} out of range [{MinExponent}, {MaxExponent}]");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "NumberType.cs" | head -20

Repository: StaticBit-io/XrplCSharp

Length of output: 111


🏁 Script executed:

cat -n Base/Xrpl.BinaryCodec/Types/NumberType.cs | head -150

Repository: StaticBit-io/XrplCSharp

Length of output: 7219


🏁 Script executed:

grep -n "ZeroExponent\|MinExponent\|MaxExponent" Base/Xrpl.BinaryCodec/Types/NumberType.cs

Repository: StaticBit-io/XrplCSharp

Length of output: 902


🏁 Script executed:

sed -n '50,80p' Base/Xrpl.BinaryCodec/Types/NumberType.cs | cat -n

Repository: StaticBit-io/XrplCSharp

Length of output: 1679


🏁 Script executed:

# Search for the FromParser method
grep -n "FromParser\|private static\|public static" Base/Xrpl.BinaryCodec/Types/NumberType.cs | head -30

Repository: StaticBit-io/XrplCSharp

Length of output: 275


🏁 Script executed:

sed -n '140,260p' Base/Xrpl.BinaryCodec/Types/NumberType.cs | cat -n

Repository: StaticBit-io/XrplCSharp

Length of output: 5135


🏁 Script executed:

grep -n "exponent" Base/Xrpl.BinaryCodec/Types/NumberType.cs | grep -A2 -B2 "FromString\|int.*exponent"

Repository: StaticBit-io/XrplCSharp

Length of output: 919


Reject ZeroExponent for non-zero mantissas in FromParser.

mantissa != 0 with exponent == int.MinValue currently passes validation, but the documented invariant explicitly requires ZeroExponent only for zero mantissas. This invalid state creates undefined behavior in ToJson() when negating int.MinValue at line 86.

Suggested fix
-            if (mantissa != 0 && exponent != ZeroExponent &&
-                (exponent < MinExponent || exponent > MaxExponent))
+            if (mantissa != 0 &&
+                (exponent == ZeroExponent || exponent < MinExponent || exponent > MaxExponent))
                 throw new FormatException(
-                    $"NumberType: exponent {exponent} out of range [{MinExponent}, {MaxExponent}]");
+                    $"NumberType: exponent {exponent} is invalid for non-zero mantissa; expected range [{MinExponent}, {MaxExponent}]");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (mantissa != 0 && exponent != ZeroExponent &&
(exponent < MinExponent || exponent > MaxExponent))
throw new FormatException(
$"NumberType: exponent {exponent} out of range [{MinExponent}, {MaxExponent}]");
if (mantissa != 0 &&
(exponent == ZeroExponent || exponent < MinExponent || exponent > MaxExponent))
throw new FormatException(
$"NumberType: exponent {exponent} is invalid for non-zero mantissa; expected range [{MinExponent}, {MaxExponent}]");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Base/Xrpl.BinaryCodec/Types/NumberType.cs` around lines 57 - 60, FromParser
currently allows mantissa != 0 with exponent == ZeroExponent (int.MinValue),
which later causes overflow in ToJson when negating int.MinValue; update the
validation in FromParser to explicitly reject exponent == ZeroExponent for
non-zero mantissas (i.e., if mantissa != 0 and (exponent == ZeroExponent ||
exponent < MinExponent || exponent > MaxExponent) then throw a FormatException),
referencing the ZeroExponent, MinExponent, MaxExponent checks and the
mantissa/exponent variables so the invalid state cannot reach ToJson.

@Platonenkov Platonenkov merged commit 78d87b1 into main May 13, 2026
7 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.

1 participant