Better handle corrupted wallets (#1384)
* Fix exchanges not showing * Fix button text on Monero receive screen * Temp fix for ERC20 and SPL tokens not having raw value * fallback to other wallets if the current wallet is corrupted so we give user access to the app --------- Co-authored-by: tuxsudo <tuxsudo@tux.pizza>
Omar Hatem committed
Apr 26, 2024 at 22:13 UTC
f3160860b1796ef0abe41299eb954ce26c1b899b
1 file changed
+44
-17
lib/core/wallet_loading_service.dart
+44
-17
@@ -1,27 +1,28 @@
1
import 'package:cake_wallet/core/generate_wallet_password.dart';
2
import 'package:cake_wallet/core/key_service.dart';
3
import 'package:cake_wallet/entities/preferences_key.dart';
4
+import 'package:cake_wallet/utils/exception_handler.dart';
5
+import 'package:cw_core/cake_hive.dart';
6
import 'package:cw_core/wallet_base.dart';
7
+import 'package:cw_core/wallet_info.dart';
8
import 'package:cw_core/wallet_service.dart';
9
import 'package:cw_core/wallet_type.dart';
10
+import 'package:flutter/material.dart';
11
import 'package:shared_preferences/shared_preferences.dart';
12
13
class WalletLoadingService {
10
- WalletLoadingService(
11
- this.sharedPreferences, this.keyService, this.walletServiceFactory);
14
+ WalletLoadingService(this.sharedPreferences, this.keyService, this.walletServiceFactory);
15
16
final SharedPreferences sharedPreferences;
17
final KeyService keyService;
18
final WalletService Function(WalletType type) walletServiceFactory;
19
17
- Future<void> renameWallet(
18
- WalletType type, String name, String newName) async {
20
+ Future<void> renameWallet(WalletType type, String name, String newName) async {
21
final walletService = walletServiceFactory.call(type);
22
final password = await keyService.getWalletPassword(walletName: name);
23
24
// Save the current wallet's password to the new wallet name's key
23
- await keyService.saveWalletPassword(
24
- walletName: newName, password: password);
25
+ await keyService.saveWalletPassword(walletName: newName, password: password);
26
// Delete previous wallet name from keyService to keep only new wallet's name
27
// otherwise keeps duplicate (old and new names)
28
await keyService.deleteWalletPassword(walletName: name);
@@ -38,15 +39,43 @@ class WalletLoadingService {
39
}
40
41
Future<WalletBase> load(WalletType type, String name) async {
41
- final walletService = walletServiceFactory.call(type);
42
- final password = await keyService.getWalletPassword(walletName: name);
43
- final wallet = await walletService.openWallet(name, password);
42
+ try {
43
+ final walletService = walletServiceFactory.call(type);
44
+ final password = await keyService.getWalletPassword(walletName: name);
45
+ final wallet = await walletService.openWallet(name, password);
46
45
- if (type == WalletType.monero) {
46
- await updateMoneroWalletPassword(wallet);
47
- }
47
+ if (type == WalletType.monero) {
48
+ await updateMoneroWalletPassword(wallet);
49
+ }
50
+
51
+ return wallet;
52
+ } catch (error, stack) {
53
+ ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
54
+
55
+ // try opening another wallet that is not corrupted to give user access to the app
56
+ final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
57
49
- return wallet;
58
+ for (var walletInfo in walletInfoSource.values) {
59
+ try {
60
+ final walletService = walletServiceFactory.call(walletInfo.type);
61
+ final password = await keyService.getWalletPassword(walletName: walletInfo.name);
62
+ final wallet = await walletService.openWallet(walletInfo.name, password);
63
+
64
+ if (walletInfo.type == WalletType.monero) {
65
+ await updateMoneroWalletPassword(wallet);
66
+ }
67
+
68
+ await sharedPreferences.setString(PreferencesKey.currentWalletName, wallet.name);
69
+ await sharedPreferences.setInt(
70
+ PreferencesKey.currentWalletType, serializeToInt(wallet.type));
71
+
72
+ return wallet;
73
+ } catch (_) {}
74
+ }
75
+
76
+ // if all user's wallets are corrupted throw exception
77
+ throw error;
78
+ }
79
}
80
81
Future<void> updateMoneroWalletPassword(WalletBase wallet) async {
@@ -61,11 +90,9 @@ class WalletLoadingService {
90
// Save new generated password with backup key for case where
91
// wallet will change password, but it will fail to update in secure storage
92
final bakWalletName = '#__${wallet.name}_bak__#';
64
- await keyService.saveWalletPassword(
65
- walletName: bakWalletName, password: password);
93
+ await keyService.saveWalletPassword(walletName: bakWalletName, password: password);
94
await wallet.changePassword(password);
67
- await keyService.saveWalletPassword(
68
- walletName: wallet.name, password: password);
95
+ await keyService.saveWalletPassword(walletName: wallet.name, password: password);
96
isPasswordUpdated = true;
97
await sharedPreferences.setBool(key, isPasswordUpdated);
98
}