FakeWalletProvisioner class

A host-VM fake WalletProvisioner — no native library, no device. Drives the OnboardingController state machine deterministically: configure what is on disk, make any step succeed or throw a TYPED failure, and count calls.

Implemented types

Constructors

FakeWalletProvisioner({bool exists = false, WalletSession? session, List<String> recoveryWords = _vectorWords})

Properties

createCount ↔ int
getter/setter pair
createWatchOnlyCount ↔ int
getter/setter pair
custodyDisclosureCount ↔ int
getter/setter pair
deleteCount ↔ int
getter/setter pair
disclosure ↔ CustodyDisclosure
What custodyDisclosure returns — a hardware tier by default; override to exercise the best-effort copy (e.g. tier: 'none' / eraseAssurance: EraseAssurance.bestEffort).
getter/setter pair
exists ↔ bool
What walletExists reports (the on-disk fork). Mutable so a test can flip it (e.g. create makes a wallet exist for a later resume).
getter/setter pair
exportedUfvk ↔ String
The UFVK string exportUfvk returns. Override per test.
getter/setter pair
exportUfvkCount ↔ int
getter/setter pair
failCreate ↔ Object?
getter/setter pair
failCreateWatchOnly ↔ Object?
getter/setter pair
failCustodyDisclosure ↔ Object?
When set, custodyDisclosure throws this.
getter/setter pair
failDelete ↔ Object?
When set, deleteWallet throws this (the wipe-fault path the controller recovers from by re-opening — set failOpen too to exercise the failed-AND-closed → OnboardingFailed route). A delete that throws does NOT flip exists (the keychain-first wipe deletes nothing on a fault).
getter/setter pair
failExportUfvk ↔ Object?
getter/setter pair
failForceDelete ↔ Object?
When set, forceDeleteWallet throws this (the rare post-force filesystem fault — the controller re-probes to a still-escapable failure). A force delete that throws does NOT flip exists.
getter/setter pair
failOpen ↔ Object?
getter/setter pair
failRescan ↔ Object?
When set, rescanFrom throws this (the handle-closed path the controller recovers from by re-opening — set failOpen too to exercise the failed-AND-closed → OnboardingFailed route).
getter/setter pair
failRestore ↔ Object?
getter/setter pair
failReveal ↔ Object?
getter/setter pair
failSwitch ↔ Object?
Thrown by switchSyncServer instead of returning — a typed WalletApiError drives the controller's refused / recovered arms.
getter/setter pair
failWalletExists ↔ Object?
When set, the matching call throws this instead of succeeding. Use a real WalletApiError to exercise the failure classifier.
getter/setter pair
forceDeleteCount ↔ int
Counts forceDeleteWallet calls (the #251 escape-hatch assertion).
getter/setter pair
hashCode → int
The hash code for this object.
no setterinherited
holdCreate ↔ Completer<void>?
When set, createGenerated blocks on this until completed (AFTER the call is counted and BEFORE it marks the wallet existing) — so a test can observe the transient OnboardingGenerating window on a slow seed-seal, or drive the controller deterministically to Generating. Mirrors holdOpen.
getter/setter pair
holdCreateWatchOnly ↔ Completer<void>?
When set, createWatchOnly blocks on this until completed (AFTER the call is counted + recorded) — the transient creating window. Mirrors holdCreate.
getter/setter pair
holdDelete ↔ Completer<void>?
When set, deleteWallet blocks on this until completed (AFTER the call is counted) — so a test can hold a delete in flight and prove a concurrent rescan is refused (the delete↔rescan mutual-exclusion).
getter/setter pair
holdOpen ↔ Completer<void>?
When set, open blocks on this until completed — so a test can dispose the container WHILE an open is in flight (the disposal-safety guard).
getter/setter pair
holdRescan ↔ Completer<void>?
When set, rescanFrom blocks on this until completed (AFTER the call is counted + recorded) — so a test can observe the transient running window.
getter/setter pair
holdRestore ↔ Completer<void>?
When set, restore blocks on this until completed (AFTER the call is counted and recorded, BEFORE it marks the wallet existing) — so a test can observe the transient OnboardingRestoring window. Mirrors holdCreate.
getter/setter pair
holdSwitch ↔ Completer<void>?
Holds switchSyncServer open until completed (in-flight latch tests).
getter/setter pair
lastEstimatedTime ↔ DateTime?
What estimateBirthdayHeight last received — the size-cue threading.
getter/setter pair
lastRescanTarget ↔ RescanTarget?
What rescanFrom last received — so a test can assert the sheet's selection reached the adapter as the intended sealed arm (a picked date / the wallet's floor height / all-history).
getter/setter pair
lastRestoreCreationTime ↔ DateTime?
getter/setter pair
lastRestoreWords ↔ List<String>?
What restore last received — so a test can assert the lowercase + trim contract held (the words reached the SDK normalized) and the birthday date was threaded.
getter/setter pair
lastSwitchChoice ↔ SyncServerChoice?
getter/setter pair
lastWatchOnlyBirthdayHeight ↔ int?
getter/setter pair
lastWatchOnlyUfvk ↔ String?
What createWatchOnly last received — so a test can assert the pasted artifact + the picker's estimated birthday reached the adapter verbatim.
getter/setter pair
openCount ↔ int
getter/setter pair
recoveryWords ↔ List<String>
The words revealMnemonic returns.
getter/setter pair
rescanCount ↔ int
getter/setter pair
rescanSession ↔ WalletSession?
The session rescanFrom returns on success — a DISTINCT session from session by default, so a test can assert the active gate swapped to a new identity (the live-sync-graph rebuild trigger). Override to pin a specific one.
getter/setter pair
restoreCount ↔ int
getter/setter pair
revealCount ↔ int
getter/setter pair
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
session ↔ WalletSession
The session createGenerated/open return.
getter/setter pair
switchCount ↔ int
getter/setter pair
switchSession ↔ WalletSession?
The session switchSyncServer returns (a FRESH instance by default, the graph-rebuild trigger the controller's swap relies on).
getter/setter pair
walletExistsCount ↔ int
getter/setter pair

Methods

createGenerated() → Future<WalletSession>
Create a BRAND-NEW wallet: the SDK generates a fresh 24-word seed in Rust (OsRng) and seals it under the device keychain — the seed NEVER crosses the bridge. Returns the live WalletSession. The caller MUST drive the recovery-phrase backup (revealMnemonic) and confirm it before the wallet is presented as deposit-ready (money-safety; the OnboardingController gate). Throws (typed) if a wallet already exists here — call walletExists first; the non-clobber is the contract, never a silent overwrite.
override
createWatchOnly(String ufvk, {required int birthdayHeight}) → Future<WalletSession>
Create a WATCH-ONLY wallet from an exported unified full viewing key (#397 §3.7 D2 / ADR-0538 — the consumer half of exportUfvk). ufvk is the standard uview1… / uviewtest1… string; garbage, a truncated artifact, or a WRONG-network key throw a typed WalletErrorKind.invalidViewingKey (a well-formed cross-network key is WalletErrorKind.networkMismatch) BEFORE any store side effect — the controller renders it as a fixable input fault, exactly like a bad mnemonic word. NOT a spend-key crossing: a UFVK is viewing capability (total history visibility, no spend, no seed), so a watch-only wallet has NOTHING to back up and goes straight to Active (no backup-confirmation step).
override
custodyDisclosure() → Future<CustodyDisclosure>
The PRODUCTION per-tier custody disclosure (FR-14 H1) for THIS wallet — the honest "are my keys hardware-backed / what does delete do" answer a host renders BEFORE deleteWallet and as an ambient custody badge. Reads ONLY the measured vault tier (no seed, no unseal, NO key material). Bounded like the other local steps. A tier == "none" (headless desktop) or an EraseAssurance.bestEffort tier is HONEST best-effort — the host MUST disclose the flash-recovery residual. No tier is permanent erasure (ADR-0571).
override
deleteWallet() → Future<void>
Delete this wallet (FR-14): the "delete wallet" / "reset" primitive. CLOSES the live handle first (a wipe refuses while an instance holds the single-writer lock — WalletOpen), THEN deletes the keychain wrap key (so this key store can no longer open the on-disk seals or the DB ciphertext; custodyDisclosure says how strongly, ADR-0571) and removes the data directory. The seed NEVER crosses the bridge.
override
estimateBirthdayHeight(DateTime time) → int
Fixed blocks-per-day slope so estimate-threading tests are deterministic (the real adapter rides the SDK's checkpoint-backed estimator).
override
exportUfvk() → Future<String>
Export this wallet's UNIFIED FULL VIEWING KEY — the ONE sanctioned UFVK egress (#397 §3.7 D1 / ADR-0538; the outbound sibling of revealMnemonic, gated by the reference UI at the SAME backup-phrase bar). Returns the standard uview1… / uviewtest1… string. Valid only after a create/open/restore/createWatchOnly on this instance (works at every custody tier including watch-only — re-export is an identity operation).
override
forceDeleteWallet() → Future<void>
FORCE-complete a deleteWallet for a wallet that cannot be opened and whose custody key is ALREADY GONE — the #251 escape out of a non-retryable OnboardingFailed (needsRecovery). The plain deleteWallet fails CLOSED (keystoreInconsistent) when its verify-real-sever guard finds no key to sever; this SKIPS that guard and removes the unreadable remnant's files. It MUST be called DELIBERATELY — only AFTER a plain deleteWallet reported keystoreInconsistent, with the device UNLOCKED (the SDK wipe_force contract: forcing past the guard could otherwise delete the wrong files). The seed is NOT on the device — funds are recovered from the recovery phrase the user then enters — so removing the remnant loses no money. THROWS on a genuine filesystem fault (the caller re-probes to a still-escapable failure, never a dead-end). After success this instance owns no wallet — the caller routes to the restore form.
override
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
open() → Future<WalletSession>
Open the EXISTING provisioned wallet at the host data dir. Throws (typed) for not-found / another-instance-open / network-mismatch / device-locked / an interrupted create — open does NOT repair a remnant (it throws provisioningIncomplete); CREATE resumes the repair from the sealed seed, which is why the boot fork routes a remnant (walletExists() == false) to create, never here.
override
rescanFrom(RescanTarget target) → Future<WalletSession>
Rescan the wallet from an EARLIER birthday to recover funds an over-high restore birthday skipped (ADR-0534 — the in-app fix for the ADR-0533 "balance reads zero, sync says done" gap). target chooses the floor: RescanFromTime is converted to a birthday HEIGHT via the SDK's CONSERVATIVE estimateBirthday (never past the time → never skips notes) and the configured network, exactly as restore threads its birthday; RescanFromWalletBirthday passes the wallet's own floor height verbatim (the sheet's default — see the type doc); RescanAllHistory scans the FULL history (floors to Sapling activation — slower, but money-SAFE; it never silently skips older funds, NEVER ~tip). NO key material crosses — the seed stays sealed in the keychain; the only thing passed is a bare height.
override
restore(List<String> mnemonicWords, {DateTime? approximateCreationTime}) → Future<WalletSession>
RESTORE an existing wallet from its BIP39 recovery phrase — the ONE sanctioned INBOUND key crossing (spec §3.3; counterpart to the outbound revealMnemonic). mnemonicWords are the recovery words in order.
override
revealMnemonic() → Future<List<String>>
The current wallet's BIP39 recovery words, in index order — the ONE sanctioned OUTBOUND key crossing (spec §3.3). Valid only after a createGenerated/open on this instance. The words ARE the whole secret: the caller shows them ONCE on a FLAG_SECURE screen, never logs / persists / screenshots / transmits them. Dart memory cannot be zeroized — the documented §10 residue; the Rust side wipes its own copies when this returns. Throws WalletErrorKind.noMnemonic for a raw-seed wallet (the host-supplied-seed path; its recovery is the host's own master phrase, never a wallet-local phrase).
override
switchSyncServer(SyncServerChoice choice) → Future<WalletSession>
Switch the active wallet onto choice and REMEMBER it (the picker, P3-13 — sync-server-picker.md D3): the SDK probes the server, stops and joins the sync loop, writes the choice, and rebuilds the session over the SAME database — no rescan, no re-download; funds, history, queued sends and the sync verdict are untouched. Returns a FRESH session over the same handle, the rescanFrom shape, so the live-sync graph (keyed on session identity) rebuilds and re-subscribes; sync auto-restarts on the new server.
override
toString() → String
A string representation of this object.
inherited
walletExists() → Future<bool>
Whether a wallet is already provisioned at the host data dir (a prior createGenerated completed). Drives the boot fork: no wallet → offer create; a wallet → open it and gate on backup confirmation.
override

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Static Methods

estimateHeightFor(DateTime time) → int
The fake estimator: days since 2020-01-01 × 1152 blocks (the ~75s cadence), floored at 1. Public so a test can compute its expectation through the same slope.