diff --git a/cw_decred/lib/wallet.dart b/cw_decred/lib/wallet.dart index ac70a4aaa..97aee775d 100644 --- a/cw_decred/lib/wallet.dart +++ b/cw_decred/lib/wallet.dart @@ -5,6 +5,8 @@ import 'package:path/path.dart' as p; import 'package:cw_core/exceptions.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/utils/print_verbose.dart'; +import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:cw_decred/amount_format.dart'; import 'package:cw_decred/pending_transaction.dart'; import 'package:cw_decred/transaction_credentials.dart'; @@ -307,9 +309,10 @@ abstract class DecredWalletBase persistantPeer = addr; await _libwallet.closeWallet(walletInfo.name); final network = isTestnet ? "testnet" : "mainnet"; + final dirPath = await pathForWalletDir(name: walletInfo.name, type: WalletType.decred); final config = { "name": walletInfo.name, - "datadir": walletInfo.dirPath, + "datadir": dirPath, "net": network, "unsyncedaddrs": true, }; @@ -605,22 +608,22 @@ abstract class DecredWalletBase final sourceDir = Directory(currentDirPath); final targetDir = Directory(newDirPath); - + if (!targetDir.existsSync()) { await targetDir.create(recursive: true); } - + await for (final entity in sourceDir.list(recursive: true)) { - final relativePath = entity.path.substring(sourceDir.path.length+1); + final relativePath = entity.path.substring(sourceDir.path.length + 1); final targetPath = p.join(targetDir.path, relativePath); - + if (entity is File) { await entity.rename(targetPath); } else if (entity is Directory) { await Directory(targetPath).create(recursive: true); } } - + await sourceDir.delete(recursive: true); } diff --git a/cw_decred/lib/wallet_service.dart b/cw_decred/lib/wallet_service.dart index e2313904e..93c708886 100644 --- a/cw_decred/lib/wallet_service.dart +++ b/cw_decred/lib/wallet_service.dart @@ -8,6 +8,7 @@ import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:path/path.dart'; import 'package:hive/hive.dart'; import 'package:collection/collection.dart'; import 'package:cw_core/unspent_coins_info.dart'; @@ -57,42 +58,93 @@ class DecredWalletService extends WalletService< @override Future create(DecredNewWalletCredentials credentials, {bool? isTestnet}) async { await this.init(); + final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); + final network = isTestnet == true ? testnet : mainnet; final config = { "name": credentials.walletInfo!.name, - "datadir": credentials.walletInfo!.dirPath, + "datadir": dirPath, "pass": credentials.password!, - "net": isTestnet == true ? testnet : mainnet, + "net": network, "unsyncedaddrs": true, }; await libwallet!.createWallet(jsonEncode(config)); final di = DerivationInfo( derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath); credentials.walletInfo!.derivationInfo = di; + credentials.walletInfo!.network = network; + // ios will move our wallet directory when updating. Since we must + // recalculate the new path every time we open the wallet, ensure this path + // is not used. An older wallet will have a directory here which is a + // condition for moving the wallet when opening, so this must be kept blank + // going forward. + credentials.walletInfo!.dirPath = ""; + credentials.walletInfo!.path = ""; final wallet = DecredWallet(credentials.walletInfo!, credentials.password!, this.unspentCoinsInfoSource, libwallet!, closeLibwallet); await wallet.init(); return wallet; } + void copyDirectorySync(Directory source, Directory destination) { + /// create destination folder if not exist + if (!destination.existsSync()) { + destination.createSync(recursive: true); + } + + /// get all files from source (recursive: false is important here) + source.listSync(recursive: false).forEach((entity) { + final newPath = destination.path + Platform.pathSeparator + basename(entity.path); + if (entity is File) { + entity.rename(newPath); + } else if (entity is Directory) { + copyDirectorySync(entity, Directory(newPath)); + } + }); + } + + Future moveWallet(String fromPath, String toPath) async { + final oldWalletDir = new Directory(fromPath); + final newWalletDir = new Directory(toPath); + copyDirectorySync(oldWalletDir, newWalletDir); + // It would be ideal to delete the old directory here, but ios will error + // sometimes with "OS Error: No such file or directory, errno = 2" even + // after checking if it exists. + } + @override Future openWallet(String name, String password) async { final walletInfo = walletInfoSource.values .firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!; - final network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet || - walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet - ? testnet - : mainnet; + if (walletInfo.network == null || walletInfo.network == "") { + walletInfo.network = walletInfo.derivationInfo?.derivationPath == seedRestorePathTestnet || + walletInfo.derivationInfo?.derivationPath == pubkeyRestorePathTestnet + ? testnet + : mainnet; + } await this.init(); - final walletDirExists = Directory(walletInfo.dirPath).existsSync(); - if (!walletDirExists) { - walletInfo.dirPath = await pathForWalletDir(name: name, type: getType()); + + // Cake wallet version 4.27.0 and earlier gave a wallet dir that did not + // match the name. Move those to the correct place. + final dirPath = await pathForWalletDir(name: name, type: getType()); + if (walletInfo.path != "") { + // On ios the stored dir no longer exists. We can only trust the basename. + // dirPath may already be updated and lost the basename, so look at path. + final randomBasename = basename(walletInfo.path); + final oldDir = await pathForWalletDir(name: randomBasename, type: getType()); + if (oldDir != dirPath) { + await this.moveWallet(oldDir, dirPath); + } + // Clear the path so this does not trigger again. + walletInfo.dirPath = ""; + walletInfo.path = ""; + await walletInfo.save(); } final config = { - "name": walletInfo.name, - "datadir": walletInfo.dirPath, - "net": network, + "name": name, + "datadir": dirPath, + "net": walletInfo.network, "unsyncedaddrs": true, }; await libwallet!.loadWallet(jsonEncode(config)); @@ -127,12 +179,11 @@ class DecredWalletService extends WalletService< await currentWallet.renameWalletFiles(newName); - final newDirPath = await pathForWalletDir(name: newName, type: getType()); final newWalletInfo = currentWalletInfo; newWalletInfo.id = WalletBase.idFor(newName, getType()); newWalletInfo.name = newName; - newWalletInfo.dirPath = newDirPath; - newWalletInfo.network = network; + newWalletInfo.dirPath = ""; + newWalletInfo.path = ""; await walletInfoSource.put(currentWalletInfo.key, newWalletInfo); } @@ -141,18 +192,23 @@ class DecredWalletService extends WalletService< Future restoreFromSeed(DecredRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { await this.init(); + final network = isTestnet == true ? testnet : mainnet; + final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); final config = { "name": credentials.walletInfo!.name, - "datadir": credentials.walletInfo!.dirPath, + "datadir": dirPath, "pass": credentials.password!, "mnemonic": credentials.mnemonic, - "net": isTestnet == true ? testnet : mainnet, + "net": network, "unsyncedaddrs": true, }; await libwallet!.createWallet(jsonEncode(config)); final di = DerivationInfo( derivationPath: isTestnet == true ? seedRestorePathTestnet : seedRestorePath); credentials.walletInfo!.derivationInfo = di; + credentials.walletInfo!.network = network; + credentials.walletInfo!.dirPath = ""; + credentials.walletInfo!.path = ""; final wallet = DecredWallet(credentials.walletInfo!, credentials.password!, this.unspentCoinsInfoSource, libwallet!, closeLibwallet); await wallet.init(); @@ -165,17 +221,22 @@ class DecredWalletService extends WalletService< Future restoreFromKeys(DecredRestoreWalletFromPubkeyCredentials credentials, {bool? isTestnet}) async { await this.init(); + final network = isTestnet == true ? testnet : mainnet; + final dirPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType()); final config = { "name": credentials.walletInfo!.name, - "datadir": credentials.walletInfo!.dirPath, + "datadir": dirPath, "pubkey": credentials.pubkey, - "net": isTestnet == true ? testnet : mainnet, + "net": network, "unsyncedaddrs": true, }; await libwallet!.createWatchOnlyWallet(jsonEncode(config)); final di = DerivationInfo( derivationPath: isTestnet == true ? pubkeyRestorePathTestnet : pubkeyRestorePath); credentials.walletInfo!.derivationInfo = di; + credentials.walletInfo!.network = network; + credentials.walletInfo!.dirPath = ""; + credentials.walletInfo!.path = ""; final wallet = DecredWallet(credentials.walletInfo!, credentials.password!, this.unspentCoinsInfoSource, libwallet!, closeLibwallet); await wallet.init(); diff --git a/scripts/android/build_decred.sh b/scripts/android/build_decred.sh index 75ed45aca..ce37a7353 100755 --- a/scripts/android/build_decred.sh +++ b/scripts/android/build_decred.sh @@ -7,7 +7,7 @@ cd "$(dirname "$0")" CW_DECRED_DIR=$(realpath ../..)/cw_decred LIBWALLET_PATH="${PWD}/decred/libwallet" LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="dba5327d35cb5d5d1ff113b780869deee154511f" +LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" if [[ -e $LIBWALLET_PATH ]]; then rm -fr $LIBWALLET_PATH || true diff --git a/scripts/ios/build_decred.sh b/scripts/ios/build_decred.sh index 6860c7776..37384f4e1 100755 --- a/scripts/ios/build_decred.sh +++ b/scripts/ios/build_decred.sh @@ -3,7 +3,7 @@ set -e . ./config.sh LIBWALLET_PATH="${EXTERNAL_IOS_SOURCE_DIR}/libwallet" LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="dba5327d35cb5d5d1ff113b780869deee154511f" +LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" if [[ -e $LIBWALLET_PATH ]]; then rm -fr $LIBWALLET_PATH diff --git a/scripts/macos/build_decred.sh b/scripts/macos/build_decred.sh index e7e5d492f..b1bbfbc43 100755 --- a/scripts/macos/build_decred.sh +++ b/scripts/macos/build_decred.sh @@ -4,7 +4,7 @@ LIBWALLET_PATH="${EXTERNAL_MACOS_SOURCE_DIR}/libwallet" LIBWALLET_URL="https://github.com/decred/libwallet.git" -LIBWALLET_VERSION="dba5327d35cb5d5d1ff113b780869deee154511f" +LIBWALLET_VERSION="05f8d7374999400fe4d525eb365c39b77d307b14" echo "======================= DECRED LIBWALLET ========================="