diff --git a/lib/di.dart b/lib/di.dart index f3de2bc96..c8d664b6e 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -54,6 +54,7 @@ import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart'; +import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/send/fees_view_model.dart'; import 'package:cw_core/receive_page_option.dart'; 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'; import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; -import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart'; import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/mweb_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; @@ -475,14 +475,6 @@ Future<void> setup({ walletType: args.walletType ?? currentWalletType); }); - getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) => - WalletRestorationFromQRVM( - getIt.get<AppStore>(), - getIt.get<WalletCreationService>(param1: type), - _walletInfoSource, - type, - getIt.get<SeedSettingsViewModel>())); - getIt.registerFactoryParam<WalletHardwareRestoreViewModel, WalletType, void>((type, _) => WalletHardwareRestoreViewModel( getIt.get<LedgerViewModel>(), @@ -1144,13 +1136,18 @@ Future<void> setup({ getIt.registerFactory(() => FaqPage(getIt.get<SettingsStore>())); - getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, void>((type, _) => + getIt.registerFactoryParam<WalletRestoreViewModel, WalletType, RestoredWallet?>((WalletType type, + restoredWallet) => WalletRestoreViewModel(getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource, getIt.get<SeedSettingsViewModel>(), - type: type)); + type: type, restoredWallet: restoredWallet)); - getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage( - getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedSettingsViewModel>())); + getIt.registerFactoryParam<WalletRestorePage, WalletType, RestoredWallet?>((WalletType type, + restoredWallet) { + return WalletRestorePage( + getIt.get<WalletRestoreViewModel>(param1: type, param2: restoredWallet), + getIt.get<SeedSettingsViewModel>()); + }); getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>( (derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations)); diff --git a/lib/router.dart b/lib/router.dart index 497bcdaa1..54cbb1531 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -120,6 +120,7 @@ import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; +import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart'; @@ -235,8 +236,9 @@ Route<dynamic> createRoute(RouteSettings settings) { return CupertinoPageRoute<void>( builder: (_) => getIt.get<NewWalletTypePage>( param1: NewWalletTypeArguments( - onTypeSelected: (BuildContext context, WalletType type) => - Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type), + onTypeSelected: (BuildContext context, WalletType type) { + final arg = {'walletType': type}; + Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);}, isCreate: false, isHardwareWallet: false, ), @@ -261,8 +263,9 @@ Route<dynamic> createRoute(RouteSettings settings) { return CupertinoPageRoute<void>( builder: (_) => getIt.get<NewWalletTypePage>( param1: NewWalletTypeArguments( - onTypeSelected: (BuildContext context, WalletType type) => - Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: type), + onTypeSelected: (BuildContext context, WalletType type) { + final arg = {'walletType': type}; + Navigator.of(context).pushNamed(Routes.restoreWallet, arguments: arg);}, isCreate: false, isHardwareWallet: false, ), @@ -318,8 +321,11 @@ Route<dynamic> createRoute(RouteSettings settings) { builder: (_) => getIt.get<WalletSeedPage>(param1: settings.arguments as bool)); case Routes.restoreWallet: + final args = settings.arguments as Map<String, dynamic>?; + final walletType = args?['walletType'] as WalletType; + final restoredWallet = args?['restoredWallet'] as RestoredWallet?; return MaterialPageRoute<void>( - builder: (_) => getIt.get<WalletRestorePage>(param1: settings.arguments as WalletType)); + builder: (_) => getIt.get<WalletRestorePage>(param1: walletType, param2: restoredWallet)); case Routes.restoreWalletChooseDerivation: return MaterialPageRoute<void>( @@ -677,6 +683,7 @@ Route<dynamic> createRoute(RouteSettings settings) { final isChildWallet = args['isChildWallet'] as bool? ?? false; final useTestnet = args['useTestnet'] as bool; final toggleTestnet = args['toggleTestnet'] as Function(bool? val); + final restoredWallet = args['restoredWallet'] as RestoredWallet?; return CupertinoPageRoute<void>( builder: (_) => AdvancedPrivacySettingsPage( diff --git a/lib/src/screens/restore/restore_options_page.dart b/lib/src/screens/restore/restore_options_page.dart index 2e9e04acd..ba1669fe5 100644 --- a/lib/src/screens/restore/restore_options_page.dart +++ b/lib/src/screens/restore/restore_options_page.dart @@ -1,18 +1,14 @@ import 'dart:io'; -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/option_tile.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/permission_handler.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart'; import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cw_core/hardware/device_connection_type.dart'; @@ -131,10 +127,8 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { ); } - void _onWalletCreateFailure(BuildContext context, String error) { - setState(() { - isRestoring = false; - }); + void _showQRScanError(BuildContext context, String error) { + setState(() => isRestoring = false); WidgetsBinding.instance.addPostFrameCallback((_) { showPopUp<void>( @@ -151,28 +145,23 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { Future<void> _onScanQRCode(BuildContext context) async { final isCameraPermissionGranted = - await PermissionHandler.checkPermission(Permission.camera, context); + await PermissionHandler.checkPermission(Permission.camera, context); if (!isCameraPermissionGranted) return; - try { - if (isRestoring) { - return; - } - setState(() { - isRestoring = true; - }); - final restoreWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context); + try { + if (isRestoring) return; - final restoreFromQRViewModel = - getIt.get<WalletRestorationFromQRVM>(param1: restoreWallet.type); + setState(() => isRestoring = true); - await restoreFromQRViewModel.create(restoreWallet: restoreWallet); - if (restoreFromQRViewModel.state is FailureState) { - _onWalletCreateFailure(context, - 'Create wallet state: ${(restoreFromQRViewModel.state as FailureState).error}'); - } - } catch (e) { - _onWalletCreateFailure(context, e.toString()); - } + final restoredWallet = await WalletRestoreFromQRCode.scanQRCodeForRestoring(context); + + final params = {'walletType': restoredWallet.type, 'restoredWallet': restoredWallet}; + + Navigator.pushNamed(context, Routes.restoreWallet, arguments: params).then((_) { + if (mounted) setState(() => isRestoring = false); + }); + } catch (e) { + _showQRScanError(context, e.toString()); } + } } diff --git a/lib/src/screens/restore/wallet_restore_from_keys_form.dart b/lib/src/screens/restore/wallet_restore_from_keys_form.dart index 0c9af6910..3dc312702 100644 --- a/lib/src/screens/restore/wallet_restore_from_keys_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_keys_form.dart @@ -1,4 +1,5 @@ import 'package:cake_wallet/src/widgets/address_text_field.dart'; +import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -10,14 +11,15 @@ import 'package:cake_wallet/entities/generate_name.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:flutter/services.dart'; -class WalletRestoreFromKeysFrom extends StatefulWidget { - WalletRestoreFromKeysFrom({ +class WalletRestoreFromKeysForm extends StatefulWidget { + WalletRestoreFromKeysForm({ required this.walletRestoreViewModel, required this.onPrivateKeyChange, required this.displayPrivateKeyField, required this.onHeightOrDateEntered, required this.displayWalletPassword, required this.onRepeatedPasswordChange, + this.restoredWallet, this.onPasswordChange, Key? key, }) : super(key: key); @@ -27,23 +29,32 @@ class WalletRestoreFromKeysFrom extends StatefulWidget { final void Function(String)? onPrivateKeyChange; final bool displayPrivateKeyField; final bool displayWalletPassword; + final RestoredWallet? restoredWallet; final void Function(String)? onPasswordChange; final void Function(String)? onRepeatedPasswordChange; @override - WalletRestoreFromKeysFromState createState() => - WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword); + WalletRestoreFromKeysFormState createState() => + WalletRestoreFromKeysFormState(displayWalletPassword: displayWalletPassword, restoredWallet: restoredWallet); } -class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> { - WalletRestoreFromKeysFromState({required bool displayWalletPassword}) +class WalletRestoreFromKeysFormState extends State<WalletRestoreFromKeysForm> { + WalletRestoreFromKeysFormState({required bool displayWalletPassword, RestoredWallet? restoredWallet}) : formKey = GlobalKey<FormState>(), blockchainHeightKey = GlobalKey<BlockchainHeightState>(), nameController = TextEditingController(), - addressController = TextEditingController(), - viewKeyController = TextEditingController(), - spendKeyController = TextEditingController(), - privateKeyController = TextEditingController(), + addressController = restoredWallet != null + ? TextEditingController(text: restoredWallet.address) + : TextEditingController(), + viewKeyController = restoredWallet != null + ? TextEditingController(text: restoredWallet.viewKey) + : TextEditingController(), + spendKeyController = restoredWallet != null + ? TextEditingController(text: restoredWallet.spendKey) + : TextEditingController(), + privateKeyController = restoredWallet != null + ? TextEditingController(text: restoredWallet.privateKey) + : TextEditingController(), nameTextEditingController = TextEditingController(), passwordTextEditingController = displayWalletPassword ? TextEditingController() : null, repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null; @@ -80,6 +91,12 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> { } widget.onPrivateKeyChange?.call(privateKeyController.text); }); + + WidgetsBinding.instance.addPostFrameCallback((_) { + if (widget.restoredWallet?.height != null) { + blockchainHeightKey.currentState?.restoreHeightController.text = widget.restoredWallet!.height.toString(); + } + }); } @override diff --git a/lib/src/screens/restore/wallet_restore_from_seed_form.dart b/lib/src/screens/restore/wallet_restore_from_seed_form.dart index f22deb3e1..d089f8c1c 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/src/widgets/seed_language_picker.dart'; import 'package:cake_wallet/src/widgets/seed_widget.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -23,6 +24,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { required this.displayWalletPassword, required this.seedSettingsViewModel, this.blockHeightFocusNode, + this.restoredWallet, this.onHeightOrDateEntered, this.onSeedChange, this.onLanguageChange, @@ -36,6 +38,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget { final bool displayWalletPassword; final SeedSettingsViewModel seedSettingsViewModel; final FocusNode? blockHeightFocusNode; + final RestoredWallet? restoredWallet; final Function(bool)? onHeightOrDateEntered; final void Function(String)? onSeedChange; final void Function(String)? onLanguageChange; @@ -184,6 +187,7 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> { Container(height: 20), SeedWidget( key: seedWidgetStateKey, + initialSeed: widget.restoredWallet?.mnemonicSeed, language: language, type: widget.type, onSeedChange: onSeedChange, diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index dcaf2f4c7..31f02617d 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -24,13 +24,13 @@ import 'package:mobx/mobx.dart'; class WalletRestorePage extends BasePage { WalletRestorePage(this.walletRestoreViewModel, this.seedSettingsViewModel) : walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(), - walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(), + walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFormState>(), _blockHeightFocusNode = FocusNode(); final WalletRestoreViewModel walletRestoreViewModel; final SeedSettingsViewModel seedSettingsViewModel; final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey; - final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey; + final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey; final FocusNode _blockHeightFocusNode; bool _formProcessing = false; @@ -52,6 +52,10 @@ class WalletRestorePage extends BasePage { // String? derivationPath = null; DerivationInfo? derivationInfo; + + @override + Function(BuildContext)? get popWidget => (context) => seedSettingsViewModel.setPassphrase(null); + @override Function(BuildContext)? get pushToNextWidget => (context) { FocusScopeNode currentFocus = FocusScope.of(context); @@ -283,7 +287,7 @@ class _WalletRestorePageBody extends StatefulWidget { final WalletRestoreViewModel walletRestoreViewModel; final SeedSettingsViewModel seedSettingsViewModel; final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey; - final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey; + final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey; final FocusNode blockHeightFocusNode; final DerivationInfo? derivationInfo; final void Function(DerivationInfo?) onDerivationInfoChanged; @@ -311,7 +315,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody> final WalletRestoreViewModel walletRestoreViewModel; final SeedSettingsViewModel seedSettingsViewModel; final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey; - final GlobalKey<WalletRestoreFromKeysFromState> walletRestoreFromKeysFormKey; + final GlobalKey<WalletRestoreFromKeysFormState> walletRestoreFromKeysFormKey; final FocusNode blockHeightFocusNode; DerivationInfo? derivationInfo; @@ -325,7 +329,14 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody> _hasKeysTab = widget.walletRestoreViewModel.availableModes.contains(WalletRestoreMode.keys); final tabCount = _hasKeysTab ? 2 : 1; - _tabController = TabController(length: tabCount, vsync: this); + + final initialIndex = walletRestoreViewModel.mode == WalletRestoreMode.seed + ? 0 + : _hasKeysTab + ? 1 + : 0; + + _tabController = TabController(length: tabCount, vsync: this, initialIndex: initialIndex); _tabController.addListener(() { if (!_tabController.indexIsChanging) { @@ -442,9 +453,10 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody> ); } - WalletRestoreFromKeysFrom _buildWalletRestoreFromKeysTab() { - return WalletRestoreFromKeysFrom( + WalletRestoreFromKeysForm _buildWalletRestoreFromKeysTab() { + return WalletRestoreFromKeysForm( key: widget.walletRestoreFromKeysFormKey, + restoredWallet: walletRestoreViewModel.restoredWallet, walletRestoreViewModel: widget.walletRestoreViewModel, displayPrivateKeyField: widget.walletRestoreViewModel.hasRestoreFromPrivateKey, displayWalletPassword: widget.walletRestoreViewModel.hasWalletPassword, @@ -466,6 +478,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody> WalletRestoreFromSeedForm _buildWalletRestoreFromSeedTab() { return WalletRestoreFromSeedForm( key: widget.walletRestoreFromSeedFormKey, + restoredWallet: walletRestoreViewModel.restoredWallet, seedSettingsViewModel: widget.seedSettingsViewModel, displayBlockHeightSelector: widget.walletRestoreViewModel.hasBlockchainHeightLanguageSelector, displayLanguageSelector: widget.walletRestoreViewModel.hasSeedLanguageSelector, diff --git a/lib/src/widgets/seed_widget.dart b/lib/src/widgets/seed_widget.dart index 1c94718f1..7747c5fb6 100644 --- a/lib/src/widgets/seed_widget.dart +++ b/lib/src/widgets/seed_widget.dart @@ -14,6 +14,7 @@ class SeedWidget extends StatefulWidget { this.onSeedChange, this.pasteButtonKey, this.seedTextFieldKey, + this.initialSeed, super.key, }); final Key? seedTextFieldKey; @@ -21,17 +22,18 @@ class SeedWidget extends StatefulWidget { final String language; final WalletType type; final void Function(String)? onSeedChange; + final String? initialSeed; @override - SeedWidgetState createState() => SeedWidgetState(language, type); + SeedWidgetState createState() => SeedWidgetState(language, type, initialSeed); } class SeedWidgetState extends State<SeedWidget> { - SeedWidgetState(String language, this.type) - : controller = TextEditingController(), + SeedWidgetState(String language, this.type, String? initialSeed) + : controller = TextEditingController(text: initialSeed ?? ''), focusNode = FocusNode(), words = SeedValidator.getWordList(type: type, language: language), - _showPlaceholder = false { + _showPlaceholder = initialSeed == null || initialSeed.isEmpty { focusNode.addListener(() { setState(() { if (!focusNode.hasFocus && controller.text.isEmpty) { @@ -57,8 +59,12 @@ class SeedWidgetState extends State<SeedWidget> { @override void initState() { super.initState(); - _showPlaceholder = true; - controller.addListener(() => widget.onSeedChange?.call(text)); + controller.addListener(() { + setState(() { + _showPlaceholder = controller.text.isEmpty; + }); + widget.onSeedChange?.call(text); + }); } void changeSeedLanguage(String language) { diff --git a/lib/view_model/restore/restore_from_qr_vm.dart b/lib/view_model/restore/restore_from_qr_vm.dart deleted file mode 100644 index f31c93911..000000000 --- a/lib/view_model/restore/restore_from_qr_vm.dart +++ /dev/null @@ -1,219 +0,0 @@ -import 'package:cake_wallet/bitcoin/bitcoin.dart'; -import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; -import 'package:cake_wallet/ethereum/ethereum.dart'; -import 'package:cake_wallet/nano/nano.dart'; -import 'package:cake_wallet/polygon/polygon.dart'; -import 'package:cake_wallet/solana/solana.dart'; -import 'package:cake_wallet/tron/tron.dart'; -import 'package:cake_wallet/view_model/restore/restore_mode.dart'; -import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; -import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; -import 'package:cake_wallet/wownero/wownero.dart'; -import 'package:cake_wallet/zano/zano.dart'; -import 'package:hive/hive.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/monero/monero.dart'; -import 'package:cake_wallet/store/app_store.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cake_wallet/core/generate_wallet_password.dart'; -import 'package:cake_wallet/core/wallet_creation_service.dart'; -import 'package:cw_core/wallet_credentials.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:cake_wallet/view_model/wallet_creation_vm.dart'; -import 'package:cw_core/wallet_info.dart'; - -part 'restore_from_qr_vm.g.dart'; - -class WalletRestorationFromQRVM = WalletRestorationFromQRVMBase with _$WalletRestorationFromQRVM; - -abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store { - WalletRestorationFromQRVMBase( - AppStore appStore, - WalletCreationService walletCreationService, - Box<WalletInfo> walletInfoSource, - WalletType type, - SeedSettingsViewModel seedSettingsViewModel) - : height = 0, - viewKey = '', - spendKey = '', - wif = '', - address = '', - super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel, - type: type, isRecovery: true); - - @observable - int height; - - @observable - String viewKey; - - @observable - String spendKey; - - @observable - String wif; - - @observable - String address; - - bool get hasRestorationHeight => type == WalletType.monero || type == WalletType.wownero; - - @override - Future<WalletCredentials> getWalletCredentialsFromQRCredentials( - RestoredWallet restoreWallet) async { - final password = generateWalletPassword(); - - switch (restoreWallet.restoreMode) { - case WalletRestoreMode.keys: - switch (restoreWallet.type) { - case WalletType.monero: - return monero!.createMoneroRestoreWalletFromKeysCredentials( - name: name, - password: password, - language: 'English', - address: restoreWallet.address ?? '', - viewKey: restoreWallet.viewKey ?? '', - spendKey: restoreWallet.spendKey ?? '', - height: restoreWallet.height ?? 0); - case WalletType.wownero: - return wownero!.createWowneroRestoreWalletFromKeysCredentials( - name: name, - password: password, - language: 'English', - address: restoreWallet.address ?? '', - viewKey: restoreWallet.viewKey ?? '', - spendKey: restoreWallet.spendKey ?? '', - height: restoreWallet.height ?? 0); - case WalletType.bitcoin: - case WalletType.litecoin: - return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials( - name: name, password: password, wif: wif); - case WalletType.ethereum: - return ethereum!.createEthereumRestoreWalletFromPrivateKey( - name: name, password: password, privateKey: restoreWallet.privateKey!); - case WalletType.polygon: - return polygon!.createPolygonRestoreWalletFromPrivateKey( - name: name, password: password, privateKey: restoreWallet.privateKey!); - case WalletType.solana: - return solana!.createSolanaRestoreWalletFromPrivateKey( - name: name, password: password, privateKey: restoreWallet.privateKey!); - case WalletType.tron: - return tron!.createTronRestoreWalletFromPrivateKey( - name: name, password: password, privateKey: restoreWallet.privateKey!); - default: - throw Exception('Unexpected type: ${restoreWallet.type.toString()}'); - } - case WalletRestoreMode.seed: - switch (restoreWallet.type) { - case WalletType.monero: - return monero!.createMoneroRestoreWalletFromSeedCredentials( - name: name, - height: restoreWallet.height ?? 0, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase ?? '', - ); - case WalletType.bitcoin: - case WalletType.litecoin: - - final derivationInfoList = await getDerivationInfoFromQRCredentials(restoreWallet); - DerivationInfo derivationInfo; - if (derivationInfoList.isEmpty) { - derivationInfo = getDefaultCreateDerivation()!; - } else { - derivationInfo = derivationInfoList.first; - } - return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - derivationType: derivationInfo.derivationType!, - derivationPath: derivationInfo.derivationPath!, - ); - case WalletType.bitcoinCash: - return bitcoinCash!.createBitcoinCashRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - ); - case WalletType.ethereum: - return ethereum!.createEthereumRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - ); - case WalletType.nano: - final derivationInfo = - (await getDerivationInfoFromQRCredentials(restoreWallet)).first; - return nano!.createNanoRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - derivationType: derivationInfo.derivationType!, - passphrase: restoreWallet.passphrase, - ); - case WalletType.polygon: - return polygon!.createPolygonRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - ); - case WalletType.solana: - return solana!.createSolanaRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - ); - case WalletType.tron: - return tron!.createTronRestoreWalletFromSeedCredentials( - name: name, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase, - ); - case WalletType.wownero: - return wownero!.createWowneroRestoreWalletFromSeedCredentials( - name: name, - height: restoreWallet.height ?? 0, - mnemonic: restoreWallet.mnemonicSeed ?? '', - password: password, - passphrase: restoreWallet.passphrase ?? '', - ); - case WalletType.zano: - return zano!.createZanoRestoreWalletFromSeedCredentials( - name: name, - password: password, - height: height, - mnemonic: restoreWallet.mnemonicSeed ?? '', - passphrase: restoreWallet.passphrase ?? '', - ); - default: - throw Exception('Unexpected type: ${type.toString()}'); - } - default: - throw Exception('Unexpected type: ${type.toString()}'); - } - } - - @override - Future<WalletBase> processFromRestoredWallet(WalletCredentials credentials, - RestoredWallet restoreWallet) async { - try { - switch (restoreWallet.restoreMode) { - case WalletRestoreMode.keys: - return walletCreationService.restoreFromKeys(credentials); - case WalletRestoreMode.seed: - return walletCreationService.restoreFromSeed(credentials); - default: - throw Exception('Unexpected restore mode: ${restoreWallet.restoreMode.toString()}'); - } - } catch (e) { - throw Exception('Unexpected restore mode: ${e.toString()}'); - } - } -} diff --git a/lib/view_model/restore/wallet_restore_from_qr_code.dart b/lib/view_model/restore/wallet_restore_from_qr_code.dart index e28a429a4..2e4e2da83 100644 --- a/lib/view_model/restore/wallet_restore_from_qr_code.dart +++ b/lib/view_model/restore/wallet_restore_from_qr_code.dart @@ -46,8 +46,6 @@ class WalletRestoreFromQRCode { 'zano_wallet': WalletType.zano, }; - static bool _containsAssetSpecifier(String code) => _extractWalletType(code) != null; - static WalletType? _extractWalletType(String code) { final sortedKeys = _walletTypeMap.keys.toList()..sort((a, b) => b.length.compareTo(a.length)); @@ -55,15 +53,18 @@ class WalletRestoreFromQRCode { if (extracted == null) { // Special case for view-only monero wallet - final codeParsed = json.decode(code); - if (codeParsed["version"] == 0 && - codeParsed["primaryAddress"] != null && - codeParsed["privateViewKey"] != null && - codeParsed["restoreHeight"] != null) { - return WalletType.monero; + try { + final codeParsed = json.decode(code); + if (codeParsed["version"] == 0 && + codeParsed["primaryAddress"] != null && + codeParsed["privateViewKey"] != null && + codeParsed["restoreHeight"] != null) { + return WalletType.monero; + } + } catch (e) { + return null; } } - return _walletTypeMap[extracted]; } @@ -93,10 +94,10 @@ class WalletRestoreFromQRCode { if (code == null) throw Exception("Unexpected scan QR code value: aborted"); if (code.isEmpty) throw Exception('Unexpected scan QR code value: value is empty'); - WalletType? walletType; String formattedUri = ''; + WalletType? walletType = _extractWalletType(code); - if (!_containsAssetSpecifier(code)) { + if (walletType == null) { await _specifyWalletAssets(context, "Can't determine wallet type, please pick it manually"); walletType = await Navigator.pushNamed(context, Routes.restoreWalletTypeFromQR) as WalletType?; @@ -108,7 +109,6 @@ class WalletRestoreFromQRCode { ? '$walletType:?seed=$seedPhrase' : throw Exception('Failed to determine valid seed phrase'); } else { - walletType = _extractWalletType(code); final index = code.indexOf(':'); final query = code.substring(index + 1).replaceAll('?', '&'); formattedUri = '$walletType:?$query'; @@ -118,12 +118,11 @@ class WalletRestoreFromQRCode { Map<String, dynamic> queryParameters = {...uri.queryParameters}; if (queryParameters['seed'] == null) { - queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType!); + queryParameters['seed'] = _extractSeedPhraseFromUrl(code, walletType); } if (queryParameters['address'] == null) { - try { - queryParameters['address'] = _extractAddressFromUrl(code, walletType!); - } catch (_) {} + queryParameters['address'] = _extractAddressFromUrl(code, walletType); + } Map<String, dynamic> credentials = {'type': walletType, ...queryParameters, 'raw_qr': code}; diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index edaff441d..4ee8069b3 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -67,8 +67,8 @@ abstract class WalletCreationVMBase with Store { bool typeExists(WalletType type) => walletCreationService.typeExists(type); - Future<void> create({dynamic options, RestoredWallet? restoreWallet}) async { - final type = restoreWallet?.type ?? this.type; + Future<void> create({dynamic options}) async { + final type = this.type; try { state = IsExecutingState(); if (name.isEmpty) { @@ -87,9 +87,7 @@ abstract class WalletCreationVMBase with Store { final dirPath = await pathForWalletDir(name: name, type: type); final path = await pathForWallet(name: name, type: type); - final credentials = restoreWallet != null - ? await getWalletCredentialsFromQRCredentials(restoreWallet) - : getCredentials(options); + final credentials = getCredentials(options); final walletInfo = WalletInfo.external( id: WalletBase.idFor(name, type), @@ -107,9 +105,7 @@ abstract class WalletCreationVMBase with Store { ); credentials.walletInfo = walletInfo; - final wallet = restoreWallet != null - ? await processFromRestoredWallet(credentials, restoreWallet) - : await process(credentials); + final wallet = await process(credentials); final isNonSeedWallet = isRecovery ? wallet.seed == null : false; walletInfo.isNonSeedWallet = isNonSeedWallet; @@ -234,14 +230,6 @@ abstract class WalletCreationVMBase with Store { Future<WalletBase> process(WalletCredentials credentials) => throw UnimplementedError(); - Future<WalletCredentials> getWalletCredentialsFromQRCredentials( - RestoredWallet restoreWallet) async => - throw UnimplementedError(); - - Future<WalletBase> processFromRestoredWallet( - WalletCredentials credentials, RestoredWallet restoreWallet) => - throw UnimplementedError(); - @action void toggleUseTestnet(bool? value) { _useTestnet = value ?? !_useTestnet; diff --git a/lib/view_model/wallet_restore_view_model.dart b/lib/view_model/wallet_restore_view_model.dart index 3e5220447..e7df1c221 100644 --- a/lib/view_model/wallet_restore_view_model.dart +++ b/lib/view_model/wallet_restore_view_model.dart @@ -12,6 +12,7 @@ import 'package:cake_wallet/solana/solana.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/view_model/restore/restore_mode.dart'; +import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_creation_vm.dart'; import 'package:cake_wallet/wownero/wownero.dart'; @@ -30,7 +31,7 @@ class WalletRestoreViewModel = WalletRestoreViewModelBase with _$WalletRestoreVi abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource, SeedSettingsViewModel seedSettingsViewModel, - {required WalletType type}) + {required WalletType type, this.restoredWallet}) : hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven || type == WalletType.wownero, hasBlockchainHeightLanguageSelector = @@ -42,7 +43,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { type == WalletType.solana || type == WalletType.tron, isButtonEnabled = false, - mode = WalletRestoreMode.seed, + mode = restoredWallet?.restoreMode ?? WalletRestoreMode.seed, super(appStore, walletInfoSource, walletCreationService, seedSettingsViewModel, type: type, isRecovery: true) { switch (type) { @@ -68,6 +69,11 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { break; } walletCreationService.changeWalletType(type: type); + if (restoredWallet != null) { + if(restoredWallet!.restoreMode == WalletRestoreMode.seed) { + seedSettingsViewModel.setPassphrase(restoredWallet!.passphrase); + } + } } static const moneroSeedMnemonicLength = 25; @@ -76,6 +82,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store { final bool hasSeedLanguageSelector; final bool hasBlockchainHeightLanguageSelector; final bool hasRestoreFromPrivateKey; + final RestoredWallet? restoredWallet; @observable WalletRestoreMode mode;