From 527983af4f9c328a844de77fe16efc2d18e7723d Mon Sep 17 00:00:00 2001 From: Matthew Fosse Date: Fri, 23 Aug 2024 15:17:28 -0400 Subject: [PATCH] updates --- cw_bitcoin/lib/electrum_wallet.dart | 102 +++++++---------- cw_bitcoin/lib/litecoin_wallet.dart | 104 +++++++++--------- .../unspent_coins_list_view_model.dart | 19 +++- 3 files changed, 110 insertions(+), 115 deletions(-) diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 4e447814a..3da039afe 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -424,9 +424,7 @@ abstract class ElectrumWalletBase @override Future startSync() async { try { - if (this is! LitecoinWallet) { - syncStatus = SyncronizingSyncStatus(); - } + syncStatus = SyncronizingSyncStatus(); if (hasSilentPaymentsScanning) { await _setInitialHeight(); @@ -1262,69 +1260,51 @@ abstract class ElectrumWalletBase updatedUnspentCoins.addAll(await fetchUnspent(address)); })); - unspentCoins = updatedUnspentCoins; - } - - Future updateUnspent() async { - await updateAllUnspents(); - - if (unspentCoinsInfo.length != unspentCoins.length) { - unspentCoins.forEach((coin) => addCoinInfo(coin)); - return; - } - - if (unspentCoins.isNotEmpty) { - unspentCoins.forEach((coin) { - final coinInfoList = unspentCoinsInfo.values.where((element) => - element.walletId.contains(id) && - element.hash.contains(coin.hash) && - element.vout == coin.vout); - - if (coinInfoList.isNotEmpty) { - final coinInfo = coinInfoList.first; - - coin.isFrozen = coinInfo.isFrozen; - coin.isSending = coinInfo.isSending; - coin.note = coinInfo.note; - if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord) - coin.bitcoinAddressRecord.balance += coinInfo.value; - } else { - addCoinInfo(coin); - } - }); + if (unspentCoinsInfo.length != updatedUnspentCoins.length) { + updatedUnspentCoins.forEach((coin) => addCoinInfo(coin)); } + await updateCoins(updatedUnspentCoins, set: true); await _refreshUnspentCoinsInfo(); } - @action - Future updateUnspents(BitcoinAddressRecord address) async { - final newUnspentCoins = await fetchUnspent(address); - - if (newUnspentCoins.isNotEmpty) { - unspentCoins.addAll(newUnspentCoins); - - newUnspentCoins.forEach((coin) { - final coinInfoList = unspentCoinsInfo.values.where( - (element) => - element.walletId.contains(id) && - element.hash.contains(coin.hash) && - element.vout == coin.vout, - ); - - if (coinInfoList.isNotEmpty) { - final coinInfo = coinInfoList.first; - - coin.isFrozen = coinInfo.isFrozen; - coin.isSending = coinInfo.isSending; - coin.note = coinInfo.note; - if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord) - coin.bitcoinAddressRecord.balance += coinInfo.value; - } else { - addCoinInfo(coin); - } - }); + Future updateCoins(List newUnspentCoins, {bool set = false}) async { + if (newUnspentCoins.isEmpty) { + return; } + + if (set) { + unspentCoins = newUnspentCoins; + } else { + unspentCoins.addAll(newUnspentCoins); + } + + newUnspentCoins.forEach((coin) { + final coinInfoList = unspentCoinsInfo.values.where( + (element) => + element.walletId.contains(id) && + element.hash.contains(coin.hash) && + element.vout == coin.vout, + ); + + if (coinInfoList.isNotEmpty) { + final coinInfo = coinInfoList.first; + + coin.isFrozen = coinInfo.isFrozen; + coin.isSending = coinInfo.isSending; + coin.note = coinInfo.note; + if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord) + coin.bitcoinAddressRecord.balance += coinInfo.value; + } else { + addCoinInfo(coin); + } + }); + } + + @action + Future updateUnspentsForAddress(BitcoinAddressRecord address) async { + final newUnspentCoins = await fetchUnspent(address); + await updateCoins(newUnspentCoins); } @action @@ -1819,7 +1799,7 @@ abstract class ElectrumWalletBase _scripthashesUpdateSubject[sh] = await electrumClient.scripthashUpdate(sh); _scripthashesUpdateSubject[sh]?.listen((event) async { try { - await updateUnspents(address); + await updateUnspentsForAddress(address); await updateBalance(); diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index bb1023164..c5e6a6df3 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -202,14 +202,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { @override Future startSync() async { print("STARTING SYNC"); - if (!mwebEnabled) { - syncStatus = SyncronizingSyncStatus(); - await subscribeForUpdates(); - await updateTransactions(); - syncStatus = SyncedSyncStatus(); - return; - } - + syncStatus = SyncronizingSyncStatus(); await subscribeForUpdates(); await updateTransactions(); await updateFeeRates(); @@ -218,6 +211,16 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { _feeRatesTimer = Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates()); + if (!mwebEnabled) { + await super.updateAllUnspents(); + await updateBalance(); + syncStatus = SyncedSyncStatus(); + return; + } + + await updateUnspent(); + await updateBalance(); + _stub = await CwMweb.stub(); _syncTimer?.cancel(); _syncTimer = Timer.periodic(const Duration(milliseconds: 1500), (timer) async { @@ -255,8 +258,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } } }); - updateUnspent(); - fetchBalances(); // this runs in the background and processes new utxos as they come in: processMwebUtxos(); } @@ -538,62 +539,60 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return true; } - @override Future updateUnspent() async { - await super.updateUnspent(); await checkMwebUtxosSpent(); + await updateAllUnspents(); } @override @action Future updateAllUnspents() async { - List updatedUnspentCoins = []; + // get ltc unspents: + await super.updateAllUnspents(); - await Future.wait(walletAddresses.allAddresses.map((address) async { - updatedUnspentCoins.addAll(await fetchUnspent(address)); - })); - - if (mwebEnabled) { - // update mweb unspents: - final mwebAddrs = (walletAddresses as LitecoinWalletAddresses).mwebAddrs; - mwebUtxosBox.keys.forEach((dynamic oId) { - final String outputId = oId as String; - final utxo = mwebUtxosBox.get(outputId); - if (utxo == null) { - return; - } - if (utxo.address.isEmpty) { - // not sure if a bug or a special case but we definitely ignore these - return; - } - final addressRecord = walletAddresses.allAddresses - .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); - - if (addressRecord == null) { - print("utxo contains an address that is not in the wallet: ${utxo.address}"); - return; - } - final unspent = BitcoinUnspent( - addressRecord, - outputId, - utxo.value.toInt(), - mwebAddrs.indexOf(utxo.address), - ); - if (unspent.vout == 0) { - unspent.isChange = true; - } - updatedUnspentCoins.add(unspent); - }); + if (!mwebEnabled) { + return; } + // add the mweb unspents to the list: + List mwebUnspentCoins = []; + // update mweb unspents: + final mwebAddrs = (walletAddresses as LitecoinWalletAddresses).mwebAddrs; + mwebUtxosBox.keys.forEach((dynamic oId) { + final String outputId = oId as String; + final utxo = mwebUtxosBox.get(outputId); + if (utxo == null) { + return; + } + if (utxo.address.isEmpty) { + // not sure if a bug or a special case but we definitely ignore these + return; + } + final addressRecord = walletAddresses.allAddresses + .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); - unspentCoins = updatedUnspentCoins; + if (addressRecord == null) { + print("utxo contains an address that is not in the wallet: ${utxo.address}"); + return; + } + final unspent = BitcoinUnspent( + addressRecord, + outputId, + utxo.value.toInt(), + mwebAddrs.indexOf(utxo.address), + ); + if (unspent.vout == 0) { + unspent.isChange = true; + } + mwebUnspentCoins.add(unspent); + }); + unspentCoins.addAll(mwebUnspentCoins); } @override Future fetchBalances() async { final balance = await super.fetchBalances(); - var confirmed = balance.confirmed; - var unconfirmed = balance.unconfirmed; + int confirmed = balance.confirmed; + int unconfirmed = balance.unconfirmed; mwebUtxosBox.values.forEach((utxo) { if (utxo.height > 0) { confirmed += utxo.value.toInt(); @@ -640,6 +639,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { // to have an accurate count, we should just keep it in sync with what we know from the tx history: for (final tx in transactionHistory.transactions.values) { // if (tx.isPending) continue; + if (tx.inputAddresses == null || tx.outputAddresses == null) { + continue; + } final txAddresses = tx.inputAddresses! + tx.outputAddresses!; for (final address in txAddresses) { final addressRecord = walletAddresses.allAddresses 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 5b6e6140f..72dcdb27b 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 @@ -38,6 +38,10 @@ abstract class UnspentCoinsListViewModelBase with Store { final info = getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout, item.keyImage); + if (info == null) { + return; + } + info.isFrozen = item.isFrozen; info.isSending = item.isSending; info.note = item.note; @@ -50,15 +54,21 @@ abstract class UnspentCoinsListViewModelBase with Store { } } - UnspentCoinsInfo getUnspentCoinInfo( - String hash, String address, int value, int vout, String? keyImage) => - _unspentCoinsInfo.values.firstWhere((element) => + UnspentCoinsInfo? getUnspentCoinInfo( + String hash, String address, int value, int vout, String? keyImage) { + try { + return _unspentCoinsInfo.values.firstWhere((element) => element.walletId == wallet.id && element.hash == hash && element.address == address && element.value == value && element.vout == vout && element.keyImage == keyImage); + } catch (e) { + print("UnspentCoinsInfo not found for coin: $e"); + return null; + } + } String formatAmountToString(int fullBalance) { if (wallet.type == WalletType.monero) @@ -108,6 +118,9 @@ abstract class UnspentCoinsListViewModelBase with Store { try { final info = getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage); + if (info == null) { + return; + } unspents.add(UnspentCoinsItem( address: elem.address,