Cw 528 backup wallet files (#1281)
* monero wallet backup changes * [skipci] updates * monero fixes * start work for bitcoin/eth * cleanup * [skipci] more cleanup * add all other coins * merge fixes * add corrupted test * build for testing * actually be able to test monero * review fixes * more review fixes
Matthew Fosse committed
Feb 7, 2024 at 07:44 UTC
26fe28891debf378dbacfb6417f40dbfdccf2716
12 files changed
+266
-119
cw_bitcoin/lib/bitcoin_wallet_service.dart
+32
-22
@@ -12,10 +12,8 @@ import 'package:cw_core/wallet_type.dart';
12
import 'package:hive/hive.dart';
13
import 'package:collection/collection.dart';
14
15
-class BitcoinWalletService extends WalletService<
16
- BitcoinNewWalletCredentials,
17
- BitcoinRestoreWalletFromSeedCredentials,
18
- BitcoinRestoreWalletFromWIFCredentials> {
15
+class BitcoinWalletService extends WalletService<BitcoinNewWalletCredentials,
16
+ BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromWIFCredentials> {
17
BitcoinWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
18
19
final Box<WalletInfo> walletInfoSource;
@@ -42,28 +40,41 @@ class BitcoinWalletService extends WalletService<
40
41
@override
42
Future<BitcoinWallet> openWallet(String name, String password) async {
45
- final walletInfo = walletInfoSource.values.firstWhereOrNull(
46
- (info) => info.id == WalletBase.idFor(name, getType()))!;
47
- final wallet = await BitcoinWalletBase.open(
48
- password: password, name: name, walletInfo: walletInfo,
49
- unspentCoinsInfo: unspentCoinsInfoSource);
50
- await wallet.init();
51
- return wallet;
43
+ final walletInfo = walletInfoSource.values
44
+ .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
45
+ try {
46
+ final wallet = await BitcoinWalletBase.open(
47
+ password: password,
48
+ name: name,
49
+ walletInfo: walletInfo,
50
+ unspentCoinsInfo: unspentCoinsInfoSource);
51
+ await wallet.init();
52
+ saveBackup(name);
53
+ return wallet;
54
+ } catch (_) {
55
+ await restoreWalletFilesFromBackup(name);
56
+ final wallet = await BitcoinWalletBase.open(
57
+ password: password,
58
+ name: name,
59
+ walletInfo: walletInfo,
60
+ unspentCoinsInfo: unspentCoinsInfoSource);
61
+ await wallet.init();
62
+ return wallet;
63
+ }
64
}
65
66
@override
67
Future<void> remove(String wallet) async {
56
- File(await pathForWalletDir(name: wallet, type: getType()))
57
- .delete(recursive: true);
58
- final walletInfo = walletInfoSource.values.firstWhereOrNull(
59
- (info) => info.id == WalletBase.idFor(wallet, getType()))!;
68
+ File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
69
+ final walletInfo = walletInfoSource.values
70
+ .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
71
await walletInfoSource.delete(walletInfo.key);
72
}
73
74
@override
75
Future<void> rename(String currentName, String password, String newName) async {
65
- final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
66
- (info) => info.id == WalletBase.idFor(currentName, getType()))!;
76
+ final currentWalletInfo = walletInfoSource.values
77
+ .firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
78
final currentWallet = await BitcoinWalletBase.open(
79
password: password,
80
name: currentName,
@@ -71,6 +82,7 @@ class BitcoinWalletService extends WalletService<
82
unspentCoinsInfo: unspentCoinsInfoSource);
83
84
await currentWallet.renameWalletFiles(newName);
85
+ await saveBackup(newName);
86
87
final newWalletInfo = currentWalletInfo;
88
newWalletInfo.id = WalletBase.idFor(newName, getType());
@@ -80,13 +92,11 @@ class BitcoinWalletService extends WalletService<
92
}
93
94
@override
83
- Future<BitcoinWallet> restoreFromKeys(
84
- BitcoinRestoreWalletFromWIFCredentials credentials) async =>
95
+ Future<BitcoinWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials) async =>
96
throw UnimplementedError();
97
98
@override
88
- Future<BitcoinWallet> restoreFromSeed(
89
- BitcoinRestoreWalletFromSeedCredentials credentials) async {
99
+ Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials) async {
100
if (!validateMnemonic(credentials.mnemonic)) {
101
throw BitcoinMnemonicIsIncorrectException();
102
}
@@ -100,4 +110,4 @@ class BitcoinWalletService extends WalletService<
110
await wallet.init();
111
return wallet;
112
}
103
-}
\ No newline at end of file
113
+}
cw_bitcoin/lib/electrum_wallet.dart
-3
@@ -601,8 +601,6 @@ abstract class ElectrumWalletBase
601
electrumClient.getHistory(scriptHash).then((history) => {scriptHash: history}));
602
final historyResults = await Future.wait(histories);
603
604
-
605
-
604
historyResults.forEach((history) {
605
history.entries.forEach((historyItem) {
606
if (historyItem.value.isNotEmpty) {
@@ -622,7 +620,6 @@ abstract class ElectrumWalletBase
620
}
621
}
622
625
-
623
addressHashes.forEach((sh, addressRecord) {
624
addressRecord.txCount = newTxCounts[sh] ?? 0;
625
});
cw_bitcoin/lib/litecoin_wallet_service.dart
+17
-5
@@ -45,11 +45,22 @@ class LitecoinWalletService extends WalletService<
45
Future<LitecoinWallet> openWallet(String name, String password) async {
46
final walletInfo = walletInfoSource.values.firstWhereOrNull(
47
(info) => info.id == WalletBase.idFor(name, getType()))!;
48
- final wallet = await LitecoinWalletBase.open(
49
- password: password, name: name, walletInfo: walletInfo,
50
- unspentCoinsInfo: unspentCoinsInfoSource);
51
- await wallet.init();
52
- return wallet;
48
+
49
+ try {
50
+ final wallet = await LitecoinWalletBase.open(
51
+ password: password, name: name, walletInfo: walletInfo,
52
+ unspentCoinsInfo: unspentCoinsInfoSource);
53
+ await wallet.init();
54
+ saveBackup(name);
55
+ return wallet;
56
+ } catch (_) {
57
+ await restoreWalletFilesFromBackup(name);
58
+ final wallet = await LitecoinWalletBase.open(
59
+ password: password, name: name, walletInfo: walletInfo,
60
+ unspentCoinsInfo: unspentCoinsInfoSource);
61
+ await wallet.init();
62
+ return wallet;
63
+ }
64
}
65
66
@override
@@ -72,6 +83,7 @@ class LitecoinWalletService extends WalletService<
83
unspentCoinsInfo: unspentCoinsInfoSource);
84
85
await currentWallet.renameWalletFiles(newName);
86
+ await saveBackup(newName);
87
88
final newWalletInfo = currentWalletInfo;
89
newWalletInfo.id = WalletBase.idFor(newName, getType());
cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart
+17
-5
@@ -51,11 +51,22 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
51
Future<BitcoinCashWallet> openWallet(String name, String password) async {
52
final walletInfo = walletInfoSource.values.firstWhereOrNull(
53
(info) => info.id == WalletBase.idFor(name, getType()))!;
54
- final wallet = await BitcoinCashWalletBase.open(
55
- password: password, name: name, walletInfo: walletInfo,
56
- unspentCoinsInfo: unspentCoinsInfoSource);
57
- await wallet.init();
58
- return wallet;
54
+
55
+ try {
56
+ final wallet = await BitcoinCashWalletBase.open(
57
+ password: password, name: name, walletInfo: walletInfo,
58
+ unspentCoinsInfo: unspentCoinsInfoSource);
59
+ await wallet.init();
60
+ saveBackup(name);
61
+ return wallet;
62
+ } catch(_) {
63
+ await restoreWalletFilesFromBackup(name);
64
+ final wallet = await BitcoinCashWalletBase.open(
65
+ password: password, name: name, walletInfo: walletInfo,
66
+ unspentCoinsInfo: unspentCoinsInfoSource);
67
+ await wallet.init();
68
+ return wallet;
69
+ }
70
}
71
72
@override
@@ -78,6 +89,7 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
89
unspentCoinsInfo: unspentCoinsInfoSource);
90
91
await currentWallet.renameWalletFiles(newName);
92
+ await saveBackup(newName);
93
94
final newWalletInfo = currentWalletInfo;
95
newWalletInfo.id = WalletBase.idFor(newName, getType());
cw_core/lib/monero_wallet_utils.dart
+15
-4
@@ -54,6 +54,17 @@ Future<void> restoreWalletFiles(String name) async {
54
}
55
}
56
57
+Future<void> resetCache(String name) async {
58
+ await removeCache(name);
59
+
60
+ final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
61
+ final cacheFilePath = '$walletDirPath/$name';
62
+ final backupCacheFile = File(backupFileName(cacheFilePath));
63
+ if (backupCacheFile.existsSync()) {
64
+ await backupCacheFile.copy(cacheFilePath);
65
+ }
66
+}
67
+
68
Future<bool> backupWalletFilesExists(String name) async {
69
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.monero);
70
final cacheFilePath = '$walletDirPath/$name';
@@ -63,9 +74,9 @@ Future<bool> backupWalletFilesExists(String name) async {
74
final backupKeysFile = File(backupFileName(keysFilePath));
75
final backupAddressListFile = File(backupFileName(addressListFilePath));
76
66
- return backupCacheFile.existsSync()
67
- && backupKeysFile.existsSync()
68
- && backupAddressListFile.existsSync();
77
+ return backupCacheFile.existsSync() &&
78
+ backupKeysFile.existsSync() &&
79
+ backupAddressListFile.existsSync();
80
}
81
82
Future<void> removeCache(String name) async {
@@ -85,4 +96,4 @@ Future<void> restoreOrResetWalletFiles(String name) async {
96
}
97
98
removeCache(name);
88
-}
\ No newline at end of file
99
+}
cw_core/lib/wallet_service.dart
+21
-2
@@ -1,7 +1,8 @@
1
-import 'package:cw_core/node.dart';
1
+import 'dart:io';
2
+
3
+import 'package:cw_core/pathForWallet.dart';
4
import 'package:cw_core/wallet_base.dart';
5
import 'package:cw_core/wallet_credentials.dart';
4
-import 'package:cw_core/wallet_info.dart';
6
import 'package:cw_core/wallet_type.dart';
7
8
abstract class WalletService<N extends WalletCredentials, RFS extends WalletCredentials,
@@ -21,4 +22,22 @@ abstract class WalletService<N extends WalletCredentials, RFS extends WalletCred
22
Future<void> remove(String wallet);
23
24
Future<void> rename(String currentName, String password, String newName);
25
+
26
+ Future<void> restoreWalletFilesFromBackup(String name) async {
27
+ final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: getType());
28
+ final walletDirPath = await pathForWalletDir(name: name, type: getType());
29
+
30
+ if (File(backupWalletDirPath).existsSync()) {
31
+ await File(backupWalletDirPath).copy(walletDirPath);
32
+ }
33
+ }
34
+
35
+ Future<void> saveBackup(String name) async {
36
+ final backupWalletDirPath = await pathForWalletDir(name: "$name.backup", type: getType());
37
+ final walletDirPath = await pathForWalletDir(name: name, type: getType());
38
+
39
+ if (File(walletDirPath).existsSync()) {
40
+ await File(walletDirPath).copy(backupWalletDirPath);
41
+ }
42
+ }
43
}
cw_ethereum/lib/ethereum_wallet_service.dart
+25
-9
@@ -39,16 +39,31 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
39
Future<EthereumWallet> openWallet(String name, String password) async {
40
final walletInfo =
41
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
42
- final wallet = await EthereumWallet.open(
43
- name: name,
44
- password: password,
45
- walletInfo: walletInfo,
46
- );
47
-
48
- await wallet.init();
49
- await wallet.save();
42
51
- return wallet;
43
+ try {
44
+ final wallet = await EthereumWallet.open(
45
+ name: name,
46
+ password: password,
47
+ walletInfo: walletInfo,
48
+ );
49
+
50
+ await wallet.init();
51
+ await wallet.save();
52
+ saveBackup(name);
53
+ return wallet;
54
+ } catch (_) {
55
+
56
+ await restoreWalletFilesFromBackup(name);
57
+
58
+ final wallet = await EthereumWallet.open(
59
+ name: name,
60
+ password: password,
61
+ walletInfo: walletInfo,
62
+ );
63
+ await wallet.init();
64
+ await wallet.save();
65
+ return wallet;
66
+ }
67
}
68
69
@override
@@ -59,6 +74,7 @@ class EthereumWalletService extends EVMChainWalletService<EthereumWallet> {
74
password: password, name: currentName, walletInfo: currentWalletInfo);
75
76
await currentWallet.renameWalletFiles(newName);
77
+ await saveBackup(newName);
78
79
final newWalletInfo = currentWalletInfo;
80
newWalletInfo.id = WalletBase.idFor(newName, getType());
cw_haven/lib/haven_wallet_service.dart
+1
@@ -163,6 +163,7 @@ class HavenWalletService extends WalletService<
163
final currentWallet = HavenWallet(walletInfo: currentWalletInfo);
164
165
await currentWallet.renameWalletFiles(newName);
166
+ await saveBackup(newName);
167
168
final newWalletInfo = currentWalletInfo;
169
newWalletInfo.id = WalletBase.idFor(newName, getType());
cw_monero/lib/monero_wallet.dart
+52
-12
@@ -36,6 +36,8 @@ import 'package:mobx/mobx.dart';
36
part 'monero_wallet.g.dart';
37
38
const moneroBlockSize = 1000;
39
+// not sure if this should just be 0 but setting it higher feels safer / should catch more cases:
40
+const MIN_RESTORE_HEIGHT = 1000;
41
42
class MoneroWallet = MoneroWalletBase with _$MoneroWallet;
43
@@ -79,7 +81,7 @@ abstract class MoneroWalletBase
81
82
Box<UnspentCoinsInfo> unspentCoinsInfo;
83
82
- void Function(FlutterErrorDetails)? _onError;
84
+ void Function(FlutterErrorDetails)? onError;
85
86
@override
87
late MoneroWalletAddresses walletAddresses;
@@ -171,7 +173,26 @@ abstract class MoneroWalletBase
173
Future<void> startSync() async {
174
try {
175
_setInitialHeight();
174
- } catch (_) {}
176
+ } catch (_) {
177
+ // our restore height wasn't correct, so lets see if using the backup works:
178
+ try {
179
+ await resetCache(name);
180
+ _setInitialHeight();
181
+ } catch (e) {
182
+ // we still couldn't get a valid height from the backup?!:
183
+ // try to use the date instead:
184
+ try {
185
+ _setHeightFromDate();
186
+ } catch (e, s) {
187
+ // we still couldn't get a valid sync height :/
188
+ onError?.call(FlutterErrorDetails(
189
+ exception: e,
190
+ stack: s,
191
+ library: this.runtimeType.toString(),
192
+ ));
193
+ }
194
+ }
195
+ }
196
197
try {
198
syncStatus = AttemptingSyncStatus();
@@ -339,6 +360,8 @@ abstract class MoneroWalletBase
360
if (currentAddressListFile.existsSync()) {
361
await currentAddressListFile.rename('$newWalletPath.address.txt');
362
}
363
+
364
+ await backupWalletFiles(newWalletName);
365
} catch (e) {
366
final currentWalletPath = await pathForWallet(name: name, type: type);
367
@@ -402,9 +425,7 @@ abstract class MoneroWalletBase
425
if (coin.spent == 0) {
426
final unspent = MoneroUnspent.fromCoinsInfoRow(coin);
427
if (unspent.hash.isNotEmpty) {
405
- unspent.isChange = transaction_history
406
- .getTransaction(unspent.hash)
407
- .direction == 1;
428
+ unspent.isChange = transaction_history.getTransaction(unspent.hash).direction == 1;
429
}
430
unspentCoins.add(unspent);
431
}
@@ -418,7 +439,7 @@ abstract class MoneroWalletBase
439
if (unspentCoins.isNotEmpty) {
440
unspentCoins.forEach((coin) {
441
final coinInfoList = unspentCoinsInfo.values.where((element) =>
421
- element.walletId.contains(id) &&
442
+ element.walletId.contains(id) &&
443
element.accountIndex == walletAddresses.account!.id &&
444
element.keyImage!.contains(coin.keyImage!));
445
@@ -438,7 +459,7 @@ abstract class MoneroWalletBase
459
_askForUpdateBalance();
460
} catch (e, s) {
461
print(e.toString());
441
- _onError?.call(FlutterErrorDetails(
462
+ onError?.call(FlutterErrorDetails(
463
exception: e,
464
stack: s,
465
library: this.runtimeType.toString(),
@@ -534,18 +555,36 @@ abstract class MoneroWalletBase
555
_listener = monero_wallet.setListeners(_onNewBlock, _onNewTransaction);
556
}
557
558
+ // check if the height is correct:
559
void _setInitialHeight() {
560
if (walletInfo.isRecovery) {
561
return;
562
}
563
542
- final currentHeight = monero_wallet.getCurrentHeight();
564
+ final height = monero_wallet.getCurrentHeight();
565
+
566
+ if (height > MIN_RESTORE_HEIGHT) {
567
+ // the restore height is probably correct, so we do nothing:
568
+ return;
569
+ }
570
+
571
+ throw Exception("height isn't > $MIN_RESTORE_HEIGHT!");
572
+ }
573
+
574
+ void _setHeightFromDate() {
575
+ if (walletInfo.isRecovery) {
576
+ return;
577
+ }
578
+
579
+ final height = _getHeightByDate(walletInfo.date);
580
544
- if (currentHeight <= 1) {
545
- final height = _getHeightByDate(walletInfo.date);
581
+ if (height > MIN_RESTORE_HEIGHT) {
582
monero_wallet.setRecoveringFromSeed(isRecovery: true);
583
monero_wallet.setRefreshFromBlockHeight(height: height);
584
+ return;
585
}
586
+
587
+ throw Exception("height isn't > $MIN_RESTORE_HEIGHT!");
588
}
589
590
int _getHeightDistance(DateTime date) {
@@ -561,7 +600,8 @@ abstract class MoneroWalletBase
600
final heightDistance = _getHeightDistance(date);
601
602
if (nodeHeight <= 0) {
564
- return 0;
603
+ // the node returned 0 (an error state), so lets just restore from cache:
604
+ throw Exception("nodeHeight is <= 0!");
605
}
606
607
return nodeHeight - heightDistance;
@@ -650,7 +690,7 @@ abstract class MoneroWalletBase
690
}
691
692
@override
653
- void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError;
693
+ void setExceptionHandler(void Function(FlutterErrorDetails) e) => onError = e;
694
695
@override
696
String signMessage(String message, {String? address}) {
cw_monero/lib/monero_wallet_service.dart
+37
-40
@@ -11,11 +11,13 @@ import 'package:cw_core/get_height_by_date.dart';
11
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
12
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
13
import 'package:cw_monero/monero_wallet.dart';
14
+import 'package:flutter/widgets.dart';
15
import 'package:hive/hive.dart';
16
import 'package:polyseed/polyseed.dart';
17
18
class MoneroNewWalletCredentials extends WalletCredentials {
18
- MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password})
19
+ MoneroNewWalletCredentials(
20
+ {required String name, required this.language, required this.isPolyseed, String? password})
21
: super(name: name, password: password);
22
23
final String language;
@@ -52,10 +54,8 @@ class MoneroRestoreWalletFromKeysCredentials extends WalletCredentials {
54
final String spendKey;
55
}
56
55
-class MoneroWalletService extends WalletService<
56
- MoneroNewWalletCredentials,
57
- MoneroRestoreWalletFromSeedCredentials,
58
- MoneroRestoreWalletFromKeysCredentials> {
57
+class MoneroWalletService extends WalletService<MoneroNewWalletCredentials,
58
+ MoneroRestoreWalletFromSeedCredentials, MoneroRestoreWalletFromKeysCredentials> {
59
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
60
61
final Box<WalletInfo> walletInfoSource;
@@ -112,6 +112,7 @@ class MoneroWalletService extends WalletService<
112
113
@override
114
Future<MoneroWallet> openWallet(String name, String password) async {
115
+ MoneroWallet? wallet;
116
try {
117
final path = await pathForWallet(name: name, type: getType());
118
@@ -119,11 +120,10 @@ class MoneroWalletService extends WalletService<
120
await repairOldAndroidWallet(name);
121
}
122
122
- await monero_wallet_manager
123
- .openWalletAsync({'path': path, 'password': password});
124
- final walletInfo = walletInfoSource.values.firstWhere(
125
- (info) => info.id == WalletBase.idFor(name, getType()));
126
- final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
123
+ await monero_wallet_manager.openWalletAsync({'path': path, 'password': password});
124
+ final walletInfo = walletInfoSource.values
125
+ .firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
126
+ wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
127
final isValid = wallet.walletAddresses.validate();
128
129
if (!isValid) {
@@ -135,7 +135,7 @@ class MoneroWalletService extends WalletService<
135
await wallet.init();
136
137
return wallet;
138
- } catch (e) {
138
+ } catch (e, s) {
139
// TODO: Implement Exception for wallet list service.
140
141
final bool isBadAlloc = e.toString().contains('bad_alloc') ||
@@ -156,16 +156,18 @@ class MoneroWalletService extends WalletService<
156
final bool invalidSignature = e.toString().contains('invalid signature') ||
157
(e is WalletOpeningException && e.message.contains('invalid signature'));
158
159
- if (isBadAlloc ||
160
- doesNotCorrespond ||
161
- isMissingCacheFilesIOS ||
162
- isMissingCacheFilesAndroid ||
163
- invalidSignature) {
164
- await restoreOrResetWalletFiles(name);
165
- return openWallet(name, password);
159
+ if (!isBadAlloc &&
160
+ !doesNotCorrespond &&
161
+ !isMissingCacheFilesIOS &&
162
+ !isMissingCacheFilesAndroid &&
163
+ !invalidSignature &&
164
+ wallet != null &&
165
+ wallet.onError != null) {
166
+ wallet.onError!(FlutterErrorDetails(exception: e, stack: s));
167
}
168
168
- rethrow;
169
+ await restoreOrResetWalletFiles(name);
170
+ return openWallet(name, password);
171
}
172
}
173
@@ -185,10 +187,9 @@ class MoneroWalletService extends WalletService<
187
}
188
189
@override
188
- Future<void> rename(
189
- String currentName, String password, String newName) async {
190
- final currentWalletInfo = walletInfoSource.values.firstWhere(
191
- (info) => info.id == WalletBase.idFor(currentName, getType()));
190
+ Future<void> rename(String currentName, String password, String newName) async {
191
+ final currentWalletInfo = walletInfoSource.values
192
+ .firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
193
final currentWallet =
194
MoneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
195
@@ -202,8 +203,7 @@ class MoneroWalletService extends WalletService<
203
}
204
205
@override
205
- Future<MoneroWallet> restoreFromKeys(
206
- MoneroRestoreWalletFromKeysCredentials credentials) async {
206
+ Future<MoneroWallet> restoreFromKeys(MoneroRestoreWalletFromKeysCredentials credentials) async {
207
try {
208
final path = await pathForWallet(name: credentials.name, type: getType());
209
await monero_wallet_manager.restoreFromKeys(
@@ -227,9 +227,7 @@ class MoneroWalletService extends WalletService<
227
}
228
229
@override
230
- Future<MoneroWallet> restoreFromSeed(
231
- MoneroRestoreWalletFromSeedCredentials credentials) async {
232
-
230
+ Future<MoneroWallet> restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials) async {
231
// Restore from Polyseed
232
if (Polyseed.isValidSeed(credentials.mnemonic)) {
233
return restoreFromPolyseed(credentials);
@@ -254,14 +252,16 @@ class MoneroWalletService extends WalletService<
252
}
253
}
254
257
- Future<MoneroWallet> restoreFromPolyseed(MoneroRestoreWalletFromSeedCredentials credentials) async {
255
+ Future<MoneroWallet> restoreFromPolyseed(
256
+ MoneroRestoreWalletFromSeedCredentials credentials) async {
257
try {
258
final path = await pathForWallet(name: credentials.name, type: getType());
259
final polyseedCoin = PolyseedCoin.POLYSEED_MONERO;
260
final lang = PolyseedLang.getByPhrase(credentials.mnemonic);
261
final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin);
262
264
- return _restoreFromPolyseed(path, credentials.password!, polyseed, credentials.walletInfo!, lang);
263
+ return _restoreFromPolyseed(
264
+ path, credentials.password!, polyseed, credentials.walletInfo!, lang);
265
} catch (e) {
266
// TODO: Implement Exception for wallet list service.
267
print('MoneroWalletsManager Error: $e');
@@ -269,11 +269,11 @@ class MoneroWalletService extends WalletService<
269
}
270
}
271
272
- Future<MoneroWallet> _restoreFromPolyseed(String path, String password, Polyseed polyseed,
273
- WalletInfo walletInfo, PolyseedLang lang,
272
+ Future<MoneroWallet> _restoreFromPolyseed(
273
+ String path, String password, Polyseed polyseed, WalletInfo walletInfo, PolyseedLang lang,
274
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
275
- final height = overrideHeight ?? getMoneroHeigthByDate(
276
- date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
275
+ final height = overrideHeight ??
276
+ getMoneroHeigthByDate(date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
277
final spendKey = polyseed.generateKey(coin, 32).toHexString();
278
final seed = polyseed.encode(lang, coin);
279
@@ -288,8 +288,7 @@ class MoneroWalletService extends WalletService<
288
restoreHeight: height,
289
spendKey: spendKey);
290
291
- final wallet = MoneroWallet(
292
- walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
291
+ final wallet = MoneroWallet(walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource);
292
await wallet.init();
293
294
return wallet;
@@ -301,16 +300,14 @@ class MoneroWalletService extends WalletService<
300
return;
301
}
302
304
- final oldAndroidWalletDirPath =
305
- await outdatedAndroidPathForWalletDir(name: name);
303
+ final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name);
304
final dir = Directory(oldAndroidWalletDirPath);
305
306
if (!dir.existsSync()) {
307
return;
308
}
309
312
- final newWalletDirPath =
313
- await pathForWalletDir(name: name, type: getType());
310
+ final newWalletDirPath = await pathForWalletDir(name: name, type: getType());
311
312
dir.listSync().forEach((f) {
313
final file = File(f.path);
cw_nano/lib/nano_wallet_service.dart
+24
-8
@@ -69,6 +69,7 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
69
NanoWallet(walletInfo: currentWalletInfo, password: password, mnemonic: randomWords);
70
71
await currentWallet.renameWalletFiles(newName);
72
+ await saveBackup(newName);
73
74
final newWalletInfo = currentWalletInfo;
75
newWalletInfo.id = WalletBase.idFor(newName, getType());
@@ -150,14 +151,29 @@ class NanoWalletService extends WalletService<NanoNewWalletCredentials,
151
Future<NanoWallet> openWallet(String name, String password) async {
152
final walletInfo =
153
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
153
- final wallet = await NanoWalletBase.open(
154
- name: name,
155
- password: password,
156
- walletInfo: walletInfo,
157
- );
154
159
- await wallet.init();
160
- await wallet.save();
161
- return wallet;
155
+ try {
156
+ final wallet = await NanoWalletBase.open(
157
+ name: name,
158
+ password: password,
159
+ walletInfo: walletInfo,
160
+ );
161
+
162
+ await wallet.init();
163
+ await wallet.save();
164
+ saveBackup(name);
165
+ return wallet;
166
+ } catch (_) {
167
+ await restoreWalletFilesFromBackup(name);
168
+ final wallet = await NanoWalletBase.open(
169
+ name: name,
170
+ password: password,
171
+ walletInfo: walletInfo,
172
+ );
173
+
174
+ await wallet.init();
175
+ await wallet.save();
176
+ return wallet;
177
+ }
178
}
179
}
cw_polygon/lib/polygon_wallet_service.dart
+25
-9
@@ -42,16 +42,31 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
42
Future<PolygonWallet> openWallet(String name, String password) async {
43
final walletInfo =
44
walletInfoSource.values.firstWhere((info) => info.id == WalletBase.idFor(name, getType()));
45
- final wallet = await PolygonWallet.open(
46
- name: name,
47
- password: password,
48
- walletInfo: walletInfo,
49
- );
50
-
51
- await wallet.init();
52
- await wallet.save();
45
54
- return wallet;
46
+ try {
47
+ final wallet = await PolygonWallet.open(
48
+ name: name,
49
+ password: password,
50
+ walletInfo: walletInfo,
51
+ );
52
+
53
+ await wallet.init();
54
+ await wallet.save();
55
+ saveBackup(name);
56
+ return wallet;
57
+ } catch (_) {
58
+ await restoreWalletFilesFromBackup(name);
59
+
60
+ final wallet = await PolygonWallet.open(
61
+ name: name,
62
+ password: password,
63
+ walletInfo: walletInfo,
64
+ );
65
+
66
+ await wallet.init();
67
+ await wallet.save();
68
+ return wallet;
69
+ }
70
}
71
72
@override
@@ -100,6 +115,7 @@ class PolygonWalletService extends EVMChainWalletService<PolygonWallet> {
115
password: password, name: currentName, walletInfo: currentWalletInfo);
116
117
await currentWallet.renameWalletFiles(newName);
118
+ await saveBackup(newName);
119
120
final newWalletInfo = currentWalletInfo;
121
newWalletInfo.id = WalletBase.idFor(newName, getType());