Cw 773 restoring from qr gives no visual feedback of progress (#1944)
* init commit * fix for passphrase * update restore from keys flow * remove WalletRestorationFromQRVM * update creation vm * fix for blockchainHeightKey * fix merge conflicts * Update wallet_restore_page.dart --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
Serhii committed
Mar 15, 2025 at 01:45 UTC
6abefc25a7fb75e1d3958c7a5b3e737645d6d775
11 files changed
+131
-323
lib/di.dart
+10
-13
@@ -54,6 +54,7 @@ import 'package:cake_wallet/view_model/link_view_model.dart';
54
import 'package:cake_wallet/tron/tron.dart';
55
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
56
import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
57
+import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
58
import 'package:cake_wallet/view_model/send/fees_view_model.dart';
59
import 'package:cw_core/receive_page_option.dart';
60
import 'package:cake_wallet/entities/preferences_key.dart';
@@ -173,7 +174,6 @@ import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
174
import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart';
175
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
176
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
176
-import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
177
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
178
import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart';
179
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
@@ -475,14 +475,6 @@ Future<void> setup({
475
walletType: args.walletType ?? currentWalletType);
476
});
477
478
- getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) =>
479
- WalletRestorationFromQRVM(
480
- getIt.get<AppStore>(),
481
- getIt.get<WalletCreationService>(param1: type),
482
- _walletInfoSource,
483
- type,
484
- getIt.get<SeedSettingsViewModel>()));
485
-
478
getIt.registerFactoryParam<WalletHardwareRestoreViewModel, WalletType, void>((type, _) =>
479
WalletHardwareRestoreViewModel(
480
getIt.get<LedgerViewModel>(),
@@ -1144,13 +1136,18 @@ Future<void> setup({
1136
1137
getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>()));
1138
1147
- getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) =>
1139
+ getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, RestoredWallet?>((WalletType type,
1140
+ restoredWallet) =>
1141
WalletRestoreViewModel(getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type),
1142
_walletInfoSource, getIt.get<SeedSettingsViewModel>(),
1150
- type: type));
1143
+ type: type, restoredWallet: restoredWallet));
1144
1152
- getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage(
1153
- getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedSettingsViewModel>()));
1145
+ getIt.registerFactoryParam<WalletRestorePage, WalletType, RestoredWallet?>((WalletType type,
1146
+ restoredWallet) {
1147
+ return WalletRestorePage(
1148
+ getIt.get<WalletRestoreViewModel>(param1: type, param2: restoredWallet),
1149
+ getIt.get<SeedSettingsViewModel>());
1150
+ });
1151
1152
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
1153
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
lib/router.dart
+12
-5
@@ -120,6 +120,7 @@ import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
120
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
121
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
122
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
123
+import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
124
import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart';
125
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
126
import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
@@ -235,8 +236,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
236
return CupertinoPageRoute<void>(
237
builder: (_) => getIt.get<NewWalletTypePage>(
238
param1: NewWalletTypeArguments(
238
- onTypeSelected: (BuildContext context, WalletType type) =>
239
- Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type),
239
+ onTypeSelected: (BuildContext context, WalletType type) {
240
+ final arg = {'walletType': type};
241
+ Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);},
242
isCreate: false,
243
isHardwareWallet: false,
244
),
@@ -261,8 +263,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
263
return CupertinoPageRoute<void>(
264
builder: (_) => getIt.get<NewWalletTypePage>(
265
param1: NewWalletTypeArguments(
264
- onTypeSelected: (BuildContext context, WalletType type) =>
265
- Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type),
266
+ onTypeSelected: (BuildContext context, WalletType type) {
267
+ final arg = {'walletType': type};
268
+ Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);},
269
isCreate: false,
270
isHardwareWallet: false,
271
),
@@ -318,8 +321,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
321
builder: (_) => getIt.get<WalletSeedPage>(param1: settings.arguments as bool));
322
323
case Routes.restoreWallet:
324
+ final args = settings.arguments as Map<String, dynamic>?;
325
+ final walletType = args?['walletType'] as WalletType;
326
+ final restoredWallet = args?['restoredWallet'] as RestoredWallet?;
327
return MaterialPageRoute<void>(
322
- builder: (_) => getIt.get<WalletRestorePage>(param1: settings.arguments as WalletType));
328
+ builder: (_) => getIt.get<WalletRestorePage>(param1: walletType, param2: restoredWallet));
329
330
case Routes.restoreWalletChooseDerivation:
331
return MaterialPageRoute<void>(
@@ -677,6 +683,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
683
final isChildWallet = args['isChildWallet'] as bool? ?? false;
684
final useTestnet = args['useTestnet'] as bool;
685
final toggleTestnet = args['toggleTestnet'] as Function(bool? val);
686
+ final restoredWallet = args['restoredWallet'] as RestoredWallet?;
687
688
return CupertinoPageRoute<void>(
689
builder: (_) => AdvancedPrivacySettingsPage(
lib/src/screens/restore/restore_options_page.dart
+18
-29
@@ -1,18 +1,14 @@
1
import 'dart:io';
2
3
-import 'package:cake_wallet/core/execution_state.dart';
4
-import 'package:cake_wallet/di.dart';
3
import 'package:cake_wallet/generated/i18n.dart';
4
import 'package:cake_wallet/routes.dart';
5
import 'package:cake_wallet/src/screens/base_page.dart';
8
-import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
6
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7
import 'package:cake_wallet/src/widgets/option_tile.dart';
8
import 'package:cake_wallet/utils/device_info.dart';
9
import 'package:cake_wallet/utils/permission_handler.dart';
10
import 'package:cake_wallet/utils/responsive_layout_util.dart';
11
import 'package:cake_wallet/utils/show_pop_up.dart';
15
-import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
12
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
13
import 'package:cake_wallet/wallet_type_utils.dart';
14
import 'package:cw_core/hardware/device_connection_type.dart';
@@ -131,10 +127,8 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
127
);
128
}
129
134
- void _onWalletCreateFailure(BuildContext context, String error) {
135
- setState(() {
136
- isRestoring = false;
137
- });
130
+ void _showQRScanError(BuildContext context, String error) {
131
+ setState(() => isRestoring = false);
132
133
WidgetsBinding.instance.addPostFrameCallback((_) {
134
showPopUp<void>(
@@ -151,28 +145,23 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> {
145
146
Future<void> _onScanQRCode(BuildContext context) async {
147
final isCameraPermissionGranted =
154
- await PermissionHandler.checkPermission(Permission.camera, context);
148
+ await PermissionHandler.checkPermission(Permission.camera, context);
149
150
if (!isCameraPermissionGranted) return;
157
- try {
158
- if (isRestoring) {
159
- return;
160
- }
161
- setState(() {
162
- isRestoring = true;
163
- });
164
- final restoreWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
165
-
166
- final restoreFromQRViewModel =
167
- getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type);
168
-
169
- await restoreFromQRViewModel.create(restoreWallet: restoreWallet);
170
- if (restoreFromQRViewModel.state is FailureState) {
171
- _onWalletCreateFailure(context,
172
- 'Create wallet state: ${(restoreFromQRViewModel.state as FailureState).error}');
173
- }
174
- } catch (e) {
175
- _onWalletCreateFailure(context, e.toString());
176
- }
151
+ try {
152
+ if (isRestoring) return;
153
+
154
+ setState(() => isRestoring = true);
155
+
156
+ final restoredWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context);
157
+
158
+ final params = {'walletType': restoredWallet.type, 'restoredWallet': restoredWallet};
159
+
160
+ Navigator.pushNamed(context, Routes.restoreWallet, arguments: params).then((_) {
161
+ if (mounted) setState(() => isRestoring = false);
162
+ });
163
+ } catch (e) {
164
+ _showQRScanError(context, e.toString());
165
}
166
+ }
167
}
lib/src/screens/restore/wallet_restore_from_keys_form.dart
+27
-10
@@ -1,4 +1,5 @@
1
import 'package:cake_wallet/src/widgets/address_text_field.dart';
2
+import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
3
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
4
import 'package:cw_core/wallet_type.dart';
5
import 'package:flutter/material.dart';
@@ -10,14 +11,15 @@ import 'package:cake_wallet/entities/generate_name.dart';
11
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
12
import 'package:flutter/services.dart';
13
13
-class WalletRestoreFromKeysFrom extends StatefulWidget {
14
- WalletRestoreFromKeysFrom({
14
+class WalletRestoreFromKeysForm extends StatefulWidget {
15
+ WalletRestoreFromKeysForm({
16
required this.walletRestoreViewModel,
17
required this.onPrivateKeyChange,
18
required this.displayPrivateKeyField,
19
required this.onHeightOrDateEntered,
20
required this.displayWalletPassword,
21
required this.onRepeatedPasswordChange,
22
+ this.restoredWallet,
23
this.onPasswordChange,
24
Key? key,
25
}) : super(key: key);
@@ -27,23 +29,32 @@ class WalletRestoreFromKeysFrom extends StatefulWidget {
29
final void Function(String)? onPrivateKeyChange;
30
final bool displayPrivateKeyField;
31
final bool displayWalletPassword;
32
+ final RestoredWallet? restoredWallet;
33
final void Function(String)? onPasswordChange;
34
final void Function(String)? onRepeatedPasswordChange;
35
36
@override
34
- WalletRestoreFromKeysFromState createState() =>
35
- WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
37
+ WalletRestoreFromKeysFormState createState() =>
38
+ WalletRestoreFromKeysFormState(displayWalletPassword: displayWalletPassword, restoredWallet: restoredWallet);
39
}
40
38
-class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
39
- WalletRestoreFromKeysFromState({required bool displayWalletPassword})
41
+class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> {
42
+ WalletRestoreFromKeysFormState({required bool displayWalletPassword, RestoredWallet? restoredWallet})
43
: formKey = GlobalKey<FormState>(),
44
blockchainHeightKey = GlobalKey<BlockchainHeightState>(),
45
nameController = TextEditingController(),
43
- addressController = TextEditingController(),
44
- viewKeyController = TextEditingController(),
45
- spendKeyController = TextEditingController(),
46
- privateKeyController = TextEditingController(),
46
+ addressController = restoredWallet != null
47
+ ? TextEditingController(text: restoredWallet.address)
48
+ : TextEditingController(),
49
+ viewKeyController = restoredWallet != null
50
+ ? TextEditingController(text: restoredWallet.viewKey)
51
+ : TextEditingController(),
52
+ spendKeyController = restoredWallet != null
53
+ ? TextEditingController(text: restoredWallet.spendKey)
54
+ : TextEditingController(),
55
+ privateKeyController = restoredWallet != null
56
+ ? TextEditingController(text: restoredWallet.privateKey)
57
+ : TextEditingController(),
58
nameTextEditingController = TextEditingController(),
59
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
60
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
@@ -80,6 +91,12 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
91
}
92
widget.onPrivateKeyChange?.call(privateKeyController.text);
93
});
94
+
95
+ WidgetsBinding.instance.addPostFrameCallback((_) {
96
+ if (widget.restoredWallet?.height != null) {
97
+ blockchainHeightKey.currentState?.restoreHeightController.text = widget.restoredWallet!.height.toString();
98
+ }
99
+ });
100
}
101
102
@override
lib/src/screens/restore/wallet_restore_from_seed_form.dart
+4
@@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
9
import 'package:cake_wallet/src/widgets/seed_widget.dart';
10
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
11
import 'package:cake_wallet/utils/show_pop_up.dart';
12
+import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
13
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
14
import 'package:cw_core/wallet_type.dart';
15
import 'package:flutter/material.dart';
@@ -23,6 +24,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
24
required this.displayWalletPassword,
25
required this.seedSettingsViewModel,
26
this.blockHeightFocusNode,
27
+ this.restoredWallet,
28
this.onHeightOrDateEntered,
29
this.onSeedChange,
30
this.onLanguageChange,
@@ -36,6 +38,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
38
final bool displayWalletPassword;
39
final SeedSettingsViewModel seedSettingsViewModel;
40
final FocusNode? blockHeightFocusNode;
41
+ final RestoredWallet? restoredWallet;
42
final Function(bool)? onHeightOrDateEntered;
43
final void Function(String)? onSeedChange;
44
final void Function(String)? onLanguageChange;
@@ -184,6 +187,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
187
Container(height: 20),
188
SeedWidget(
189
key: seedWidgetStateKey,
190
+ initialSeed: widget.restoredWallet?.mnemonicSeed,
191
language: language,
192
type: widget.type,
193
onSeedChange: onSeedChange,
lib/src/screens/restore/wallet_restore_page.dart
+20
-7
@@ -24,13 +24,13 @@ import 'package:mobx/mobx.dart';
24
class WalletRestorePage extends BasePage {
25
WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel)
26
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
27
- walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
27
+ walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFormState>(),
28
_blockHeightFocusNode = FocusNode();
29
30
final WalletRestoreViewModel walletRestoreViewModel;
31
final SeedSettingsViewModel seedSettingsViewModel;
32
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
33
- final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
33
+ final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
34
final FocusNode _blockHeightFocusNode;
35
36
bool _formProcessing = false;
@@ -52,6 +52,10 @@ class WalletRestorePage extends BasePage {
52
// String? derivationPath = null;
53
DerivationInfo? derivationInfo;
54
55
+
56
+ @override
57
+ Function(BuildContext)? get popWidget => (context) => seedSettingsViewModel.setPassphrase(null);
58
+
59
@override
60
Function(BuildContext)? get pushToNextWidget => (context) {
61
FocusScopeNode currentFocus = FocusScope.of(context);
@@ -283,7 +287,7 @@ class _WalletRestorePageBody extends StatefulWidget {
287
final WalletRestoreViewModel walletRestoreViewModel;
288
final SeedSettingsViewModel seedSettingsViewModel;
289
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
286
- final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
290
+ final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
291
final FocusNode blockHeightFocusNode;
292
final DerivationInfo? derivationInfo;
293
final void Function(DerivationInfo?) onDerivationInfoChanged;
@@ -311,7 +315,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
315
final WalletRestoreViewModel walletRestoreViewModel;
316
final SeedSettingsViewModel seedSettingsViewModel;
317
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
314
- final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey;
318
+ final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey;
319
final FocusNode blockHeightFocusNode;
320
DerivationInfo? derivationInfo;
321
@@ -325,7 +329,14 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
329
330
_hasKeysTab = widget.walletRestoreViewModel.availableModes.contains(WalletRestoreMode.keys);
331
final tabCount = _hasKeysTab ? 2 : 1;
328
- _tabController = TabController(length: tabCount, vsync: this);
332
+
333
+ final initialIndex = walletRestoreViewModel.mode == WalletRestoreMode.seed
334
+ ? 0
335
+ : _hasKeysTab
336
+ ? 1
337
+ : 0;
338
+
339
+ _tabController = TabController(length: tabCount, vsync: this, initialIndex: initialIndex);
340
341
_tabController.addListener(() {
342
if (!_tabController.indexIsChanging) {
@@ -442,9 +453,10 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
453
);
454
}
455
445
- WalletRestoreFromKeysFrom _buildWalletRestoreFromKeysTab() {
446
- return WalletRestoreFromKeysFrom(
456
+ WalletRestoreFromKeysForm _buildWalletRestoreFromKeysTab() {
457
+ return WalletRestoreFromKeysForm(
458
key: widget.walletRestoreFromKeysFormKey,
459
+ restoredWallet: walletRestoreViewModel.restoredWallet,
460
walletRestoreViewModel: widget.walletRestoreViewModel,
461
displayPrivateKeyField: widget.walletRestoreViewModel.hasRestoreFromPrivateKey,
462
displayWalletPassword: widget.walletRestoreViewModel.hasWalletPassword,
@@ -466,6 +478,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
478
WalletRestoreFromSeedForm _buildWalletRestoreFromSeedTab() {
479
return WalletRestoreFromSeedForm(
480
key: widget.walletRestoreFromSeedFormKey,
481
+ restoredWallet: walletRestoreViewModel.restoredWallet,
482
seedSettingsViewModel: widget.seedSettingsViewModel,
483
displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
484
displayLanguageSelector: widget.walletRestoreViewModel.hasSeedLanguageSelector,
lib/src/widgets/seed_widget.dart
+12
-6
@@ -14,6 +14,7 @@ class SeedWidget extends StatefulWidget {
14
this.onSeedChange,
15
this.pasteButtonKey,
16
this.seedTextFieldKey,
17
+ this.initialSeed,
18
super.key,
19
});
20
final Key? seedTextFieldKey;
@@ -21,17 +22,18 @@ class SeedWidget extends StatefulWidget {
22
final String language;
23
final WalletType type;
24
final void Function(String)? onSeedChange;
25
+ final String? initialSeed;
26
27
@override
26
- SeedWidgetState createState() => SeedWidgetState(language, type);
28
+ SeedWidgetState createState() => SeedWidgetState(language, type, initialSeed);
29
}
30
31
class SeedWidgetState extends State<SeedWidget> {
30
- SeedWidgetState(String language, this.type)
31
- : controller = TextEditingController(),
32
+ SeedWidgetState(String language, this.type, String? initialSeed)
33
+ : controller = TextEditingController(text: initialSeed ?? ''),
34
focusNode = FocusNode(),
35
words = SeedValidator.getWordList(type: type, language: language),
34
- _showPlaceholder = false {
36
+ _showPlaceholder = initialSeed == null || initialSeed.isEmpty {
37
focusNode.addListener(() {
38
setState(() {
39
if (!focusNode.hasFocus && controller.text.isEmpty) {
@@ -57,8 +59,12 @@ class SeedWidgetState extends State<SeedWidget> {
59
@override
60
void initState() {
61
super.initState();
60
- _showPlaceholder = true;
61
- controller.addListener(() => widget.onSeedChange?.call(text));
62
+ controller.addListener(() {
63
+ setState(() {
64
+ _showPlaceholder = controller.text.isEmpty;
65
+ });
66
+ widget.onSeedChange?.call(text);
67
+ });
68
}
69
70
void changeSeedLanguage(String language) {
lib/view_model/restore/restore_from_qr_vm.dart
deleted
-219
@@ -1,219 +0,0 @@
1
-import 'package:cake_wallet/bitcoin/bitcoin.dart';
2
-import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
3
-import 'package:cake_wallet/ethereum/ethereum.dart';
4
-import 'package:cake_wallet/nano/nano.dart';
5
-import 'package:cake_wallet/polygon/polygon.dart';
6
-import 'package:cake_wallet/solana/solana.dart';
7
-import 'package:cake_wallet/tron/tron.dart';
8
-import 'package:cake_wallet/view_model/restore/restore_mode.dart';
9
-import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
10
-import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
11
-import 'package:cake_wallet/wownero/wownero.dart';
12
-import 'package:cake_wallet/zano/zano.dart';
13
-import 'package:hive/hive.dart';
14
-import 'package:mobx/mobx.dart';
15
-import 'package:cake_wallet/monero/monero.dart';
16
-import 'package:cake_wallet/store/app_store.dart';
17
-import 'package:cw_core/wallet_base.dart';
18
-import 'package:cake_wallet/core/generate_wallet_password.dart';
19
-import 'package:cake_wallet/core/wallet_creation_service.dart';
20
-import 'package:cw_core/wallet_credentials.dart';
21
-import 'package:cw_core/wallet_type.dart';
22
-import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
23
-import 'package:cw_core/wallet_info.dart';
24
-
25
-part 'restore_from_qr_vm.g.dart';
26
-
27
-class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRestorationFromQRVM;
28
-
29
-abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store {
30
- WalletRestorationFromQRVMBase(
31
- AppStore appStore,
32
- WalletCreationService walletCreationService,
33
- Box<WalletInfo> walletInfoSource,
34
- WalletType type,
35
- SeedSettingsViewModel seedSettingsViewModel)
36
- : height = 0,
37
- viewKey = '',
38
- spendKey = '',
39
- wif = '',
40
- address = '',
41
- super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
42
- type: type, isRecovery: true);
43
-
44
- @observable
45
- int height;
46
-
47
- @observable
48
- String viewKey;
49
-
50
- @observable
51
- String spendKey;
52
-
53
- @observable
54
- String wif;
55
-
56
- @observable
57
- String address;
58
-
59
- bool get hasRestorationHeight => type == WalletType.monero || type == WalletType.wownero;
60
-
61
- @override
62
- Future<WalletCredentials> getWalletCredentialsFromQRCredentials(
63
- RestoredWallet restoreWallet) async {
64
- final password = generateWalletPassword();
65
-
66
- switch (restoreWallet.restoreMode) {
67
- case WalletRestoreMode.keys:
68
- switch (restoreWallet.type) {
69
- case WalletType.monero:
70
- return monero!.createMoneroRestoreWalletFromKeysCredentials(
71
- name: name,
72
- password: password,
73
- language: 'English',
74
- address: restoreWallet.address ?? '',
75
- viewKey: restoreWallet.viewKey ?? '',
76
- spendKey: restoreWallet.spendKey ?? '',
77
- height: restoreWallet.height ?? 0);
78
- case WalletType.wownero:
79
- return wownero!.createWowneroRestoreWalletFromKeysCredentials(
80
- name: name,
81
- password: password,
82
- language: 'English',
83
- address: restoreWallet.address ?? '',
84
- viewKey: restoreWallet.viewKey ?? '',
85
- spendKey: restoreWallet.spendKey ?? '',
86
- height: restoreWallet.height ?? 0);
87
- case WalletType.bitcoin:
88
- case WalletType.litecoin:
89
- return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
90
- name: name, password: password, wif: wif);
91
- case WalletType.ethereum:
92
- return ethereum!.createEthereumRestoreWalletFromPrivateKey(
93
- name: name, password: password, privateKey: restoreWallet.privateKey!);
94
- case WalletType.polygon:
95
- return polygon!.createPolygonRestoreWalletFromPrivateKey(
96
- name: name, password: password, privateKey: restoreWallet.privateKey!);
97
- case WalletType.solana:
98
- return solana!.createSolanaRestoreWalletFromPrivateKey(
99
- name: name, password: password, privateKey: restoreWallet.privateKey!);
100
- case WalletType.tron:
101
- return tron!.createTronRestoreWalletFromPrivateKey(
102
- name: name, password: password, privateKey: restoreWallet.privateKey!);
103
- default:
104
- throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
105
- }
106
- case WalletRestoreMode.seed:
107
- switch (restoreWallet.type) {
108
- case WalletType.monero:
109
- return monero!.createMoneroRestoreWalletFromSeedCredentials(
110
- name: name,
111
- height: restoreWallet.height ?? 0,
112
- mnemonic: restoreWallet.mnemonicSeed ?? '',
113
- password: password,
114
- passphrase: restoreWallet.passphrase ?? '',
115
- );
116
- case WalletType.bitcoin:
117
- case WalletType.litecoin:
118
-
119
- final derivationInfoList = await getDerivationInfoFromQRCredentials(restoreWallet);
120
- DerivationInfo derivationInfo;
121
- if (derivationInfoList.isEmpty) {
122
- derivationInfo = getDefaultCreateDerivation()!;
123
- } else {
124
- derivationInfo = derivationInfoList.first;
125
- }
126
- return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
127
- name: name,
128
- mnemonic: restoreWallet.mnemonicSeed ?? '',
129
- password: password,
130
- passphrase: restoreWallet.passphrase,
131
- derivationType: derivationInfo.derivationType!,
132
- derivationPath: derivationInfo.derivationPath!,
133
- );
134
- case WalletType.bitcoinCash:
135
- return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials(
136
- name: name,
137
- mnemonic: restoreWallet.mnemonicSeed ?? '',
138
- password: password,
139
- passphrase: restoreWallet.passphrase,
140
- );
141
- case WalletType.ethereum:
142
- return ethereum!.createEthereumRestoreWalletFromSeedCredentials(
143
- name: name,
144
- mnemonic: restoreWallet.mnemonicSeed ?? '',
145
- password: password,
146
- passphrase: restoreWallet.passphrase,
147
- );
148
- case WalletType.nano:
149
- final derivationInfo =
150
- (await getDerivationInfoFromQRCredentials(restoreWallet)).first;
151
- return nano!.createNanoRestoreWalletFromSeedCredentials(
152
- name: name,
153
- mnemonic: restoreWallet.mnemonicSeed ?? '',
154
- password: password,
155
- derivationType: derivationInfo.derivationType!,
156
- passphrase: restoreWallet.passphrase,
157
- );
158
- case WalletType.polygon:
159
- return polygon!.createPolygonRestoreWalletFromSeedCredentials(
160
- name: name,
161
- mnemonic: restoreWallet.mnemonicSeed ?? '',
162
- password: password,
163
- passphrase: restoreWallet.passphrase,
164
- );
165
- case WalletType.solana:
166
- return solana!.createSolanaRestoreWalletFromSeedCredentials(
167
- name: name,
168
- mnemonic: restoreWallet.mnemonicSeed ?? '',
169
- password: password,
170
- passphrase: restoreWallet.passphrase,
171
- );
172
- case WalletType.tron:
173
- return tron!.createTronRestoreWalletFromSeedCredentials(
174
- name: name,
175
- mnemonic: restoreWallet.mnemonicSeed ?? '',
176
- password: password,
177
- passphrase: restoreWallet.passphrase,
178
- );
179
- case WalletType.wownero:
180
- return wownero!.createWowneroRestoreWalletFromSeedCredentials(
181
- name: name,
182
- height: restoreWallet.height ?? 0,
183
- mnemonic: restoreWallet.mnemonicSeed ?? '',
184
- password: password,
185
- passphrase: restoreWallet.passphrase ?? '',
186
- );
187
- case WalletType.zano:
188
- return zano!.createZanoRestoreWalletFromSeedCredentials(
189
- name: name,
190
- password: password,
191
- height: height,
192
- mnemonic: restoreWallet.mnemonicSeed ?? '',
193
- passphrase: restoreWallet.passphrase ?? '',
194
- );
195
- default:
196
- throw Exception('Unexpected type: ${type.toString()}');
197
- }
198
- default:
199
- throw Exception('Unexpected type: ${type.toString()}');
200
- }
201
- }
202
-
203
- @override
204
- Future<WalletBase> processFromRestoredWallet(WalletCredentials credentials,
205
- RestoredWallet restoreWallet) async {
206
- try {
207
- switch (restoreWallet.restoreMode) {
208
- case WalletRestoreMode.keys:
209
- return walletCreationService.restoreFromKeys(credentials);
210
- case WalletRestoreMode.seed:
211
- return walletCreationService.restoreFromSeed(credentials);
212
- default:
213
- throw Exception('Unexpected restore mode: ${restoreWallet.restoreMode.toString()}');
214
- }
215
- } catch (e) {
216
- throw Exception('Unexpected restore mode: ${e.toString()}');
217
- }
218
- }
219
-}
lib/view_model/restore/wallet_restore_from_qr_code.dart
+15
-16
@@ -46,8 +46,6 @@ class WalletRestoreFromQRCode {
46
'zano_wallet': WalletType.zano,
47
};
48
49
- static bool _containsAssetSpecifier(String code) => _extractWalletType(code) != null;
50
-
49
static WalletType? _extractWalletType(String code) {
50
final sortedKeys = _walletTypeMap.keys.toList()..sort((a, b) => b.length.compareTo(a.length));
51
@@ -55,15 +53,18 @@ class WalletRestoreFromQRCode {
53
54
if (extracted == null) {
55
// Special case for view-only monero wallet
58
- final codeParsed = json.decode(code);
59
- if (codeParsed["version"] == 0 &&
60
- codeParsed["primaryAddress"] != null &&
61
- codeParsed["privateViewKey"] != null &&
62
- codeParsed["restoreHeight"] != null) {
63
- return WalletType.monero;
56
+ try {
57
+ final codeParsed = json.decode(code);
58
+ if (codeParsed["version"] == 0 &&
59
+ codeParsed["primaryAddress"] != null &&
60
+ codeParsed["privateViewKey"] != null &&
61
+ codeParsed["restoreHeight"] != null) {
62
+ return WalletType.monero;
63
+ }
64
+ } catch (e) {
65
+ return null;
66
}
67
}
66
-
68
return _walletTypeMap[extracted];
69
}
70
@@ -93,10 +94,10 @@ class WalletRestoreFromQRCode {
94
if (code == null) throw Exception("Unexpected scan QR code value: aborted");
95
if (code.isEmpty) throw Exception('Unexpected scan QR code value: value is empty');
96
96
- WalletType? walletType;
97
String formattedUri = '';
98
+ WalletType? walletType = _extractWalletType(code);
99
99
- if (!_containsAssetSpecifier(code)) {
100
+ if (walletType == null) {
101
await _specifyWalletAssets(context, "Can't determine wallet type, please pick it manually");
102
walletType =
103
await Navigator.pushNamed(context, Routes.restoreWalletTypeFromQR) as WalletType?;
@@ -108,7 +109,6 @@ class WalletRestoreFromQRCode {
109
? '$walletType:?seed=$seedPhrase'
110
: throw Exception('Failed to determine valid seed phrase');
111
} else {
111
- walletType = _extractWalletType(code);
112
final index = code.indexOf(':');
113
final query = code.substring(index + 1).replaceAll('?', '&');
114
formattedUri = '$walletType:?$query';
@@ -118,12 +118,11 @@ class WalletRestoreFromQRCode {
118
Map<String, dynamic> queryParameters = {...uri.queryParameters};
119
120
if (queryParameters['seed'] == null) {
121
- queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType!);
121
+ queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType);
122
}
123
if (queryParameters['address'] == null) {
124
- try {
125
- queryParameters['address'] = _extractAddressFromUrl(code, walletType!);
126
- } catch (_) {}
124
+ queryParameters['address'] = _extractAddressFromUrl(code, walletType);
125
+
126
}
127
128
Map<String, dynamic> credentials = {'type': walletType, ...queryParameters, 'raw_qr': code};
lib/view_model/wallet_creation_vm.dart
+4
-16
@@ -67,8 +67,8 @@ abstract class WalletCreationVMBase with Store {
67
68
bool typeExists(WalletType type) => walletCreationService.typeExists(type);
69
70
- Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async {
71
- final type = restoreWallet?.type ?? this.type;
70
+ Future<void> create({dynamic options}) async {
71
+ final type = this.type;
72
try {
73
state = IsExecutingState();
74
if (name.isEmpty) {
@@ -87,9 +87,7 @@ abstract class WalletCreationVMBase with Store {
87
final dirPath = await pathForWalletDir(name: name, type: type);
88
final path = await pathForWallet(name: name, type: type);
89
90
- final credentials = restoreWallet != null
91
- ? await getWalletCredentialsFromQRCredentials(restoreWallet)
92
- : getCredentials(options);
90
+ final credentials = getCredentials(options);
91
92
final walletInfo = WalletInfo.external(
93
id: WalletBase.idFor(name, type),
@@ -107,9 +105,7 @@ abstract class WalletCreationVMBase with Store {
105
);
106
107
credentials.walletInfo = walletInfo;
110
- final wallet = restoreWallet != null
111
- ? await processFromRestoredWallet(credentials, restoreWallet)
112
- : await process(credentials);
108
+ final wallet = await process(credentials);
109
110
final isNonSeedWallet = isRecovery ? wallet.seed == null : false;
111
walletInfo.isNonSeedWallet = isNonSeedWallet;
@@ -234,14 +230,6 @@ abstract class WalletCreationVMBase with Store {
230
231
Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError();
232
237
- Future<WalletCredentials> getWalletCredentialsFromQRCredentials(
238
- RestoredWallet restoreWallet) async =>
239
- throw UnimplementedError();
240
-
241
- Future<WalletBase> processFromRestoredWallet(
242
- WalletCredentials credentials, RestoredWallet restoreWallet) =>
243
- throw UnimplementedError();
244
-
233
@action
234
void toggleUseTestnet(bool? value) {
235
_useTestnet = value ?? !_useTestnet;
lib/view_model/wallet_restore_view_model.dart
+9
-2
@@ -12,6 +12,7 @@ import 'package:cake_wallet/solana/solana.dart';
12
import 'package:cake_wallet/store/app_store.dart';
13
import 'package:cake_wallet/tron/tron.dart';
14
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
15
+import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
16
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
17
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
18
import 'package:cake_wallet/wownero/wownero.dart';
@@ -30,7 +31,7 @@ class WalletRestoreViewModel = WalletRestoreViewModelBase with _$WalletRestoreVi
31
abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
32
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
33
Box<WalletInfo> walletInfoSource, SeedSettingsViewModel seedSettingsViewModel,
33
- {required WalletType type})
34
+ {required WalletType type, this.restoredWallet})
35
: hasSeedLanguageSelector =
36
type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero,
37
hasBlockchainHeightLanguageSelector =
@@ -42,7 +43,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
43
type == WalletType.solana ||
44
type == WalletType.tron,
45
isButtonEnabled = false,
45
- mode = WalletRestoreMode.seed,
46
+ mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed,
47
super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel,
48
type: type, isRecovery: true) {
49
switch (type) {
@@ -68,6 +69,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
69
break;
70
}
71
walletCreationService.changeWalletType(type: type);
72
+ if (restoredWallet != null) {
73
+ if(restoredWallet!.restoreMode == WalletRestoreMode.seed) {
74
+ seedSettingsViewModel.setPassphrase(restoredWallet!.passphrase);
75
+ }
76
+ }
77
}
78
79
static const moneroSeedMnemonicLength = 25;
@@ -76,6 +82,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
82
final bool hasSeedLanguageSelector;
83
final bool hasBlockchainHeightLanguageSelector;
84
final bool hasRestoreFromPrivateKey;
85
+ final RestoredWallet? restoredWallet;
86
87
@observable
88
WalletRestoreMode mode;