walletIdentityProvider top-level property
The wallet IDENTITY the money surfaces key their last-known values on
(#381 (c) — the converged HIGH). Riverpod retains an async
provider's previous value through a rebuild (copyWithPrevious), which is
exactly right for a transient re-read or the rescan's same-wallet session
swap — and exactly WRONG across a wallet identity change, where it painted
the DELETED wallet's balance, as-of stamp, Send gate, and parked/in-flight
amounts onto the NEXT wallet's first frames (persistently under a busy
first read), and on a duress/decoy multi-identity host flashed the OWNER's
balance on the DECOY's surface — the same leak class the settings store
got its identity fence for (A4/#348). The four money read providers below
drop their retained value whenever THIS value changes.
Derivation:
- no session ⇒
null— a change to/from null is an identity edge (the #380 (c) wallet-gone set closes the gate, so a delete → create/restore always crosses null even if intermediate states coalesce). - the package gate owns the session (an OnboardingActive whose session IS this session) ⇒ the state's OnboardingActive.identityEpoch — the controller keeps it stable across a rescan's session swap (same wallet, new handle ⇒ retention survives; NO blank frame mid-rescan) and bumps it for every genuinely new wallet life.
- a SESSION-ONLY host (walletSessionProvider overridden; the package gate not Active) ⇒ the session OBJECT itself. Every session flip is then an identity change — exactly right for the duress/decoy host, and conservatively right for a host that swaps handles over the same wallet (it gets an honest cold reload instead of retention; a host wanting same-wallet retention integrates via the package gate).
Implementation
final walletIdentityProvider = Provider<Object?>((ref) {
final session = ref.watch(walletSessionProvider);
if (session == null) return null;
final onboarding = ref.watch(onboardingControllerProvider);
if (onboarding is OnboardingActive &&
identical(onboarding.session, session)) {
return onboarding.identityEpoch;
}
return session;
});