isWatchOnlyProvider top-level property
Is the active wallet WATCH-ONLY (#397 §3.7 D4/D5)? — the UI chrome key: a
"Watch-only" badge, hidden Send/Shield/Swap affordances, and the Security
screen's export-instead-of-backup arm read this. CHROME-ONLY by design: the
SDK's typed WalletErrorKind.watchOnly refusals stand regardless, so this
provider is allowed to fail SAFE — false (the full-spend chrome). A
spurious false only shows an affordance the SDK then refuses honestly
(never a wrong spend); a spurious true only hides an affordance.
SYNCHRONOUS on the package-gate path (the converged HIGH fix): the
wallet KIND is IMMUTABLE and is captured into OnboardingActive.isWatchOnly
at the moment the session becomes active (a watch-only import ⇒ known true; a
create/restore ⇒ known false; a boot open ⇒ the controller's bounded
once-read). Reading it from there resolves the chrome on the FIRST frame —
no flash of Send/Swap/Shield while an async FFI read settles (the old
.value ?? false painted the full-spend chrome on every watch-only mount
until the read landed). A SESSION-ONLY host (which overrides
walletSessionProvider and never reaches OnboardingActive) has no captured
kind to read, so it falls back to the bounded async once-read below — keyed
to the wallet identity so a watch-only true never bleeds onto the next
wallet.
Implementation
final isWatchOnlyProvider = Provider<bool>((ref) {
final session = ref.watch(walletSessionProvider);
if (session == null) return false;
final onboarding = ref.watch(onboardingControllerProvider);
if (onboarding is OnboardingActive &&
identical(onboarding.session, session)) {
return onboarding.isWatchOnly;
}
// Session-only host: no captured kind — the bounded async fallback (fail-safe
// false until it resolves; the SDK's typed refusals stand meanwhile).
final identity = ref.watch(walletIdentityProvider);
return ref.watch(_isWatchOnlyReadProvider(identity)).value ?? false;
});