Cw 773 restoring from qr gives no visual feedback of progress ()

* 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>
This commit is contained in:
Serhii 2025-03-15 01:45:46 +02:00 committed by GitHub
parent 9f3078740e
commit 6abefc25a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 129 additions and 321 deletions

View file

@ -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));

View file

@ -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(

View file

@ -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());
}
}
}

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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) {

View file

@ -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()}');
}
}
}

View file

@ -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};

View file

@ -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;

View file

@ -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;