FakeWalletSession class

A host-VM fake for WalletSession — no native library, no device. It mirrors the real watchSyncStatus contract (CURRENT status emitted on subscribe) and gives tests direct handles to drive the live stream (push / error / complete) and to count subscribes, cancels, snapshots, and start/stop calls.

Implemented types

Constructors

FakeWalletSession({SyncStatus current = const SyncStatus.idle(), WalletState? snapshotValue, bool failOnSubscribe = false, bool dropAfterReplay = false, bool snapshotThrows = false})

Properties

authorizeParkedSendCount ↔ int
getter/setter pair
authorizeParkedSendGate ↔ Future<void>?
Set to hold authorizeParkedSend open until the future completes — the slow-sign shape (a ZK prove is tens of seconds on a phone), for single-flight and mid-call-dispose tests. Null (the default) resolves immediately.
getter/setter pair
authorizeParkedSendResult ↔ ParkedAuthorization
What authorizeParkedSend resolves to unless authorizeParkedSendThrows is set (FR-23-b / #361). Defaults to the happy signed; drive ParkedAuthorization.stillQueued to exercise the "still waiting, NOT a failure" copy, and notFound for the already-gone re-read path.
getter/setter pair
authorizeParkedSendThrows ↔ Object?
getter/setter pair
birthdayHeightCount ↔ int
getter/setter pair
birthdayHeightGate ↔ Completer<void>?
When set, birthdayHeight PARKS (after counting) until this completes — lets a test observe the rescan sheet's transient "resolving" window (Start disabled, the recommended-range cue) before the floor lands.
getter/setter pair
birthdayHeightResult ↔ int?
The fake scan floor (#317). Defaults to a plausible mainnet birthday; null models the pre-provision wallet. birthdayHeightThrows models the wedged-read fallback arm the rescan sheet must degrade through.
getter/setter pair
birthdayHeightThrows ↔ Object?
getter/setter pair
cancelCount ↔ int
getter/setter pair
cancelParkedSendCount ↔ int
getter/setter pair
cancelParkedSendResult ↔ bool
What cancelParkedSend returns unless cancelParkedSendThrows is set (true = removed; set false to model an already-gone / draining / reused no-op the host must NOT present as "cancelled").
getter/setter pair
cancelParkedSendThrows ↔ Object?
getter/setter pair
checkOlderSwapAddressesCount ↔ int
getter/setter pair
checkOlderSwapAddressesNeverCompletes ↔ bool
When true, checkOlderSwapAddresses never completes — the in-flight (disabled + spinner) state the deep-scan button must hold through.
getter/setter pair
checkOlderSwapAddressesResult ↔ SwapAddressCheckReport
What checkOlderSwapAddresses returns unless checkOlderSwapAddressesThrows is set. Defaults to a one-STEP widen with the band fully pending.
getter/setter pair
checkOlderSwapAddressesThrows ↔ Object?
getter/setter pair
composeCount ↔ int
getter/setter pair
composeThrows ↔ Object?
When set, composePaymentUri throws this (e.g. a typed addressInvalid).
getter/setter pair
currentAddressCount ↔ int
getter/setter pair
currentAddressNeverCompletes ↔ bool
When true, currentAddress returns a future that never completes — the hung-FFI mobile edge the receive provider's timeout must convert into the honest error state rather than an infinite spinner.
getter/setter pair
currentAddressResult ↔ String
The fake receive address (a plausible mainnet UA-ish string; the screen only renders it). Override per test as needed.
getter/setter pair
currentAddressThrows ↔ Object?
getter/setter pair
currentTransparentAddressCount ↔ int
getter/setter pair
currentTransparentAddressGate ↔ Completer<void>?
When set, currentTransparentAddress PARKS until this gate completes — the mid-flight interleaving harness (#330), like proposeGate.
getter/setter pair
currentTransparentAddressNeverCompletes ↔ bool
When true, currentTransparentAddress never completes — the hung-FFI edge the transparent-address provider's timeout converts into an honest error state.
getter/setter pair
currentTransparentAddressResult ↔ String
The fake TRANSPARENT receive address (a plausible mainnet t-addr; the screen only renders it). Distinct from currentAddressResult so the toggle test can prove the screen swaps between the two.
getter/setter pair
currentTransparentAddressThrows ↔ Object?
getter/setter pair
deliveryStateCount ↔ int
How many times deliveryState was asked.
getter/setter pair
deliveryStates ↔ Map<String, DeliveryState?>
What deliveryState answers per txid (stage S8 obligation). A txid NOT listed reads DeliveryState.retryPending — the reading the core gives an interactive send whose broadcast failed (its persisted row IS the obligation), so the existing send-flow tests keep their meaning. A test of the negative lists the txid with null or another state, or sets deliveryStateThrows.
getter/setter pair
deliveryStateThrows ↔ Object?
When set, deliveryState throws this.
getter/setter pair
dismissSwapRecordCount ↔ int
getter/setter pair
dismissSwapRecordResult ↔ bool
What dismissSwapRecord returns unless dismissSwapRecordThrows is set (true = removed; false models the idempotent already-absent case).
getter/setter pair
dismissSwapRecordThrows ↔ Object?
getter/setter pair
dropAfterReplay ↔ bool
When true, every subscription delivers its current-first replay THEN immediately errors — a flapping link that connects, replays, and drops. Used to prove the replay alone does NOT reset the reconnect backoff.
getter/setter pair
enableNearSwapCount ↔ int
getter/setter pair
enableNearSwapThrows ↔ Object?
When set, enableNearSwap throws this; else it records the config.
getter/setter pair
exportUfvkCount ↔ int
getter/setter pair
exportUfvkResult ↔ String
The fake UFVK the session-port export returns (G1 / #361 companion) — a plausible uview… shape; the screen only renders + copies it.
getter/setter pair
exportUfvkThrows ↔ Object?
getter/setter pair
failOnIncomingSubscribe ↔ bool
When true, a subscribe faults immediately (the malformed-cursor typed reject / transport-drop shape — a stream ERROR, not a sync throw).
getter/setter pair
failOnSubscribe ↔ bool
When true, every subscription immediately errors instead of emitting — a persistently failing endpoint, for the reconnect-backoff test.
getter/setter pair
failStart ↔ bool
When true, startSync throws — the (rare) sync-loop start command failing (e.g. the handle closed underneath us). Drives the drive-failed path.
getter/setter pair
failStop ↔ bool
When true, stopSync throws — a (rarer) stop failing. Used to prove a stop failure does NOT masquerade as a start failure (the loop is still up).
getter/setter pair
failSwapOnSubscribe ↔ bool
When true, every swap subscription immediately errors — an establish-time typed failure (SwapDisabled / closed handle / bad id), which the notifier surfaces and STOPS on (the core never routes a transient fault here).
getter/setter pair
hasActiveIncomingSubscription → bool
no setter
hasActiveSubscription → bool
no setter
hasActiveSwapSubscription → bool
no setter
hashCode → int
The hash code for this object.
no setterinherited
holdSwapSubscribe ↔ bool
When true, the swap subscription connects but emits NOTHING — the real-world "re-attached to a provider-GC'd order the core retries forever" shape (the poll never terminates, the notifier never leaves loading). Drives the HIGH-1 escape test.
getter/setter pair
incomingCancelCount ↔ int
getter/setter pair
incomingCursorsSeen → List<String?>
The sinceCursor values passed to watchIncomingFunds, in call order — tests pin that a reconnect/resume re-subscribes WITH the last event's cursor (the catch-up contract), not from scratch.
final
incomingReplay ↔ IncomingFundsEvent
The replay event a new subscription emits first. Defaults to the count-0 baseline the core produces for a null cursor.
getter/setter pair
incomingSubscribeCount ↔ int
Subscription bookkeeping for the incoming stream (parallel to subscribeCount/cancelCount, which stay sync-status-only).
getter/setter pair
inFlightSendsResult ↔ List<InFlightSend>
The in-flight two-step sends listInFlightSends returns unless listInFlightSendsThrows is set. Defaults to empty (nothing mid-flight); set rows to drive the durable "on its way — don't send it again" cue (#309).
getter/setter pair
inFlightSwapsResult ↔ List<SwapRecord>
The durable in-flight swaps listInFlightSwaps returns unless listInFlightSwapsThrows is set. Defaults to empty (nothing in flight); set rows to drive the durable swap home (W-swap-5, #366).
getter/setter pair
isWatchOnlyResult ↔ bool
#397: the fake watch-only flag — the chrome key. Override per test.
getter/setter pair
lastAuthorizeCreatedAt ↔ int?
getter/setter pair
lastAuthorizeId ↔ int?
getter/setter pair
lastCancelCreatedAt ↔ int?
getter/setter pair
lastCancelId ↔ int?
getter/setter pair
lastComposeAmountZat ↔ int?
getter/setter pair
lastComposeMemo ↔ String?
getter/setter pair
lastComposeMemoBytes ↔ List<int>?
FR-28: the opaque machine-memo bytes the last compose was handed, copied verbatim. null when the leg carried none.
getter/setter pair
lastComposeRecipient ↔ String?
getter/setter pair
lastDismissedSwapId ↔ String?
getter/setter pair
lastEnableConfig ↔ SwapProviderConfig?
getter/setter pair
lastEnableDeclaredKill ↔ SwapKill?
getter/setter pair
lastEnableSwapEnabled ↔ bool?
getter/setter pair
lastMachineMemosTxid ↔ String?
getter/setter pair
lastOutcomeSwapId ↔ String?
getter/setter pair
lastParsedUri ↔ String?
getter/setter pair
lastProbedChoice ↔ SyncServerChoice?
getter/setter pair
lastProposeUri ↔ String?
getter/setter pair
lastQueueUri ↔ String?
getter/setter pair
lastRecordedOutcome ↔ SwapOutcome?
getter/setter pair
lastRetryCreatedAt ↔ int?
getter/setter pair
lastRetryId ↔ int?
getter/setter pair
lastSendProposalId ↔ int?
getter/setter pair
lastSwapExecuteQuote ↔ SwapQuote?
getter/setter pair
lastSwapQuoteRequest ↔ QuoteRequest?
getter/setter pair
lastTransactionsAfter ↔ String?
getter/setter pair
lastTransactionsLimit ↔ int?
getter/setter pair
lastValidatedRecipient ↔ String?
getter/setter pair
lastWatchedSwapId ↔ String?
getter/setter pair
listInFlightSendsCount ↔ int
getter/setter pair
listInFlightSendsThrows ↔ Object?
getter/setter pair
listInFlightSwapsCount ↔ int
getter/setter pair
listInFlightSwapsThrows ↔ Object?
getter/setter pair
listParkedSendsCount ↔ int
getter/setter pair
listParkedSendsGate ↔ Completer<void>?
When set, listParkedSends PARKS (after counting) until this completes — the birthdayHeightGate shape, for observing the section's in-flight re-pull window (the #407 R5 retry-label live region renders only there).
getter/setter pair
listParkedSendsThrows ↔ Object?
getter/setter pair
machineMemosByTxid → Map<String, List<Uint8List>>
Returned by machineMemos; keyed by txid so a test can model "this transaction carries an envelope and that one does not".
final
machineMemosThrows ↔ Object?
When set, machineMemos throws this (e.g. a typed scope refusal).
getter/setter pair
mintDiversifiedAddressCount ↔ int
getter/setter pair
mintDiversifiedAddressIndex ↔ int
getter/setter pair
mintDiversifiedAddressNeverCompletes ↔ bool
When true, mintDiversifiedAddress never completes — the hung-FFI edge the receive screen's action timeout converts into the honest error snackbar rather than a stuck spinner.
getter/setter pair
mintDiversifiedAddressResult ↔ String
The fake FRESH diversified receive address (FR-8 / Recv-4). Mint semantics: every call returns a DISTINCT address, so the fake appends the (post-increment) call count and advances mintDiversifiedAddressIndex — a repeated-tap test observes two different addresses without re-wiring. Override mintDiversifiedAddressResult for an exact-string pin (the suffix is still appended on the second call onward: count 1 returns it verbatim).
getter/setter pair
mintDiversifiedAddressThrows ↔ Object?
getter/setter pair
nextCursorResult ↔ String?
The FIRST page's opaque cursor (null ⇒ no more pages — the default).
getter/setter pair
pagesByCursor → Map<String?, HistoryPage>
Optional keyset map for multi-page tests: keyed by the after cursor (null = first page), each value is the page to return. When non-empty it takes precedence over transactionsResult/nextCursorResult, so a test can drive a full "load more" walk deterministically.
final
parkedSendsResult ↔ List<ParkedSend>
The parked sends listParkedSends returns unless listParkedSendsThrows is set. Defaults to empty (no parked send); set parkedSendFixture rows to drive the "saved & pending" surface.
getter/setter pair
parseSendRequestCount ↔ int
getter/setter pair
parseSendRequestResult ↔ WalletSendRequest?
Drives parseSendRequest (the FR-25 ZIP-321 prefill door). When set, the fake returns this canned request — a prefill/lock test drives the send screen with a KNOWN request, no native parser. Default null → the fake echoes a minimal request whose address is the raw URI (the default validateRecipient classifies any address valid, so the prefilled form is Review-enabled).
getter/setter pair
parseSendRequestThrows ↔ Object?
When set, parseSendRequest throws this — model a malformed / wrong-network / multi-leg / unsupported-memo URI (the real adapter throws a typed WalletSendRequestException).
getter/setter pair
probeCount ↔ int
getter/setter pair
probeGate ↔ Completer<void>?
getter/setter pair
probeResult ↔ SyncServerProbe?
What probeSyncServer answers; null ⇒ a probe at tip 3,482,911.
getter/setter pair
probeThrows ↔ Object?
getter/setter pair
proposeCount ↔ int
getter/setter pair
proposeGate ↔ Completer<void>?
When set, propose PARKS (after counting/recording) until this gate completes — the mid-flight interleaving harness (#330): a test can swap the wallet session (or fire a second action) while a propose is in flight, then release it and assert the stale continuation writes nothing.
getter/setter pair
proposeResult ↔ SendProposal?
Returned by propose unless proposeThrows is set; defaults to a simple shielded proposal.
getter/setter pair
proposeShieldCount ↔ int
getter/setter pair
proposeShieldGate ↔ Completer<void>?
When set, proposeShield PARKS until this gate completes — the mid-flight interleaving harness (#330), like proposeGate.
getter/setter pair
proposeShieldNeverCompletes ↔ bool
When true, proposeShield returns a future that never completes — the wedged-FFI/blocking-pool-starvation edge the controller's timeout must convert into an honest error state rather than an infinite "Preparing…" spinner.
getter/setter pair
proposeShieldResult ↔ SendProposal?
Returned by proposeShield. null (the default) models "nothing to shield" (below threshold / no transparent funds); set a shieldProposalFixture to model a shieldable balance. Ignored when proposeShieldThrows is set.
getter/setter pair
proposeShieldThrows ↔ Object?
When set, proposeShield throws this (e.g. a typed proposalStale).
getter/setter pair
proposeThrows ↔ Object?
When set, propose throws this (e.g. a typed WalletApiError).
getter/setter pair
queueCount ↔ int
getter/setter pair
queuedId ↔ String
Returned by queueSend unless queueThrows is set.
getter/setter pair
queueThrows ↔ Object?
When set, queueSend throws this.
getter/setter pair
reclaimCount ↔ int
getter/setter pair
reclaimNeverCompletes ↔ bool
When true, reclaimEphemeralSlots never completes — the in-flight (disabled) state the reclaim button must hold through.
getter/setter pair
reclaimResult ↔ ReclaimOutcome
The outcome reclaimEphemeralSlots returns unless reclaimThrows is set (#315 slice 2). Defaults to Minted (the reopen-initiated path); set NothingToReclaim/NotBroadcast or reclaimThrows to drive the others.
getter/setter pair
reclaimThrows ↔ Object?
getter/setter pair
recordSwapOutcomeCount ↔ int
getter/setter pair
recordSwapOutcomeResult ↔ bool
What recordSwapOutcome returns unless recordSwapOutcomeThrows is set (true = pinned; false models the idempotent absent/lapsed/already- pinned case). Records the last pin so tests assert the #367 observation→pin contract (the tracking stream pins, never dismisses).
getter/setter pair
recordSwapOutcomeThrows ↔ Object?
getter/setter pair
recoverableEphemeralFundsCount ↔ int
getter/setter pair
recoverableEphemeralFundsResult ↔ List<RecoverableEphemeralFunds>
The recoverable one-time-address (ephemeral) funds. Defaults to empty (the dormant production state); set entries to drive the balance card's subset row in a widget test.
getter/setter pair
recoverableEphemeralFundsThrows ↔ Object?
When set, recoverableEphemeralFunds errors with this — the failed-read edge the "recover now" CTA must gate on (a failed read must NOT read as "nothing to recover", hiding held funds).
getter/setter pair
retryParkedSendCount ↔ int
getter/setter pair
retryParkedSendResult ↔ bool
What retryParkedSend returns unless retryParkedSendThrows is set (true = re-armed; set false to model an already-gone / draining / reused no-op the host re-reads the parked list on).
getter/setter pair
retryParkedSendThrows ↔ Object?
getter/setter pair
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
sendCount ↔ int
getter/setter pair
sendGate ↔ Completer<void>?
When set, send PARKS (after counting/recording) until this gate completes — the sibling of proposeGate for the sign+broadcast half. The harness for anything that has to happen WHILE a send is in flight: leaving the screen mid-submit, stacking a second entry over a running send, or releasing the landing afterwards to prove it wrote nothing it shouldn't.
getter/setter pair
sendResults ↔ List<TxSubmitResult>?
Returned by send unless sendThrows is set; defaults to one success.
getter/setter pair
sendThrows ↔ Object?
When set, send throws this.
getter/setter pair
snapshotCount ↔ int
getter/setter pair
snapshotThrows ↔ bool
When true, snapshot throws — a cold read failing (e.g. a busy DB).
getter/setter pair
startCount ↔ int
getter/setter pair
startSyncGate ↔ Completer<void>?
When set, startSync PARKS (after counting) until this gate completes — the WEDGED-BRIDGE harness (#409 R2), twin of stopSyncGate. A start that never answers is the case the walletFfiWedgeTimeout bound exists for, and it is NOT the same as failStart: a throw is the SDK saying no, whereas a silent start is the SDK saying nothing while the Rust loop it was asked to spawn most likely runs.
getter/setter pair
stopCount ↔ int
getter/setter pair
stopSyncGate ↔ Completer<void>?
When set, stopSync PARKS (after counting) until this gate completes — the mid-flight interleaving harness for the sync controller's command chain (#330 class / ), like proposeGate.
getter/setter pair
subscribeCount ↔ int
getter/setter pair
swapAddressCheckCoverageCount ↔ int
getter/setter pair
swapAddressCheckCoverageResult ↔ SwapAddressCoverage
What swapAddressCheckCoverage returns unless swapAddressCheckCoverageThrows is set. Defaults to a restored wallet mid-check (63 covered, band pending).
getter/setter pair
swapAddressCheckCoverageThrows ↔ Object?
getter/setter pair
swapCancelCount ↔ int
getter/setter pair
swapCurrent ↔ SwapStatus
The status a swap subscription replays on subscribe (current-first).
getter/setter pair
swapExecuteCount ↔ int
getter/setter pair
swapExecuteGate ↔ Completer<void>?
When set, swapExecute PARKS until this gate completes — holds the screen in SwapExecuting to exercise the #367 execute pop-guard (the swapQuoteGate sibling).
getter/setter pair
swapExecuteResult ↔ String
Returned by swapExecute unless swapExecuteThrows is set.
getter/setter pair
swapExecuteThrows ↔ Object?
getter/setter pair
swapListTokensCount ↔ int
getter/setter pair
swapListTokensResult ↔ SwapTokenList?
Returned by swapListTokens unless swapListTokensThrows is set.
getter/setter pair
swapListTokensThrows ↔ Object?
getter/setter pair
swapQuoteCount ↔ int
getter/setter pair
swapQuoteGate ↔ Completer<void>?
When set, swapQuote PARKS until this gate completes — the mid-flight interleaving harness (#330), like proposeGate.
getter/setter pair
swapQuoteNeverCompletes ↔ bool
When true, swapQuote never completes — models a stalled dial so a test can drive the controller's host-side timeout (the "Getting a quote…" hang).
getter/setter pair
swapQuoteResult ↔ SwapQuote?
Returned by swapQuote unless swapQuoteThrows is set.
getter/setter pair
swapQuoteThrows ↔ Object?
getter/setter pair
swapSubscribeCount ↔ int
getter/setter pair
sweepCount ↔ int
getter/setter pair
sweepNeverCompletes ↔ bool
When true, sweepEphemeralFunds never completes — the slow/stalled sweep the recover button's in-flight (disabled + spinner) state must hold through.
getter/setter pair
sweepResult ↔ EphemeralSweepSummary
The summary sweepEphemeralFunds returns unless sweepThrows is set. Defaults to an empty no-op (the dormant production state); set a funded ephemeralSweepSummaryFixture to drive the recovery sheet's outcome.
getter/setter pair
sweepThrows ↔ Object?
getter/setter pair
syncServersResult ↔ List<SyncServer>
What syncServers returns — the host's offered list.
getter/setter pair
syncServerStatusResult ↔ SyncServerStatus?
What syncServerStatus returns; null ⇒ the default zec.rocks status with no choice and no fallback.
getter/setter pair
syncServerStatusThrows ↔ Object?
getter/setter pair
transactionsCount ↔ int
getter/setter pair
transactionsNeverCompletes ↔ bool
When true, transactions never completes — the wedged-FFI edge the activity provider's timeout converts into the honest error state, not an endless spinner.
getter/setter pair
transactionsResult ↔ List<TxSummary>
The FIRST page's rows (after == null). Defaults to empty (no history); override with txSummaryFixture rows to drive the activity list.
getter/setter pair
transactionsThrows ↔ Object?
When set, transactions returns a future that errors with this.
getter/setter pair
validateRecipientCount ↔ int
getter/setter pair
validateRecipientResult ↔ ValidatedAddress
Drives validateRecipient in widget/unit tests. Default: a shielded, memo-capable recipient — so the existing send tests that enter the default recipient and tap Review keep a VALID (Review-enabled) recipient. Override to ValidatedAddress(memoCapable: false) to model a transparent recipient, or set validateRecipientThrows to a typed WalletApiError (addressInvalid / networkMismatch) to model a bad/wrong-network paste.
getter/setter pair
validateRecipientThrows ↔ Object?
When set, validateRecipient throws this (a malformed / other-network address — the real bridge throws a typed WalletApiError).
getter/setter pair

Methods

authorizeParkedSend({required int id, required int createdAt}) → Future<ParkedAuthorization>
AUTHORIZE a parked send NOW (FR-23-b / #361) — sign a send the user already committed, at this user-present moment, instead of waiting for a background pass to sign it. Pass BOTH the id AND the createdAt from the ParkedSend.
override
birthdayHeight() → Future<int?>
The account's birthday height — the scan FLOOR the wallet's history starts at (#317). null before the account is provisioned (the first sync hasn't run yet). The rescan sheet uses it as the range DEFAULT: a rescan from the floor covers everything THIS wallet has ever seen without hiding older funds (an above-floor rebuild hides the span between the old and new floor — the SDK's LOWER-ONLY contract) and without scanning pointlessly before the wallet existed. NOT a clamp on user picks: an explicitly EARLIER date is the post-restore recovery path (this floor may itself be a too-recent restore estimate). A height, never money. Cheap, local, no network.
override
cancelParkedSend({required int id, required int createdAt}) → Future<bool>
CANCEL a parked (queued) send (2e-2b-v-4a) — the user-facing escape hatch to DISCARD a parked send of EITHER kind (the SAFE counter-affordance; never a re-send; the guard is kind-agnostic — any still-Queued row is fundless). Pass BOTH the id AND the createdAt from the ParkedSend the user is cancelling. Returns true if removed, false if it was already gone / began sending / its rowid was reused (idempotent). On false, re-read listParkedSends — but do NOT present it as definitively "cancelled" nor invite a re-send: a send that began sending may be IN-FLIGHT (direct the user to the activity list; a re-send risks a DOUBLE-PAY). MONEY-SAFE: only a still-Queued intent is deleted (nothing signed, no tx on-chain). IRREVERSIBLE — the host MUST confirm before calling. Throws a typed WalletApiError (invalid-state on a closed handle).
override
checkOlderSwapAddresses() → Future<SwapAddressCheckReport>
#390 — "Check older swap addresses": widen the range the wallet watches so the normal sync surfaces older swap deposits/refunds that a SEED-ONLY RESTORE of a long swap history left unchecked. It does NOT itself find funds — it WIDENS, then any older swap money appears in the balance over the next minutes of sync. Returns a COUNTS-only SwapAddressCheckReport (never an address/index) — render "checking as your wallet syncs; anything found will appear in your balance", NEVER "found X". Rerunnable (each accepted run goes deeper). Moves NO money (no authorizer). Throws a typed WalletApiError `swapAddressCheckRefused` (branch on reason: swapDisabled — swap is off; checkOutstanding — a prior check is still running, one per settlement window) or invalid-state on a closed handle.
override
complete() → void
Complete the active stream (EOF).
completeIncoming() → void
Complete the active incoming stream (EOF — teardown shape).
completeSwap() → void
Complete the active swap stream (EOF) — the core ending the poll WITHOUT a terminal first (a Hard kill / teardown; the core never EOFs on a transport fault). The notifier must STOP on this, never reconnect.
composePaymentUri({required String recipient, required int amountZat, String? memoText, List<int>? memoBytes}) → String
Compose a ZIP-321 payment URI (the §2.4 lossless request token) from one form leg — the form flow's bridge into propose/queueSend; a scanned-QR flow would call those with the URI directly. SYNCHRONOUS, no money movement: the adapter validates the recipient + memo against the wallet's OWN network (so a cross-network address is the SDK's typed NetworkMismatch, never a host-supplied-network footgun) and returns the URI string. The bridge crossing (encodePaymentUri) lives in the adapter — never in the UI layer — so this whole flow stays host-VM testable behind a fake. Throws a typed WalletApiError for a bad address / un-sendable memo.
override
currentAddress() → Future<String>
The wallet's current receive address (the unified address for account 0) — what the user shares to RECEIVE ZEC. NOT key material (it is public by design; the spending key never leaves Rust), so it belongs on this port. §5.4 NEVER-LOG applies (an address is a never-log value) — display it, allow copy, but never write it to a log. Cheap, local, no network.
override
currentTransparentAddress() → Future<String>
The wallet's TRANSPARENT receive address (Recv-2 / ADR-0528) — the account's external-scope P2PKH t-address, surfaced ALONGSIDE the shielded UA behind the receive screen's address-type toggle (default shielded). PUBLIC + visible on-chain + reused-address-linkable: the UI labels it as such and keeps the shielded UA the recommended default. NOT key material (the spending key never leaves Rust); §5.4 NEVER-LOG applies. Cheap, local, no network.
override
deliveryState(String txidHex) → Future<DeliveryState?>
The wallet's DELIVERY OBLIGATION for one transaction it created (stage S8 obligation) — the same reading a history row carries on TxSummary.delivery, for the txidHex a send result named. Read it after a send that was not all-success: only DeliveryState.retryPending licenses "saved — your wallet will send it on a later sync"; null (not the wallet's, expired, or no row) and every other state do not.
override
dismissSwapRecord({required String swapId}) → Future<bool>
Remove one in-flight swap record. USER-INTENT only since #367 — the terminal card's Done (the outcome rendered = seen) or the home row's explicit Remove; a terminal OBSERVATION pins via recordSwapOutcome instead. Display-only state: never touches the deposit outbox / guard / detection. Idempotent (false for an already-absent id — a raced double-dismiss is harmless).
override
emitError([Object error = 'fake transport drop']) → void
Fault the active stream (transport drop / EOF-as-error).
emitIncomingError([Object error = 'fake incoming drop']) → void
Fault the active incoming stream (transport drop).
enableNearSwap({required SwapProviderConfig config, required bool swapEnabled, SwapKill? declaredKill}) → Future<void>
Turn the swap on-ramp ON — construct the NEAR provider over the wallet's OWN transport (the same host-provided dialer + Tor policy sync uses; internal Tor is OPTIONAL — the host may bring its own) and apply the §3.5 kill state. A ONE-TIME setup, called after the wallet is open (set-once, first-wins). On a build compiled WITHOUT the adapter it degrades honestly to a typed SwapDisabled (the method is always present so the surface is stable). Throws a typed SwapApiError (watchOnly on a watch-only wallet — STRUCTURAL, never retryable, checked first (#397 §3.7 D3): render view-only framing, not a retry; providerUnavailable when the transport can't be resolved — retryable; swapStateUnavailable on a torn-down handle).
override
exportUfvk() → Future<String>
EXPORT this wallet's Unified Full Viewing Key (#397 §3.7 D1 / ADR-0538) — the uview… string that grants FULL history visibility (every past and future transaction, amounts, memos) and NO spend authority.
override
isWatchOnly() → Future<bool>
Is this a WATCH-ONLY wallet (#397 §3.7 D4/D5)? The reference UI keys its chrome on this: a "Watch-only" header badge, hidden Send/Shield/Swap affordances, and the Security screen's no-backup ("Export viewing key") arm. The typed WalletErrorKind.watchOnly refusals stand at the SDK regardless, so a host ignoring this only ever sees honest errors — never a wrong behavior. Cheap, local, no network, no key material.
override
listInFlightSends() → Future<List<InFlightSend>>
The IN-FLIGHT two-step (TEX) sends (#309): first leg signed + broadcast, send not yet complete — money is IN MOTION through a wallet-controlled one-time address. Drives the DURABLE wallet-screen "on its way — don't send it again" cue (the post-send result screen's caution is dismissible; without this, an in-flight two-step reads as an ordinary pending send exactly when a worried user is most tempted to re-pay). DISJOINT from listParkedSends (parked = queued, nothing signed; in-flight = signed + broadcast). A row leaves by three exits: completion, the strand transition (recoverableEphemeralFunds takes over — the two can OVERLAP while the unshield settles; both cues together is correct), or a return to the queue (every tx expired unmined — no money moved; it reappears parked, cancellable again). AMOUNT-only (§5.4 — no recipient/txid); the amount annotates the SAME pending payment the activity list shows — never double-count it. Cheap, LOCAL, no network; empty is the common case.
override
listInFlightSwaps() → Future<List<SwapRecord>>
The durable IN-FLIGHT SWAP surface (W-swap-5, #366): every swap whose order was registered at execute and has neither been dismissed nor self-lapsed. THE kill→relaunch re-attach — after a process restart the wallet screen lists these and re-opens live tracking by feeding SwapRecord.id to watchSwapStatus. NOT gated on swap being enabled or the §3.5 kill (a local read is not swap traffic — the user never loses sight of money in motion). Read-only, cheap + LOCAL; called on the same edges as the parked/in-flight send surfaces. §5.4: SwapRecord.id is render-never-log.
override
listParkedSends() → Future<List<ParkedSend>>
EVERY queued send that has not completed yet (2e-2b-v-3, widened by #331): a one-time-address (TEX) two-step awaiting drain / ceiling-parked, or a plain single-step send waiting in the offline queue — the ParkedSend.kind says which (presentation-only). They sit in the queue with NO on-chain transaction (INVISIBLE in the activity list), so across an app relaunch this surface is the ONLY place the committed spend exists — hidden, a queued send is a DOUBLE-PAY window (the user re-enters it and both drain on reconnect). Each ParkedSend is amount + id + kind + createdAt; the recipient address NEVER crosses the bridge (§5.4 never-render). A read-only PULL; each parked send auto-broadcasts once it can drain — present it per the DOUBLE-PAY caution (never invite a re-send) and EARMARK its amount over the balance (it stays spendable). Cheap, LOCAL, no network. LIVE since gate-removal (2e-2b-v-5a): both the interactive send and queueSend paths can park here.
override
machineMemos(String txidHex) → Future<List<Uint8List>>
FR-27 — the machine-memo bytes of one transaction, scoped to the prefixes registered on the wallet's WalletConfig. Returns them in output order; txidHex is passed back verbatim from a history row.
override
mintDiversifiedAddress() → Future<WalletMintedAddress>
Mint the NEXT public diversified receive address (FR-8 / Recv-4, ADR-0537): a fresh unlinkable unified address for a contact/invoice that still credits this one wallet — payments to it are detected by the normal shielded scan (including after a seed-only restore), with no extra host work. Same receiver set as currentAddress (shielded-only), so no compatibility downgrade. Every call returns a NEW address from the SDK's never-recycle, restore-surviving counter; deterministic per WalletMintedAddress.diversifierIndex — keep the index as the durable host-side attribution key. Cheap, local, no network, not gated on sync. Throws the typed bridge error before an account is provisioned (exotic — accounts import eagerly at create). §5.4 NEVER-LOG applies to BOTH fields.
override
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
parseSendRequest(String uri) → WalletSendRequest
Parse a ZIP-321 zcash: payment URI (a scanned QR, a deep link — HOSTILE input) into a WalletSendRequest for the FR-25 prefilled-send seam — the DECODE inverse of composePaymentUri. SYNCHRONOUS, no money movement: the adapter runs it through the audited core payment_uri parser against the wallet's OWN network (so a cross-network URI is the SDK's typed NetworkMismatch, never a host-supplied-network footgun), and applies the single-recipient / text-memo seam policy. The bridge crossing (parsePaymentUri) lives in the adapter — never in the UI layer — so the prefill flow stays host-VM testable behind a fake. Throws a typed WalletSendRequestException (malformed / wrong-network / multi-leg / unsupported-memo) so the host rejects at the seam, never a half-filled form. WalletSendRequest.fromUri is the public sugar over this.
override
probeSyncServer(SyncServerChoice choice) → Future<SyncServerProbe>
Dial choice under the wallet's own Tor policy and ask the server who it is (one round trip, 15 s budget). Throws typed — WalletErrorKind.syncServerUnreachable, .networkMismatch, .syncServerNotOffered, .invalidEndpoint (a custom URL the door refuses) — and NEVER switches: the picker's "Check server" step. The switch itself is the provisioner's (WalletProvisioner.switchSyncServer) because it swaps the session.
override
propose(String requestUri) → Future<SendProposal>
Prepare a send from a ZIP-321 payment URI (the §2.4 lossless request token the host composes via composePaymentUri, or a scanned QR). DETERMINISTIC, LOCAL: runs the audited note-selection + fee + change over the wallet DB and returns the numbers the user confirms before signing — no keys, no proofs, no network, no DB writes, nothing sent. The proposal stays an opaque, Rust-retained one-shot token; send consumes it by proposalId.
override
proposeShield() → Future<SendProposal?>
Propose shielding the wallet's detected TRANSPARENT funds into its shielded pool (Recv-3 — the companion to currentTransparentAddress). Exchange withdrawals + swap-in deliveries land transparent; this is the privacy-POSITIVE "move them shielded" action. DETERMINISTIC, LOCAL like propose: no keys, no proofs, no network, no DB writes — NOTHING is sent.
override
push(SyncStatus status) → void
Push a new live status to the active subscription (and make it the value a later subscribe replays).
pushIncoming(IncomingFundsEvent event) → void
Push a live/memo-refresh event to the active incoming subscription.
pushSwap(SwapStatus status) → void
Push a new live swap status to the active subscription (and make it the value a later subscribe replays).
pushSwapTerminal(SwapStatus status) → void
The CORE's terminal pattern: emit the terminal status, THEN close the stream (the poll loop emits the final status and ends). The notifier must read this as a clean end, NOT a reconnect.
queueSend(String requestUri) → Future<String>
Queue a send for OFFLINE-first delivery (invariant 4): durably persist the send INTENT (the same ZIP-321 URI) and return immediately — no network, no signing, no money movement. It survives a process kill and proposes → signs → broadcasts on the next online sync (proposing at SEND time, not now, is what stops a long-queued send from ever carrying a stale anchor). Returns the opaque queued-send id; throws queuedSendsFull at the durable cap (a real send is never silently dropped).
override
reclaimEphemeralSlots() → Future<ReclaimOutcome>
REOPEN a one-time-address (TEX) send window bricked by leaked reservations (#315 slice 2) — sends that reserved a one-time address but never confirmed, which the wallet cannot free on its own. Self-mints a small amount from your SHIELDED balance to the highest provably-abandoned one-time address; mining it reopens the whole window. MONEY-MOVING + EXPLICIT: authorize it (the #327 seam) with the honest-cost disclosure (the mint + a later recovery are TWO transactions, ~4 network fees; the moved principal returns to your wallet via sweepEphemeralFunds). Returns a ReclaimOutcome: Minted (INITIATED — the window reopens once it confirms), NothingToReclaim (no abandoned reservation — the window is transient), or NotBroadcast (money-safe transport miss; retry). It unblocks the WINDOW only — it NEVER re-sends a paused/queued payment (no double-pay). ⚠ HOST GATING: offer it ONLY when a send is actually parked/paused — the SDK cannot tell a bricked window from a healthy one (no engine occupancy read), so a call otherwise mints uselessly (fee-waste, never fund-loss). Throws a typed WalletApiError (seedRequired with no key, insufficientFunds when the shielded balance can't fund the mint, invalid-state on a closed handle).
override
recordSwapOutcome({required String swapId, required SwapOutcome outcome}) → Future<bool>
Pin an OBSERVED terminal outcome into an in-flight swap record (#367) — call when the tracking stream reports a TERMINAL status, so the home row renders the truth even if the user was away at observation time (deleting on observation erased outcomes the user never saw — durably, if the process died in the gap). First-wins + idempotent (false for an absent / lapsed / already-pinned id). Display-only state.
override
recoverableEphemeralFunds() → Future<List<RecoverableEphemeralFunds>>
The wallet's RECOVERABLE one-time-address funds (2e-2b) — amounts sitting on wallet-controlled single-use (ephemeral) transparent addresses: an expired TEX forward whose second step never completed, OR an exchange that returned a deposit to such an address. Each entry is AMOUNT-ONLY — the one-time address is wallet-internal and NEVER crosses the bridge (§5.4 never-render). The amount is a SUBSET of BalanceSnapshot.transparentZat/.totalZat (the engine already folds these outputs into the displayed balance), so the host renders it as "X OF your balance is on a one-time address", NEVER "+X" (that would over-count holdings ~2×). Cheap, LOCAL (a SQLite read), no network, no money movement. LIVE since gate-removal (2e-2b-v-5a) — empty only on a wallet that has stranded nothing on a one-time address.
override
retryParkedSend({required int id, required int createdAt}) → Future<bool>
RETRY a paused parked send (#315 slice 1) — resume the SAME queued intent after the wallet gave up auto-retrying it (ParkedSend.paused): retries of a one-time-address send are capped because each one permanently uses up one of a small number of address slots. When the user believes conditions changed (back online, the recipient service reachable), THIS is the resume path — never cancel + re-enter (double-pay risk + it silently evades the retry cap on a fresh send). Pass BOTH the id AND the createdAt from the ParkedSend. Returns true if re-armed (it attempts again on the next background pass — not instantly), false if already gone / began sending / rowid reused (idempotent — re-read listParkedSends). MONEY-SAFE: only re-arms the existing intent's retry budget; nothing is signed or sent by the call itself. Throws a typed WalletApiError (invalid-state on a closed handle).
override
send(int proposalId) → Future<List<TxSubmitResult>>
Sign + broadcast a prepared proposal — consumes the one-shot proposalId. A per-tx broadcast outcome is first-class DATA (the returned list), NEVER a thrown error: a tx that fails to broadcast is persisted and re-sent by the resubmission machinery on the next sync, so even a total broadcast failure loses no funds, only immediacy. Throws only for a consumed token (proposalAlreadyUsed), a stale anchor (proposalStale ⇒ re-propose), or a build/sign failure (signFailed).
override
setSnapshot(WalletState state) → void
Set the cold-read state. Also moves _current so the two stay coherent — see snapshot for why the fake must not present a split the core cannot.
snapshot() → Future<WalletState>
The on-resume cold snapshot (spec §3.3): balance, sync status, Tor state, chain tip, balance age, and the monotonic seq. Cheap; safe to call on resume before re-subscribing to the live stream.
override
startSync() → Future<void>
Start the background sync loop — required for watchSyncStatus to advance past idle. Idempotent.
override
stopSync() → Future<void>
Stop the background sync loop. Idempotent; durable progress is kept (the chain is the source of truth). Pauses sync WITHOUT closing.
override
swapAddressCheckCoverage() → Future<SwapAddressCoverage>
#390 — the render-only coverage read for the "Check older swap addresses" sheet: how far the wallet has already checked (coveredSwaps) and how many addresses are still to be registered + polled (pending; 0 = nothing outstanding). COUNTS-only. Read-only, side-effect-free — safe to re-pull while the sheet is open. Throws invalid-state on a closed handle.
override
swapExecute({required SwapQuote quote}) → Future<String>
Execute a quote — register the swap intent with the provider and (for an OutOfZec quote) queue the §4.4 ZEC deposit send. Pass back the SwapQuote swapQuote returned; the SDK claims its own durable single-flight by the quote id BEFORE anything happens (idempotent against a double-tap / crash retry — exactly ONE deposit per quote), and the deposit uses the SDK's own frozen record, NEVER this DTO, so a tampered field can't redirect funds. Returns the opaque provider swap id (do NOT parse it; pass it to watchSwapStatus). Throws a typed SwapApiError (quoteExpired ⇒ re-quote — since #367 this also covers a not-issued/already-executed quote (every take-miss reads "no longer valid"); swapStateBusy ⇒ retry the SAME execute (nothing consumed); depositSendFailed ⇒ re-quote).
override
swapListTokens() → Future<SwapTokenList>
The dynamic source-asset list for the IntoZec picker (spec §3.3b D5/L6). LAZY — called when the user opens the IntoZec form (NOT on launch: §5.2 honest-off, an idle user emits no token traffic). The SDK fetches /v0/tokens over the swap dialer (Tor-optional, its OWN circuit), filters the ZEC asset + $0/null-price entries, and caches the result. On a fetch fault it serves the LAST good list with SwapTokenList.fresh = false (the host shows a "couldn't refresh, showing cached" banner — honest degradation, never a blank picker); a first-ever fault with no cache throws a typed SwapApiError. An empty tokens with fresh == true is the honest "no assets available right now". No wallet key material crosses — token metadata is §5.4 never-logged.
override
swapQuote({required QuoteRequest request}) → Future<SwapQuote>
Request a bounds-checked swap quote (spec §2.6) — the FIRST step of the on-ramp. DETERMINISTIC against the user's exact side; funds NEVER move. The returned SwapQuote carries the deposit address, the min-out floor, the ZEC side in zatoshis, and the §2.6 privacy disclosure the host MUST render. Throws a typed SwapApiError (slippageToleranceTooHigh, quoteOutOfBounds, destinationInvalid, providerUnavailable, swapDisabled, …) the controller maps to an honest inline fault.
override
sweepEphemeralFunds() → Future<EphemeralSweepSummary>
MANUALLY recover funds stranded on wallet-controlled one-time (ephemeral) transparent addresses into the wallet's OWN shielded balance (2e-2b-v-2) — the "recover now" action behind the recoverableEphemeralFunds note, PLUS late exchange returns / a 2nd deposit the automatic surface can't see. MONEY-MOVING: it signs + broadcasts one consolidating tx per funded address (each over its own circuit, never co-spent — so a recovery never links the one-time-address set on-chain). The returned EphemeralSweepSummary is COUNTS-only (the one-time addresses NEVER cross the bridge); recoveredZat is PROVISIONAL (accepted ≠ mined — render "pending" until the scan settles it) and IDEMPOTENT on re-run (the engine excludes already-spent UTXOs, so it can never double-spend); failed > 0 ⇒ some funds stay on-chain + re-runnable; truncated > 0 ⇒ a heavy wallet hit the per-invocation cap — run again. Throws a typed WalletApiError (seedRequired when the wallet cannot sign, invalid-state on a closed handle). Gate the affordance on a SUCCESSFUL recoverableEphemeralFunds read showing funds — NEVER offer it from an error/empty fallback (a failed read must not read as "nothing to recover", hiding held funds). LIVE since gate-removal (2e-2b-v-5a): a no-op only when no one-time address holds funds.
override
syncServers() → Future<List<SyncServer>>
The sync servers the host OFFERS (the picker, P3-13 — WalletConfig. syncServers as validated), WITHOUT their keys (authValue is always null here; authHeader says whether an entry is gated). Read-only.
override
syncServerStatus() → Future<SyncServerStatus>
Which server the wallet dials, which remembered choice produced it, and whether a fallback is in force — the connection's own truth, which is what the sync sheet's Server row renders (host only, never the URL).
override
toString() → String
A string representation of this object.
inherited
transactions({required int limit, String? after}) → Future<HistoryPage>
The transaction history for the activity list (FR-1), newest first and paginated by an OPAQUE keyset cursor: pending (unmined) rows sort above confirmed ones; after is null for the first page or the previous HistoryPage.nextCursor for the following page (passed back VERBATIM — never parse it); limit caps the page (clamped Rust-side). The keyset cursor means a page boundary never drops a same-height row nor strands the confirmed history behind a full page of pending txs. Each TxSummary carries the SIGNED net amount, status/confirmations, fee, and a memo flag — DISPLAY data only (no key material; §5.4 NEVER-LOG: txids/amounts/cursors). Reads librustzcash's v_transactions view off the sync lock, so it's cheap and never blocks scanning.
override
validateRecipient(String address) → ValidatedAddress
Classify a recipient address against the wallet's OWN network — its memo capability (the §5.1 SHIELDED-vs-TRANSPARENT / private-vs-public axis) — WITHOUT composing or proposing anything. Drives the send form's LIVE recipient feedback + memo gating. The screen never needs to know mainnet/testnet (the same network-hiding seam as composePaymentUri, so a host-supplied network can never be a footgun). SYNCHRONOUS, local, NO network, no money movement — safe to call on every keystroke and fully offline (the same audited Address::parse gate propose lowers through, so the live check can never disagree with what a send will accept). Throws a typed WalletApiError (addressInvalid for malformed, networkMismatch for an other-network address) the host maps to an honest inline status.
override
watchIncomingFunds({String? sinceCursor}) → Stream<IncomingFundsEvent>
The incoming-funds event stream (spec §3.3 / ADR-0536, amended by ADR-0539 — the FR-1 "funds arrived" hook). ONE replay event first (arrivals already in history strictly above sinceCursor; a null cursor gets a count-0 baseline that hands the subscriber a cursor to keep), then a live event per scan batch that detected arrivals, and a memoRefresh nudge when a later enhancement pass changes how existing rows read — either decrypted tx data landed, or a transaction's chain status did, so memoRefresh means "re-pull", NEVER "new memo data exists". The payload is counts + heights + an opaque cursor ONLY (safe to log or forward); details are a pull via transactions. Delivery is at-least-once with latest-wins coalescing — totalTxDetected is the coalesce-proof monotonic. A rescan/restore REPLAYS history with old spans: the stream is a freshness signal, never an accounting ledger. A malformed sinceCursor surfaces as a stream error (typed storeCorrupt) — including a HistoryPage.nextCursor keyset token passed here by mistake (the two cursor families are deliberately incompatible). NOTIFICATION-driving hosts: gate on spanToHeight > your own acked watermark (the max you have told the user about — tracked on YOUR side; the cursor is only for sinceCursor) plus your own consumed-txid ledger for exactly-once.
override
watchSwapStatus({required String swapId}) → Stream<SwapStatus>
The live SwapStatus stream for one in-flight swap (spec §3.3/§7). Emits the CURRENT status immediately on subscribe (so a re-subscribe after a background gap re-renders at once), then polls at a bounded cadence. It NEVER completes on a transient provider fault (a stall is retried behind the scenes, not a dead stream); it completes only on a TERMINAL status (success/refunded/failed) — drained first — or when the wallet is closed/swap is hard-killed. swapId is the opaque id swapExecute returned.
override
watchSyncStatus() → Stream<SyncStatus>
The live SyncStatus stream (spec §3.3). Emits the CURRENT status immediately on subscribe (so a re-subscribe after a background gap re-renders at once), then every change coalesced latest-wins. It NEVER completes on a transient fault — a stall is a SyncStatus.stalled EVENT, not an error or EOF.
override

Operators

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