Files
minibits_wallet/__tests__
minibits-cashandClaude Opus 5 03e532e7c9 Delegate keyset choice to cashu-ts, reuse the restore wallet, persist lazy keychain updates
Three changes to WalletStore, all following from what 4.10 now offers.

1. Keyset selection. getOptimalKeyset mirrored KeyChain.getCheapestKeyset by
hand, and the two orderings had diverged: 4.10 (#836) sorts by keyset id
VERSION first, then fee, then final_expiry, while the copy sorted by fee and
used version only as a tiebreak. They disagree whenever a mint prices its
newer keyset above an older one, and the copy would then keep minting on the
superseded keyset — which is the one a mint can retire, stranding ecash on it.
The library's order is now used.

This is a deliberate behaviour change, not just dedup: a user CAN pay a higher
input fee after this, when a mint prices its current keyset above a retired
one. keysetSelection.test.ts pins the ordering against the real library and
also pins the divergence, asserting the old fee-first rule would have chosen
differently, so the decision stays visible.

Delegating also picks up two things the copy could not express: getCheapestKeyset
filters on hasKeys, so a keyset whose keys are missing is never selected (it
cannot create outputs) rather than being selected and failing later; and
hasHexId classifies odd-length hex ids as legacy (#840), which the old
/^[0-9a-f]+$/i test accepted. getWallet now builds the KeyChain cache once and
uses it for both the choice and loadMintFromCache.

2. Restore. WalletStore.restore built a CashuMint, a CashuWallet and called
loadMint() on EVERY batch. SeedRecoveryScreen calls it once per 50 counters, so
a recovery scanning a few hundred indices repeated getInfo/getKeysets/getKeys
that many times, and discarded the BIP-32 parent-node cache that 4.7.2 (#802)
added to the deriver — per-instance, and meant for exactly this repeated
derivation. The instance is now reused per mintUrl|unit|keysetId, held in
volatile state so the seed is never snapshotted, and cleared by resetWallets.

3. Keychain writeback. cashu-ts updates its keychain mid-operation — lazily
loading keys for a keyset we lack, or repairing an unknown id via loadMint(true)
— and nothing persisted it, so the next wallet built from the Mint model
re-fetched the same keys. Newly created wallets now subscribe to
on.keychainUpdated and write the cache back. This matters more since the
receive-path ensureKeysetKeys loop was removed: that lazy fetch is now the only
thing loading those keys. The handler swallows its errors — it runs inside the
caller's operation and must not break it, and initKeyset throws on a unit the
wallet does not support, which a multi-unit mint produces.

Also de-flakes proofSelectionRotating.test.ts from the earlier commit. Two of
its assertions compared two independent selectProofsRGLI runs, but RGLI is
Randomized Greedy with Local Improvement and may return different, equally
valid sets per call, so those comparisons failed intermittently (caught by
repeated full-suite runs, ~2 in 5). They now assert stable properties —
rotating adds no stale bias when nothing is stale, RGLI never force-includes a
whole stale bucket, and rotating is always dearer when one exists — over
repeated draws instead of equality between single runs.

Verified: tsc --noEmit unchanged against baseline (89 pre-existing, none new),
48 suites / 650 tests pass across six consecutive full runs, clean device
reload with all mints hydrated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 23:50:49 +02:00
..
2026-06-27 23:55:40 +02:00
2026-07-08 15:44:11 +02:00