What changed, and why it matters
This commit refactors how the app decides which wallet setup path to use when restoring or verifying a wallet. It replaces exact class-name checks (like 'is this specifically a Monero wallet?') with broader category checks (like 'is this a CryptoNote-style wallet?'). This is mostly a code cleanup, but it could fix a subtle bug where a new or inherited wallet type would accidentally skip the restore-specific initialization and instead run a normal setup, potentially causing setup problems rather than direct theft of funds.
Treat as a low-risk correctness fix. Review whether any previously unlisted wallet subclass relied on the non-restore `init()` path; if not, this is a safe cleanup. No immediate user action is required, but the change should be included in release notes as a wallet-restore reliability improvement.
Security signals we found
Behavioral change in control flow: previously unlisted wallet subclasses now take the restore-specific branch
Pattern switch on inherited type instead of exact runtimeType
Removal of explicit concrete wallet imports in favor of intermediate abstraction
Potential for inconsistent wallet initialization state if a subclass was missed before
Evidence from the diff
The patch switches Dart switch statements from switch (wallet.runtimeType) with case const (ConcreteWallet): to switch (wallet) with pattern-matching cases like case CryptonoteWallet():. It also replaces concrete imports of MoneroWallet, WowneroWallet, and SalviumWallet with the intermediate CryptonoteWallet import. The functional change is that all subclasses of CryptonoteWallet now match the CryptonoteWallet() case and therefore call init(isRestore: true). Previously, any subclass not explicitly listed (e.g., a new or inherited coin wallet) would fall through to default and call init() without the restore flag. The same pattern is applied in restore_view_only_wallet_view.dart, restore_wallet_view.dart, and verify_recovery_phrase_view.dart.
Changed components
lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dartlib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dartlib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dartWallet initialization/restore logic for CryptoNote-family coinsInspect captured patch +74 / −100
diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart
index e0d3871..845ed7f 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_view_only_wallet_view.dart
@@ -26,9 +26,8 @@ import '../../../wallets/crypto_currency/intermediate/cryptonote_currency.dart';
import '../../../wallets/isar/models/wallet_info.dart';
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
import '../../../wallets/wallet/impl/mimblewimblecoin_wallet.dart';
-import '../../../wallets/wallet/impl/monero_wallet.dart';
-import '../../../wallets/wallet/impl/wownero_wallet.dart';
import '../../../wallets/wallet/impl/xelis_wallet.dart';
+import '../../../wallets/wallet/intermediate/cryptonote_wallet.dart';
import '../../../wallets/wallet/wallet.dart';
import '../../../wallets/wallet/wallet_mixin_interfaces/extended_keys_interface.dart';
import '../../../widgets/custom_buttons/app_bar_icon_button.dart';
@@ -109,10 +108,9 @@ class _RestoreViewOnlyWalletViewState
final ViewOnlyWalletType viewOnlyWalletType;
if (widget.coin is Bip39HDCurrency) {
- viewOnlyWalletType =
- _addressOnly
- ? ViewOnlyWalletType.addressOnly
- : ViewOnlyWalletType.xPub;
+ viewOnlyWalletType = _addressOnly
+ ? ViewOnlyWalletType.addressOnly
+ : ViewOnlyWalletType.xPub;
} else if (widget.coin is CryptonoteCurrency) {
viewOnlyWalletType = ViewOnlyWalletType.cryptonote;
} else {
@@ -216,25 +214,21 @@ class _RestoreViewOnlyWalletViewState
);
// TODO: extract interface with isRestore param
- switch (wallet.runtimeType) {
- case const (EpiccashWallet):
- await (wallet as EpiccashWallet).init(isRestore: true);
- break;
-
- case const (MimblewimblecoinWallet):
- await (wallet as MimblewimblecoinWallet).init(isRestore: true);
+ switch (wallet) {
+ case EpiccashWallet():
+ await wallet.init(isRestore: true);
break;
- case const (MoneroWallet):
- await (wallet as MoneroWallet).init(isRestore: true);
+ case MimblewimblecoinWallet():
+ await wallet.init(isRestore: true);
break;
- case const (WowneroWallet):
- await (wallet as WowneroWallet).init(isRestore: true);
+ case CryptonoteWallet():
+ await wallet.init(isRestore: true);
break;
- case const (XelisWallet):
- await (wallet as XelisWallet).init(isRestore: true);
+ case XelisWallet():
+ await wallet.init(isRestore: true);
break;
default:
@@ -316,10 +310,9 @@ class _RestoreViewOnlyWalletViewState
viewKeyController = TextEditingController();
if (widget.coin is Bip39HDCurrency) {
- _currentDropDownValue =
- (widget.coin as Bip39HDCurrency)
- .supportedHardenedDerivationPaths
- .last;
+ _currentDropDownValue = (widget.coin as Bip39HDCurrency)
+ .supportedHardenedDerivationPaths
+ .last;
}
}
@@ -338,28 +331,27 @@ class _RestoreViewOnlyWalletViewState
return MasterScaffold(
isDesktop: isDesktop,
- appBar:
- isDesktop
- ? const DesktopAppBar(
- isCompactHeight: false,
- leading: AppBarBackButton(),
- trailing: ExitToMyStackButton(),
- )
- : AppBar(
- leading: AppBarBackButton(
- onPressed: () async {
- if (FocusScope.of(context).hasFocus) {
- FocusScope.of(context).unfocus();
- await Future<void>.delayed(
- const Duration(milliseconds: 50),
- );
- }
- if (context.mounted) {
- Navigator.of(context).pop();
- }
- },
- ),
+ appBar: isDesktop
+ ? const DesktopAppBar(
+ isCompactHeight: false,
+ leading: AppBarBackButton(),
+ trailing: ExitToMyStackButton(),
+ )
+ : AppBar(
+ leading: AppBarBackButton(
+ onPressed: () async {
+ if (FocusScope.of(context).hasFocus) {
+ FocusScope.of(context).unfocus();
+ await Future<void>.delayed(
+ const Duration(milliseconds: 50),
+ );
+ }
+ if (context.mounted) {
+ Navigator.of(context).pop();
+ }
+ },
),
+ ),
body: Container(
color: Theme.of(context).extension<StackColors>()!.background,
child: LayoutBuilder(
@@ -384,10 +376,9 @@ class _RestoreViewOnlyWalletViewState
SizedBox(height: isDesktop ? 0 : 4),
Text(
"Enter view only details",
- style:
- isDesktop
- ? STextStyles.desktopH2(context)
- : STextStyles.pageTitleH1(context),
+ style: isDesktop
+ ? STextStyles.desktopH2(context)
+ : STextStyles.pageTitleH1(context),
),
if (isElectrumX) SizedBox(height: isDesktop ? 24 : 16),
if (isElectrumX)
@@ -398,14 +389,12 @@ class _RestoreViewOnlyWalletViewState
key: UniqueKey(),
onText: "Extended pub key",
offText: "Single address",
- onColor:
- Theme.of(
- context,
- ).extension<StackColors>()!.popupBG,
- offColor:
- Theme.of(context)
- .extension<StackColors>()!
- .textFieldDefaultBG,
+ onColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.popupBG,
+ offColor: Theme.of(
+ context,
+ ).extension<StackColors>()!.textFieldDefaultBG,
isOn: _addressOnly,
onValueChanged: (value) {
setState(() {
@@ -469,10 +458,9 @@ class _RestoreViewOnlyWalletViewState
isExpanded: true,
buttonStyleData: ButtonStyleData(
decoration: BoxDecoration(
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .textFieldDefaultBG,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
@@ -485,10 +473,9 @@ class _RestoreViewOnlyWalletViewState
Assets.svg.chevronDown,
width: 12,
height: 6,
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .textFieldActiveSearchIconRight,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .textFieldActiveSearchIconRight,
),
),
),
@@ -496,10 +483,9 @@ class _RestoreViewOnlyWalletViewState
offset: const Offset(0, -10),
elevation: 0,
decoration: BoxDecoration(
- color:
- Theme.of(context)
- .extension<StackColors>()!
- .textFieldDefaultBG,
+ color: Theme.of(context)
+ .extension<StackColors>()!
+ .textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
diff --git a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
index 1627c3c..5d101de 100644
--- a/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
+++ b/lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
@@ -43,10 +43,8 @@ import '../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../wallets/isar/models/wallet_info.dart';
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
import '../../../wallets/wallet/impl/mimblewimblecoin_wallet.dart';
-import '../../../wallets/wallet/impl/monero_wallet.dart';
-import '../../../wallets/wallet/impl/salvium_wallet.dart';
-import '../../../wallets/wallet/impl/wownero_wallet.dart';
import '../../../wallets/wallet/impl/xelis_wallet.dart';
+import '../../../wallets/wallet/intermediate/cryptonote_wallet.dart';
import '../../../wallets/wallet/intermediate/external_wallet.dart';
import '../../../wallets/wallet/supporting/epiccash_wallet_info_extension.dart';
import '../../../wallets/wallet/supporting/mimblewimblecoin_wallet_info_extension.dart';
@@ -343,35 +341,26 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
);
// TODO: extract interface with isRestore param
- switch (wallet.runtimeType) {
- case const (EpiccashWallet):
- await (wallet as EpiccashWallet).init(isRestore: true);
+ switch (wallet) {
+ case EpiccashWallet():
+ await wallet.init(isRestore: true);
break;
- case const (MimblewimblecoinWallet):
- await (wallet as MimblewimblecoinWallet).init(isRestore: true);
+ case MimblewimblecoinWallet():
+ await wallet.init(isRestore: true);
break;
- case const (MoneroWallet):
- await (wallet as MoneroWallet).init(isRestore: true);
+ case CryptonoteWallet():
+ await wallet.init(isRestore: true);
break;
- case const (WowneroWallet):
- await (wallet as WowneroWallet).init(isRestore: true);
- break;
-
- case const (SalviumWallet):
- await (wallet as SalviumWallet).init(isRestore: true);
- break;
-
- case const (XelisWallet):
- await (wallet as XelisWallet).init(isRestore: true);
+ case XelisWallet():
+ await wallet.init(isRestore: true);
break;
default:
await wallet.init();
}
-
await wallet.recover(isRescan: false);
if (wallet is ExternalWallet) {
diff --git a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart
index e19eca1..e57507c 100644
--- a/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart
+++ b/lib/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart
@@ -34,8 +34,7 @@ import '../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../wallets/crypto_currency/intermediate/bip39_hd_currency.dart';
import '../../../wallets/isar/models/wallet_info.dart';
import '../../../wallets/wallet/impl/epiccash_wallet.dart';
-import '../../../wallets/wallet/impl/monero_wallet.dart';
-import '../../../wallets/wallet/impl/wownero_wallet.dart';
+import '../../../wallets/wallet/impl/mimblewimblecoin_wallet.dart';
import '../../../wallets/wallet/impl/xelis_wallet.dart';
import '../../../wallets/wallet/intermediate/cryptonote_wallet.dart';
import '../../../wallets/wallet/wallet.dart';
@@ -204,21 +203,21 @@ class _VerifyRecoveryPhraseViewState
try {
// TODO: extract interface with isRestore param
- switch (voWallet.runtimeType) {
- case const (EpiccashWallet):
- await (voWallet as EpiccashWallet).init(isRestore: true);
+ switch (voWallet) {
+ case EpiccashWallet():
+ await voWallet.init(isRestore: true);
break;
- case const (MoneroWallet):
- await (voWallet as MoneroWallet).init(isRestore: true);
+ case MimblewimblecoinWallet():
+ await voWallet.init(isRestore: true);
break;
- case const (WowneroWallet):
- await (voWallet as WowneroWallet).init(isRestore: true);
+ case CryptonoteWallet():
+ await voWallet.init(isRestore: true);
break;
- case const (XelisWallet):
- await (voWallet as XelisWallet).init(isRestore: true);
+ case XelisWallet():
+ await voWallet.init(isRestore: true);
break;
default:
Why this scored 29/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.