Skip to content

Commit 4a4250a

Browse files
author
Rafael Saes
committed
feat: tx history worker
1 parent 02fabf8 commit 4a4250a

13 files changed

+922
-699
lines changed

cw_bitcoin/lib/bitcoin_address_record.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ abstract class BaseBitcoinAddressRecord {
2424
bool operator ==(Object o) => o is BaseBitcoinAddressRecord && address == o.address;
2525

2626
final String address;
27-
final bool _isHidden;
27+
bool _isHidden;
2828
bool get isHidden => _isHidden;
2929
final bool _isChange;
3030
bool get isChange => _isChange;
@@ -46,7 +46,12 @@ abstract class BaseBitcoinAddressRecord {
4646

4747
bool get isUsed => _isUsed;
4848

49-
void setAsUsed() => _isUsed = true;
49+
void setAsUsed() {
50+
_isUsed = true;
51+
// TODO: check is hidden flow on addr list
52+
_isHidden = true;
53+
}
54+
5055
void setNewName(String label) => _name = label;
5156

5257
int get hashCode => address.hashCode;
@@ -119,6 +124,26 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
119124
'type': type.toString(),
120125
'scriptHash': scriptHash,
121126
});
127+
128+
@override
129+
operator ==(Object other) {
130+
if (identical(this, other)) return true;
131+
132+
return other is BitcoinAddressRecord &&
133+
other.address == address &&
134+
other.index == index &&
135+
other.derivationInfo == derivationInfo &&
136+
other.scriptHash == scriptHash &&
137+
other.type == type;
138+
}
139+
140+
@override
141+
int get hashCode =>
142+
address.hashCode ^
143+
index.hashCode ^
144+
derivationInfo.hashCode ^
145+
scriptHash.hashCode ^
146+
type.hashCode;
122147
}
123148

124149
class BitcoinSilentPaymentAddressRecord extends BaseBitcoinAddressRecord {

cw_bitcoin/lib/bitcoin_wallet.dart

Lines changed: 116 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import 'package:cw_bitcoin/psbt_transaction_builder.dart';
1111
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
1212
import 'package:cw_bitcoin/bitcoin_unspent.dart';
1313
import 'package:cw_bitcoin/electrum_transaction_info.dart';
14-
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
14+
// import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
1515
import 'package:cw_core/encryption_file_utils.dart';
1616
import 'package:cw_bitcoin/electrum_derivations.dart';
1717
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
@@ -240,6 +240,36 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
240240
);
241241
}
242242

243+
Future<bool> getNodeSupportsSilentPayments() async {
244+
return true;
245+
// As of today (august 2024), only ElectrumRS supports silent payments
246+
// if (!(await getNodeIsElectrs())) {
247+
// return false;
248+
// }
249+
250+
// if (node == null) {
251+
// return false;
252+
// }
253+
254+
// try {
255+
// final tweaksResponse = await electrumClient.getTweaks(height: 0);
256+
257+
// if (tweaksResponse != null) {
258+
// node!.supportsSilentPayments = true;
259+
// node!.save();
260+
// return node!.supportsSilentPayments!;
261+
// }
262+
// } on RequestFailedTimeoutException catch (_) {
263+
// node!.supportsSilentPayments = false;
264+
// node!.save();
265+
// return node!.supportsSilentPayments!;
266+
// } catch (_) {}
267+
268+
// node!.supportsSilentPayments = false;
269+
// node!.save();
270+
// return node!.supportsSilentPayments!;
271+
}
272+
243273
LedgerConnection? _ledgerConnection;
244274
BitcoinLedgerApp? _bitcoinLedgerApp;
245275

@@ -327,11 +357,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
327357

328358
_isolate?.then((value) => value.kill(priority: Isolate.immediate));
329359

330-
if (rpc!.isConnected) {
331-
syncStatus = SyncedSyncStatus();
332-
} else {
333-
syncStatus = NotConnectedSyncStatus();
334-
}
360+
// if (rpc!.isConnected) {
361+
// syncStatus = SyncedSyncStatus();
362+
// } else {
363+
// syncStatus = NotConnectedSyncStatus();
364+
// }
335365
}
336366
}
337367

@@ -367,7 +397,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
367397
return;
368398
}
369399

370-
await updateCoins(unspentCoins);
400+
await updateCoins(unspentCoins.toSet());
371401
await refreshUnspentCoinsInfo();
372402
}
373403

@@ -449,6 +479,20 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
449479
// }
450480
// }
451481

482+
@action
483+
Future<void> registerSilentPaymentsKey() async {
484+
final registered = await electrumClient.tweaksRegister(
485+
secViewKey: walletAddresses.silentAddress!.b_scan.toHex(),
486+
pubSpendKey: walletAddresses.silentAddress!.B_spend.toHex(),
487+
labels: walletAddresses.silentAddresses
488+
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.labelIndex >= 1)
489+
.map((addr) => addr.labelIndex)
490+
.toList(),
491+
);
492+
493+
print("registered: $registered");
494+
}
495+
452496
@action
453497
void _updateSilentAddressRecord(BitcoinUnspent unspent) {
454498
final receiveAddressRecord = unspent.bitcoinAddressRecord as BitcoinReceivedSPAddressRecord;
@@ -593,41 +637,42 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
593637
@override
594638
@action
595639
Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
596-
try {
597-
final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
598-
599-
await Future.wait(
600-
BITCOIN_ADDRESS_TYPES.map(
601-
(type) => fetchTransactionsForAddressType(historiesWithDetails, type),
602-
),
603-
);
604-
605-
transactionHistory.transactions.values.forEach((tx) async {
606-
final isPendingSilentPaymentUtxo =
607-
(tx.isPending || tx.confirmations == 0) && historiesWithDetails[tx.id] == null;
608-
609-
if (isPendingSilentPaymentUtxo) {
610-
final info = await fetchTransactionInfo(hash: tx.id, height: tx.height);
611-
612-
if (info != null) {
613-
tx.confirmations = info.confirmations;
614-
tx.isPending = tx.confirmations == 0;
615-
transactionHistory.addOne(tx);
616-
await transactionHistory.save();
617-
}
618-
}
619-
});
620-
621-
return historiesWithDetails;
622-
} catch (e) {
623-
print("fetchTransactions $e");
624-
return {};
625-
}
640+
throw UnimplementedError();
641+
// try {
642+
// final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
643+
644+
// await Future.wait(
645+
// BITCOIN_ADDRESS_TYPES.map(
646+
// (type) => fetchTransactionsForAddressType(historiesWithDetails, type),
647+
// ),
648+
// );
649+
650+
// transactionHistory.transactions.values.forEach((tx) async {
651+
// final isPendingSilentPaymentUtxo =
652+
// (tx.isPending || tx.confirmations == 0) && historiesWithDetails[tx.id] == null;
653+
654+
// if (isPendingSilentPaymentUtxo) {
655+
// final info = await fetchTransactionInfo(hash: tx.id, height: tx.height);
656+
657+
// if (info != null) {
658+
// tx.confirmations = info.confirmations;
659+
// tx.isPending = tx.confirmations == 0;
660+
// transactionHistory.addOne(tx);
661+
// await transactionHistory.save();
662+
// }
663+
// }
664+
// });
665+
666+
// return historiesWithDetails;
667+
// } catch (e) {
668+
// print("fetchTransactions $e");
669+
// return {};
670+
// }
626671
}
627672

628673
@override
629674
@action
630-
Future<void> updateTransactions() async {
675+
Future<void> updateTransactions([List<BitcoinAddressRecord>? addresses]) async {
631676
super.updateTransactions();
632677

633678
transactionHistory.transactions.values.forEach((tx) {
@@ -641,32 +686,32 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
641686
});
642687
}
643688

644-
@action
645-
Future<ElectrumBalance> fetchBalances() async {
646-
final balance = await super.fetchBalances();
647-
648-
int totalFrozen = balance.frozen;
649-
int totalConfirmed = balance.confirmed;
650-
651-
// Add values from unspent coins that are not fetched by the address list
652-
// i.e. scanned silent payments
653-
transactionHistory.transactions.values.forEach((tx) {
654-
if (tx.unspents != null) {
655-
tx.unspents!.forEach((unspent) {
656-
if (unspent.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
657-
if (unspent.isFrozen) totalFrozen += unspent.value;
658-
totalConfirmed += unspent.value;
659-
}
660-
});
661-
}
662-
});
689+
// @action
690+
// Future<ElectrumBalance> fetchBalances() async {
691+
// final balance = await super.fetchBalances();
692+
693+
// int totalFrozen = balance.frozen;
694+
// int totalConfirmed = balance.confirmed;
695+
696+
// // Add values from unspent coins that are not fetched by the address list
697+
// // i.e. scanned silent payments
698+
// transactionHistory.transactions.values.forEach((tx) {
699+
// if (tx.unspents != null) {
700+
// tx.unspents!.forEach((unspent) {
701+
// if (unspent.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
702+
// if (unspent.isFrozen) totalFrozen += unspent.value;
703+
// totalConfirmed += unspent.value;
704+
// }
705+
// });
706+
// }
707+
// });
663708

664-
return ElectrumBalance(
665-
confirmed: totalConfirmed,
666-
unconfirmed: balance.unconfirmed,
667-
frozen: totalFrozen,
668-
);
669-
}
709+
// return ElectrumBalance(
710+
// confirmed: totalConfirmed,
711+
// unconfirmed: balance.unconfirmed,
712+
// frozen: totalFrozen,
713+
// );
714+
// }
670715

671716
@override
672717
@action
@@ -713,15 +758,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
713758
}
714759
}
715760

716-
@override
717-
@action
718-
void onHeadersResponse(ElectrumHeaderResponse response) {
719-
super.onHeadersResponse(response);
761+
// @override
762+
// @action
763+
// void onHeadersResponse(ElectrumHeaderResponse response) {
764+
// super.onHeadersResponse(response);
720765

721-
if (alwaysScan == true && syncStatus is SyncedSyncStatus) {
722-
_setListeners(walletInfo.restoreHeight);
723-
}
724-
}
766+
// if (alwaysScan == true && syncStatus is SyncedSyncStatus) {
767+
// _setListeners(walletInfo.restoreHeight);
768+
// }
769+
// }
725770

726771
@override
727772
@action

cw_bitcoin/lib/bitcoin_wallet_service.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'dart:io';
22
import 'package:bitcoin_base/bitcoin_base.dart';
33
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
44
import 'package:cw_bitcoin/bitcoin_mnemonics_bip39.dart';
5-
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
65
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
76
import 'package:cw_core/encryption_file_utils.dart';
87
import 'package:cw_core/unspent_coins_info.dart';
@@ -14,7 +13,6 @@ import 'package:cw_core/wallet_info.dart';
1413
import 'package:cw_core/wallet_type.dart';
1514
import 'package:hive/hive.dart';
1615
import 'package:collection/collection.dart';
17-
import 'package:bip39/bip39.dart' as bip39;
1816

1917
class BitcoinWalletService extends WalletService<
2018
BitcoinNewWalletCredentials,
@@ -172,10 +170,6 @@ class BitcoinWalletService extends WalletService<
172170
@override
173171
Future<BitcoinWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
174172
{bool? isTestnet}) async {
175-
if (!validateMnemonic(credentials.mnemonic) && !bip39.validateMnemonic(credentials.mnemonic)) {
176-
throw BitcoinMnemonicIsIncorrectException();
177-
}
178-
179173
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
180174
credentials.walletInfo?.network = network.value;
181175

0 commit comments

Comments
 (0)