Skip to content

Commit 4b572ab

Browse files
committed
dcr: Always fetch the current dir path.
On ios devices the path will change between updates breaking decred. Never save the path and always check to ensure it is up to date. Previous wallets were also not creating a directory in the correct place. Move those when found.
1 parent b1fc9ba commit 4b572ab

File tree

2 files changed

+85
-25
lines changed

2 files changed

+85
-25
lines changed

cw_decred/lib/wallet.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import 'package:path/path.dart' as p;
55
import 'package:cw_core/exceptions.dart';
66
import 'package:cw_core/transaction_direction.dart';
77
import 'package:cw_core/utils/print_verbose.dart';
8+
import 'package:cw_core/pathForWallet.dart';
9+
import 'package:cw_core/wallet_type.dart';
810
import 'package:cw_decred/amount_format.dart';
911
import 'package:cw_decred/pending_transaction.dart';
1012
import 'package:cw_decred/transaction_credentials.dart';
@@ -307,9 +309,10 @@ abstract class DecredWalletBase
307309
persistantPeer = addr;
308310
await _libwallet.closeWallet(walletInfo.name);
309311
final network = isTestnet ? "testnet" : "mainnet";
312+
final dirPath = await pathForWalletDir(name: walletInfo.name, type: WalletType.decred);
310313
final config = {
311314
"name": walletInfo.name,
312-
"datadir": walletInfo.dirPath,
315+
"datadir": dirPath,
313316
"net": network,
314317
"unsyncedaddrs": true,
315318
};
@@ -605,22 +608,22 @@ abstract class DecredWalletBase
605608

606609
final sourceDir = Directory(currentDirPath);
607610
final targetDir = Directory(newDirPath);
608-
611+
609612
if (!targetDir.existsSync()) {
610613
await targetDir.create(recursive: true);
611614
}
612-
615+
613616
await for (final entity in sourceDir.list(recursive: true)) {
614-
final relativePath = entity.path.substring(sourceDir.path.length+1);
617+
final relativePath = entity.path.substring(sourceDir.path.length + 1);
615618
final targetPath = p.join(targetDir.path, relativePath);
616-
619+
617620
if (entity is File) {
618621
await entity.rename(targetPath);
619622
} else if (entity is Directory) {
620623
await Directory(targetPath).create(recursive: true);
621624
}
622625
}
623-
626+
624627
await sourceDir.delete(recursive: true);
625628
}
626629

cw_decred/lib/wallet_service.dart

Lines changed: 76 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'package:cw_core/wallet_service.dart';
88
import 'package:cw_core/pathForWallet.dart';
99
import 'package:cw_core/wallet_info.dart';
1010
import 'package:cw_core/wallet_type.dart';
11+
import 'package:path/path.dart';
1112
import 'package:hive/hive.dart';
1213
import 'package:collection/collection.dart';
1314
import 'package:cw_core/unspent_coins_info.dart';
@@ -57,42 +58,89 @@ class DecredWalletService extends WalletService<
5758
@override
5859
Future<DecredWallet> create(DecredNewWalletCredentials credentials, {bool? isTestnet}) async {
5960
await this.init();
61+
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
62+
final network = isTestnet == true ? testnet : mainnet;
6063
final config = {
6164
"name": credentials.walletInfo!.name,
62-
"datadir": credentials.walletInfo!.dirPath,
65+
"datadir": dirPath,
6366
"pass": credentials.password!,
64-
"net": isTestnet == true ? testnet : mainnet,
67+
"net": network,
6568
"unsyncedaddrs": true,
6669
};
6770
await libwallet!.createWallet(jsonEncode(config));
6871
final di = DerivationInfo(
6972
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
7073
credentials.walletInfo!.derivationInfo = di;
74+
credentials.walletInfo!.network = network;
75+
// ios will move our wallet directory when updating. Since we must
76+
// recalculate the new path every time we open the wallet, ensure this path
77+
// is not used. An older wallet will have a directory here which is a
78+
// condition for moving the wallet when opening, so this must be kept blank
79+
// going forward.
80+
credentials.walletInfo!.dirPath = "";
81+
credentials.walletInfo!.path = "";
7182
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
7283
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
7384
await wallet.init();
7485
return wallet;
7586
}
7687

88+
void copyDirectorySync(Directory source, Directory destination) {
89+
/// create destination folder if not exist
90+
if (!destination.existsSync()) {
91+
destination.createSync(recursive: true);
92+
}
93+
94+
/// get all files from source (recursive: false is important here)
95+
source.listSync(recursive: false).forEach((entity) {
96+
final newPath = destination.path + Platform.pathSeparator + basename(entity.path);
97+
if (entity is File) {
98+
entity.rename(newPath);
99+
} else if (entity is Directory) {
100+
copyDirectorySync(entity, Directory(newPath));
101+
}
102+
});
103+
}
104+
105+
Future<void> moveWallet(String fromPath, String toPath) async {
106+
final oldWalletDir = new Directory(fromPath);
107+
final newWalletDir = new Directory(toPath);
108+
copyDirectorySync(oldWalletDir, newWalletDir);
109+
await oldWalletDir.delete(recursive: true);
110+
}
111+
77112
@override
78113
Future<DecredWallet> openWallet(String name, String password) async {
79114
final walletInfo = walletInfoSource.values
80115
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
81-
final network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
82-
walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
83-
? testnet
84-
: mainnet;
116+
if (walletInfo.network == null || walletInfo.network == "") {
117+
walletInfo.network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet ||
118+
walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet
119+
? testnet
120+
: mainnet;
121+
}
85122

86123
await this.init();
87-
final walletDirExists = Directory(walletInfo.dirPath).existsSync();
88-
if (!walletDirExists) {
89-
walletInfo.dirPath = await pathForWalletDir(name: name, type: getType());
124+
125+
// Cake wallet version 4.27.0 and earlier gave a wallet dir that did not
126+
// match the name. Move those to the correct place.
127+
final dirPath = await pathForWalletDir(name: name, type: getType());
128+
if (walletInfo.dirPath != "") {
129+
// On ios the stored dir no longer exists. We can only trust the basename.
130+
final randomBasename = basename(walletInfo.dirPath);
131+
final oldDir = await pathForWalletDir(name: randomBasename, type: getType());
132+
if (oldDir != dirPath) {
133+
await this.moveWallet(oldDir, dirPath);
134+
}
135+
// Clear the path so this does not trigger again.
136+
walletInfo.dirPath = "";
137+
walletInfo.path = "";
90138
}
91139

92140
final config = {
93-
"name": walletInfo.name,
94-
"datadir": walletInfo.dirPath,
95-
"net": network,
141+
"name": name,
142+
"datadir": dirPath,
143+
"net": walletInfo.network,
96144
"unsyncedaddrs": true,
97145
};
98146
await libwallet!.loadWallet(jsonEncode(config));
@@ -127,12 +175,11 @@ class DecredWalletService extends WalletService<
127175

128176
await currentWallet.renameWalletFiles(newName);
129177

130-
final newDirPath = await pathForWalletDir(name: newName, type: getType());
131178
final newWalletInfo = currentWalletInfo;
132179
newWalletInfo.id = WalletBase.idFor(newName, getType());
133180
newWalletInfo.name = newName;
134-
newWalletInfo.dirPath = newDirPath;
135-
newWalletInfo.network = network;
181+
newWalletInfo.dirPath = "";
182+
newWalletInfo.path = "";
136183

137184
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
138185
}
@@ -141,18 +188,23 @@ class DecredWalletService extends WalletService<
141188
Future<DecredWallet> restoreFromSeed(DecredRestoreWalletFromSeedCredentials credentials,
142189
{bool? isTestnet}) async {
143190
await this.init();
191+
final network = isTestnet == true ? testnet : mainnet;
192+
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
144193
final config = {
145194
"name": credentials.walletInfo!.name,
146-
"datadir": credentials.walletInfo!.dirPath,
195+
"datadir": dirPath,
147196
"pass": credentials.password!,
148197
"mnemonic": credentials.mnemonic,
149-
"net": isTestnet == true ? testnet : mainnet,
198+
"net": network,
150199
"unsyncedaddrs": true,
151200
};
152201
await libwallet!.createWallet(jsonEncode(config));
153202
final di = DerivationInfo(
154203
derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath);
155204
credentials.walletInfo!.derivationInfo = di;
205+
credentials.walletInfo!.network = network;
206+
credentials.walletInfo!.dirPath = "";
207+
credentials.walletInfo!.path = "";
156208
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
157209
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
158210
await wallet.init();
@@ -165,17 +217,22 @@ class DecredWalletService extends WalletService<
165217
Future<DecredWallet> restoreFromKeys(DecredRestoreWalletFromPubkeyCredentials credentials,
166218
{bool? isTestnet}) async {
167219
await this.init();
220+
final network = isTestnet == true ? testnet : mainnet;
221+
final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
168222
final config = {
169223
"name": credentials.walletInfo!.name,
170-
"datadir": credentials.walletInfo!.dirPath,
224+
"datadir": dirPath,
171225
"pubkey": credentials.pubkey,
172-
"net": isTestnet == true ? testnet : mainnet,
226+
"net": network,
173227
"unsyncedaddrs": true,
174228
};
175229
await libwallet!.createWatchOnlyWallet(jsonEncode(config));
176230
final di = DerivationInfo(
177231
derivationPath: isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath);
178232
credentials.walletInfo!.derivationInfo = di;
233+
credentials.walletInfo!.network = network;
234+
credentials.walletInfo!.dirPath = "";
235+
credentials.walletInfo!.path = "";
179236
final wallet = DecredWallet(credentials.walletInfo!, credentials.password!,
180237
this.unspentCoinsInfoSource, libwallet!, closeLibwallet);
181238
await wallet.init();

0 commit comments

Comments
 (0)