Redesign the mainnet migration screens - #650
Conversation
The checking page turns into the outcome page on its own once testnet answers (after a 1.5 s minimum), with one page per outcome: blocks mined, nothing carried over, couldn't check. Keeping the wallet leads to an all-set page with Get QTC and Go to wallet. Creating a new wallet asks first and then adds a wallet next to the existing one via the shared createSoftwareWalletFlow, which the welcome screen now uses too. Debug builds show the notice on every launch with an outcome picker on the checking page. QuantusDialog gains a banner slot and cancelIsPrimary, QuantusBanner a label on the icon layout, QuantusBadge a leading dot.
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT 5.6 Sol
Verdict (advisory): Request changes
Blocking finding:
mobile-app/lib/services/wallet_creation_service.dart:61-81,93-115— Make the new-wallet flow retry-safe once persistence has begun.createNewWalletstores the mnemonic and marks the mainnet migration done before it inserts the root account; after insertion,_createSoftwareWalletstill awaits active-account selection and encrypted-account backfill. An insert failure therefore suppresses this migration screen after restart even though the requested wallet was not created. A failure in either later await is also caught and shown as “wallet creation failed” even though the new root is already stored; tapping Create again recomputesnextWalletIndexfrom that root and creates another wallet. Please define a commit point and either roll the operation back fully or treat post-commit work as best-effort/success, and add coverage for failures immediately before and after the root-account insert.
Validation:
- Reviewed exact base
9eccf8d7to head6043373f;git diff --checkpassed. - Changed Dart files pass
dart format --output=none --set-exit-if-changed --line-length=120. mobile-app: all 446 tests passed.quantus_sdk: all 484 non-native tests passed.cold-wallet-app: all 285 tests passed, covering the shared dialog consumers.- Repository analysis completed cleanly for
quantus_sdk,miner-app, andcold-wallet-app; local mobile analysis exceeded the required 10-second cutoff, while the PR's GitHub Analyze check is successful. - The linked Figma node was not accessible in this unattended environment, so visual fidelity was not independently compared.
| Text(l10n.mainnetMigrationChecking, style: text.bodyLarge.copyWith(color: colors.textMuted)), | ||
| if (onPickOutcome != null) ...[ | ||
| const SizedBox(height: 24), | ||
| Text('DEBUG: pick the testnet outcome', style: text.caption.copyWith(color: colors.textMuted)), |
There was a problem hiding this comment.
We need to remove this debug text
| spacing: 8, | ||
| runSpacing: 8, | ||
| children: [ | ||
| for (final outcome in [...debugTestnetOutcomes, null]) |
There was a problem hiding this comment.
hm, so if debug Testnet is not exist, it will be null. Then outcome null will be passed. IDK this is kinda weird.
| onDebugOutcome: (outcome) => ref.read(forcedTestnetOutcomeProvider.notifier).state = outcome, | ||
| ), | ||
| _StatusPage( | ||
| _CheckingPage(l10n: l10n, onPickOutcome: ref.watch(debugMainnetMigrationProvider) ? _pickOutcome : null), |
There was a problem hiding this comment.
Is this checking page only for debugging?
| trailingParagraphs: [l10n.mainnetMigrationMinerBalance(AppConstants.tokenSymbol)], | ||
| actions: [_finishButton(l10n.commonDone, TestnetUserKind.miner)], | ||
| TestnetUserKind.miner => _outcome( | ||
| kind: TestnetUserKind.miner, |
There was a problem hiding this comment.
Let's be consistent whether we pass explicit enum or reuse the variable status.kind
dewabisma
left a comment
There was a problem hiding this comment.
Few nits, overall good no blocker.
The root-account insert is now the commit point. The mnemonic is written first and deleted again if the insert fails, so a failed attempt leaves nothing behind and the migration notice stays pending. The active-account, wallet-origin and migration-done writes move after the insert and are best-effort, as is the encrypted-account backfill: the wallet already exists, and reporting those as a failed creation prompted a retry that created a second wallet. The old existing-root branch, which overwrote a stored wallet's mnemonic with a fresh one on retry, is gone with it.
n13
left a comment
There was a problem hiding this comment.
Reviewer model: GPT 5.6 Sol
Verdict (advisory): Approve
No blocking findings.
The follow-up commit resolves the earlier wallet-creation blocker: the root insert is now the commit point, a failed insert removes the just-written mnemonic and remains retryable, and failures after a persisted root no longer surface as a failed creation that invites an immediate duplicate. The old existing-root path that could replace a stored wallet's mnemonic is also gone, with focused coverage on both sides of the commit point.
Validation:
- Reviewed the complete 19-file diff from exact base
9eccf8d7bdf74c0a92f8c461de774091672d5c1fto current head1865bdf66da363fb783fceddf60eb9b877f2b7ac; the head was rechecked before posting. git diff --checkpassed, and all 17 changed Dart files passdart format --output=none --set-exit-if-changed --line-length=120.mobile-app: all 448 tests passed.quantus_sdk: all 484 non-native tests passed.- Repository analysis completed cleanly for
cold-wallet-app,miner-app, andquantus_sdk; the local run was stopped at the required 10-second cutoff asmobile-appbegan, while the current GitHub Analyze check passes. - The linked Figma node was not accessible from this unattended environment, so visual fidelity was not independently compared.
Summary
Implements the Figma "Mainnet Migration" section (node 372-6813), frames 01–07.
READING TESTNET HISTORY. No Next button any more: the page turns into the outcome on its own once the testnet check answers (1.5 s minimum so it never flashes past).BLOCKS MINED ON TESTNET, "Keep this wallet." + body, single primary button.COULDN'T CHECKbadge, two paragraphs, same two buttons. The Retry button is gone as in the design.MAINNETbadge, "You're all set.", Get QTC (retires the notice and opens the Receive screen) and Go to wallet."Create new wallet" now does what the dialog copy says: it adds a fresh software wallet on the next free wallet index and keeps the existing one on the device (previously it went through the reset flow, which wipes the wallet). The creation logic was extracted from the welcome screen into
createSoftwareWalletFlow, so the welcome screen and the migration screen share it; the new wallet's root becomes the active account and the flow lands on the existing Wallet Created page.Testing buttons
Debug builds show the notice on every launch (
AppConstants.debugMainnetMigration = true) and the checking page has a picker:miner,holder,newcomer,error,real. Each pick runs that flow with fake data; hot restart to pick another. Flip the constant tofalseto see the notice only when it is due.Shared components (quantus_sdk)
QuantusDialog/showQuantusDialog: optionalbannerslot,cancelIsPrimary, title now Title/Screen (20) per the design, body scrolls instead of overflowing on short screens.QuantusBanner: optionallabelon the icon layout (label in tone colour, message in muted caption).QuantusBadge:dotfor the leading status dot.None of these change existing call sites.
Not included
Frame 08 (home activity empty state, "Nothing on mainnet yet / Your testnet activity stayed on testnet") is not in this PR: the copy only makes sense for wallets that came from testnet, and nothing persists that distinction today (creating or importing a wallet also sets the migration-done flag). Happy to add it with a stored marker if wanted.
Verification
flutter testin mobile-app: 446 tests pass, including the rewrittenmainnet_migration_screen_test.dart(auto-advance, all three outcomes, both dialogs, Get QTC, failed completion write, debug picker).app_en.arbandapp_id.arb;flutter gen-l10nrun.