Skip to content

feat: Add optional expanded response format to account_currencies - #7829

Open
Platonenkov wants to merge 1 commit into
XRPLF:developfrom
Platonenkov:feature/account-currencies-expanded
Open

feat: Add optional expanded response format to account_currencies#7829
Platonenkov wants to merge 1 commit into
XRPLF:developfrom
Platonenkov:feature/account-currencies-expanded

Conversation

@Platonenkov

Copy link
Copy Markdown

High Level Overview of Change

Adds an optional boolean expanded request parameter to the account_currencies method.

When expanded: true, send_currencies and receive_currencies contain objects keyed by asset instead of plain currency codes: currency, issuer and value (the remaining capacity of the trust line). The account's own issuance is aggregated into a single entry per currency, so issuing accounts with many holders do not produce one entry per trust line. The default response format is unchanged.

Fixes #6629

Context of Change

Currency codes alone are ambiguous: an account may hold trust lines with the same currency code from different issuers, and one of them may be available for sending while another is only available for receiving. The legacy response ("send_currencies": ["USD"]) gives no way to tell which issuer-specific asset is meant, so clients fall back to account_lines and reimplement the aggregation logic that already exists inside this handler.

Design decisions:

  • Entries are keyed by asset, not by trust line. Tokens held (or receivable) from a counterparty produce one entry per line with issuer = counterparty and value = remaining capacity (limit - balance for receive, balance for send). Each entry has the shape of a standard currency amount object.
  • Own issuance is aggregated into a single entry per currency with issuer = the requested account and no value, mirroring the aggregated obligations section of gateway_balances. Without this, an issuer with thousands of holders would get one (misleading) entry per trust line.
  • Membership semantics are identical to the legacy format: derived from trust line limits and balances alone, ignoring freeze and authorization state (the legacy behavior covered by existing tests). The expanded currency set is exactly the legacy currency set. Per-line state remains the responsibility of account_lines; evaluating effective transferability here would also require extra ledger reads (e.g. lsfRequireAuth lives on the issuer's AccountRoot).
  • No additional ledger reads: the expanded response is computed in the same single pass over the already-loaded trust lines as the legacy response.

Alternatives considered are documented in the linked issue (including an earlier revision with per-line state flags, which was dropped to keep the method focused on "which assets and how much").

API Impact

  • Public API: New feature (new methods and/or new fields)
  • libxrpl change (any change that may affect libxrpl or dependents of libxrpl)

API-CHANGELOG.md is updated in this PR. The only libxrpl change is one new constant in jss.h (JSS(expanded)).

The new parameter is opt-in and fully backward compatible: without expanded (or with expanded: false) the response is unchanged. A non-boolean expanded returns invalidParams, consistent with the parameter validation introduced in #6529.

Before / After

Request:

{
  "command": "account_currencies",
  "account": "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
  "ledger_index": "validated",
  "expanded": true
}

Before (and still the response when expanded is omitted):

{
  "receive_currencies": ["EUR", "USD"],
  "send_currencies": ["USD"]
}

After, with expanded: true (holder account; two USD issuers are now distinguishable and carry the remaining line capacity):

{
  "receive_currencies": [
    { "currency": "EUR", "issuer": "rGateway...", "value": "100" },
    { "currency": "USD", "issuer": "rIssuerA...", "value": "50" },
    { "currency": "USD", "issuer": "rIssuerB...", "value": "100" }
  ],
  "send_currencies": [
    { "currency": "USD", "issuer": "rIssuerA...", "value": "50" }
  ]
}

Issuing account (own issuance aggregated, holders not enumerated):

{
  "receive_currencies": [
    { "currency": "USD", "issuer": "rIssuingAccount..." }
  ],
  "send_currencies": [
    { "currency": "USD", "issuer": "rIssuingAccount..." }
  ]
}

Performance: no impact on the default path (identical code path). The expanded path performs the same single pass over the same trust line vector, with one STAmount subtraction per entry; no additional ledger reads, locks or async processing.

Test Plan

Extended AccountCurrencies_test with:

  • multi-issuer disambiguation (two issuers with the same currency code) and value checks for send/receive capacities;
  • verification that entries contain exactly currency, issuer, value;
  • verification that freezing a line does not change the expanded response (same semantics as the legacy format, mirroring the existing legacy freeze test);
  • issuer aggregation (two holders produce a single self-issuance entry per currency, without value);
  • expanded: false producing the legacy string-array format;
  • invalidParams for non-boolean expanded values.

Full local runs on top of current develop (gcc 15.2, Release, Linux): xrpld --unittest — 238 suites, 4513 cases, 0 failures; xrpl_tests — 708 tests passed.

@github-actions

Copy link
Copy Markdown

⚠️ This PR contains unsigned commits. To get your PR merged, please sign them. ⚠️

If only the most recent commit is unsigned, you can run:

  1. Amend the commit: git commit --amend --no-edit -n -S
  2. Overwrite the commit: git push --force-with-lease

If multiple commits are unsigned, you can run:

  1. Go into interactive rebase mode: git rebase --interactive HEAD~<NUM_OF_COMMITS>, where NUM_OF_COMMITS is the number of most recent commits that will be available to edit.
  2. Change "pick" to "edit" for the commits you need to sign, and then save and exit.
  3. For each commit, run: git commit --amend --no-edit -n -S
  4. Continue the rebase: git rebase --continue
  5. Overwrite the commit(s): git push --force-with-lease

If you're new to commit signing, there are different ways to set it up:

Sign commits with gpg

Follow the steps below to set up commit signing with gpg:

  1. Generate a GPG key
  2. Add the GPG key to your GitHub account
  3. Configure git to use your GPG key for commit signing
Sign commits with ssh-agent

Follow the steps below to set up commit signing with ssh-agent:

  1. Generate an SSH key and add it to ssh-agent
  2. Add the SSH key to your GitHub account
  3. Configure git to use your SSH key for commit signing
Sign commits with 1Password

You can also sign commits using 1Password, which lets you sign commits with biometrics without the signing key leaving the local 1Password process.
See use 1Password to sign your commits.

@Platonenkov
Platonenkov marked this pull request as draft July 20, 2026 01:55
@Platonenkov
Platonenkov marked this pull request as ready for review July 20, 2026 01:55
@Platonenkov
Platonenkov force-pushed the feature/account-currencies-expanded branch from e6be48d to d129bb7 Compare July 20, 2026 01:55
Add an optional boolean 'expanded' request parameter to the
account_currencies method. When expanded is true, send_currencies and
receive_currencies contain objects keyed by asset instead of plain
currency codes.

Entries for tokens held (or receivable) from a counterparty carry
currency, issuer (the counterparty) and value (the maximum amount that
can be received or sent on that line). The account's own issuance is
aggregated into a single entry per currency with issuer set to the
requested account and no value, so that issuing accounts with many
holders do not produce one entry per trust line (compare the
obligations section of gateway_balances).

Like the legacy format, membership and value are derived from trust
line limits and balances alone and do not reflect freeze or
authorization state; account_lines reports the full per-line state.

Currency codes alone are ambiguous because an account may hold trust
lines with the same currency code from different issuers, and the
legacy response gives no way to tell which issuer-specific asset is
usable. The default response format is unchanged for backward
compatibility.
@Platonenkov
Platonenkov marked this pull request as draft July 20, 2026 11:49
@Platonenkov
Platonenkov marked this pull request as ready for review July 20, 2026 11:49
@Platonenkov
Platonenkov force-pushed the feature/account-currencies-expanded branch from d129bb7 to cdace5c Compare July 20, 2026 11:49
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.

Enrich account_currencies response with issuer entries (Version: rippled 3.x)

1 participant