Skip to content

feat: use a dedicated HD branch for wormhole change addresses - #590

Merged
n13 merged 5 commits into
mainfrom
feat/id_change_addresses
Jul 31, 2026
Merged

feat: use a dedicated HD branch for wormhole change addresses#590
n13 merged 5 commits into
mainfrom
feat/id_change_addresses

Conversation

@n13

@n13 n13 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Change addresses derive from a dedicated HD branch; discovery scans both branches and change indices are tracked separately.

  • Removed Planck and Quan references

n13 added 5 commits July 30, 2026 17:01
State files written before the planck -> token rename persist pending
spends under 'changeAmountPlanck'. Without a fallback, fromJson threw on
the missing 'changeAmountToken' key, breaking encrypted-account load for
anyone with an in-flight send at upgrade time.

@n13 n13 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review (two passes: full diff review, fix, re-review)

Scope reviewed: HD change-branch feature (encrypted_account_service, hd_wallet_service, wormhole_utxo_service, wormhole_coin_selection, wormhole_send_service) + the planck→token / QUAN→token rename across mobile-app, miner-app, cold-wallet-app, l10n, and all test changes.

Issue found and fixed (pushed as 753be70)

PendingSpend.fromJson crashed on legacy state files — the rename changed the persisted JSON key changeAmountPlanckchangeAmountToken, but pending-spend records are written to getApplicationSupportDirectory() (encrypted_account_w{N}.json), which survives app updates on both iOS and Android and is only wiped on logout. A user with an in-flight send at upgrade time would hit a null-cast TypeError inside _readState, breaking every encrypted-account load. Fixed with a fallback to the legacy key, plus a regression test. (The sibling nextChangeIndex field already had a correct ?? 0 migration — old change addresses stay covered on the external branch by the persisted nextIndex.)

Verified sound

  • Branch separation logic: discovery scans both branches in parallel; nextIndex/nextChangeIndex are tracked and persisted independently; change-index reservation (_reserveChangeIndex) and per-batch bump of nextChangeIndex are correct, including the exact-max send (no change → no index consumed).
  • Migration path for existing wallets: old change UTXOs on the external branch are still rediscovered (they carry transfers, so gap-limit discovery finds them) and remain spendable — secrets are re-derived from the UTXO owner's isChange flag, and ownsAddress covers both branches.
  • Pending-spend pruning correctly treats change-branch scan entries as discovered-used while filtering the synthetic external index 0.
  • Totals: totalReceivedToken/changeReceivedToken computed from byAddress which is initialized for every requested address, so the ! lookups are safe; incomingToken identity (incoming + changeReceived − spent = balance) is test-covered.
  • Rename consistency: no stale planck/QUAN/deriveWormhole references remain; l10n placeholders ({tokenSymbol}) match between app_en.arb, app_id.arb, and the generated localizations; generated localization signatures match all call sites.
  • Tests: the updated tests genuinely strengthen coverage (dual-branch ownsAddress, distinct change indices for overlapping sends, change-owned input secret re-derivation, legacy state file without nextChangeIndex) — no weakened assertions found.

Non-blocking observation

EncryptedAccountState.incomingToken (external receipts excluding returning change) is added and tested but not yet consumed by the UI — encryptedTotalReceivedProvider (activity_screen.dart "Total received") still shows totalReceivedToken, which includes change. That's the pre-existing behavior, so not a regression, but if the intent was to report externally received funds separately, the provider should switch to s.incomingToken. Product call.

Checks run

  • melos run analyze (flutter analyze --fatal-infos, 4 packages): SUCCESS
  • quantus_sdk: encrypted_account / coin_selection / utxo / send service tests, call_decoder, payload parser, generate_keys — all pass (incl. new legacy-key test)
  • mobile-app unit tests (amount input, exchange rate, pos, locale handling): all pass
  • cold-wallet transaction_signing_test: all pass

Verdict

Approve (posted as comment — can't self-approve as author). The one real bug found (legacy persisted-key crash) is fixed and tested; the rest of the feature is well-designed and the rename is thorough and consistent. Good to merge once CI is green.

@dewabisma dewabisma left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is mixed with the quan to token word changes. So, noisy.

But I saw the dedicated HD branch update for change addresses. LGTM!

@n13
n13 merged commit a801c08 into main Jul 31, 2026
1 check passed
@n13

n13 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

This is mixed with the quan to token word changes. So, noisy.

But I saw the dedicated HD branch update for change addresses. LGTM!

yeah sorry I noticed the planck thing in the middle of doing this, didn't realize its so wide-spread

Should have been 2 PRs

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.

2 participants