Skip to content

feat(balances): v1-aligned key/token fields; rename balance to total - #138

Merged
aristidesstaffieri merged 1 commit into
mainfrom
feat/balances-v1-field-alignment
Jul 17, 2026
Merged

feat(balances): v1-aligned key/token fields; rename balance to total#138
aristidesstaffieri merged 1 commit into
mainfrom
feat/balances-v1-field-alignment

Conversation

@aristidesstaffieri

@aristidesstaffieri aristidesstaffieri commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Aligns the POST /api/v1/accounts/balances response with the v1 backend pattern: every balance entry now carries a server-derived key and token, and the on-ledger amount is exposed as total instead of balance. These are exactly the fields the extension and mobile currently re-derive client-side when mapping v2 responses into the legacy v1 shape (see the discussion on stellar/freighter#2906) — with them server-provided, clients need only a generic snake_case→camelCase + string→BigNumber pass, with no per-asset identity logic to keep in sync across repos.

Verified against v1 before renaming: v1 exposes total/available and never balance (confirmed in the v1 source and a live prd response), and total is the raw on-ledger amount — so this is a pure rename, value unchanged.

Breaking wire change: balance is removed from balance entries. Deliberately out of scope: minimum_balance stays the bare base reserve and available semantics are unchanged — the extension mapper already compensates for both.

Closes #137

What's in this PR

  • internal/types/account_balances.go — new Token/TokenIssuer types; BalanceBase gains key and optional token; balancetotal.
  • internal/services/account_balances_mapping.go — per-variant key/token derivation; SAC asset type derived from code length (the SDK carries none), trustline type passed through verbatim.
  • internal/types/account_balances_test.go — wire-contract assertions for key/token/total; forbids "balance":; SEP-41 token is typeless; LP entries carry no token.
  • internal/services/account_balances_mapping_test.go — expectations updated; new edge cases: >4-char SAC code → credit_alphanum12, nil trustline code/issuer, nil SEP-41 symbol.

Wire shape

Key formats: native, CODE:ISSUER (classic/SAC), SYMBOL:CONTRACT_ID (SEP-41), POOLID:lp (LP shares). Example native entry:

{
  "key": "native",
  "token": { "type": "native", "code": "XLM" },
  "total": "100.0000000",
  "available": "98.0000000",
  "token_id": "native",
  "token_type": "NATIVE",
  "minimum_balance": "1.5000000",
  ...
}

SEP-41 tokens get { "code": "<symbol>", "issuer": { "key": "<contract_id>" } } with no type, and liquidity-pool entries have a key but no token — both matching v1.

Test plan

  • make unit-test, make check (fmt/vet/golangci-lint/shadow/deadcode), make build all green locally
  • End-to-end smoke test: server run against a stub wallet-backend serving all five variants; response verified for key/token/total per variant and absence of balance
  • Server-derived key/token values cross-checked against what the extension's mapAccountBalancesV2.ts (feat(src): balances v2 migration freighter#2906) derives today
  • CI green
  • Coordinate client updates (extension #2906, mobile) before deploying — the balancetotal rename is breaking

Followups

  • Extension and mobile mappers can drop their key/token derivation and read total directly.
  • Known v1 divergence left intentionally: v2's native available also subtracts minimum_balance (v1 subtracts only selling liabilities); revisit only if clients stop compensating.

🤖 Generated with Claude Code

…otal

  Aligns the POST /api/v1/accounts/balances response with the v1 backend
  pattern (stellar/freighter-backend#319) so the extension and mobile
  clients no longer re-derive per-asset identity when mapping to the
  legacy shape (see stellar/freighter#2906 discussion).

  Every balance entry now carries:
  - key: the v1 balance-map key — "native", "CODE:ISSUER" (classic/SAC),
    "SYMBOL:CONTRACT_ID" (SEP-41), "POOLID:lp" (LP shares)
  - token: the v1 token identity — {type,code} for native,
    {type,code,issuer:{key}} for classic (type verbatim from the
    trustline) and SAC (type derived from code length; the SDK carries
    none), {code,issuer:{key}} without type for SEP-41 (v1 Mercury
    parity), and omitted for LP entries (v1 has no token there)
  - total: renamed from "balance"; same raw on-ledger value (v1 exposes
    total/available, never balance — verified against v1 source and a
    live prd response)

  available, token_id, token_type, and all per-variant fields are
  unchanged; minimum_balance stays the bare base reserve.

  Covers edge cases: >4-char SAC codes map to credit_alphanum12, nil
  trustline code/issuer and nil SEP-41 symbol degrade to empty key parts,
  mirroring the client-side fallbacks this replaces.
@aristidesstaffieri aristidesstaffieri self-assigned this Jul 16, 2026
@aristidesstaffieri aristidesstaffieri changed the title feat(balances): add v1-aligned key/token fields, rename balance to t… feat(balances): v1-aligned key/token fields; rename balance to total Jul 16, 2026
@aristidesstaffieri
aristidesstaffieri marked this pull request as ready for review July 16, 2026 19:58
Copilot AI review requested due to automatic review settings July 16, 2026 19:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Aligns account-balance responses with the legacy v1 wire shape.

Changes:

  • Adds server-derived key and token fields.
  • Renames balance to total.
  • Expands mapping and wire-contract tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
internal/types/account_balances.go Defines v1-aligned response fields and token types.
internal/types/account_balances_test.go Verifies the updated JSON contract.
internal/services/account_balances_mapping.go Derives keys and token identities per balance variant.
internal/services/account_balances_mapping_test.go Tests mappings and optional-field edge cases.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +28 to +31
// shares, which carry no token in v1). Total is the raw on-ledger amount and
// Available is the spendable portion (total minus the reserved amount for
// native/classic; equal to total for contract tokens and pool shares). Both
// are Stellar amount strings so JavaScript clients never lose precision.

@piyalbasu piyalbasu left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice!

@aristidesstaffieri
aristidesstaffieri merged commit 17b3bd2 into main Jul 17, 2026
9 checks passed
@aristidesstaffieri
aristidesstaffieri deleted the feat/balances-v1-field-alignment branch July 17, 2026 16:36
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.

Align balances response fields with v1

4 participants