From 7b8ddf9685a25d3e9d5ece681560cfc8d7d0cb9e Mon Sep 17 00:00:00 2001 From: rafael_xmr Date: Sun, 25 May 2025 16:28:08 -0300 Subject: [PATCH] FIX (#2283) * FIX! * resolve conflicts with main * undo debug changes * fix: methods * fix: methods2 * Fix Tron issue * fix: 1k limit & reaching top * fix: missing unspents * fix: missing commit --------- Co-authored-by: OmarHatem --- cw_bitcoin/lib/address_from_output.dart | 21 +- cw_bitcoin/lib/bitcoin_address_record.dart | 2 +- .../lib/bitcoin_receive_page_option.dart | 16 +- cw_bitcoin/lib/bitcoin_wallet.dart | 64 ++-- cw_bitcoin/lib/bitcoin_wallet_addresses.dart | 4 +- cw_bitcoin/lib/electrum_wallet.dart | 343 +++++++++++++++--- cw_bitcoin/lib/electrum_wallet_addresses.dart | 58 +-- cw_bitcoin/lib/electrum_wallet_snapshot.dart | 8 +- cw_bitcoin/lib/litecoin_wallet.dart | 17 +- cw_bitcoin/lib/litecoin_wallet_addresses.dart | 10 +- cw_bitcoin/lib/payjoin/manager.dart | 28 +- cw_bitcoin/lib/psbt/signer.dart | 78 ++-- cw_bitcoin/lib/psbt/transaction_builder.dart | 34 +- cw_bitcoin/lib/psbt/utils.dart | 2 +- cw_bitcoin/pubspec.lock | 22 +- cw_bitcoin/pubspec.yaml | 6 +- cw_bitcoin_cash/pubspec.yaml | 4 +- cw_core/lib/solana_rpc_http_service.dart | 33 +- cw_core/pubspec.lock | 12 +- cw_core/pubspec.yaml | 2 +- cw_decred/pubspec.lock | 12 +- cw_monero/pubspec.lock | 12 +- cw_nano/pubspec.lock | 12 +- cw_solana/lib/solana_client.dart | 32 +- cw_solana/lib/solana_wallet.dart | 2 +- cw_solana/pubspec.yaml | 4 +- cw_tron/lib/tron_client.dart | 8 +- cw_tron/lib/tron_http_provider.dart | 49 +-- cw_tron/lib/tron_transaction_model.dart | 3 +- cw_tron/lib/tron_wallet.dart | 43 ++- cw_tron/pubspec.yaml | 4 +- cw_wownero/pubspec.lock | 12 +- cw_zano/pubspec.lock | 12 +- lib/bitcoin/cw_bitcoin.dart | 18 +- pubspec_base.yaml | 6 +- tool/download_moneroc_prebuilds.py | 76 ++++ 36 files changed, 667 insertions(+), 402 deletions(-) create mode 100755 tool/download_moneroc_prebuilds.py diff --git a/cw_bitcoin/lib/address_from_output.dart b/cw_bitcoin/lib/address_from_output.dart index 0d985b237..d6e931068 100644 --- a/cw_bitcoin/lib/address_from_output.dart +++ b/cw_bitcoin/lib/address_from_output.dart @@ -17,21 +17,16 @@ BitcoinBaseAddress addressFromScript(Script script, switch (addressType) { case P2pkhAddressType.p2pkh: - return P2pkhAddress.fromScriptPubkey( - script: script, network: BitcoinNetwork.mainnet); + return P2pkhAddress.fromScriptPubkey(script: script); case P2shAddressType.p2pkhInP2sh: case P2shAddressType.p2pkInP2sh: - return P2shAddress.fromScriptPubkey( - script: script, network: BitcoinNetwork.mainnet); - case SegwitAddresType.p2wpkh: - return P2wpkhAddress.fromScriptPubkey( - script: script, network: BitcoinNetwork.mainnet); - case SegwitAddresType.p2wsh: - return P2wshAddress.fromScriptPubkey( - script: script, network: BitcoinNetwork.mainnet); - case SegwitAddresType.p2tr: - return P2trAddress.fromScriptPubkey( - script: script, network: BitcoinNetwork.mainnet); + return P2shAddress.fromScriptPubkey(script: script); + case SegwitAddressType.p2wpkh: + return P2wpkhAddress.fromScriptPubkey(script: script); + case SegwitAddressType.p2wsh: + return P2wshAddress.fromScriptPubkey(script: script); + case SegwitAddressType.p2tr: + return P2trAddress.fromScriptPubkey(script: script); } throw ArgumentError("Invalid script"); diff --git a/cw_bitcoin/lib/bitcoin_address_record.dart b/cw_bitcoin/lib/bitcoin_address_record.dart index 1509f913a..97b3c08f8 100644 --- a/cw_bitcoin/lib/bitcoin_address_record.dart +++ b/cw_bitcoin/lib/bitcoin_address_record.dart @@ -82,7 +82,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord { type: decoded['type'] != null && decoded['type'] != '' ? BitcoinAddressType.values .firstWhere((type) => type.toString() == decoded['type'] as String) - : SegwitAddresType.p2wpkh, + : SegwitAddressType.p2wpkh, scriptHash: decoded['scriptHash'] as String?, network: network, ); diff --git a/cw_bitcoin/lib/bitcoin_receive_page_option.dart b/cw_bitcoin/lib/bitcoin_receive_page_option.dart index 07083e111..8331a182d 100644 --- a/cw_bitcoin/lib/bitcoin_receive_page_option.dart +++ b/cw_bitcoin/lib/bitcoin_receive_page_option.dart @@ -36,9 +36,9 @@ class BitcoinReceivePageOption implements ReceivePageOption { BitcoinAddressType toType() { switch (this) { case BitcoinReceivePageOption.p2tr: - return SegwitAddresType.p2tr; + return SegwitAddressType.p2tr; case BitcoinReceivePageOption.p2wsh: - return SegwitAddresType.p2wsh; + return SegwitAddressType.p2wsh; case BitcoinReceivePageOption.p2pkh: return P2pkhAddressType.p2pkh; case BitcoinReceivePageOption.p2sh: @@ -46,20 +46,20 @@ class BitcoinReceivePageOption implements ReceivePageOption { case BitcoinReceivePageOption.silent_payments: return SilentPaymentsAddresType.p2sp; case BitcoinReceivePageOption.mweb: - return SegwitAddresType.mweb; + return SegwitAddressType.mweb; case BitcoinReceivePageOption.p2wpkh: default: - return SegwitAddresType.p2wpkh; + return SegwitAddressType.p2wpkh; } } factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) { switch (type) { - case SegwitAddresType.p2tr: + case SegwitAddressType.p2tr: return BitcoinReceivePageOption.p2tr; - case SegwitAddresType.p2wsh: + case SegwitAddressType.p2wsh: return BitcoinReceivePageOption.p2wsh; - case SegwitAddresType.mweb: + case SegwitAddressType.mweb: return BitcoinReceivePageOption.mweb; case P2pkhAddressType.p2pkh: return BitcoinReceivePageOption.p2pkh; @@ -67,7 +67,7 @@ class BitcoinReceivePageOption implements ReceivePageOption { return BitcoinReceivePageOption.p2sh; case SilentPaymentsAddresType.p2sp: return BitcoinReceivePageOption.silent_payments; - case SegwitAddresType.p2wpkh: + case SegwitAddressType.p2wpkh: default: return BitcoinReceivePageOption.p2wpkh; } diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index a23b72660..73a6ad0ea 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -73,9 +73,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { initialBalance: initialBalance, seedBytes: seedBytes, encryptionFileUtils: encryptionFileUtils, - currency: networkParam == BitcoinNetwork.testnet - ? CryptoCurrency.tbtc - : CryptoCurrency.btc, + currency: + networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc, alwaysScan: alwaysScan, ) { // in a standard BIP44 wallet, mainHd derivation path = m/84'/0'/0'/0 (account 0, index unspecified here) @@ -94,14 +93,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { mainHd: hd, sideHd: accountHD.childKey(Bip32KeyIndex(1)), network: networkParam ?? network, - masterHd: - seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null, + masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null, isHardwareWallet: walletInfo.isHardwareWallet, payjoinManager: payjoinManager); autorun((_) { - this.walletAddresses.isEnabledAutoGenerateSubaddress = - this.isEnabledAutoGenerateSubaddress; + this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress; }); } @@ -136,8 +133,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { break; case DerivationType.electrum: default: - seedBytes = - await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); + seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); break; } @@ -210,10 +206,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { walletInfo.derivationInfo ??= DerivationInfo(); // set the default if not present: - walletInfo.derivationInfo!.derivationPath ??= - snp?.derivationPath ?? electrum_path; - walletInfo.derivationInfo!.derivationType ??= - snp?.derivationType ?? DerivationType.electrum; + walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path; + walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum; Uint8List? seedBytes = null; final mnemonic = keysData.mnemonic; @@ -222,8 +216,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { if (mnemonic != null) { switch (walletInfo.derivationInfo!.derivationType) { case DerivationType.electrum: - seedBytes = - await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); + seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? ""); break; case DerivationType.bip39: default: @@ -269,8 +262,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { late final PayjoinManager payjoinManager; bool get isPayjoinAvailable => unspentCoinsInfo.values - .where((element) => - element.walletId == id && element.isSending && !element.isFrozen) + .where((element) => element.walletId == id && element.isSending && !element.isFrozen) .isNotEmpty; Future buildPsbt({ @@ -287,10 +279,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { }) async { final psbtReadyInputs = []; for (final utxo in utxos) { - final rawTx = - await electrumClient.getTransactionHex(hash: utxo.utxo.txHash); - final publicKeyAndDerivationPath = - publicKeys[utxo.ownerDetails.address.pubKeyHash()]!; + final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash); + final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!; psbtReadyInputs.add(PSBTReadyUtxoWithAddress( utxo: utxo.utxo, @@ -302,8 +292,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { )); } - return PSBTTransactionBuild( - inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF) + return PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF) .psbt; } @@ -342,8 +331,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { Future createTransaction(Object credentials) async { credentials = credentials as BitcoinTransactionCredentials; - final tx = (await super.createTransaction(credentials)) - as PendingBitcoinTransaction; + final tx = (await super.createTransaction(credentials)) as PendingBitcoinTransaction; final payjoinUri = credentials.payjoinUri; if (payjoinUri == null) return tx; @@ -366,12 +354,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { publicKeys: tx.publicKeys!, masterFingerprint: Uint8List(0)); - final originalPsbt = await signPsbt( - base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys()); + final originalPsbt = + await signPsbt(base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys()); tx.commitOverride = () async { - final sender = await payjoinManager.initSender( - payjoinUri, originalPsbt, int.parse(tx.feeRate)); + final sender = + await payjoinManager.initSender(payjoinUri, originalPsbt, int.parse(tx.feeRate)); payjoinManager.spawnNewSender( sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount)); }; @@ -387,8 +375,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { Future commitPsbt(String finalizedPsbt) { final psbt = PsbtV2()..deserializeV0(base64.decode(finalizedPsbt)); - final btcTx = - BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract())); + final btcTx = BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract())); return PendingBitcoinTransaction( btcTx, @@ -402,12 +389,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { ).commit(); } - Future signPsbt( - String preProcessedPsbt, List utxos) async { + Future signPsbt(String preProcessedPsbt, List utxos) async { final psbt = PsbtV2()..deserializeV0(base64Decode(preProcessedPsbt)); await psbt.signWithUTXO(utxos, (txDigest, utxo, key, sighash) { - return utxo.utxo.isP2tr() + return utxo.utxo.isP2tr ? key.signTapRoot( txDigest, sighash: sighash, @@ -428,17 +414,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store { Future signMessage(String message, {String? address = null}) async { if (walletInfo.isHardwareWallet) { final addressEntry = address != null - ? walletAddresses.allAddresses - .firstWhere((element) => element.address == address) + ? walletAddresses.allAddresses.firstWhere((element) => element.address == address) : null; final index = addressEntry?.index ?? 0; final isChange = addressEntry?.isHidden == true ? 1 : 0; final accountPath = walletInfo.derivationInfo?.derivationPath; - final derivationPath = - accountPath != null ? "$accountPath/$isChange/$index" : null; + final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null; - final signature = await _bitcoinLedgerApp!.signMessage( - message: ascii.encode(message), signDerivationPath: derivationPath); + final signature = await _bitcoinLedgerApp! + .signMessage(message: ascii.encode(message), signDerivationPath: derivationPath); return base64Encode(signature); } diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart index 0fefe4e57..dd6dc5fae 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart @@ -47,10 +47,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S if (addressType == P2pkhAddressType.p2pkh) return generateP2PKHAddress(hd: hd, index: index, network: network); - if (addressType == SegwitAddresType.p2tr) + if (addressType == SegwitAddressType.p2tr) return generateP2TRAddress(hd: hd, index: index, network: network); - if (addressType == SegwitAddresType.p2wsh) + if (addressType == SegwitAddressType.p2wsh) return generateP2WSHAddress(hd: hd, index: index, network: network); if (addressType == P2shAddressType.p2wpkhInP2sh) diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index 35c15682c..d7449c011 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -5,7 +5,6 @@ import 'dart:isolate'; import 'package:bitcoin_base/bitcoin_base.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_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart'; @@ -18,7 +17,7 @@ import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/bitcoin_unspent.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_derivations.dart'; import 'package:cw_bitcoin/electrum_transaction_history.dart'; @@ -69,7 +68,7 @@ abstract class ElectrumWalletBase Uint8List? seedBytes, this.passphrase, List? initialAddresses, - ElectrumClient? electrumClient, + electrum.ElectrumClient? electrumClient, ElectrumBalance? initialBalance, CryptoCurrency? currency, this.alwaysScan, @@ -96,7 +95,7 @@ abstract class ElectrumWalletBase this.isTestnet = !network.isMainnet, this._mnemonic = mnemonic, super(walletInfo) { - this.electrumClient = electrumClient ?? ElectrumClient(); + this.electrumClient = electrumClient ?? electrum.ElectrumClient(); this.walletInfo = walletInfo; transactionHistory = ElectrumTransactionHistory( walletInfo: walletInfo, @@ -167,7 +166,7 @@ abstract class ElectrumWalletBase @observable bool isEnabledAutoGenerateSubaddress; - late ElectrumClient electrumClient; + late electrum.ElectrumClient electrumClient; Box unspentCoinsInfo; @override @@ -182,7 +181,7 @@ abstract class ElectrumWalletBase SyncStatus syncStatus; Set get addressesSet => walletAddresses.allAddresses - .where((element) => element.type != SegwitAddresType.mweb) + .where((element) => element.type != SegwitAddressType.mweb) .map((addr) => addr.address) .toSet(); @@ -333,14 +332,14 @@ abstract class ElectrumWalletBase final receivePort = ReceivePort(); _isolate = Isolate.spawn( - startRefresh, + _handleScanSilentPayments, ScanData( sendPort: receivePort.sendPort, silentAddress: walletAddresses.silentAddress!, network: network, height: height, chainTip: chainTip, - electrumClient: ElectrumClient(), + electrumClient: electrum.ElectrumClient(), transactionHistoryIds: transactionHistory.transactions.keys.toList(), node: (await getNodeSupportsSilentPayments()) == true ? ScanNode(node!.uri, node!.useSSL) @@ -439,7 +438,6 @@ abstract class ElectrumWalletBase BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)), ) : silentAddress.B_spend, - network: network, ); final addressRecord = walletAddresses.silentAddresses @@ -564,7 +562,7 @@ abstract class ElectrumWalletBase node!.save(); return node!.supportsSilentPayments!; } - } on RequestFailedTimeoutException catch (_) { + } on electrum.RequestFailedTimeoutException catch (_) { node!.supportsSilentPayments = false; node!.save(); return node!.supportsSilentPayments!; @@ -625,9 +623,9 @@ abstract class ElectrumWalletBase switch (coinTypeToSpendFrom) { case UnspentCoinType.mweb: - return utx.bitcoinAddressRecord.type == SegwitAddresType.mweb; + return utx.bitcoinAddressRecord.type == SegwitAddressType.mweb; case UnspentCoinType.nonMweb: - return utx.bitcoinAddressRecord.type != SegwitAddresType.mweb; + return utx.bitcoinAddressRecord.type != SegwitAddressType.mweb; case UnspentCoinType.any: return true; } @@ -635,7 +633,7 @@ abstract class ElectrumWalletBase final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList(); // sort the unconfirmed coins so that mweb coins are last: - availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? 1 : -1); + availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddressType.mweb ? 1 : -1); for (int i = 0; i < availableInputs.length; i++) { final utx = availableInputs[i]; @@ -643,7 +641,7 @@ abstract class ElectrumWalletBase if (paysToSilentPayment) { // Check inputs for shared secret derivation - if (utx.bitcoinAddressRecord.type == SegwitAddresType.p2wsh) { + if (utx.bitcoinAddressRecord.type == SegwitAddressType.p2wsh) { throw BitcoinTransactionSilentPaymentsNotSupported(); } } @@ -678,7 +676,7 @@ abstract class ElectrumWalletBase if (privkey != null) { inputPrivKeyInfos.add(ECPrivateInfo( privkey, - address.type == SegwitAddresType.p2tr, + address.type == SegwitAddressType.p2tr, tweak: !isSilentPayment, )); @@ -1164,7 +1162,7 @@ abstract class ElectrumWalletBase throw Exception(error); } - if (utxo.utxo.isP2tr()) { + if (utxo.utxo.isP2tr) { hasTaprootInputs = true; return key.privkey.signTapRoot( txDigest, @@ -1176,20 +1174,18 @@ abstract class ElectrumWalletBase } }); - return PendingBitcoinTransaction( - transaction, - type, - electrumClient: electrumClient, - amount: estimatedTx.amount, - fee: estimatedTx.fee, - feeRate: feeRateInt.toString(), - network: network, - hasChange: estimatedTx.hasChange, - isSendAll: estimatedTx.isSendAll, - hasTaprootInputs: hasTaprootInputs, - utxos: estimatedTx.utxos, - publicKeys: estimatedTx.publicKeys - )..addListener((transaction) async { + return PendingBitcoinTransaction(transaction, type, + electrumClient: electrumClient, + amount: estimatedTx.amount, + fee: estimatedTx.fee, + feeRate: feeRateInt.toString(), + network: network, + hasChange: estimatedTx.hasChange, + isSendAll: estimatedTx.isSendAll, + hasTaprootInputs: hasTaprootInputs, + utxos: estimatedTx.utxos, + publicKeys: estimatedTx.publicKeys) + ..addListener((transaction) async { transactionHistory.addOne(transaction); if (estimatedTx.spendsSilentPayment) { transactionHistory.transactions.values.forEach((tx) { @@ -1233,7 +1229,7 @@ abstract class ElectrumWalletBase 'change_address_index': walletAddresses.currentChangeAddressIndexByType, 'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(), 'address_page_type': walletInfo.addressPageType == null - ? SegwitAddresType.p2wpkh.toString() + ? SegwitAddressType.p2wpkh.toString() : walletInfo.addressPageType.toString(), 'balance': balance[currency]?.toJSON(), 'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index, @@ -1373,7 +1369,7 @@ abstract class ElectrumWalletBase List updatedUnspentCoins = []; final previousUnspentCoins = List.from(unspentCoins.where((utxo) => - utxo.bitcoinAddressRecord.type != SegwitAddresType.mweb && + utxo.bitcoinAddressRecord.type != SegwitAddressType.mweb && utxo.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord)); if (hasSilentPaymentsScanning) { @@ -1387,13 +1383,13 @@ abstract class ElectrumWalletBase // Set the balance of all non-silent payment and non-mweb addresses to 0 before updating walletAddresses.allAddresses - .where((element) => element.type != SegwitAddresType.mweb) + .where((element) => element.type != SegwitAddressType.mweb) .forEach((addr) { if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0; }); final addressFutures = walletAddresses.allAddresses - .where((element) => element.type != SegwitAddresType.mweb) + .where((element) => element.type != SegwitAddressType.mweb) .map((address) => fetchUnspent(address)) .toList(); @@ -1834,7 +1830,7 @@ abstract class ElectrumWalletBase throw Exception("Cannot find private key"); } - if (utxo.utxo.isP2tr()) { + if (utxo.utxo.isP2tr) { return key.signTapRoot(txDigest, sighash: sighash); } else { return key.signInput(txDigest, sigHash: sighash); @@ -1984,7 +1980,7 @@ abstract class ElectrumWalletBase .map((type) => fetchTransactionsForAddressType(historiesWithDetails, type))); } else if (type == WalletType.litecoin) { await Future.wait(LITECOIN_ADDRESS_TYPES - .where((type) => type != SegwitAddresType.mweb) + .where((type) => type != SegwitAddressType.mweb) .map((type) => fetchTransactionsForAddressType(historiesWithDetails, type))); } @@ -2173,7 +2169,7 @@ abstract class ElectrumWalletBase final unsubscribedScriptHashes = walletAddresses.allAddresses.where( (address) => !_scripthashesUpdateSubject.containsKey(address.getScriptHash(network)) && - address.type != SegwitAddresType.mweb, + address.type != SegwitAddressType.mweb, ); await Future.wait(unsubscribedScriptHashes.map((address) async { @@ -2396,9 +2392,9 @@ abstract class ElectrumWalletBase derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1); @action - void _onConnectionStatusChange(ConnectionStatus status) { + void _onConnectionStatusChange(electrum.ConnectionStatus status) { switch (status) { - case ConnectionStatus.connected: + case electrum.ConnectionStatus.connected: if (syncStatus is NotConnectedSyncStatus || syncStatus is LostConnectionSyncStatus || syncStatus is ConnectingSyncStatus) { @@ -2406,19 +2402,19 @@ abstract class ElectrumWalletBase } break; - case ConnectionStatus.disconnected: + case electrum.ConnectionStatus.disconnected: if (syncStatus is! NotConnectedSyncStatus && syncStatus is! ConnectingSyncStatus && syncStatus is! SyncronizingSyncStatus) { syncStatus = NotConnectedSyncStatus(); } break; - case ConnectionStatus.failed: + case electrum.ConnectionStatus.failed: if (syncStatus is! LostConnectionSyncStatus) { syncStatus = LostConnectionSyncStatus(); } break; - case ConnectionStatus.connecting: + case electrum.ConnectionStatus.connecting: if (syncStatus is! ConnectingSyncStatus) { syncStatus = ConnectingSyncStatus(); } @@ -2530,7 +2526,7 @@ class ScanData { final ScanNode? node; final BasedUtxoNetwork network; final int chainTip; - final ElectrumClient electrumClient; + final electrum.ElectrumClient electrumClient; final List transactionHistoryIds; final Map labels; final List labelIndexes; @@ -2574,6 +2570,234 @@ class SyncResponse { SyncResponse(this.height, this.syncStatus); } +Future _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, + ); + + 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 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 unspents = []; + + addToWallet.forEach((BSpend, scanResultPerLabel) { + scanResultPerLabel.forEach((label, scanOutput) { + final labelValue = label == "None" ? null : label.toString(); + + (scanOutput as Map).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 startRefresh(ScanData scanData) async { int syncHeight = scanData.height; int initialSyncHeight = syncHeight; @@ -2586,7 +2810,7 @@ Future startRefresh(ScanData scanData) async { useSSL: scanData.node?.useSSL ?? false, ); - int getCountPerRequest(int syncHeight) { + int getCountToScanPerRequest(int syncHeight) { if (scanData.isSingleScan) { return 1; } @@ -2601,11 +2825,10 @@ Future startRefresh(ScanData scanData) async { scanData.silentAddress.B_spend.toHex(), scanData.network == BitcoinNetwork.testnet, scanData.labelIndexes, - scanData.labelIndexes.length, ); // 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))); tweaksSubscription = await electrumClient.tweaksSubscribe( @@ -2616,22 +2839,24 @@ Future startRefresh(ScanData scanData) async { Future listenFn(t) async { final tweaks = t as Map; final msg = tweaks["message"]; - // success or error msg + + // is success or error msg final noData = msg != null; if (noData) { + if (scanData.isSingleScan) { + return; + } + // re-subscribe to continue receiving messages, starting from the next unscanned height final nextHeight = syncHeight + 1; - final nextCount = getCountPerRequest(nextHeight); - if (nextCount > 0) { - tweaksSubscription?.close(); - - final nextTweaksSubscription = electrumClient.tweaksSubscribe( + if (nextHeight <= scanData.chainTip) { + final nextStream = electrumClient.tweaksSubscribe( height: nextHeight, - count: nextCount, + count: getCountToScanPerRequest(nextHeight), ); - nextTweaksSubscription?.listen(listenFn); + nextStream?.listen(listenFn); } return; @@ -2713,7 +2938,7 @@ Future startRefresh(ScanData scanData) async { isUsed: true, network: scanData.network, silentPaymentTweak: t_k, - type: SegwitAddresType.p2tr, + type: SegwitAddressType.p2tr, txCount: 1, balance: amount!, ); @@ -2806,15 +3031,15 @@ BitcoinAddressType _getScriptType(BitcoinBaseAddress type) { } else if (type is P2shAddress) { return P2shAddressType.p2wpkhInP2sh; } else if (type is P2wshAddress) { - return SegwitAddresType.p2wsh; + return SegwitAddressType.p2wsh; } else if (type is P2trAddress) { - return SegwitAddresType.p2tr; + return SegwitAddressType.p2tr; } else if (type is MwebAddress) { - return SegwitAddresType.mweb; + return SegwitAddressType.mweb; } else if (type is SilentPaymentsAddresType) { return SilentPaymentsAddresType.p2sp; } else { - return SegwitAddresType.p2wpkh; + return SegwitAddressType.p2wpkh; } } diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index 614a06a3b..9d1ae54aa 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -17,16 +17,16 @@ part 'electrum_wallet_addresses.g.dart'; class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses; const List BITCOIN_ADDRESS_TYPES = [ - SegwitAddresType.p2wpkh, + SegwitAddressType.p2wpkh, P2pkhAddressType.p2pkh, - SegwitAddresType.p2tr, - SegwitAddresType.p2wsh, + SegwitAddressType.p2tr, + SegwitAddressType.p2wsh, P2shAddressType.p2wpkhInP2sh, ]; const List LITECOIN_ADDRESS_TYPES = [ - SegwitAddresType.p2wpkh, - SegwitAddresType.mweb, + SegwitAddressType.p2wpkh, + SegwitAddressType.mweb, ]; const List BITCOIN_CASH_ADDRESS_TYPES = [ @@ -62,7 +62,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { _addressPageType = initialAddressPageType ?? (walletInfo.addressPageType != null ? BitcoinAddressType.fromValue(walletInfo.addressPageType!) - : SegwitAddresType.p2wpkh), + : SegwitAddressType.p2wpkh), silentAddresses = ObservableList.of( (initialSilentAddresses ?? []).toSet()), currentSilentAddressIndex = initialSilentAddressIndex, @@ -71,9 +71,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { super(walletInfo) { if (masterHd != null) { silentAddress = SilentPaymentOwner.fromPrivateKeys( - b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()), - b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()), - network: network, + b_scan: ECPrivate.fromHex( + masterHd.derivePath("m/352'/1'/0'/1'/0").privateKey.toHex(), + ), + b_spend: ECPrivate.fromHex( + masterHd.derivePath("m/352'/1'/0'/0'/0").privateKey.toHex(), + ), ); if (silentAddresses.length == 0) { @@ -144,12 +147,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { return silentAddress.toString(); } - final typeMatchingAddresses = _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList(); - final typeMatchingReceiveAddresses = typeMatchingAddresses.where((addr) => !addr.isUsed).toList(); + final typeMatchingAddresses = + _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList(); + final typeMatchingReceiveAddresses = + typeMatchingAddresses.where((addr) => !addr.isUsed).toList(); if (!isEnabledAutoGenerateSubaddress) { - if (previousAddressRecord != null && - previousAddressRecord!.type == addressPageType) { + if (previousAddressRecord != null && previousAddressRecord!.type == addressPageType) { return previousAddressRecord!.address; } @@ -249,17 +253,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { if (walletInfo.type == WalletType.bitcoinCash) { await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); } else if (walletInfo.type == WalletType.litecoin) { - await _generateInitialAddresses(type: SegwitAddresType.p2wpkh); + await _generateInitialAddresses(type: SegwitAddressType.p2wpkh); if ((Platform.isAndroid || Platform.isIOS) && !isHardwareWallet) { - await _generateInitialAddresses(type: SegwitAddresType.mweb); + await _generateInitialAddresses(type: SegwitAddressType.mweb); } } else if (walletInfo.type == WalletType.bitcoin) { await _generateInitialAddresses(); if (!isHardwareWallet) { await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); - await _generateInitialAddresses(type: SegwitAddresType.p2tr); - await _generateInitialAddresses(type: SegwitAddresType.p2wsh); + await _generateInitialAddresses(type: SegwitAddressType.p2tr); + await _generateInitialAddresses(type: SegwitAddressType.p2wsh); } } @@ -323,7 +327,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { BaseBitcoinAddressRecord generateNewAddress({String label = ''}) { if (addressPageType == SilentPaymentsAddresType.p2sp && silentAddress != null) { final currentSilentAddressIndex = silentAddresses - .where((addressRecord) => addressRecord.type != SegwitAddresType.p2tr) + .where((addressRecord) => addressRecord.type != SegwitAddressType.p2tr) .length - 1; @@ -381,7 +385,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { void addBitcoinAddressTypes() { final lastP2wpkh = _addresses .where((addressRecord) => - _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh)) + _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wpkh)) .toList() .last; if (lastP2wpkh.address != address) { @@ -407,7 +411,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } final lastP2tr = _addresses.firstWhere( - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2tr)); + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2tr)); if (lastP2tr.address != address) { addressesMap[lastP2tr.address] = 'P2TR'; } else { @@ -415,7 +419,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } final lastP2wsh = _addresses.firstWhere( - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wsh)); + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wsh)); if (lastP2wsh.address != address) { addressesMap[lastP2wsh.address] = 'P2WSH'; } else { @@ -440,7 +444,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { void addLitecoinAddressTypes() { final lastP2wpkh = _addresses .where((addressRecord) => - _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh)) + _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wpkh)) .toList() .last; if (lastP2wpkh.address != address) { @@ -450,7 +454,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } final lastMweb = _addresses.firstWhere( - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.mweb)); + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.mweb)); if (lastMweb.address != address) { addressesMap[lastMweb.address] = 'MWEB'; } else { @@ -560,14 +564,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { addressRecord.isHidden && !addressRecord.isUsed && // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type - (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddresType.p2wpkh)); + (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddressType.p2wpkh)); changeAddresses.addAll(newAddresses); } @action Future discoverAddresses(List addressList, bool isHidden, Future Function(BitcoinAddressRecord) getAddressHistory, - {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async { + {BitcoinAddressType type = SegwitAddressType.p2wpkh}) async { final newAddresses = await _createNewAddresses(gap, startIndex: addressList.length, isHidden: isHidden, type: type); addAddresses(newAddresses); @@ -581,7 +585,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { } Future _generateInitialAddresses( - {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async { + {BitcoinAddressType type = SegwitAddressType.p2wpkh}) async { var countOfReceiveAddresses = 0; var countOfHiddenAddresses = 0; @@ -658,7 +662,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { void _validateAddresses() { _addresses.forEach((element) async { - if (element.type == SegwitAddresType.mweb) { + if (element.type == SegwitAddressType.mweb) { // this would add a ton of startup lag for mweb addresses since we have 1000 of them return; } diff --git a/cw_bitcoin/lib/electrum_wallet_snapshot.dart b/cw_bitcoin/lib/electrum_wallet_snapshot.dart index 990719089..3e5f331df 100644 --- a/cw_bitcoin/lib/electrum_wallet_snapshot.dart +++ b/cw_bitcoin/lib/electrum_wallet_snapshot.dart @@ -87,8 +87,8 @@ class ElectrumWalletSnapshot { final balance = ElectrumBalance.fromJSON(data['balance'] as String?) ?? ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0); - var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0}; - var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0}; + var regularAddressIndexByType = {SegwitAddressType.p2wpkh.toString(): 0}; + var changeAddressIndexByType = {SegwitAddressType.p2wpkh.toString(): 0}; var silentAddressIndex = 0; final derivationType = DerivationType @@ -97,10 +97,10 @@ class ElectrumWalletSnapshot { try { regularAddressIndexByType = { - SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0') + SegwitAddressType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0') }; changeAddressIndexByType = { - SegwitAddresType.p2wpkh.toString(): + SegwitAddressType.p2wpkh.toString(): int.parse(data['change_address_index'] as String? ?? '0') }; silentAddressIndex = int.parse(data['silent_address_index'] as String? ?? '0'); diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index 08c56c600..4e6b2536a 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -16,7 +16,6 @@ import 'package:fixnum/fixnum.dart'; import 'package:bip39/bip39.dart' as bip39; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; -import 'package:blockchain_utils/signer/ecdsa_signing_key.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_mnemonic.dart'; import 'package:cw_bitcoin/bitcoin_transaction_priority.dart'; @@ -971,9 +970,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { List? inputPrivKeyInfos, List? vinOutpoints, }) async { - bool spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddresType.mweb); + bool spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddressType.mweb); bool paysToMweb = outputs - .any((output) => output.toOutput.scriptPubKey.getAddressType() == SegwitAddresType.mweb); + .any((output) => output.toOutput.scriptPubKey.getAddressType() == SegwitAddressType.mweb); bool isRegular = !spendsMweb && !paysToMweb; bool isMweb = spendsMweb || paysToMweb; @@ -1064,9 +1063,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { tx.isMweb = mwebEnabled; if (!mwebEnabled) { - tx.changeAddressOverride = - (await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb)) - .address; + tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses) + .getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb)) + .address; return tx; } await waitForMwebAddresses(); @@ -1108,7 +1107,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { // check if mweb inputs are used: for (final utxo in tx.utxos) { - if (utxo.utxo.scriptType == SegwitAddresType.mweb) { + if (utxo.utxo.scriptType == SegwitAddressType.mweb) { hasMwebInput = true; } } @@ -1119,7 +1118,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { bool isRegular = !hasMwebInput && !hasMwebOutput; bool shouldNotUseMwebChange = isPegIn || isRegular || !hasMwebInput; tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses) - .getChangeAddress(coinTypeToSpendFrom: shouldNotUseMwebChange ? UnspentCoinType.nonMweb : UnspentCoinType.any)) + .getChangeAddress( + coinTypeToSpendFrom: + shouldNotUseMwebChange ? UnspentCoinType.nonMweb : UnspentCoinType.any)) .address; if (isRegular) { tx.isMweb = false; diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index bbb987766..5e5a27fe8 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -106,7 +106,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with .map((e) => BitcoinAddressRecord( e.value, index: e.key, - type: SegwitAddresType.mweb, + type: SegwitAddressType.mweb, network: network, )) .toList(); @@ -128,7 +128,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType, }) { - if (addressType == SegwitAddresType.mweb) { + if (addressType == SegwitAddressType.mweb) { return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1]; } return generateP2WPKHAddress(hd: hd, index: index, network: network); @@ -140,7 +140,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType, }) async { - if (addressType == SegwitAddresType.mweb) { + if (addressType == SegwitAddressType.mweb) { await ensureMwebAddressUpToIndexExists(index); } return getAddress(index: index, hd: hd, addressType: addressType); @@ -195,7 +195,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with return BitcoinAddressRecord( mwebAddrs[0], index: 0, - type: SegwitAddresType.mweb, + type: SegwitAddressType.mweb, network: network, ); } @@ -207,7 +207,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with String get addressForExchange { // don't use mweb addresses for exchange refund address: final addresses = receiveAddresses - .where((element) => element.type == SegwitAddresType.p2wpkh && !element.isUsed); + .where((element) => element.type == SegwitAddressType.p2wpkh && !element.isUsed); return addresses.first.address; } } diff --git a/cw_bitcoin/lib/payjoin/manager.dart b/cw_bitcoin/lib/payjoin/manager.dart index 7ba3ceb9b..9476ce23e 100644 --- a/cw_bitcoin/lib/payjoin/manager.dart +++ b/cw_bitcoin/lib/payjoin/manager.dart @@ -31,8 +31,8 @@ class PayjoinManager { 'https://ohttp.cakewallet.com', ]; - static Future randomOhttpRelayUrl() => PayjoinUri.Url.fromStr( - ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]); + static Future randomOhttpRelayUrl() => + PayjoinUri.Url.fromStr(ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]); static const payjoinDirectoryUrl = 'https://payjo.in'; @@ -59,8 +59,7 @@ class PayjoinManager { Future initSender( String pjUriString, String originalPsbt, int networkFeesSatPerVb) async { try { - final pjUri = - (await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported(); + final pjUri = (await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported(); final minFeeRateSatPerKwu = BigInt.from(networkFeesSatPerVb * 250); final senderBuilder = await SenderBuilder.fromPsbtAndUri( psbtBase64: originalPsbt, @@ -79,8 +78,7 @@ class PayjoinManager { bool isTestnet = false, }) async { final pjUri = Uri.parse(pjUrl).queryParameters['pj']!; - await _payjoinStorage.insertSenderSession( - sender, pjUri, _wallet.id, amount); + await _payjoinStorage.insertSenderSession(sender, pjUri, _wallet.id, amount); return _spawnSender(isTestnet: isTestnet, sender: sender, pjUri: pjUri); } @@ -140,11 +138,9 @@ class PayjoinManager { return completer.future; } - Future initReceiver(String address, - [bool isTestnet = false]) async { + Future initReceiver(String address, [bool isTestnet = false]) async { try { - final payjoinDirectory = - await PayjoinUri.Url.fromStr(payjoinDirectoryUrl); + final payjoinDirectory = await PayjoinUri.Url.fromStr(payjoinDirectoryUrl); final ohttpKeys = await PayjoinUri.fetchOhttpKeys( ohttpRelay: await randomOhttpRelayUrl(), @@ -199,8 +195,7 @@ class PayjoinManager { _payjoinStorage.markReceiverSessionInProgress(receiver.id()); final inputScript = message['input_script'] as Uint8List; - final isOwned = - _wallet.isMine(Script.fromRaw(byteData: inputScript)); + final isOwned = _wallet.isMine(Script.fromRaw(bytes: inputScript)); mainToIsolateSendPort?.send({ 'requestId': message['requestId'], 'result': isOwned, @@ -209,8 +204,7 @@ class PayjoinManager { case PayjoinReceiverRequestTypes.checkIsReceiverOutput: final outputScript = message['output_script'] as Uint8List; - final isReceiverOutput = - _wallet.isMine(Script.fromRaw(byteData: outputScript)); + final isReceiverOutput = _wallet.isMine(Script.fromRaw(bytes: outputScript)); mainToIsolateSendPort?.send({ 'requestId': message['requestId'], 'result': isReceiverOutput, @@ -243,15 +237,13 @@ class PayjoinManager { } } catch (e) { _cleanupSession(receiver.id()); - await _payjoinStorage.markReceiverSessionUnrecoverable( - receiver.id(), e.toString()); + await _payjoinStorage.markReceiverSessionUnrecoverable(receiver.id(), e.toString()); completer.completeError(e); } } else if (message is PayjoinSessionError) { _cleanupSession(receiver.id()); if (message is UnrecoverableError) { - await _payjoinStorage.markReceiverSessionUnrecoverable( - receiver.id(), message.message); + await _payjoinStorage.markReceiverSessionUnrecoverable(receiver.id(), message.message); completer.complete(); } else if (message is RecoverableError) { completer.complete(); diff --git a/cw_bitcoin/lib/psbt/signer.dart b/cw_bitcoin/lib/psbt/signer.dart index 1d0ceba8b..a56aec37d 100644 --- a/cw_bitcoin/lib/psbt/signer.dart +++ b/cw_bitcoin/lib/psbt/signer.dart @@ -40,8 +40,7 @@ extension PsbtSigner on PsbtV2 { return tx.buffer(); } - Future signWithUTXO( - List utxos, UTXOSignerCallBack signer, + Future signWithUTXO(List utxos, UTXOSignerCallBack signer, [UTXOGetterCallBack? getTaprootPair]) async { final raw = BytesUtils.toHexString(extractUnsignedTX(getSegwit: false)); final tx = BtcTransaction.fromRaw(raw); @@ -51,10 +50,10 @@ extension PsbtSigner on PsbtV2 { List taprootAmounts = []; List