Skip to content

feat(wallet): unify wallet lifecycle loaders behind an app-wide overlay - #1062

Merged
llbartekll merged 7 commits into
developfrom
feat/wallet-lifecycle-overlay
Aug 25, 2026
Merged

feat(wallet): unify wallet lifecycle loaders behind an app-wide overlay#1062
llbartekll merged 7 commits into
developfrom
feat/wallet-lifecycle-overlay

Conversation

@llbartekll

@llbartekll llbartekll commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Issue being fixed or feature implemented

Supersedes #1054 and carries its two commits unchanged — the review there grew the scope from a network-switch overlay into unifying every wallet-lifecycle loader, so this single PR replaces the stacked pair.

Two problems on top of the original freeze fix:

  • Wallet switch and removal used a screen-local overlay owned by a per-screen view model. The DASHPAY tab rebuild on the active-wallet change destroys that screen mid-flow, so removing the active wallet continued with no visible progress and failures were silently lost; the Home "Switch Wallet" shortcut had no loader at all for a ~10 s operation.
  • waitForPendingWipe reported completion when wallet data was deleted while the runtime teardown was merely enqueued — wipe HUDs dropped early, and a wallet created right after could race the still-queued reset.

Platform dependency: dashpay/platform#4469 is now MERGED — this PR requires platform v4.2-dev at or past 1e26927c61 (the #4469 merge, whose ancestor #4470 changed the estimateShieldedFee API). Based on #1063, which adapts the app to that API; merge #1063 first.

What was done?

  • WalletLifecycleTransitionState (own file): one presentational phase machine (network switch, wallet switch, removal, wipe) with a MainActor-atomic admission gate for interactive operations. A wipe is admitted from EVERY failure phase, keeping the reset route as the universal escape hatch. Admission matrix pinned by a compile-ready table test (WalletLifecycleTransitionStateTests; repo test target is temporarily broken).
  • WalletLifecycleOverlay (own file): the dedicated-UIWindow presenter, Obj-C bridge, view model and per-phase cards. Failure cards: blocking Retry + Switch Back for network switches (failedNetworkSwitch carries from, preserved across repeated failed retries); blocking Retry + Switch Back for wallet switches (previousId preserved likewise); dismissable OK for removal failures.
  • WalletsViewModel.gatedSwitchWallet: one gated wrapper shared by the row switch, the post-add switch, the pre-remove auto-switch, and the overlay card's actions; active-wallet removal advances Switching → Removing without dropping the window.
  • Wipe contract: performWipe blocks the wipe executor's queue until the runtime's fullReset completes (bounded at 180 s — on expiry it reports failure, never success, while the queued teardown finishes in the background), so waitForPendingWipe means "data wiped AND runtime torn down".
  • The Obj-C wipe flows (root Delete All, phrase-authorized recover wipe) render in the same overlay via DWWalletLifecycleOverlayBridge: rejected admission refuses to start a concurrent wipe and says so (alert), every gate acquisition is paired with a release on all paths, and the DASHPAY tab rebuild is deferred (not dropped) while a wipe is in flight.
  • Detached managers shut down on every path, including a throwing loadFromPersistor().

How Has This Been Tested?

  • DashPay Debug build for a generic iOS Simulator against platform v4.2-dev @ 1e26927c61 (rebuilt FFI, both slices): BUILD SUCCEEDED — for this branch and fix(wallet): adopt instance estimateShieldedFee from platform #4470 #1063 standalone.
  • Simulator smokes on testnet: mainnet ↔ testnet switch (overlay over the rebuilt root), wallet create with post-add switch (overlay above the sheet), row switch (overlay above the tab bar, landing on Home after the tab rebuild).
  • Manual verification of the removal flows, failure cards, and both wipe flows is in progress.

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change introduces asynchronous SDK lifecycle management, serialized wallet and network transitions, an app-wide lifecycle overlay, completion-aware wallet wiping, and asynchronous shielded transaction lookup refreshes with explicit operation reasons.

Changes

Wallet lifecycle and shielded synchronization

Layer / File(s) Summary
Asynchronous SDK startup and teardown
DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKHost.swift, DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKSPVCoordinator.swift
SDK startup and shutdown now use async APIs. Manager construction and teardown await completion, and temporary managers are closed on success and failure paths.
Asynchronous shielded transaction lookup
DashWallet/Sources/Infrastructure/SwiftDashSDK/PlatformAddressSyncCoordinator.swift, DashWallet/Sources/Infrastructure/SwiftDashSDK/AssetLockRecoveryService.swift, DashWallet/Sources/Infrastructure/SwiftDashSDK/UnconfirmedTransactionRemover.swift, DashWallet/Sources/UI/Home/Views/HomeViewModel.swift, DashWallet/Sources/UI/Payments/InternalTransfer/*
Shielded snapshots now use detached SwiftData reads, generation checks, error preservation, and diagnostics. Refresh callers now await the API and provide operation reasons.
Managed network and wallet transitions
DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift, DashWallet/Sources/Infrastructure/SwiftDashSDK/WalletEnvironment.swift, DashWallet/Sources/UI/Menu/Security/Wallets/*, DashWallet/Sources/UI/Menu/Settings/*, DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift, DashWallet/Sources/UI/Main/MainTabbarController.swift
Network and wallet operations now use shared admission and transition phases. Runtime readiness, managed notifications, retries, failure states, and the app-wide overlay coordinate these operations.
Completion-aware wallet wiping
DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletWiper.swift, DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift, DashWallet/Sources/UI/RootNavigation/DWAppRootViewController.m, DashWallet/Sources/UI/Setup/RecoverWallet/DWRecoverViewController.m, DashWallet/Sources/UI/Menu/Settings/SettingsScreen.swift
Wipe flows now use lifecycle admission and a shared overlay. Runtime teardown and temporary-manager cleanup complete before wipe completion handling continues.

Estimated code review effort: 5 (Critical) | ~90 minutes

Merge Risk: 🟡 Moderate · up to 03dd5

The PR unifies wallet lifecycle progress handling, but wipe operations can still remain blocked indefinitely if runtime teardown stalls, and failed persisted-wallet loading can leave temporary runtime resources alive. These paths may prevent recovery flows from completing or cause follow-up wallet operations to race cleanup, so merge should wait for bounded teardown and failure-path cleanup or explicit owner acceptance.

Suggested reviewers: quantumexplorer, jeanpierreroma

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.20% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 17 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: wallet lifecycle loading states now use a unified app-wide overlay. It is concise and specific.
Full details: Docstring Coverage

Explanation

Docstring coverage is 66.20% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 71 functions across 17 files. (2 skipped: 2 unsupported.)

✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/wallet-lifecycle-overlay

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift (1)

650-759: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move WalletLifecycleTransitionState into its own file.

This type is a published UI-presentation state machine plus an admission gate. It now lives in the same file as the runtime lifecycle pipeline, which already owns network switching, wallet switching, and full-reset teardown. The coding guidelines require one responsibility per file and call out exactly this accumulation pattern for a coordinator that gathers published UI state next to storage teardown.

Extract it to WalletLifecycleTransitionState.swift. No behavior change is needed.

As per coding guidelines: "One file = one responsibility — a 'coordinator' that accumulates published UI counters, storage wipes, and money movement gets split."

🤖 Prompt for AI Agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

In
`@DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift`
around lines 650 - 759, Extract the WalletLifecycleTransitionState class,
including its Phase enum and lifecycle methods, into a dedicated
WalletLifecycleTransitionState.swift file; remove the duplicate definition from
SwiftDashSDKWalletRuntime.swift and preserve its behavior and access levels
unchanged.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.

Inline comments:
In `@DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKHost.swift`:
- Around line 932-941: Update managerForStoredWalletOperation to be async and
ensure the detached manager is shut down if loadFromPersistor() throws before
rethrowing; propagate try await through managerForWipe and both
createOrImportWallet/addWallet call sites while preserving existing
temporary-manager cleanup.

In
`@DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletWiper.swift`:
- Around line 345-361: Bound the non-main-thread wait in the
SwiftDashSDKWalletWiper teardown flow so it cannot block indefinitely when
startup work stalls. Coordinate the timeout with
SwiftDashSDKWalletRuntime.handleWalletWiped and fullReset: do not report the
wipe as complete or allow a new wallet to proceed until runtime teardown has
finished, even if the wait deadline expires; preserve the existing main-thread
deadlock avoidance behavior.

In `@DashWallet/Sources/UI/Menu/Settings/SettingsScreen.swift`:
- Around line 280-281: Extract WalletLifecycleOverlayPresenter,
WalletLifecycleOverlayBridge, WalletLifecycleOverlayViewModel, and
WalletLifecycleOverlayView from SettingsScreen.swift into a dedicated
lifecycle-overlay source file, preserving their existing behavior and
declarations. Leave SettingsScreen.swift responsible only for settings UI and
update any required references or imports.

---

Nitpick comments:
In
`@DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift`:
- Around line 650-759: Extract the WalletLifecycleTransitionState class,
including its Phase enum and lifecycle methods, into a dedicated
WalletLifecycleTransitionState.swift file; remove the duplicate definition from
SwiftDashSDKWalletRuntime.swift and preserve its behavior and access levels
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 90d49426-a209-47ba-8e7a-32180e79f2de

📥 Commits

Reviewing files that changed from the base of the PR and between 53bb20d and 03dd5f4.

📒 Files selected for processing (19)
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/AssetLockRecoveryService.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/PlatformAddressSyncCoordinator.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKHost.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKSPVCoordinator.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletRuntime.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/SwiftDashSDKWalletWiper.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/UnconfirmedTransactionRemover.swift
  • DashWallet/Sources/Infrastructure/SwiftDashSDK/WalletEnvironment.swift
  • DashWallet/Sources/UI/Home/HomeViewController+Shortcuts.swift
  • DashWallet/Sources/UI/Home/Views/HomeViewModel.swift
  • DashWallet/Sources/UI/Main/MainTabbarController.swift
  • DashWallet/Sources/UI/Menu/Security/Wallets/WalletsScreen.swift
  • DashWallet/Sources/UI/Menu/Security/Wallets/WalletsViewModel.swift
  • DashWallet/Sources/UI/Menu/Settings/SettingsMenuViewModel.swift
  • DashWallet/Sources/UI/Menu/Settings/SettingsScreen.swift
  • DashWallet/Sources/UI/Payments/InternalTransfer/InternalTransferConfirmSheet.swift
  • DashWallet/Sources/UI/Payments/InternalTransfer/ShieldedTransferCoordinator.swift
  • DashWallet/Sources/UI/RootNavigation/DWAppRootViewController.m
  • DashWallet/Sources/UI/Setup/RecoverWallet/DWRecoverViewController.m

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment thread DashWallet/Sources/UI/Menu/Settings/SettingsScreen.swift Outdated
@romchornyi

Copy link
Copy Markdown
Contributor

Reviewed this. The design is careful and the comments are honest about their own trade-offs. One cross-repo problem blocks the merge outright, and one design gap is worth fixing before it lands.

Blocking: the declared dependency cannot be taken as written

The PR depends on dashpay/platform#4469, and genuinely needs it — await manager.shutdown() and SwiftDashSDKHost.stopAsync() are that API. The problem is where that commit sits on v4.2-dev:

1e26927c61  #4469  feat(swift-sdk): async off-main wallet manager shutdown   <- the dependency
bea4122858  #4470  estimate shielded fees at the network's active protocol version
d3b53db31e  #4477  ...

git merge-base --is-ancestor bea4122858 1e26927c61 confirms #4470 is an ancestor of #4469. #4470 turned estimateShieldedFee from a static func into an instance method, and this branch still calls it statically:

InternalTransferConfirmSheet.swift:226,228
SDKIdentityProfileSheet.swift:445
InternalTransferViewModel.swift, SendScreen.swift, ShieldedTransferCoordinator.swift

So pinning at #4469 fails to compile on estimateShieldedFee; pinning below it leaves shutdown() undefined. There is no platform revision that satisfies both until the #4470 adaptation lands on the app side, and no open dashwallet PR does that today. Worth splitting out as its own small PR ahead of this one.

The failure phases have no escape hatch, and they lock out the reset path

tryBegin admits .wiping only from .idle:

case (.idle, .switchingNetwork), (.idle, .switchingWallet),
     (.idle, .removingWallet), (.idle, .wiping),
     (.failedNetworkSwitch, .switchingNetwork),
     (.failedWalletSwitch, .switchingWallet):

While any .failed* phase is showing, both wipe entry points — DWAppRootViewController Delete All and DWRecoverViewController's phrase-authorized wipe — are rejected and return silently. And .failedNetworkSwitch offers only Retry.

Concretely: a user switches to testnet, the runtime does not come up (no peers, DAPI down). The card says "Switching to Testnet failed" with a Retry that keeps failing. The overlay window sits at .alert + 1 and blocks everything, so Settings -> Reset Wallet is unreachable. Reinstalling the app becomes the only exit — the worst possible dead end for a wallet.

It is also structurally hard to offer a way back: .failedNetworkSwitch(target:message:) does not carry from, so a "Switch Back" action would need a signature change even though .switchingNetwork(from:to:) already has that value and drops it when building the failure phase.

Minimum fix: admit .wiping from any .failed* phase so the reset route stays reachable.

Gate leak in beginWipeWalletWithAuthorization:

The gate is taken, then the dispatch_after body can return without releasing it:

if (![DWWalletLifecycleOverlayBridge beginWipingWithTitle:nil]) { return; }
self.walletWipeInProgress = YES;
...
dispatch_after(startTime, dispatch_get_main_queue(), ^{
    typeof(self) strongSelf = weakSelf;
    if (strongSelf == nil) {
        return;            // finishWiping never runs
    }

.wiping then sticks forever, which combined with the point above means a permanently blocked app. Unlikely for the app root controller to die inside 100 ms, but the cost is total and the fix is one line.

Smaller things

MainTabbarController drops the reconfiguration instead of deferring it. The sibling branch sets pendingDashPayTabReconfiguration = true and returns; the new .wiping branch just returns. That is right for a successful wipe (onboarding replaces the stack), but a failed wipe leaves the app in the main UI with a potentially stale DashPay tab set.

performWipe returns true on the main-thread path. The timeout path correctly returns false, but the Thread.isMainThread branch logs and falls through to return true — reporting "data wiped AND runtime torn down" when the teardown is merely queued, which is exactly the contract this PR sets out to fix. Worth making it as conservative as the timeout path.

advance(to:) guards with assert, which is a no-op in release. If it ever runs from .idle, a release build shows an overlay with no owner left to clear it.

Rejected admission is silent at both wipe entry points. In DWRecoverViewController the user has just typed their recovery phrase and confirmed a destructive action, and nothing visible happens.

No tests. tryBegin is a pure MainActor function; a small table test would pin the admission matrix, which is the safety-critical part of this change.

The branch is 9 commits behind develop.

What is right

The wipe contract — waitForPendingWipe meaning "data wiped AND runtime torn down" — is the correct call and well argued. The bounded 180 s wait that reports failure rather than success on expiry is the right default. Detached managers are shut down on every path including the throwing ones, rather than left to a deinit fallback. isRuntimeReady collapses a duplicated predicate. The .managedSwitch notification source stops the observer from double-driving the lifecycle. previousId carried forward across repeated retries is a nice detail that is easy to get wrong. finishWiping running before the weakSelf guard is deliberate and correct. #1054 is properly closed.

llbartekll and others added 7 commits August 25, 2026 15:24
platform v4.2-dev's bea4122858 turned PlatformWalletManager
.estimateShieldedFee from a static func into an instance method computed
at the manager's network-tracked platform version. Migrate all call
sites to the live host manager so the app compiles against v4.2-dev at
or past that commit (prerequisite for consuming the merged #4469
shutdown API).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Await native SDK teardown off the main thread, serialize managed network switches behind an app-wide transition overlay, and move shielded transaction snapshot reads to a private SwiftData context with timing telemetry.
- WalletLifecycleTransitionState: one presentational phase machine with a
  MainActor-atomic admission gate (tryBegin/advance/finish/fail) for
  interactive operations; generalizes NetworkTransitionState in place
- WalletLifecycleOverlayPresenter/-View: the single dedicated-UIWindow
  overlay now covers network switches, wallet switches, per-wallet
  removal and full wipes; per-operation failure cards (blocking Retry
  for network, Retry + Switch Back for wallet switch, dismissable OK
  for removal)
- WalletsViewModel.gatedSwitchWallet: one gated switch shared by the row
  switch, post-add switch, pre-remove auto-switch and the overlay
  card's Retry/Switch Back; the remove flow advances Switching to
  Removing without dropping the window, and failures surface in the
  overlay (the DASHPAY tab rebuild destroys the Wallets screen
  mid-flow, which previously made removal failures silent); the
  screen-local ZStack overlay is gone
- wipe contract: performWipe now blocks the wipe executor's queue until
  the runtime's fullReset completes, so waitForPendingWipe means "data
  wiped AND runtime torn down" - wipe HUDs hold to the real end and a
  wallet created right after can no longer race a still-queued reset
- Obj-C wipe flows (root Delete All, phrase-authorized recover wipe)
  render in the same overlay via DWWalletLifecycleOverlayBridge; their
  UIKit failure alerts stay (DWRecoverViewController.m also carries a
  pre-existing clang-format whitespace realignment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- beginWiping now returns the admission-gate verdict and both Obj-C wipe
  flows refuse to start when another lifecycle operation is in flight (a
  concurrent wipe would mutate wallet state under a switch's teardown)
- finishWiping runs before the weakSelf guard in both wipe completions,
  so the wiping phase can never outlive the wiper barrier when the
  initiating controller is gone
- the DASHPAY tab rebuild is skipped while a wipe is in flight: the
  wallet-removed notification fires mid-wipe and rebuilding would
  deallocate the recover flow awaiting the barrier - losing both the
  overlay dismissal and the transition to onboarding
- a wallet-switch Retry starting from failedWalletSwitch carries the
  saved previousId forward instead of re-sampling the host (which is
  empty or fallback-bound after a failure), so Switch Back survives
  repeated failed retries

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- managerForStoredWalletOperation shuts the detached manager down before
  rethrowing a loadFromPersistor failure (async ripple to managerForWipe
  callers) instead of leaking its native teardown to the deinit fallback
- the wipe's runtime-teardown wait is bounded (180 s): on expiry the wipe
  reports failure - never success while fullReset is unfinished - and the
  queued teardown keeps running in the background
- WalletLifecycleTransitionState and the overlay quartet (presenter,
  Obj-C bridge, view model, card view) move to their own files per the
  one-file-one-responsibility guideline; no behavior change

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Addresses romchornyi's review of the lifecycle overlay:

- failedNetworkSwitch now carries `from` and its card offers Switch Back
  toward the network that was active when the switch began (preserved
  across repeated failed retries, like the wallet card's previousId)
- a wipe is admitted from EVERY failure phase, so Settings -> Reset
  Wallet stays reachable and a persistently failing switch can no longer
  wall the user off behind the overlay
- the Delete All dispatch_after body releases the wiping gate when the
  root controller is gone, instead of leaking `.wiping` forever
- MainTabbarController defers (pendingDashPayTabReconfiguration) instead
  of dropping the rebuild during a wipe, so a FAILED wipe still gets its
  reconfiguration
- performWipe's main-thread branch reports failure like the timeout path
  instead of claiming "torn down" for a merely-queued teardown
- advance(to:) hard-rejects an idle transition in Release rather than
  relying on a debug-only assert
- both Obj-C wipe entry points alert on a rejected admission instead of
  silently swallowing a confirmed destructive action
- WalletLifecycleTransitionStateTests: compile-ready table test pinning
  the admission matrix (repo test-target posture: unrunnable until the
  target is repaired)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@llbartekll
llbartekll changed the base branch from develop to fix/shielded-fee-instance-api August 25, 2026 13:34
@llbartekll
llbartekll force-pushed the feat/wallet-lifecycle-overlay branch from 7401489 to bb2692d Compare August 25, 2026 13:37
@llbartekll

Copy link
Copy Markdown
Contributor Author

@romchornyi Thanks — every point was actionable. All addressed; the branch is rebased onto current develop and force-pushed (now 7 commits, ending bb2692d05).

Blocking (platform dependency): confirmed exactly as you described — 1e26927c61 is the tip of v4.2-dev with bea4122858 (#4470) as its ancestor. Split out as #1063 (fix/shielded-fee-instance-api): all 15 static estimateShieldedFee call sites migrated to the live host manager's instance method. This PR is now based on #1063 and both build green against v4.2-dev @ 1e26927c61 with a rebuilt FFI (both slices). The PR body's dependency note is updated to name the required platform revision.

Escape hatch: .wiping is now admitted from every .failed* phase, and failedNetworkSwitch carries from — its card offers Switch Back toward the network that was active when the saga began, preserved across repeated failed retries (same treatment as the wallet card's previousId). Your exact dead-end scenario (destination network down, Retry loops forever, reinstall as the only exit) now has two ways out.

Gate leak in dispatch_after: fixed — the nil-self path releases the gate before returning.

Smaller things, all taken: the tab rebuild is deferred (pendingDashPayTabReconfiguration = true) rather than dropped during a wipe; performWipe's main-thread branch now reports failure like the timeout path; advance(to:) hard-rejects an idle transition in Release instead of relying on a debug assert; both Obj-C wipe entry points alert on rejected admission instead of silently swallowing a confirmed destructive action; WalletLifecycleTransitionStateTests pins the full admission matrix as a table test (compile-ready per the repo's current test-target posture); rebase done as part of restacking onto #1063.

🤖 Addressed by Claude Code

@romchornyi romchornyi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@llbartekll
llbartekll deleted the branch develop August 25, 2026 17:01
@llbartekll llbartekll closed this Aug 25, 2026
@llbartekll llbartekll reopened this Aug 25, 2026
@llbartekll
llbartekll changed the base branch from fix/shielded-fee-instance-api to develop August 25, 2026 17:03
@llbartekll
llbartekll merged commit 08c3be5 into develop Aug 25, 2026
4 checks passed
@llbartekll
llbartekll deleted the feat/wallet-lifecycle-overlay branch August 25, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants