diff --git a/cw_bitcoin/lib/electrum_derivations.dart b/cw_bitcoin/lib/electrum_derivations.dart index 81a3626d2..87e18a885 100644 --- a/cw_bitcoin/lib/electrum_derivations.dart +++ b/cw_bitcoin/lib/electrum_derivations.dart @@ -8,20 +8,26 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = { description: "Electrum", scriptType: "p2wpkh", ), + DerivationInfo( + derivationType: DerivationType.electrum, + derivationPath: "m/1'", + description: "Electrum", + scriptType: "p2wpkh", + ), ], DerivationType.bip39: [ - DerivationInfo( - derivationType: DerivationType.bip39, - derivationPath: "m/44'/0'/0'", - description: "Standard BIP44", - scriptType: "p2pkh", - ), - DerivationInfo( - derivationType: DerivationType.bip39, - derivationPath: "m/49'/0'/0'", - description: "Standard BIP49 compatibility segwit", - scriptType: "p2wpkh-p2sh", - ), + // DerivationInfo( + // derivationType: DerivationType.bip39, + // derivationPath: "m/44'/0'/0'", + // description: "Standard BIP44", + // scriptType: "p2pkh", + // ), + // DerivationInfo( + // derivationType: DerivationType.bip39, + // derivationPath: "m/49'/0'/0'", + // description: "Standard BIP49 compatibility segwit", + // scriptType: "p2wpkh-p2sh", + // ), DerivationInfo( derivationType: DerivationType.bip39, derivationPath: "m/84'/0'/0'", @@ -34,21 +40,27 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = { description: "Standard BIP86 Taproot", scriptType: "p2tr", ), + // DerivationInfo( + // derivationType: DerivationType.bip39, + // derivationPath: "m/0'", + // description: "Non-standard legacy", + // scriptType: "p2pkh", + // ), + // DerivationInfo( + // derivationType: DerivationType.bip39, + // derivationPath: "m/0'", + // description: "Non-standard compatibility segwit", + // scriptType: "p2wpkh-p2sh", + // ), DerivationInfo( derivationType: DerivationType.bip39, derivationPath: "m/0'", - description: "Non-standard legacy", - scriptType: "p2pkh", + description: "Non-standard native segwit", + scriptType: "p2wpkh", ), DerivationInfo( derivationType: DerivationType.bip39, - derivationPath: "m/0'", - description: "Non-standard compatibility segwit", - scriptType: "p2wpkh-p2sh", - ), - DerivationInfo( - derivationType: DerivationType.bip39, - derivationPath: "m/0'", + derivationPath: "m/1'", description: "Non-standard native segwit", scriptType: "p2wpkh", ), @@ -106,6 +118,7 @@ Map<DerivationType, List<DerivationInfo>> electrum_derivations = { description: "Default Litecoin", scriptType: "p2wpkh", ), + ], }; diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 9a7e45d05..9a55aab89 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -990,6 +990,11 @@ abstract class ElectrumWalletBase @override Future<PendingTransaction> createTransaction(Object credentials) async { try { + _onError?.call(FlutterErrorDetails( + exception: "testing exception", + stack: StackTrace.current, + library: this.runtimeType.toString(), + )); // start by updating unspent coins await updateAllUnspents(); @@ -1365,7 +1370,7 @@ abstract class ElectrumWalletBase List<BitcoinUnspent> updatedUnspentCoins = []; final previousUnspentCoins = List<BitcoinUnspent>.from(unspentCoins.where((utxo) => - utxo.bitcoinAddressRecord.type != SegwitAddresType.mweb && + utxo.bitcoinAddressRecord.type != SegwitAddresType.mweb && utxo.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord)); if (hasSilentPaymentsScanning) { @@ -1423,7 +1428,6 @@ abstract class ElectrumWalletBase required List<BitcoinUnspent> updatedUnspentCoins, required List<List<BitcoinUnspent>?> results, }) { - if (failedCount == results.length) { printV("All UTXOs failed to fetch, falling back to previous UTXOs"); return previousUnspentCoins; diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 13a32c68c..c8655f5ac 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -47,7 +47,6 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { List<BitcoinAddressRecord>? initialMwebAddresses, Bip32Slip10Secp256k1? masterHd, BitcoinAddressType? initialAddressPageType, - }) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()), addressesByReceiveType = ObservableList<BaseBitcoinAddressRecord>.of((<BitcoinAddressRecord>[]).toSet()), @@ -187,13 +186,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { return; } try { - final addressRecord = _addresses.firstWhere( - (addressRecord) => addressRecord.address == addr, - ); + final addressRecord = _addresses.firstWhere( + (addressRecord) => addressRecord.address == addr, + ); - previousAddressRecord = addressRecord; - receiveAddresses.remove(addressRecord); - receiveAddresses.insert(0, addressRecord); + previousAddressRecord = addressRecord; + receiveAddresses.remove(addressRecord); + receiveAddresses.insert(0, addressRecord); } catch (e) { printV("ElectrumWalletAddressBase: set address ($addr): $e"); } @@ -274,7 +273,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } @action - Future<BitcoinAddressRecord> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async { + Future<BitcoinAddressRecord> getChangeAddress( + {List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async { updateChangeAddresses(); if (changeAddresses.isEmpty) { diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index afe3c75b8..27613b19d 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -33,10 +33,10 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with super.initialRegularAddressIndex, super.initialChangeAddressIndex, }) : super(walletInfo) { - for (int i = 0; i < mwebAddresses.length; i++) { - mwebAddrs.add(mwebAddresses[i].address); - } - printV("initialized with ${mwebAddrs.length} mweb addresses"); + // for (int i = 0; i < mwebAddresses.length; i++) { + // mwebAddrs.add(mwebAddresses[i].address); + // } + // printV("initialized with ${mwebAddrs.length} mweb addresses"); } final Bip32Slip10Secp256k1? mwebHd; @@ -62,6 +62,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with } Future<void> ensureMwebAddressUpToIndexExists(int index) async { + return null; if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) { return null; } @@ -127,9 +128,9 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType, }) { - if (addressType == SegwitAddresType.mweb) { - return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1]; - } + // if (addressType == SegwitAddresType.mweb) { + // return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1]; + // } return generateP2WPKHAddress(hd: hd, index: index, network: network); } @@ -139,9 +140,9 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType, }) async { - if (addressType == SegwitAddresType.mweb) { - await ensureMwebAddressUpToIndexExists(index); - } + // if (addressType == SegwitAddresType.mweb) { + // await ensureMwebAddressUpToIndexExists(index); + // } return getAddress(index: index, hd: hd, addressType: addressType); } diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index bf9ec0c4d..e5103a380 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -330,9 +330,9 @@ class CWBitcoin extends Bitcoin { List<DerivationInfo> list = []; List<DerivationType> types = await compareDerivationMethods(mnemonic: mnemonic, node: node); - if (types.length == 1 && types.first == DerivationType.electrum) { - return [getElectrumDerivations()[DerivationType.electrum]!.first]; - } + // if (types.length == 1 && types.first == DerivationType.electrum) { + // return [getElectrumDerivations()[DerivationType.electrum]!.first]; + // } final electrumClient = ElectrumClient(); await electrumClient.connectToUri(node.uri, useSSL: node.useSSL); @@ -348,66 +348,149 @@ class CWBitcoin extends Bitcoin { break; } - for (DerivationType dType in electrum_derivations.keys) { + bool found = false; + print("types: $types"); + for (DerivationType typ in types) { + if (found) { + break; + } + late Uint8List seedBytes; - if (dType == DerivationType.electrum) { + // if (dType == DerivationType.electrum) { + // seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); + // } else if (dType == DerivationType.bip39) { + // seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? ''); + // } + + if (typ == DerivationType.electrum) { seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); - } else if (dType == DerivationType.bip39) { + } else if (typ == DerivationType.bip39) { seedBytes = bip39.mnemonicToSeed(mnemonic, passphrase: passphrase ?? ''); } - for (DerivationInfo dInfo in electrum_derivations[dType]!) { - try { - DerivationInfo dInfoCopy = DerivationInfo( - derivationType: dInfo.derivationType, - derivationPath: dInfo.derivationPath, - description: dInfo.description, - scriptType: dInfo.scriptType, - ); + String addedPath = ""; + List<String> addedPaths = [ + "", + "/0", + "/1", + "/0/1", + "/1/0", + "/0/0", + "/1/1", + "/0/0/1", + "/1/1/0", + "/0'", + "/1'", + "/0'/0'", + "/1'/1'", + "/0'/0'/0'", + "/1'/1'/1'", + "/0'/0", + "/1'/1", + "/0'/0/0", + "/1'/1/1", + "/0'/0/1", + "/1'/1/0" + ]; + for (String addedPath in addedPaths) { + if (found) { + print("found!!!!!!!!!!!"); + break; + } + var dType = DerivationType.bip39; + for (DerivationInfo dInfo in electrum_derivations[dType]!) { + try { + DerivationInfo dInfoCopy = DerivationInfo( + derivationType: dInfo.derivationType, + derivationPath: dInfo.derivationPath, + description: dInfo.description, + scriptType: dInfo.scriptType, + ); - String balancePath = dInfoCopy.derivationPath!; - int derivationDepth = _countCharOccurrences(balancePath, '/'); + String balancePath = dInfoCopy.derivationPath!; + // int derivationDepth = _countCharOccurrences(balancePath, '/'); - // for BIP44 - if (derivationDepth == 3 || derivationDepth == 1) { + // for BIP44 + // if (derivationDepth == 3 || derivationDepth == 1) { // we add "/0" so that we generate account 0 - balancePath += "/0"; + // balancePath += "/0"; + // } + + balancePath += addedPath; + + final hd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(balancePath) + as Bip32Slip10Secp256k1; + final sideHd = hd.childKey(Bip32KeyIndex(1)); + + print("searching: $typ : add: $addedPath : $balancePath"); + + // derive address at index 0: + String? address; + switch (dInfoCopy.scriptType) { + case "p2wpkh": + address = generateP2WPKHAddress(hd: hd, network: network, index: 0); + break; + case "p2pkh": + address = generateP2PKHAddress(hd: hd, network: network, index: 0); + break; + case "p2wpkh-p2sh": + address = generateP2SHAddress(hd: hd, network: network, index: 0); + break; + case "p2tr": + address = generateP2TRAddress(hd: hd, network: network, index: 0); + break; + default: + continue; + } + + // check if it's the search address: + String searchAddress = "ltc1q8t38ltq733p3652sdxqufyet2s9dzdx79rutp7"; + String searchAddress2 = "ltc1q2qpl43h8sldxtd2l66a7jzmncfgy0n7cl3clt6"; + + String searchAddress3 = "ltc1quwvyhz3678u6fgqqtummepqp4l45dl2swm5ksz"; + String searchAddress4 = "ltc1qvhy3n52mektgnchl9qkdgmffs4yxkk3ejdvv5t"; + String searchAddress5 = "ltc1qtrnqxc6tf2jfnj35x5dvsk93y6g0ndsn98rcg4"; + String searchAddress6 = "ltc1q8t38ltq733p3652sdxqufyet2s9dzdx79rutp7"; + List<String> searchAddresses = [ + searchAddress, + searchAddress2, + searchAddress3, + searchAddress4, + searchAddress5, + searchAddress6 + ]; + + for (var i = 0; i < 100; i++) { + String indexAddress = generateP2WPKHAddress(hd: hd, network: network, index: i); + String indexAddress2 = generateP2WPKHAddress(hd: sideHd, network: network, index: i); + if (searchAddresses.contains(indexAddress) || searchAddresses.contains(indexAddress2)) { + printV( + "@@@@@@@@@@@@@@@@@@@@@ FOUND ADDRESS @ index: $i @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + found = true; + break; + } + // if (i == 1000) { + // printV("address: $indexAddress"); + // } + } + + if (found) { + break; + } + + // final sh = BitcoinAddressUtils.scriptHash(address, network: network); + // final history = await electrumClient.getHistory(sh); + + // final balance = await electrumClient.getBalance(sh); + // dInfoCopy.balance = balance.entries.firstOrNull?.value.toString() ?? "0"; + // dInfoCopy.address = address; + // dInfoCopy.transactionsCount = history.length; + + list.add(dInfoCopy); + } catch (e, s) { + printV("derivationInfoError: $e"); + printV("derivationInfoStack: $s"); } - - final hd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(balancePath) - as Bip32Slip10Secp256k1; - - // derive address at index 0: - String? address; - switch (dInfoCopy.scriptType) { - case "p2wpkh": - address = generateP2WPKHAddress(hd: hd, network: network, index: 0); - break; - case "p2pkh": - address = generateP2PKHAddress(hd: hd, network: network, index: 0); - break; - case "p2wpkh-p2sh": - address = generateP2SHAddress(hd: hd, network: network, index: 0); - break; - case "p2tr": - address = generateP2TRAddress(hd: hd, network: network, index: 0); - break; - default: - continue; - } - - final sh = BitcoinAddressUtils.scriptHash(address, network: network); - final history = await electrumClient.getHistory(sh); - - final balance = await electrumClient.getBalance(sh); - dInfoCopy.balance = balance.entries.firstOrNull?.value.toString() ?? "0"; - dInfoCopy.address = address; - dInfoCopy.transactionsCount = history.length; - - list.add(dInfoCopy); - } catch (e, s) { - printV("derivationInfoError: $e"); - printV("derivationInfoStack: $s"); } } } diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart index f1996bae8..5e49eb1b8 100644 --- a/lib/core/wallet_loading_service.dart +++ b/lib/core/wallet_loading_service.dart @@ -79,7 +79,7 @@ class WalletLoadingService { final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName); WalletBase? wallet; for (var walletInfo in walletInfoSource.values) { - try { + // try { final walletService = walletServiceFactory.call(walletInfo.type); final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name); wallet = await walletService.openWallet(walletInfo.name, walletPassword); @@ -95,18 +95,18 @@ class WalletLoadingService { // if found a wallet that is not corrupted, then still display the seeds of the corrupted ones authenticatedErrorStreamController.add(corruptedWalletsSeeds); - } catch (e) { - printV(e); - // save seeds and show corrupted wallets' seeds to the user - try { - final seeds = await _getCorruptedWalletSeeds(walletInfo.name, walletInfo.type); - if (!corruptedWalletsSeeds.contains(seeds)) { - corruptedWalletsSeeds += seeds; - } - } catch (e) { - corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; - } - } + // } catch (e) { + // printV(e); + // // save seeds and show corrupted wallets' seeds to the user + // try { + // final seeds = await _getCorruptedWalletSeeds(walletInfo.name, walletInfo.type); + // if (!corruptedWalletsSeeds.contains(seeds)) { + // corruptedWalletsSeeds += seeds; + // } + // } catch (e) { + // corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; + // } + // } } // if all user's wallets are corrupted throw exception diff --git a/lib/src/screens/restore/wallet_restore_page.dart b/lib/src/screens/restore/wallet_restore_page.dart index 6215e26c3..44695cb17 100644 --- a/lib/src/screens/restore/wallet_restore_page.dart +++ b/lib/src/screens/restore/wallet_restore_page.dart @@ -394,7 +394,7 @@ class WalletRestorePage extends BasePage { } } - if (derivationsWithHistory > 1) { + if (derivationsWithHistory > 1 || true) { dInfo = await Navigator.of(context).pushNamed( Routes.restoreWalletChooseDerivation, arguments: derivations, diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index b949c9968..08001b2b0 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -8,8 +9,10 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_core/root_dir.dart'; import 'package:cw_core/utils/print_verbose.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -78,29 +81,36 @@ class ExceptionHandler { await _addDeviceInfo(_file!); - // Check if a mail client is available - final bool canSend = await FlutterMailer.canSendMail(); + // await _addElectrumWalletData(_file!); - if (Platform.isIOS && !canSend) { - printV('Mail app is not available'); - return; + // // Check if a mail client is available + // final bool canSend = await FlutterMailer.canSendMail(); + + // if (Platform.isIOS && !canSend) { + // printV('Mail app is not available'); + // return; + // } + + // print the file content line by line: + for (var line in _file!.readAsLinesSync()) { + printV(line); } - final MailOptions mailOptions = MailOptions( - subject: 'Mobile App Issue', - recipients: ['support@cakewallet.com'], - attachments: [_file!.path], - ); + // final MailOptions mailOptions = MailOptions( + // subject: 'Mobile App Issue', + // recipients: ['support@cakewallet.com'], + // attachments: [_file!.path], + // ); - final result = await FlutterMailer.send(mailOptions); + // final result = await FlutterMailer.send(mailOptions); // Clear file content if the error was sent or saved. // On android we can't know if it was sent or saved - if (result.name == MailerResponse.sent.name || - result.name == MailerResponse.saved.name || - result.name == MailerResponse.android.name) { + // if (result.name == MailerResponse.sent.name || + // result.name == MailerResponse.saved.name || + // result.name == MailerResponse.android.name) { _file!.writeAsString("", mode: FileMode.write); - } + // } } catch (e, s) { _saveException(e.toString(), s); } @@ -113,8 +123,9 @@ class ExceptionHandler { static Future<void> onError(FlutterErrorDetails errorDetails) async { if (kDebugMode || kProfileMode) { - FlutterError.presentError(errorDetails); - printV(errorDetails.toString()); + // FlutterError.presentError(errorDetails); + // printV(errorDetails.toString()); + // _sendExceptionFile(); return; } @@ -255,6 +266,70 @@ class ExceptionHandler { ); } + static Future<void> _addElectrumWalletData(File file) async { + final walletLoadingService = getIt.get<WalletLoadingService>(); + final walletName = getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName); + final walletTypeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType)!; + final walletType = deserializeFromInt(walletTypeRaw); + if (walletName == null) return; + if (![WalletType.bitcoin, WalletType.litecoin].contains(walletType)) return; + + final loadedWallet = await walletLoadingService.load(walletType, walletName); + + final wallet = loadedWallet as ElectrumWallet; + + await wallet.updateAllUnspents(); + + final receiveAddresses = + wallet.walletAddresses.receiveAddresses.where((e) => !e.address.contains("mweb")).toList(); + final changeAddresses = + wallet.walletAddresses.changeAddresses.where((e) => !e.address.contains("mweb")).toList(); + final unspentCoins = wallet.unspentCoins.where((e) => !e.address.contains("mweb")).toList(); + final unspentCoinsInfo = + wallet.unspentCoinsInfo.values.where((e) => !e.address.contains("mweb")).toList(); + + String searchAddress = "ltc1q8t38ltq733p3652sdxqufyet2s9dzdx79rutp7"; + + await file.writeAsString("Search address: $searchAddress\n", mode: FileMode.append); + + await file.writeAsString("\n\nReceive Addresses:\n", mode: FileMode.append); + for (var address in receiveAddresses) { + if (address.address == searchAddress) { + printV("@@@@@@@@@@@@@@@@@@@@@ FOUND ADDRESS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + } + String addressStr = + "address: ${address.address} isHidden: ${address.isHidden ? "1" : "0"} isUsed: ${address.isUsed ? "1" : "0"}"; + await file.writeAsString("$addressStr\n", mode: FileMode.append); + } + await file.writeAsString("\n\nChange Addresses:\n", mode: FileMode.append); + for (var address in changeAddresses) { + if (address.address == searchAddress) { + printV("@@@@@@@@@@@@@@@@@@@@@ FOUND ADDRESS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + } + String addressStr = + "address: ${address.address} isHidden: ${address.isHidden ? "1" : "0"} isUsed: ${address.isUsed ? "1" : "0"}"; + await file.writeAsString("$addressStr\n", mode: FileMode.append); + } + await file.writeAsString("\n\nUnspent Coins:\n", mode: FileMode.append); + for (var coin in unspentCoins) { + if (coin.address == searchAddress) { + printV("@@@@@@@@@@@@@@@@@@@@@ FOUND ADDRESS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + } + String coinStr = + "address: ${coin.address} isChange: ${coin.isChange ? "1" : "0"} vout: ${coin.vout} value: ${coin.value}"; + await file.writeAsString("$coinStr\n", mode: FileMode.append); + } + await file.writeAsString("\n\nUnspent Coins Info:\n", mode: FileMode.append); + for (var info in unspentCoinsInfo) { + if (info.address == searchAddress) { + printV("@@@@@@@@@@@@@@@@@@@@@ FOUND ADDRESS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + } + String infoStr = + "address: ${info.address} isChange: ${info.isChange ? "1" : "0"} vout: ${info.vout} value: ${info.value}"; + await file.writeAsString("$infoStr\n", mode: FileMode.append); + } + } + static Map<String, dynamic> _readAndroidBuildData(AndroidDeviceInfo build) { return <String, dynamic>{ 'brand': build.brand, diff --git a/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart b/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart index 52820adcb..46dffd689 100644 --- a/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart +++ b/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart @@ -68,7 +68,6 @@ abstract class UnspentCoinsListViewModelBase with Store { bool get hasAdjustableFieldChanged => items.any(_hasAdjustableFieldChanged); - Future<void> saveUnspentCoinInfo(UnspentCoinsItem item) async { try { final existingInfo = _unspentCoinsInfo.values @@ -79,7 +78,6 @@ abstract class UnspentCoinsListViewModelBase with Store { existingInfo.isSending = item.isSending; existingInfo.note = item.note; - await existingInfo.save(); _updateUnspentCoinsInfo(); } catch (e) { @@ -162,7 +160,14 @@ abstract class UnspentCoinsListViewModelBase with Store { .whereType<UnspentCoinsItem>() .toList(); - unspents.sort((a, b) => b.value.compareTo(a.value)); + // sort by hash so that even if the addresses are the same, they don't jump around when selected (because that calls updateBalance) + unspents.sort((a, b) => a.hash.compareTo(b.hash)); + + // sort unspents by address so that if something changes it's easier to see: + unspents.sort((a, b) => a.address.compareTo(b.address)); + + // sort change addresses to the end: + unspents.sort((a, b) => a.isChange ? 1 : -1); items.addAll(unspents); } diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index c2cfcbd24..f930062e5 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -206,8 +206,8 @@ abstract class WalletCreationVMBase with Store { passphrase: restoreWallet.passphrase, ); - if (derivationList.firstOrNull?.transactionsCount == 0 && derivationList.length > 1) - return []; + // if (derivationList.firstOrNull?.transactionsCount == 0 && derivationList.length > 1) + // return []; return derivationList; case WalletType.nano: