apply some changes from SP Fix pr

This commit is contained in:
OmarHatem 2025-06-26 09:39:20 +03:00
parent d2f0a97764
commit 46c1d6fd8d
6 changed files with 286 additions and 47 deletions

View file

@ -4,9 +4,7 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/litecoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart';
@ -19,7 +17,7 @@ import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart';
import 'package:cw_bitcoin/bitcoin_wallet_keys.dart'; import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
import 'package:cw_bitcoin/electrum.dart'; import 'package:cw_bitcoin/electrum.dart' as electrum;
import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/electrum_derivations.dart'; import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum_transaction_history.dart'; import 'package:cw_bitcoin/electrum_transaction_history.dart';
@ -50,6 +48,7 @@ import 'package:mobx/mobx.dart';
import 'package:rxdart/subjects.dart'; import 'package:rxdart/subjects.dart';
import 'package:sp_scanner/sp_scanner.dart'; import 'package:sp_scanner/sp_scanner.dart';
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
import 'package:http/http.dart' as http;
part 'electrum_wallet.g.dart'; part 'electrum_wallet.g.dart';
@ -69,7 +68,7 @@ abstract class ElectrumWalletBase
Uint8List? seedBytes, Uint8List? seedBytes,
this.passphrase, this.passphrase,
List<BitcoinAddressRecord>? initialAddresses, List<BitcoinAddressRecord>? initialAddresses,
ElectrumClient? electrumClient, electrum.ElectrumClient? electrumClient,
ElectrumBalance? initialBalance, ElectrumBalance? initialBalance,
CryptoCurrency? currency, CryptoCurrency? currency,
this.alwaysScan, this.alwaysScan,
@ -96,7 +95,7 @@ abstract class ElectrumWalletBase
this.isTestnet = !network.isMainnet, this.isTestnet = !network.isMainnet,
this._mnemonic = mnemonic, this._mnemonic = mnemonic,
super(walletInfo) { super(walletInfo) {
this.electrumClient = electrumClient ?? ElectrumClient(); this.electrumClient = electrumClient ?? electrum.ElectrumClient();
this.walletInfo = walletInfo; this.walletInfo = walletInfo;
transactionHistory = ElectrumTransactionHistory( transactionHistory = ElectrumTransactionHistory(
walletInfo: walletInfo, walletInfo: walletInfo,
@ -167,7 +166,7 @@ abstract class ElectrumWalletBase
@observable @observable
bool isEnabledAutoGenerateSubaddress; bool isEnabledAutoGenerateSubaddress;
late ElectrumClient electrumClient; late electrum.ElectrumClient electrumClient;
Box<UnspentCoinsInfo> unspentCoinsInfo; Box<UnspentCoinsInfo> unspentCoinsInfo;
@override @override
@ -333,14 +332,14 @@ abstract class ElectrumWalletBase
final receivePort = ReceivePort(); final receivePort = ReceivePort();
_isolate = Isolate.spawn( _isolate = Isolate.spawn(
startRefresh, _handleScanSilentPayments,
ScanData( ScanData(
sendPort: receivePort.sendPort, sendPort: receivePort.sendPort,
silentAddress: walletAddresses.silentAddress!, silentAddress: walletAddresses.silentAddress!,
network: network, network: network,
height: height, height: height,
chainTip: chainTip, chainTip: chainTip,
electrumClient: ElectrumClient(), electrumClient: electrum.ElectrumClient(),
transactionHistoryIds: transactionHistory.transactions.keys.toList(), transactionHistoryIds: transactionHistory.transactions.keys.toList(),
node: (await getNodeSupportsSilentPayments()) == true node: (await getNodeSupportsSilentPayments()) == true
? ScanNode(node!.uri, node!.useSSL) ? ScanNode(node!.uri, node!.useSSL)
@ -492,9 +491,10 @@ abstract class ElectrumWalletBase
Future<void> updateFeeRates() async { Future<void> updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) { if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
try { try {
final response = await ProxyWrapper() final response = await http
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended")) .get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
.timeout(Duration(seconds: 15)); .timeout(Duration(seconds: 5));
final result = json.decode(response.body) as Map<String, dynamic>; final result = json.decode(response.body) as Map<String, dynamic>;
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0; final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0; int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
@ -562,7 +562,7 @@ abstract class ElectrumWalletBase
node!.save(); node!.save();
return node!.supportsSilentPayments!; return node!.supportsSilentPayments!;
} }
} on RequestFailedTimeoutException catch (_) { } on electrum.RequestFailedTimeoutException catch (_) {
node!.supportsSilentPayments = false; node!.supportsSilentPayments = false;
node!.save(); node!.save();
return node!.supportsSilentPayments!; return node!.supportsSilentPayments!;
@ -1876,17 +1876,20 @@ abstract class ElectrumWalletBase
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) { if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
try { try {
final blockHash = await ProxyWrapper() final blockHash = await http.get(
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height")) Uri.parse(
.timeout(Duration(seconds: 15)); "https://mempool.cakewallet.com/api/v1/block-height/$height",
),
);
if (blockHash.statusCode == 200 && if (blockHash.statusCode == 200 &&
blockHash.body.isNotEmpty && blockHash.body.isNotEmpty &&
jsonDecode(blockHash.body) != null) { jsonDecode(blockHash.body) != null) {
final blockResponse = await ProxyWrapper() final blockResponse = await http.get(
.get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}")) Uri.parse(
.timeout(Duration(seconds: 15)); "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}",
),
);
if (blockResponse.statusCode == 200 && if (blockResponse.statusCode == 200 &&
blockResponse.body.isNotEmpty && blockResponse.body.isNotEmpty &&
jsonDecode(blockResponse.body)['timestamp'] != null) { jsonDecode(blockResponse.body)['timestamp'] != null) {
@ -2389,9 +2392,9 @@ abstract class ElectrumWalletBase
derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1); derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
@action @action
void _onConnectionStatusChange(ConnectionStatus status) { void _onConnectionStatusChange(electrum.ConnectionStatus status) {
switch (status) { switch (status) {
case ConnectionStatus.connected: case electrum.ConnectionStatus.connected:
if (syncStatus is NotConnectedSyncStatus || if (syncStatus is NotConnectedSyncStatus ||
syncStatus is LostConnectionSyncStatus || syncStatus is LostConnectionSyncStatus ||
syncStatus is ConnectingSyncStatus) { syncStatus is ConnectingSyncStatus) {
@ -2399,19 +2402,19 @@ abstract class ElectrumWalletBase
} }
break; break;
case ConnectionStatus.disconnected: case electrum.ConnectionStatus.disconnected:
if (syncStatus is! NotConnectedSyncStatus && if (syncStatus is! NotConnectedSyncStatus &&
syncStatus is! ConnectingSyncStatus && syncStatus is! ConnectingSyncStatus &&
syncStatus is! SyncronizingSyncStatus) { syncStatus is! SyncronizingSyncStatus) {
syncStatus = NotConnectedSyncStatus(); syncStatus = NotConnectedSyncStatus();
} }
break; break;
case ConnectionStatus.failed: case electrum.ConnectionStatus.failed:
if (syncStatus is! LostConnectionSyncStatus) { if (syncStatus is! LostConnectionSyncStatus) {
syncStatus = LostConnectionSyncStatus(); syncStatus = LostConnectionSyncStatus();
} }
break; break;
case ConnectionStatus.connecting: case electrum.ConnectionStatus.connecting:
if (syncStatus is! ConnectingSyncStatus) { if (syncStatus is! ConnectingSyncStatus) {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
} }
@ -2523,7 +2526,7 @@ class ScanData {
final ScanNode? node; final ScanNode? node;
final BasedUtxoNetwork network; final BasedUtxoNetwork network;
final int chainTip; final int chainTip;
final ElectrumClient electrumClient; final electrum.ElectrumClient electrumClient;
final List<String> transactionHistoryIds; final List<String> transactionHistoryIds;
final Map<String, String> labels; final Map<String, String> labels;
final List<int> labelIndexes; final List<int> labelIndexes;
@ -2567,6 +2570,235 @@ class SyncResponse {
SyncResponse(this.height, this.syncStatus); SyncResponse(this.height, this.syncStatus);
} }
Future<void> _handleScanSilentPayments(ScanData scanData) async {
try {
// if (scanData.shouldSwitchNodes) {
var scanningClient = await ElectrumProvider.connect(
ElectrumTCPService.connect(
Uri.parse("tcp://electrs.cakewallet.com:50001"),
),
);
// }
int syncHeight = scanData.height;
int initialSyncHeight = syncHeight;
final receiver = Receiver(
scanData.silentAddress.b_scan.toHex(),
scanData.silentAddress.B_spend.toHex(),
scanData.network == BitcoinNetwork.testnet,
scanData.labelIndexes,
scanData.labelIndexes.length,
);
int getCountToScanPerRequest(int syncHeight) {
if (scanData.isSingleScan) {
return 1;
}
final amountLeft = scanData.chainTip - syncHeight + 1;
return amountLeft;
}
// Initial status UI update, send how many blocks in total to scan
scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
final req = ElectrumTweaksSubscribe(
height: syncHeight,
count: getCountToScanPerRequest(syncHeight),
historicalMode: false,
);
var _scanningStream = await scanningClient.subscribe(req);
void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) {
final response = req.onResponse(event);
if (response == null || _scanningStream == null) {
return;
}
// is success or error msg
final noData = response.message != null;
if (noData) {
if (scanData.isSingleScan) {
return;
}
// re-subscribe to continue receiving messages, starting from the next unscanned height
final nextHeight = syncHeight + 1;
if (nextHeight <= scanData.chainTip) {
final nextStream = scanningClient.subscribe(
ElectrumTweaksSubscribe(
height: nextHeight,
count: getCountToScanPerRequest(nextHeight),
historicalMode: false,
),
);
if (nextStream != null) {
nextStream.listen((event) => listenFn(event, req));
} else {
scanData.sendPort.send(
SyncResponse(scanData.height, LostConnectionSyncStatus()),
);
}
}
return;
}
final tweakHeight = response.block;
if (initialSyncHeight < tweakHeight) initialSyncHeight = tweakHeight;
// Continuous status UI update, send how many blocks left to scan
final syncingStatus = scanData.isSingleScan
? SyncingSyncStatus(1, 0)
: SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, tweakHeight);
scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
try {
final blockTweaks = response.blockTweaks;
for (final txid in blockTweaks.keys) {
final tweakData = blockTweaks[txid];
final outputPubkeys = tweakData!.outputPubkeys;
final tweak = tweakData.tweak;
try {
final addToWallet = {};
// receivers.forEach((receiver) {
// NOTE: scanOutputs, from sp_scanner package, called from rust here
final scanResult = scanOutputs([outputPubkeys.keys.toList()], tweak, receiver);
if (scanResult.isEmpty) {
continue;
}
if (addToWallet[receiver.BSpend] == null) {
addToWallet[receiver.BSpend] = scanResult;
} else {
addToWallet[receiver.BSpend].addAll(scanResult);
}
// });
if (addToWallet.isEmpty) {
// no results tx, continue to next tx
continue;
}
// initial placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s) on the following loop
final txInfo = ElectrumTransactionInfo(
WalletType.bitcoin,
id: txid,
height: tweakHeight,
amount: 0,
fee: 0,
direction: TransactionDirection.incoming,
isReplaced: false,
date: DateTime.fromMillisecondsSinceEpoch(
DateTime.now().millisecondsSinceEpoch * 1000,
),
confirmations: scanData.chainTip - tweakHeight + 1,
isReceivedSilentPayment: true,
isPending: false,
unspents: [],
);
List<BitcoinUnspent> unspents = [];
addToWallet.forEach((BSpend, scanResultPerLabel) {
scanResultPerLabel.forEach((label, scanOutput) {
final labelValue = label == "None" ? null : label.toString();
(scanOutput as Map<String, dynamic>).forEach((outputPubkey, tweak) {
final t_k = tweak as String;
final receivingOutputAddress = ECPublic.fromHex(outputPubkey)
.toTaprootAddress(tweak: false)
.toAddress(scanData.network);
final matchingOutput = outputPubkeys[outputPubkey]!;
final amount = matchingOutput.amount;
final pos = matchingOutput.vout;
// final matchingSPWallet = scanData.silentPaymentsWallets.firstWhere(
// (receiver) => receiver.B_spend.toHex() == BSpend.toString(),
// );
// final labelIndex = labelValue != null ? scanData.labels[label] : 0;
// final balance = ElectrumBalance();
// balance.confirmed = amount;
final receivedAddressRecord = BitcoinSilentPaymentAddressRecord(
receivingOutputAddress,
index: 0,
isHidden: false,
isUsed: true,
network: scanData.network,
silentPaymentTweak: t_k,
type: SegwitAddressType.p2tr,
txCount: 1,
balance: amount,
);
final unspent = BitcoinSilentPaymentsUnspent(
receivedAddressRecord,
txid,
amount,
pos,
silentPaymentTweak: t_k,
silentPaymentLabel: labelValue,
);
unspents.add(unspent);
txInfo.unspents!.add(unspent);
txInfo.amount += unspent.value;
});
});
});
scanData.sendPort.send({txInfo.id: txInfo});
} catch (e, stacktrace) {
printV(stacktrace);
printV(e.toString());
}
}
} catch (e, stacktrace) {
printV(stacktrace);
printV(e.toString());
}
syncHeight = tweakHeight;
if ((tweakHeight >= scanData.chainTip) || scanData.isSingleScan) {
if (tweakHeight >= scanData.chainTip)
scanData.sendPort.send(
SyncResponse(syncHeight, SyncedTipSyncStatus(scanData.chainTip)),
);
if (scanData.isSingleScan) {
scanData.sendPort.send(SyncResponse(syncHeight, SyncedSyncStatus()));
}
_scanningStream?.close();
_scanningStream = null;
return;
}
}
_scanningStream?.listen((event) => listenFn(event, req));
} catch (e) {
printV("Error in _handleScanSilentPayments: $e");
scanData.sendPort.send(SyncResponse(scanData.height, LostConnectionSyncStatus()));
}
}
Future<void> startRefresh(ScanData scanData) async { Future<void> startRefresh(ScanData scanData) async {
int syncHeight = scanData.height; int syncHeight = scanData.height;
int initialSyncHeight = syncHeight; int initialSyncHeight = syncHeight;
@ -2579,7 +2811,7 @@ Future<void> startRefresh(ScanData scanData) async {
useSSL: scanData.node?.useSSL ?? false, useSSL: scanData.node?.useSSL ?? false,
); );
int getCountPerRequest(int syncHeight) { int getCountToScanPerRequest(int syncHeight) {
if (scanData.isSingleScan) { if (scanData.isSingleScan) {
return 1; return 1;
} }
@ -2598,7 +2830,7 @@ Future<void> startRefresh(ScanData scanData) async {
); );
// Initial status UI update, send how many blocks in total to scan // Initial status UI update, send how many blocks in total to scan
final initialCount = getCountPerRequest(syncHeight); final initialCount = getCountToScanPerRequest(syncHeight);
scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight))); scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
tweaksSubscription = await electrumClient.tweaksSubscribe( tweaksSubscription = await electrumClient.tweaksSubscribe(
@ -2609,22 +2841,24 @@ Future<void> startRefresh(ScanData scanData) async {
Future<void> listenFn(t) async { Future<void> listenFn(t) async {
final tweaks = t as Map<String, dynamic>; final tweaks = t as Map<String, dynamic>;
final msg = tweaks["message"]; final msg = tweaks["message"];
// success or error msg
// is success or error msg
final noData = msg != null; final noData = msg != null;
if (noData) { if (noData) {
if (scanData.isSingleScan) {
return;
}
// re-subscribe to continue receiving messages, starting from the next unscanned height // re-subscribe to continue receiving messages, starting from the next unscanned height
final nextHeight = syncHeight + 1; final nextHeight = syncHeight + 1;
final nextCount = getCountPerRequest(nextHeight);
if (nextCount > 0) { if (nextHeight <= scanData.chainTip) {
tweaksSubscription?.close(); final nextStream = electrumClient.tweaksSubscribe(
final nextTweaksSubscription = electrumClient.tweaksSubscribe(
height: nextHeight, height: nextHeight,
count: nextCount, count: getCountToScanPerRequest(nextHeight),
); );
nextTweaksSubscription?.listen(listenFn); nextStream?.listen(listenFn);
} }
return; return;

View file

@ -3,7 +3,6 @@ import 'dart:io' show Platform;
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/unspent_coin_type.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart';
@ -71,9 +70,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
super(walletInfo) { super(walletInfo) {
if (masterHd != null) { if (masterHd != null) {
silentAddress = SilentPaymentOwner.fromPrivateKeys( silentAddress = SilentPaymentOwner.fromPrivateKeys(
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()), b_scan: ECPrivate.fromHex(
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()), masterHd.derivePath("m/352'/1'/0'/1'/0").privateKey.toHex(),
network: network, ),
b_spend: ECPrivate.fromHex(
masterHd.derivePath("m/352'/1'/0'/0'/0").privateKey.toHex(),
),
); );
if (silentAddresses.length == 0) { if (silentAddresses.length == 0) {
@ -109,8 +111,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType; final ObservableList<BaseBitcoinAddressRecord> addressesByReceiveType;
final ObservableList<BitcoinAddressRecord> receiveAddresses; final ObservableList<BitcoinAddressRecord> receiveAddresses;
final ObservableList<BitcoinAddressRecord> changeAddresses; final ObservableList<BitcoinAddressRecord> changeAddresses;
// TODO: add this variable in `bitcoin_wallet_addresses` and just add a cast in cw_bitcoin to use it // TODO: add this variable in `bitcoin_wallet_addresses` and just add a cast in cw_bitcoin to use it
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses; final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
// TODO: add this variable in `litecoin_wallet_addresses` and just add a cast in cw_bitcoin to use it // TODO: add this variable in `litecoin_wallet_addresses` and just add a cast in cw_bitcoin to use it
final ObservableList<BitcoinAddressRecord> mwebAddresses; final ObservableList<BitcoinAddressRecord> mwebAddresses;
final BasedUtxoNetwork network; final BasedUtxoNetwork network;
@ -144,12 +148,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
return silentAddress.toString(); return silentAddress.toString();
} }
final typeMatchingAddresses = _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList(); final typeMatchingAddresses =
final typeMatchingReceiveAddresses = typeMatchingAddresses.where((addr) => !addr.isUsed).toList(); _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList();
final typeMatchingReceiveAddresses =
typeMatchingAddresses.where((addr) => !addr.isUsed).toList();
if (!isEnabledAutoGenerateSubaddress) { if (!isEnabledAutoGenerateSubaddress) {
if (previousAddressRecord != null && if (previousAddressRecord != null && previousAddressRecord!.type == addressPageType) {
previousAddressRecord!.type == addressPageType) {
return previousAddressRecord!.address; return previousAddressRecord!.address;
} }

View file

@ -3,7 +3,7 @@ import 'dart:isolate';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base_old/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart'; import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
import 'package:cw_bitcoin/payjoin/payjoin_persister.dart'; import 'package:cw_bitcoin/payjoin/payjoin_persister.dart';

View file

@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base_old/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';

View file

@ -1,6 +1,6 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base_old/bitcoin_base.dart';
import 'package:convert/convert.dart'; import 'package:convert/convert.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:ledger_bitcoin/psbt.dart'; import 'package:ledger_bitcoin/psbt.dart';

View file

@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base_old/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/bitcoin_wallet.dart';
import 'package:cw_bitcoin/psbt/v0_deserialize.dart'; import 'package:cw_bitcoin/psbt/v0_deserialize.dart';