Cw 853 mweb utxos are not displayed in coin control screen (#1873)

* fix displaying mweb utxos

* fallback for failed electrum UTXO updates

* remove throwing uncaught exception and un needed try/catch

---------

Co-authored-by: OmarHatem <omarh.ismail1@gmail.com>
This commit is contained in:
Serhii 2024-12-14 02:37:48 +02:00 committed by GitHub
parent 707395b71a
commit d55e635f61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 47 deletions

View file

@ -235,21 +235,21 @@ class ElectrumClient {
return []; return [];
}); });
Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) => Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) async {
call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]) final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]);
.then((dynamic result) {
if (result is List) {
return result.map((dynamic val) {
if (val is Map<String, dynamic>) {
return val;
}
return <String, dynamic>{}; if (result is List) {
}).toList(); return result.map((dynamic val) {
if (val is Map<String, dynamic>) {
return val;
} }
return []; return <String, dynamic>{};
}); }).toList();
}
return [];
}
Future<List<Map<String, dynamic>>> getMempool(String scriptHash) => Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>
call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash]) call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash])

View file

@ -1382,8 +1382,9 @@ abstract class ElectrumWalletBase
})); }));
unspentCoins = updatedUnspentCoins; unspentCoins = updatedUnspentCoins;
final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) => element.walletId == id); final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId == id);
if (currentWalletUnspentCoins.length != updatedUnspentCoins.length) { if (currentWalletUnspentCoins.length != updatedUnspentCoins.length) {
unspentCoins.forEach((coin) => addCoinInfo(coin)); unspentCoins.forEach((coin) => addCoinInfo(coin));
@ -1450,10 +1451,9 @@ abstract class ElectrumWalletBase
@action @action
Future<void> addCoinInfo(BitcoinUnspent coin) async { Future<void> addCoinInfo(BitcoinUnspent coin) async {
// Check if the coin is already in the unspentCoinsInfo for the wallet // Check if the coin is already in the unspentCoinsInfo for the wallet
final existingCoinInfo = unspentCoinsInfo.values.firstWhereOrNull( final existingCoinInfo = unspentCoinsInfo.values
(element) => element.walletId == walletInfo.id && element == coin); .firstWhereOrNull((element) => element.walletId == walletInfo.id && element == coin);
if (existingCoinInfo == null) { if (existingCoinInfo == null) {
final newInfo = UnspentCoinsInfo( final newInfo = UnspentCoinsInfo(
@ -1475,19 +1475,18 @@ abstract class ElectrumWalletBase
Future<void> _refreshUnspentCoinsInfo() async { Future<void> _refreshUnspentCoinsInfo() async {
try { try {
final List<dynamic> keys = <dynamic>[]; final List<dynamic> keys = [];
final currentWalletUnspentCoins = final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId.contains(id)); unspentCoinsInfo.values.where((record) => record.walletId == id);
if (currentWalletUnspentCoins.isNotEmpty) { for (final element in currentWalletUnspentCoins) {
currentWalletUnspentCoins.forEach((element) { if (RegexUtils.addressTypeFromStr(element.address, network) is MwebAddress) continue;
final existUnspentCoins = unspentCoins
.where((coin) => element.hash.contains(coin.hash) && element.vout == coin.vout);
if (existUnspentCoins.isEmpty) { final existUnspentCoins = unspentCoins.where((coin) => element == coin);
keys.add(element.key);
} if (existUnspentCoins.isEmpty) {
}); keys.add(element.key);
}
} }
if (keys.isNotEmpty) { if (keys.isNotEmpty) {
@ -1499,7 +1498,8 @@ abstract class ElectrumWalletBase
} }
Future<void> cleanUpDuplicateUnspentCoins() async { Future<void> cleanUpDuplicateUnspentCoins() async {
final currentWalletUnspentCoins = unspentCoinsInfo.values.where((element) => element.walletId == id); final currentWalletUnspentCoins =
unspentCoinsInfo.values.where((element) => element.walletId == id);
final Map<String, UnspentCoinsInfo> uniqueUnspentCoins = {}; final Map<String, UnspentCoinsInfo> uniqueUnspentCoins = {};
final List<dynamic> duplicateKeys = []; final List<dynamic> duplicateKeys = [];
@ -1535,7 +1535,8 @@ abstract class ElectrumWalletBase
final ownAddresses = walletAddresses.allAddresses.map((addr) => addr.address).toSet(); final ownAddresses = walletAddresses.allAddresses.map((addr) => addr.address).toSet();
final receiverAmount = outputs final receiverAmount = outputs
.where((output) => !ownAddresses.contains(addressFromOutputScript(output.scriptPubKey, network))) .where((output) =>
!ownAddresses.contains(addressFromOutputScript(output.scriptPubKey, network)))
.fold<int>(0, (sum, output) => sum + output.amount.toInt()); .fold<int>(0, (sum, output) => sum + output.amount.toInt());
if (receiverAmount == 0) { if (receiverAmount == 0) {
@ -1584,7 +1585,7 @@ abstract class ElectrumWalletBase
allInputsAmount += outTransaction.amount.toInt(); allInputsAmount += outTransaction.amount.toInt();
final addressRecord = final addressRecord =
walletAddresses.allAddresses.firstWhere((element) => element.address == address); walletAddresses.allAddresses.firstWhere((element) => element.address == address);
final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network); final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network);
final privkey = generateECPrivate( final privkey = generateECPrivate(
hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
@ -1602,7 +1603,7 @@ abstract class ElectrumWalletBase
scriptType: _getScriptType(btcAddress), scriptType: _getScriptType(btcAddress),
), ),
ownerDetails: ownerDetails:
UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: btcAddress), UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: btcAddress),
), ),
); );
} }
@ -1630,7 +1631,7 @@ abstract class ElectrumWalletBase
// Calculate the total amount and fees // Calculate the total amount and fees
int totalOutAmount = int totalOutAmount =
outputs.fold<int>(0, (previousValue, output) => previousValue + output.value.toInt()); outputs.fold<int>(0, (previousValue, output) => previousValue + output.value.toInt());
int currentFee = allInputsAmount - totalOutAmount; int currentFee = allInputsAmount - totalOutAmount;
int remainingFee = newFee - currentFee; int remainingFee = newFee - currentFee;
@ -1686,7 +1687,7 @@ abstract class ElectrumWalletBase
vout: utxo.vout, vout: utxo.vout,
scriptType: _getScriptType(address)), scriptType: _getScriptType(address)),
ownerDetails: ownerDetails:
UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address), UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address),
)); ));
allInputsAmount += utxo.value; allInputsAmount += utxo.value;
@ -1743,11 +1744,11 @@ abstract class ElectrumWalletBase
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
final List<BitcoinOutput> changeOutputs = outputs final List<BitcoinOutput> changeOutputs = outputs
.where((output) => changeAddresses .where((output) => changeAddresses
.any((element) => element.address == output.address.toAddress(network))) .any((element) => element.address == output.address.toAddress(network)))
.toList(); .toList();
int totalChangeAmount = int totalChangeAmount =
changeOutputs.fold<int>(0, (sum, output) => sum + output.value.toInt()); changeOutputs.fold<int>(0, (sum, output) => sum + output.value.toInt());
// The final amount that the receiver will receive // The final amount that the receiver will receive
int sendingAmount = allInputsAmount - newFee - totalChangeAmount; int sendingAmount = allInputsAmount - newFee - totalChangeAmount;
@ -1764,7 +1765,7 @@ abstract class ElectrumWalletBase
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) { final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
final key = final key =
privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey); privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey);
if (key == null) { if (key == null) {
throw Exception("Cannot find private key"); throw Exception("Cannot find private key");
} }
@ -1774,7 +1775,6 @@ abstract class ElectrumWalletBase
} else { } else {
return key.signInput(txDigest, sigHash: sighash); return key.signInput(txDigest, sigHash: sighash);
} }
}); });
return PendingBitcoinTransaction( return PendingBitcoinTransaction(
@ -1787,16 +1787,16 @@ abstract class ElectrumWalletBase
hasChange: changeOutputs.isNotEmpty, hasChange: changeOutputs.isNotEmpty,
feeRate: newFee.toString(), feeRate: newFee.toString(),
)..addListener((transaction) async { )..addListener((transaction) async {
transactionHistory.transactions.values.forEach((tx) { transactionHistory.transactions.values.forEach((tx) {
if (tx.id == hash) { if (tx.id == hash) {
tx.isReplaced = true; tx.isReplaced = true;
tx.isPending = false; tx.isPending = false;
transactionHistory.addOne(tx); transactionHistory.addOne(tx);
} }
});
transactionHistory.addOne(transaction);
await updateBalance();
}); });
transactionHistory.addOne(transaction);
await updateBalance();
});
} catch (e) { } catch (e) {
throw e; throw e;
} }

View file

@ -154,7 +154,7 @@ class UnspentCoinsListFormState extends State<UnspentCoinsListForm> {
SizedBox(height: 15), SizedBox(height: 15),
Expanded( Expanded(
child: unspentCoinsListViewModel.items.isEmpty child: unspentCoinsListViewModel.items.isEmpty
? Center(child: Text('No unspent coins available\ntry to reconnect',textAlign: TextAlign.center)) ? Center(child: Text('No unspent coins available',textAlign: TextAlign.center))
: ListView.separated( : ListView.separated(
itemCount: unspentCoinsListViewModel.items.length, itemCount: unspentCoinsListViewModel.items.length,
separatorBuilder: (_, __) => SizedBox(height: 15), separatorBuilder: (_, __) => SizedBox(height: 15),