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 <omarh.ismail1@gmail.com>

rafael_xmr committed May 25, 2025 at 16:28 UTC 7b8ddf9685a25d3e9d5ece681560cfc8d7d0cb9e
36 files changed +667 -402
cw_bitcoin/lib/address_from_output.dart
+8 -13
@@ -17,21 +17,16 @@ BitcoinBaseAddress addressFromScript(Script script,
17
18 switch (addressType) {
19 case P2pkhAddressType.p2pkh:
20 - return P2pkhAddress.fromScriptPubkey(
21 - script: script, network: BitcoinNetwork.mainnet);
20 + return P2pkhAddress.fromScriptPubkey(script: script);
21 case P2shAddressType.p2pkhInP2sh:
22 case P2shAddressType.p2pkInP2sh:
24 - return P2shAddress.fromScriptPubkey(
25 - script: script, network: BitcoinNetwork.mainnet);
26 - case SegwitAddresType.p2wpkh:
27 - return P2wpkhAddress.fromScriptPubkey(
28 - script: script, network: BitcoinNetwork.mainnet);
29 - case SegwitAddresType.p2wsh:
30 - return P2wshAddress.fromScriptPubkey(
31 - script: script, network: BitcoinNetwork.mainnet);
32 - case SegwitAddresType.p2tr:
33 - return P2trAddress.fromScriptPubkey(
34 - script: script, network: BitcoinNetwork.mainnet);
23 + return P2shAddress.fromScriptPubkey(script: script);
24 + case SegwitAddressType.p2wpkh:
25 + return P2wpkhAddress.fromScriptPubkey(script: script);
26 + case SegwitAddressType.p2wsh:
27 + return P2wshAddress.fromScriptPubkey(script: script);
28 + case SegwitAddressType.p2tr:
29 + return P2trAddress.fromScriptPubkey(script: script);
30 }
31
32 throw ArgumentError("Invalid script");
cw_bitcoin/lib/bitcoin_address_record.dart
+1 -1
@@ -82,7 +82,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
82 type: decoded['type'] != null && decoded['type'] != ''
83 ? BitcoinAddressType.values
84 .firstWhere((type) => type.toString() == decoded['type'] as String)
85 - : SegwitAddresType.p2wpkh,
85 + : SegwitAddressType.p2wpkh,
86 scriptHash: decoded['scriptHash'] as String?,
87 network: network,
88 );
cw_bitcoin/lib/bitcoin_receive_page_option.dart
+8 -8
@@ -36,9 +36,9 @@ class BitcoinReceivePageOption implements ReceivePageOption {
36 BitcoinAddressType toType() {
37 switch (this) {
38 case BitcoinReceivePageOption.p2tr:
39 - return SegwitAddresType.p2tr;
39 + return SegwitAddressType.p2tr;
40 case BitcoinReceivePageOption.p2wsh:
41 - return SegwitAddresType.p2wsh;
41 + return SegwitAddressType.p2wsh;
42 case BitcoinReceivePageOption.p2pkh:
43 return P2pkhAddressType.p2pkh;
44 case BitcoinReceivePageOption.p2sh:
@@ -46,20 +46,20 @@ class BitcoinReceivePageOption implements ReceivePageOption {
46 case BitcoinReceivePageOption.silent_payments:
47 return SilentPaymentsAddresType.p2sp;
48 case BitcoinReceivePageOption.mweb:
49 - return SegwitAddresType.mweb;
49 + return SegwitAddressType.mweb;
50 case BitcoinReceivePageOption.p2wpkh:
51 default:
52 - return SegwitAddresType.p2wpkh;
52 + return SegwitAddressType.p2wpkh;
53 }
54 }
55
56 factory BitcoinReceivePageOption.fromType(BitcoinAddressType type) {
57 switch (type) {
58 - case SegwitAddresType.p2tr:
58 + case SegwitAddressType.p2tr:
59 return BitcoinReceivePageOption.p2tr;
60 - case SegwitAddresType.p2wsh:
60 + case SegwitAddressType.p2wsh:
61 return BitcoinReceivePageOption.p2wsh;
62 - case SegwitAddresType.mweb:
62 + case SegwitAddressType.mweb:
63 return BitcoinReceivePageOption.mweb;
64 case P2pkhAddressType.p2pkh:
65 return BitcoinReceivePageOption.p2pkh;
@@ -67,7 +67,7 @@ class BitcoinReceivePageOption implements ReceivePageOption {
67 return BitcoinReceivePageOption.p2sh;
68 case SilentPaymentsAddresType.p2sp:
69 return BitcoinReceivePageOption.silent_payments;
70 - case SegwitAddresType.p2wpkh:
70 + case SegwitAddressType.p2wpkh:
71 default:
72 return BitcoinReceivePageOption.p2wpkh;
73 }
cw_bitcoin/lib/bitcoin_wallet.dart
+24 -40
@@ -73,9 +73,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
73 initialBalance: initialBalance,
74 seedBytes: seedBytes,
75 encryptionFileUtils: encryptionFileUtils,
76 - currency: networkParam == BitcoinNetwork.testnet
77 - ? CryptoCurrency.tbtc
78 - : CryptoCurrency.btc,
76 + currency:
77 + networkParam == BitcoinNetwork.testnet ? CryptoCurrency.tbtc : CryptoCurrency.btc,
78 alwaysScan: alwaysScan,
79 ) {
80 // 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 {
93 mainHd: hd,
94 sideHd: accountHD.childKey(Bip32KeyIndex(1)),
95 network: networkParam ?? network,
97 - masterHd:
98 - seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
96 + masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
97 isHardwareWallet: walletInfo.isHardwareWallet,
98 payjoinManager: payjoinManager);
99
100 autorun((_) {
103 - this.walletAddresses.isEnabledAutoGenerateSubaddress =
104 - this.isEnabledAutoGenerateSubaddress;
101 + this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
102 });
103 }
104
@@ -136,8 +133,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
133 break;
134 case DerivationType.electrum:
135 default:
139 - seedBytes =
140 - await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
136 + seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
137 break;
138 }
139
@@ -210,10 +206,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
206 walletInfo.derivationInfo ??= DerivationInfo();
207
208 // set the default if not present:
213 - walletInfo.derivationInfo!.derivationPath ??=
214 - snp?.derivationPath ?? electrum_path;
215 - walletInfo.derivationInfo!.derivationType ??=
216 - snp?.derivationType ?? DerivationType.electrum;
209 + walletInfo.derivationInfo!.derivationPath ??= snp?.derivationPath ?? electrum_path;
210 + walletInfo.derivationInfo!.derivationType ??= snp?.derivationType ?? DerivationType.electrum;
211
212 Uint8List? seedBytes = null;
213 final mnemonic = keysData.mnemonic;
@@ -222,8 +216,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
216 if (mnemonic != null) {
217 switch (walletInfo.derivationInfo!.derivationType) {
218 case DerivationType.electrum:
225 - seedBytes =
226 - await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
219 + seedBytes = await mnemonicToSeedBytes(mnemonic, passphrase: passphrase ?? "");
220 break;
221 case DerivationType.bip39:
222 default:
@@ -269,8 +262,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
262 late final PayjoinManager payjoinManager;
263
264 bool get isPayjoinAvailable => unspentCoinsInfo.values
272 - .where((element) =>
273 - element.walletId == id && element.isSending && !element.isFrozen)
265 + .where((element) => element.walletId == id && element.isSending && !element.isFrozen)
266 .isNotEmpty;
267
268 Future<PsbtV2> buildPsbt({
@@ -287,10 +279,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
279 }) async {
280 final psbtReadyInputs = <PSBTReadyUtxoWithAddress>[];
281 for (final utxo in utxos) {
290 - final rawTx =
291 - await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
292 - final publicKeyAndDerivationPath =
293 - publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
282 + final rawTx = await electrumClient.getTransactionHex(hash: utxo.utxo.txHash);
283 + final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
284
285 psbtReadyInputs.add(PSBTReadyUtxoWithAddress(
286 utxo: utxo.utxo,
@@ -302,8 +292,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
292 ));
293 }
294
305 - return PSBTTransactionBuild(
306 - inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF)
295 + return PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF)
296 .psbt;
297 }
298
@@ -342,8 +331,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
331 Future<PendingTransaction> createTransaction(Object credentials) async {
332 credentials = credentials as BitcoinTransactionCredentials;
333
345 - final tx = (await super.createTransaction(credentials))
346 - as PendingBitcoinTransaction;
334 + final tx = (await super.createTransaction(credentials)) as PendingBitcoinTransaction;
335
336 final payjoinUri = credentials.payjoinUri;
337 if (payjoinUri == null) return tx;
@@ -366,12 +354,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
354 publicKeys: tx.publicKeys!,
355 masterFingerprint: Uint8List(0));
356
369 - final originalPsbt = await signPsbt(
370 - base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());
357 + final originalPsbt =
358 + await signPsbt(base64.encode(transaction.asPsbtV0()), getUtxoWithPrivateKeys());
359
360 tx.commitOverride = () async {
373 - final sender = await payjoinManager.initSender(
374 - payjoinUri, originalPsbt, int.parse(tx.feeRate));
361 + final sender =
362 + await payjoinManager.initSender(payjoinUri, originalPsbt, int.parse(tx.feeRate));
363 payjoinManager.spawnNewSender(
364 sender: sender, pjUrl: payjoinUri, amount: BigInt.from(tx.amount));
365 };
@@ -387,8 +375,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
375 Future<void> commitPsbt(String finalizedPsbt) {
376 final psbt = PsbtV2()..deserializeV0(base64.decode(finalizedPsbt));
377
390 - final btcTx =
391 - BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract()));
378 + final btcTx = BtcTransaction.fromRaw(BytesUtils.toHexString(psbt.extract()));
379
380 return PendingBitcoinTransaction(
381 btcTx,
@@ -402,12 +389,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
389 ).commit();
390 }
391
405 - Future<String> signPsbt(
406 - String preProcessedPsbt, List<UtxoWithPrivateKey> utxos) async {
392 + Future<String> signPsbt(String preProcessedPsbt, List<UtxoWithPrivateKey> utxos) async {
393 final psbt = PsbtV2()..deserializeV0(base64Decode(preProcessedPsbt));
394
395 await psbt.signWithUTXO(utxos, (txDigest, utxo, key, sighash) {
410 - return utxo.utxo.isP2tr()
396 + return utxo.utxo.isP2tr
397 ? key.signTapRoot(
398 txDigest,
399 sighash: sighash,
@@ -428,17 +414,15 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
414 Future<String> signMessage(String message, {String? address = null}) async {
415 if (walletInfo.isHardwareWallet) {
416 final addressEntry = address != null
431 - ? walletAddresses.allAddresses
432 - .firstWhere((element) => element.address == address)
417 + ? walletAddresses.allAddresses.firstWhere((element) => element.address == address)
418 : null;
419 final index = addressEntry?.index ?? 0;
420 final isChange = addressEntry?.isHidden == true ? 1 : 0;
421 final accountPath = walletInfo.derivationInfo?.derivationPath;
437 - final derivationPath =
438 - accountPath != null ? "$accountPath/$isChange/$index" : null;
422 + final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
423
440 - final signature = await _bitcoinLedgerApp!.signMessage(
441 - message: ascii.encode(message), signDerivationPath: derivationPath);
424 + final signature = await _bitcoinLedgerApp!
425 + .signMessage(message: ascii.encode(message), signDerivationPath: derivationPath);
426 return base64Encode(signature);
427 }
428
cw_bitcoin/lib/bitcoin_wallet_addresses.dart
+2 -2
@@ -47,10 +47,10 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
47 if (addressType == P2pkhAddressType.p2pkh)
48 return generateP2PKHAddress(hd: hd, index: index, network: network);
49
50 - if (addressType == SegwitAddresType.p2tr)
50 + if (addressType == SegwitAddressType.p2tr)
51 return generateP2TRAddress(hd: hd, index: index, network: network);
52
53 - if (addressType == SegwitAddresType.p2wsh)
53 + if (addressType == SegwitAddressType.p2wsh)
54 return generateP2WSHAddress(hd: hd, index: index, network: network);
55
56 if (addressType == P2shAddressType.p2wpkhInP2sh)
cw_bitcoin/lib/electrum_wallet.dart
+284 -59
@@ -5,7 +5,6 @@ import 'dart:isolate';
5
6 import 'package:bitcoin_base/bitcoin_base.dart';
7 import 'package:cw_bitcoin/bitcoin_amount_format.dart';
8 -import 'package:cw_core/format_amount.dart';
8 import 'package:cw_core/utils/print_verbose.dart';
9 import 'package:cw_bitcoin/bitcoin_wallet.dart';
10 import 'package:cw_bitcoin/litecoin_wallet.dart';
@@ -18,7 +17,7 @@ import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
17 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
18 import 'package:cw_bitcoin/bitcoin_unspent.dart';
19 import 'package:cw_bitcoin/bitcoin_wallet_keys.dart';
21 -import 'package:cw_bitcoin/electrum.dart';
20 +import 'package:cw_bitcoin/electrum.dart' as electrum;
21 import 'package:cw_bitcoin/electrum_balance.dart';
22 import 'package:cw_bitcoin/electrum_derivations.dart';
23 import 'package:cw_bitcoin/electrum_transaction_history.dart';
@@ -69,7 +68,7 @@ abstract class ElectrumWalletBase
68 Uint8List? seedBytes,
69 this.passphrase,
70 List<BitcoinAddressRecord>? initialAddresses,
72 - ElectrumClient? electrumClient,
71 + electrum.ElectrumClient? electrumClient,
72 ElectrumBalance? initialBalance,
73 CryptoCurrency? currency,
74 this.alwaysScan,
@@ -96,7 +95,7 @@ abstract class ElectrumWalletBase
95 this.isTestnet = !network.isMainnet,
96 this._mnemonic = mnemonic,
97 super(walletInfo) {
99 - this.electrumClient = electrumClient ?? ElectrumClient();
98 + this.electrumClient = electrumClient ?? electrum.ElectrumClient();
99 this.walletInfo = walletInfo;
100 transactionHistory = ElectrumTransactionHistory(
101 walletInfo: walletInfo,
@@ -167,7 +166,7 @@ abstract class ElectrumWalletBase
166 @observable
167 bool isEnabledAutoGenerateSubaddress;
168
170 - late ElectrumClient electrumClient;
169 + late electrum.ElectrumClient electrumClient;
170 Box<UnspentCoinsInfo> unspentCoinsInfo;
171
172 @override
@@ -182,7 +181,7 @@ abstract class ElectrumWalletBase
181 SyncStatus syncStatus;
182
183 Set<String> get addressesSet => walletAddresses.allAddresses
185 - .where((element) => element.type != SegwitAddresType.mweb)
184 + .where((element) => element.type != SegwitAddressType.mweb)
185 .map((addr) => addr.address)
186 .toSet();
187
@@ -333,14 +332,14 @@ abstract class ElectrumWalletBase
332
333 final receivePort = ReceivePort();
334 _isolate = Isolate.spawn(
336 - startRefresh,
335 + _handleScanSilentPayments,
336 ScanData(
337 sendPort: receivePort.sendPort,
338 silentAddress: walletAddresses.silentAddress!,
339 network: network,
340 height: height,
341 chainTip: chainTip,
343 - electrumClient: ElectrumClient(),
342 + electrumClient: electrum.ElectrumClient(),
343 transactionHistoryIds: transactionHistory.transactions.keys.toList(),
344 node: (await getNodeSupportsSilentPayments()) == true
345 ? ScanNode(node!.uri, node!.useSSL)
@@ -439,7 +438,6 @@ abstract class ElectrumWalletBase
438 BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)),
439 )
440 : silentAddress.B_spend,
442 - network: network,
441 );
442
443 final addressRecord = walletAddresses.silentAddresses
@@ -564,7 +562,7 @@ abstract class ElectrumWalletBase
562 node!.save();
563 return node!.supportsSilentPayments!;
564 }
567 - } on RequestFailedTimeoutException catch (_) {
565 + } on electrum.RequestFailedTimeoutException catch (_) {
566 node!.supportsSilentPayments = false;
567 node!.save();
568 return node!.supportsSilentPayments!;
@@ -625,9 +623,9 @@ abstract class ElectrumWalletBase
623
624 switch (coinTypeToSpendFrom) {
625 case UnspentCoinType.mweb:
628 - return utx.bitcoinAddressRecord.type == SegwitAddresType.mweb;
626 + return utx.bitcoinAddressRecord.type == SegwitAddressType.mweb;
627 case UnspentCoinType.nonMweb:
630 - return utx.bitcoinAddressRecord.type != SegwitAddresType.mweb;
628 + return utx.bitcoinAddressRecord.type != SegwitAddressType.mweb;
629 case UnspentCoinType.any:
630 return true;
631 }
@@ -635,7 +633,7 @@ abstract class ElectrumWalletBase
633 final unconfirmedCoins = availableInputs.where((utx) => utx.confirmations == 0).toList();
634
635 // sort the unconfirmed coins so that mweb coins are last:
638 - availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddresType.mweb ? 1 : -1);
636 + availableInputs.sort((a, b) => a.bitcoinAddressRecord.type == SegwitAddressType.mweb ? 1 : -1);
637
638 for (int i = 0; i < availableInputs.length; i++) {
639 final utx = availableInputs[i];
@@ -643,7 +641,7 @@ abstract class ElectrumWalletBase
641
642 if (paysToSilentPayment) {
643 // Check inputs for shared secret derivation
646 - if (utx.bitcoinAddressRecord.type == SegwitAddresType.p2wsh) {
644 + if (utx.bitcoinAddressRecord.type == SegwitAddressType.p2wsh) {
645 throw BitcoinTransactionSilentPaymentsNotSupported();
646 }
647 }
@@ -678,7 +676,7 @@ abstract class ElectrumWalletBase
676 if (privkey != null) {
677 inputPrivKeyInfos.add(ECPrivateInfo(
678 privkey,
681 - address.type == SegwitAddresType.p2tr,
679 + address.type == SegwitAddressType.p2tr,
680 tweak: !isSilentPayment,
681 ));
682
@@ -1164,7 +1162,7 @@ abstract class ElectrumWalletBase
1162 throw Exception(error);
1163 }
1164
1167 - if (utxo.utxo.isP2tr()) {
1165 + if (utxo.utxo.isP2tr) {
1166 hasTaprootInputs = true;
1167 return key.privkey.signTapRoot(
1168 txDigest,
@@ -1176,20 +1174,18 @@ abstract class ElectrumWalletBase
1174 }
1175 });
1176
1179 - return PendingBitcoinTransaction(
1180 - transaction,
1181 - type,
1182 - electrumClient: electrumClient,
1183 - amount: estimatedTx.amount,
1184 - fee: estimatedTx.fee,
1185 - feeRate: feeRateInt.toString(),
1186 - network: network,
1187 - hasChange: estimatedTx.hasChange,
1188 - isSendAll: estimatedTx.isSendAll,
1189 - hasTaprootInputs: hasTaprootInputs,
1190 - utxos: estimatedTx.utxos,
1191 - publicKeys: estimatedTx.publicKeys
1192 - )..addListener((transaction) async {
1177 + return PendingBitcoinTransaction(transaction, type,
1178 + electrumClient: electrumClient,
1179 + amount: estimatedTx.amount,
1180 + fee: estimatedTx.fee,
1181 + feeRate: feeRateInt.toString(),
1182 + network: network,
1183 + hasChange: estimatedTx.hasChange,
1184 + isSendAll: estimatedTx.isSendAll,
1185 + hasTaprootInputs: hasTaprootInputs,
1186 + utxos: estimatedTx.utxos,
1187 + publicKeys: estimatedTx.publicKeys)
1188 + ..addListener((transaction) async {
1189 transactionHistory.addOne(transaction);
1190 if (estimatedTx.spendsSilentPayment) {
1191 transactionHistory.transactions.values.forEach((tx) {
@@ -1233,7 +1229,7 @@ abstract class ElectrumWalletBase
1229 'change_address_index': walletAddresses.currentChangeAddressIndexByType,
1230 'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
1231 'address_page_type': walletInfo.addressPageType == null
1236 - ? SegwitAddresType.p2wpkh.toString()
1232 + ? SegwitAddressType.p2wpkh.toString()
1233 : walletInfo.addressPageType.toString(),
1234 'balance': balance[currency]?.toJSON(),
1235 'derivationTypeIndex': walletInfo.derivationInfo?.derivationType?.index,
@@ -1373,7 +1369,7 @@ abstract class ElectrumWalletBase
1369 List<BitcoinUnspent> updatedUnspentCoins = [];
1370
1371 final previousUnspentCoins = List<BitcoinUnspent>.from(unspentCoins.where((utxo) =>
1376 - utxo.bitcoinAddressRecord.type != SegwitAddresType.mweb &&
1372 + utxo.bitcoinAddressRecord.type != SegwitAddressType.mweb &&
1373 utxo.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord));
1374
1375 if (hasSilentPaymentsScanning) {
@@ -1387,13 +1383,13 @@ abstract class ElectrumWalletBase
1383
1384 // Set the balance of all non-silent payment and non-mweb addresses to 0 before updating
1385 walletAddresses.allAddresses
1390 - .where((element) => element.type != SegwitAddresType.mweb)
1386 + .where((element) => element.type != SegwitAddressType.mweb)
1387 .forEach((addr) {
1388 if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0;
1389 });
1390
1391 final addressFutures = walletAddresses.allAddresses
1396 - .where((element) => element.type != SegwitAddresType.mweb)
1392 + .where((element) => element.type != SegwitAddressType.mweb)
1393 .map((address) => fetchUnspent(address))
1394 .toList();
1395
@@ -1834,7 +1830,7 @@ abstract class ElectrumWalletBase
1830 throw Exception("Cannot find private key");
1831 }
1832
1837 - if (utxo.utxo.isP2tr()) {
1833 + if (utxo.utxo.isP2tr) {
1834 return key.signTapRoot(txDigest, sighash: sighash);
1835 } else {
1836 return key.signInput(txDigest, sigHash: sighash);
@@ -1984,7 +1980,7 @@ abstract class ElectrumWalletBase
1980 .map((type) => fetchTransactionsForAddressType(historiesWithDetails, type)));
1981 } else if (type == WalletType.litecoin) {
1982 await Future.wait(LITECOIN_ADDRESS_TYPES
1987 - .where((type) => type != SegwitAddresType.mweb)
1983 + .where((type) => type != SegwitAddressType.mweb)
1984 .map((type) => fetchTransactionsForAddressType(historiesWithDetails, type)));
1985 }
1986
@@ -2173,7 +2169,7 @@ abstract class ElectrumWalletBase
2169 final unsubscribedScriptHashes = walletAddresses.allAddresses.where(
2170 (address) =>
2171 !_scripthashesUpdateSubject.containsKey(address.getScriptHash(network)) &&
2176 - address.type != SegwitAddresType.mweb,
2172 + address.type != SegwitAddressType.mweb,
2173 );
2174
2175 await Future.wait(unsubscribedScriptHashes.map((address) async {
@@ -2396,9 +2392,9 @@ abstract class ElectrumWalletBase
2392 derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
2393
2394 @action
2399 - void _onConnectionStatusChange(ConnectionStatus status) {
2395 + void _onConnectionStatusChange(electrum.ConnectionStatus status) {
2396 switch (status) {
2401 - case ConnectionStatus.connected:
2397 + case electrum.ConnectionStatus.connected:
2398 if (syncStatus is NotConnectedSyncStatus ||
2399 syncStatus is LostConnectionSyncStatus ||
2400 syncStatus is ConnectingSyncStatus) {
@@ -2406,19 +2402,19 @@ abstract class ElectrumWalletBase
2402 }
2403
2404 break;
2409 - case ConnectionStatus.disconnected:
2405 + case electrum.ConnectionStatus.disconnected:
2406 if (syncStatus is! NotConnectedSyncStatus &&
2407 syncStatus is! ConnectingSyncStatus &&
2408 syncStatus is! SyncronizingSyncStatus) {
2409 syncStatus = NotConnectedSyncStatus();
2410 }
2411 break;
2416 - case ConnectionStatus.failed:
2412 + case electrum.ConnectionStatus.failed:
2413 if (syncStatus is! LostConnectionSyncStatus) {
2414 syncStatus = LostConnectionSyncStatus();
2415 }
2416 break;
2421 - case ConnectionStatus.connecting:
2417 + case electrum.ConnectionStatus.connecting:
2418 if (syncStatus is! ConnectingSyncStatus) {
2419 syncStatus = ConnectingSyncStatus();
2420 }
@@ -2530,7 +2526,7 @@ class ScanData {
2526 final ScanNode? node;
2527 final BasedUtxoNetwork network;
2528 final int chainTip;
2533 - final ElectrumClient electrumClient;
2529 + final electrum.ElectrumClient electrumClient;
2530 final List<String> transactionHistoryIds;
2531 final Map<String, String> labels;
2532 final List<int> labelIndexes;
@@ -2574,6 +2570,234 @@ class SyncResponse {
2570 SyncResponse(this.height, this.syncStatus);
2571 }
2572
2573 +Future<void> _handleScanSilentPayments(ScanData scanData) async {
2574 + try {
2575 + // if (scanData.shouldSwitchNodes) {
2576 + var scanningClient = await ElectrumProvider.connect(
2577 + ElectrumTCPService.connect(
2578 + Uri.parse("tcp://electrs.cakewallet.com:50001"),
2579 + ),
2580 + );
2581 + // }
2582 +
2583 + int syncHeight = scanData.height;
2584 + int initialSyncHeight = syncHeight;
2585 +
2586 + final receiver = Receiver(
2587 + scanData.silentAddress.b_scan.toHex(),
2588 + scanData.silentAddress.B_spend.toHex(),
2589 + scanData.network == BitcoinNetwork.testnet,
2590 + scanData.labelIndexes,
2591 + );
2592 +
2593 + int getCountToScanPerRequest(int syncHeight) {
2594 + if (scanData.isSingleScan) {
2595 + return 1;
2596 + }
2597 +
2598 + final amountLeft = scanData.chainTip - syncHeight + 1;
2599 + return amountLeft;
2600 + }
2601 +
2602 + // Initial status UI update, send how many blocks in total to scan
2603 + scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
2604 +
2605 + final req = ElectrumTweaksSubscribe(
2606 + height: syncHeight,
2607 + count: getCountToScanPerRequest(syncHeight),
2608 + historicalMode: false,
2609 + );
2610 +
2611 + var _scanningStream = await scanningClient.subscribe(req);
2612 +
2613 + void listenFn(Map<String, dynamic> event, ElectrumTweaksSubscribe req) {
2614 + final response = req.onResponse(event);
2615 +
2616 + if (response == null || _scanningStream == null) {
2617 + return;
2618 + }
2619 +
2620 + // is success or error msg
2621 + final noData = response.message != null;
2622 +
2623 + if (noData) {
2624 + if (scanData.isSingleScan) {
2625 + return;
2626 + }
2627 +
2628 + // re-subscribe to continue receiving messages, starting from the next unscanned height
2629 + final nextHeight = syncHeight + 1;
2630 +
2631 + if (nextHeight <= scanData.chainTip) {
2632 + final nextStream = scanningClient.subscribe(
2633 + ElectrumTweaksSubscribe(
2634 + height: nextHeight,
2635 + count: getCountToScanPerRequest(nextHeight),
2636 + historicalMode: false,
2637 + ),
2638 + );
2639 +
2640 + if (nextStream != null) {
2641 + nextStream.listen((event) => listenFn(event, req));
2642 + } else {
2643 + scanData.sendPort.send(
2644 + SyncResponse(scanData.height, LostConnectionSyncStatus()),
2645 + );
2646 + }
2647 + }
2648 +
2649 + return;
2650 + }
2651 +
2652 + final tweakHeight = response.block;
2653 +
2654 + if (initialSyncHeight < tweakHeight) initialSyncHeight = tweakHeight;
2655 +
2656 + // Continuous status UI update, send how many blocks left to scan
2657 + final syncingStatus = scanData.isSingleScan
2658 + ? SyncingSyncStatus(1, 0)
2659 + : SyncingSyncStatus.fromHeightValues(scanData.chainTip, initialSyncHeight, tweakHeight);
2660 +
2661 + scanData.sendPort.send(SyncResponse(syncHeight, syncingStatus));
2662 +
2663 + try {
2664 + final blockTweaks = response.blockTweaks;
2665 +
2666 + for (final txid in blockTweaks.keys) {
2667 + final tweakData = blockTweaks[txid];
2668 + final outputPubkeys = tweakData!.outputPubkeys;
2669 + final tweak = tweakData.tweak;
2670 +
2671 + try {
2672 + final addToWallet = {};
2673 +
2674 + // receivers.forEach((receiver) {
2675 + // NOTE: scanOutputs, from sp_scanner package, called from rust here
2676 + final scanResult = scanOutputs([outputPubkeys.keys.toList()], tweak, receiver);
2677 +
2678 + if (scanResult.isEmpty) {
2679 + continue;
2680 + }
2681 +
2682 + if (addToWallet[receiver.BSpend] == null) {
2683 + addToWallet[receiver.BSpend] = scanResult;
2684 + } else {
2685 + addToWallet[receiver.BSpend].addAll(scanResult);
2686 + }
2687 + // });
2688 +
2689 + if (addToWallet.isEmpty) {
2690 + // no results tx, continue to next tx
2691 + continue;
2692 + }
2693 +
2694 + // initial placeholder ElectrumTransactionInfo object to update values based on new scanned unspent(s) on the following loop
2695 + final txInfo = ElectrumTransactionInfo(
2696 + WalletType.bitcoin,
2697 + id: txid,
2698 + height: tweakHeight,
2699 + amount: 0,
2700 + fee: 0,
2701 + direction: TransactionDirection.incoming,
2702 + isReplaced: false,
2703 + date: DateTime.fromMillisecondsSinceEpoch(
2704 + DateTime.now().millisecondsSinceEpoch * 1000,
2705 + ),
2706 + confirmations: scanData.chainTip - tweakHeight + 1,
2707 + isReceivedSilentPayment: true,
2708 + isPending: false,
2709 + unspents: [],
2710 + );
2711 +
2712 + List<BitcoinUnspent> unspents = [];
2713 +
2714 + addToWallet.forEach((BSpend, scanResultPerLabel) {
2715 + scanResultPerLabel.forEach((label, scanOutput) {
2716 + final labelValue = label == "None" ? null : label.toString();
2717 +
2718 + (scanOutput as Map<String, dynamic>).forEach((outputPubkey, tweak) {
2719 + final t_k = tweak as String;
2720 +
2721 + final receivingOutputAddress = ECPublic.fromHex(outputPubkey)
2722 + .toTaprootAddress(tweak: false)
2723 + .toAddress(scanData.network);
2724 +
2725 + final matchingOutput = outputPubkeys[outputPubkey]!;
2726 + final amount = matchingOutput.amount;
2727 + final pos = matchingOutput.vout;
2728 +
2729 + // final matchingSPWallet = scanData.silentPaymentsWallets.firstWhere(
2730 + // (receiver) => receiver.B_spend.toHex() == BSpend.toString(),
2731 + // );
2732 +
2733 + // final labelIndex = labelValue != null ? scanData.labels[label] : 0;
2734 + // final balance = ElectrumBalance();
2735 + // balance.confirmed = amount;
2736 +
2737 + final receivedAddressRecord = BitcoinSilentPaymentAddressRecord(
2738 + receivingOutputAddress,
2739 + index: 0,
2740 + isHidden: false,
2741 + isUsed: true,
2742 + network: scanData.network,
2743 + silentPaymentTweak: t_k,
2744 + type: SegwitAddressType.p2tr,
2745 + txCount: 1,
2746 + balance: amount,
2747 + );
2748 +
2749 + final unspent = BitcoinSilentPaymentsUnspent(
2750 + receivedAddressRecord,
2751 + txid,
2752 + amount,
2753 + pos,
2754 + silentPaymentTweak: t_k,
2755 + silentPaymentLabel: labelValue,
2756 + );
2757 +
2758 + unspents.add(unspent);
2759 + txInfo.unspents!.add(unspent);
2760 + txInfo.amount += unspent.value;
2761 + });
2762 + });
2763 + });
2764 +
2765 + scanData.sendPort.send({txInfo.id: txInfo});
2766 + } catch (e, stacktrace) {
2767 + printV(stacktrace);
2768 + printV(e.toString());
2769 + }
2770 + }
2771 + } catch (e, stacktrace) {
2772 + printV(stacktrace);
2773 + printV(e.toString());
2774 + }
2775 +
2776 + syncHeight = tweakHeight;
2777 +
2778 + if ((tweakHeight >= scanData.chainTip) || scanData.isSingleScan) {
2779 + if (tweakHeight >= scanData.chainTip)
2780 + scanData.sendPort.send(
2781 + SyncResponse(syncHeight, SyncedTipSyncStatus(scanData.chainTip)),
2782 + );
2783 +
2784 + if (scanData.isSingleScan) {
2785 + scanData.sendPort.send(SyncResponse(syncHeight, SyncedSyncStatus()));
2786 + }
2787 +
2788 + _scanningStream?.close();
2789 + _scanningStream = null;
2790 + return;
2791 + }
2792 + }
2793 +
2794 + _scanningStream?.listen((event) => listenFn(event, req));
2795 + } catch (e) {
2796 + printV("Error in _handleScanSilentPayments: $e");
2797 + scanData.sendPort.send(SyncResponse(scanData.height, LostConnectionSyncStatus()));
2798 + }
2799 +}
2800 +
2801 Future<void> startRefresh(ScanData scanData) async {
2802 int syncHeight = scanData.height;
2803 int initialSyncHeight = syncHeight;
@@ -2586,7 +2810,7 @@ Future<void> startRefresh(ScanData scanData) async {
2810 useSSL: scanData.node?.useSSL ?? false,
2811 );
2812
2589 - int getCountPerRequest(int syncHeight) {
2813 + int getCountToScanPerRequest(int syncHeight) {
2814 if (scanData.isSingleScan) {
2815 return 1;
2816 }
@@ -2601,11 +2825,10 @@ Future<void> startRefresh(ScanData scanData) async {
2825 scanData.silentAddress.B_spend.toHex(),
2826 scanData.network == BitcoinNetwork.testnet,
2827 scanData.labelIndexes,
2604 - scanData.labelIndexes.length,
2828 );
2829
2830 // Initial status UI update, send how many blocks in total to scan
2608 - final initialCount = getCountPerRequest(syncHeight);
2831 + final initialCount = getCountToScanPerRequest(syncHeight);
2832 scanData.sendPort.send(SyncResponse(syncHeight, StartingScanSyncStatus(syncHeight)));
2833
2834 tweaksSubscription = await electrumClient.tweaksSubscribe(
@@ -2616,22 +2839,24 @@ Future<void> startRefresh(ScanData scanData) async {
2839 Future<void> listenFn(t) async {
2840 final tweaks = t as Map<String, dynamic>;
2841 final msg = tweaks["message"];
2619 - // success or error msg
2842 +
2843 + // is success or error msg
2844 final noData = msg != null;
2845
2846 if (noData) {
2847 + if (scanData.isSingleScan) {
2848 + return;
2849 + }
2850 +
2851 // re-subscribe to continue receiving messages, starting from the next unscanned height
2852 final nextHeight = syncHeight + 1;
2625 - final nextCount = getCountPerRequest(nextHeight);
2626 -
2627 - if (nextCount > 0) {
2628 - tweaksSubscription?.close();
2853
2630 - final nextTweaksSubscription = electrumClient.tweaksSubscribe(
2854 + if (nextHeight <= scanData.chainTip) {
2855 + final nextStream = electrumClient.tweaksSubscribe(
2856 height: nextHeight,
2632 - count: nextCount,
2857 + count: getCountToScanPerRequest(nextHeight),
2858 );
2634 - nextTweaksSubscription?.listen(listenFn);
2859 + nextStream?.listen(listenFn);
2860 }
2861
2862 return;
@@ -2713,7 +2938,7 @@ Future<void> startRefresh(ScanData scanData) async {
2938 isUsed: true,
2939 network: scanData.network,
2940 silentPaymentTweak: t_k,
2716 - type: SegwitAddresType.p2tr,
2941 + type: SegwitAddressType.p2tr,
2942 txCount: 1,
2943 balance: amount!,
2944 );
@@ -2806,15 +3031,15 @@ BitcoinAddressType _getScriptType(BitcoinBaseAddress type) {
3031 } else if (type is P2shAddress) {
3032 return P2shAddressType.p2wpkhInP2sh;
3033 } else if (type is P2wshAddress) {
2809 - return SegwitAddresType.p2wsh;
3034 + return SegwitAddressType.p2wsh;
3035 } else if (type is P2trAddress) {
2811 - return SegwitAddresType.p2tr;
3036 + return SegwitAddressType.p2tr;
3037 } else if (type is MwebAddress) {
2813 - return SegwitAddresType.mweb;
3038 + return SegwitAddressType.mweb;
3039 } else if (type is SilentPaymentsAddresType) {
3040 return SilentPaymentsAddresType.p2sp;
3041 } else {
2817 - return SegwitAddresType.p2wpkh;
3042 + return SegwitAddressType.p2wpkh;
3043 }
3044 }
3045
cw_bitcoin/lib/electrum_wallet_addresses.dart
+31 -27
@@ -17,16 +17,16 @@ part 'electrum_wallet_addresses.g.dart';
17 class ElectrumWalletAddresses = ElectrumWalletAddressesBase with _$ElectrumWalletAddresses;
18
19 const List<BitcoinAddressType> BITCOIN_ADDRESS_TYPES = [
20 - SegwitAddresType.p2wpkh,
20 + SegwitAddressType.p2wpkh,
21 P2pkhAddressType.p2pkh,
22 - SegwitAddresType.p2tr,
23 - SegwitAddresType.p2wsh,
22 + SegwitAddressType.p2tr,
23 + SegwitAddressType.p2wsh,
24 P2shAddressType.p2wpkhInP2sh,
25 ];
26
27 const List<BitcoinAddressType> LITECOIN_ADDRESS_TYPES = [
28 - SegwitAddresType.p2wpkh,
29 - SegwitAddresType.mweb,
28 + SegwitAddressType.p2wpkh,
29 + SegwitAddressType.mweb,
30 ];
31
32 const List<BitcoinAddressType> BITCOIN_CASH_ADDRESS_TYPES = [
@@ -62,7 +62,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
62 _addressPageType = initialAddressPageType ??
63 (walletInfo.addressPageType != null
64 ? BitcoinAddressType.fromValue(walletInfo.addressPageType!)
65 - : SegwitAddresType.p2wpkh),
65 + : SegwitAddressType.p2wpkh),
66 silentAddresses = ObservableList<BitcoinSilentPaymentAddressRecord>.of(
67 (initialSilentAddresses ?? []).toSet()),
68 currentSilentAddressIndex = initialSilentAddressIndex,
@@ -71,9 +71,12 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
71 super(walletInfo) {
72 if (masterHd != null) {
73 silentAddress = SilentPaymentOwner.fromPrivateKeys(
74 - b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()),
75 - b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()),
76 - network: network,
74 + b_scan: ECPrivate.fromHex(
75 + masterHd.derivePath("m/352'/1'/0'/1'/0").privateKey.toHex(),
76 + ),
77 + b_spend: ECPrivate.fromHex(
78 + masterHd.derivePath("m/352'/1'/0'/0'/0").privateKey.toHex(),
79 + ),
80 );
81
82 if (silentAddresses.length == 0) {
@@ -144,12 +147,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
147 return silentAddress.toString();
148 }
149
147 - final typeMatchingAddresses = _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList();
148 - final typeMatchingReceiveAddresses = typeMatchingAddresses.where((addr) => !addr.isUsed).toList();
150 + final typeMatchingAddresses =
151 + _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList();
152 + final typeMatchingReceiveAddresses =
153 + typeMatchingAddresses.where((addr) => !addr.isUsed).toList();
154
155 if (!isEnabledAutoGenerateSubaddress) {
151 - if (previousAddressRecord != null &&
152 - previousAddressRecord!.type == addressPageType) {
156 + if (previousAddressRecord != null && previousAddressRecord!.type == addressPageType) {
157 return previousAddressRecord!.address;
158 }
159
@@ -249,17 +253,17 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
253 if (walletInfo.type == WalletType.bitcoinCash) {
254 await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
255 } else if (walletInfo.type == WalletType.litecoin) {
252 - await _generateInitialAddresses(type: SegwitAddresType.p2wpkh);
256 + await _generateInitialAddresses(type: SegwitAddressType.p2wpkh);
257 if ((Platform.isAndroid || Platform.isIOS) && !isHardwareWallet) {
254 - await _generateInitialAddresses(type: SegwitAddresType.mweb);
258 + await _generateInitialAddresses(type: SegwitAddressType.mweb);
259 }
260 } else if (walletInfo.type == WalletType.bitcoin) {
261 await _generateInitialAddresses();
262 if (!isHardwareWallet) {
263 await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
264 await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh);
261 - await _generateInitialAddresses(type: SegwitAddresType.p2tr);
262 - await _generateInitialAddresses(type: SegwitAddresType.p2wsh);
265 + await _generateInitialAddresses(type: SegwitAddressType.p2tr);
266 + await _generateInitialAddresses(type: SegwitAddressType.p2wsh);
267 }
268 }
269
@@ -323,7 +327,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
327 BaseBitcoinAddressRecord generateNewAddress({String label = ''}) {
328 if (addressPageType == SilentPaymentsAddresType.p2sp && silentAddress != null) {
329 final currentSilentAddressIndex = silentAddresses
326 - .where((addressRecord) => addressRecord.type != SegwitAddresType.p2tr)
330 + .where((addressRecord) => addressRecord.type != SegwitAddressType.p2tr)
331 .length -
332 1;
333
@@ -381,7 +385,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
385 void addBitcoinAddressTypes() {
386 final lastP2wpkh = _addresses
387 .where((addressRecord) =>
384 - _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh))
388 + _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wpkh))
389 .toList()
390 .last;
391 if (lastP2wpkh.address != address) {
@@ -407,7 +411,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
411 }
412
413 final lastP2tr = _addresses.firstWhere(
410 - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2tr));
414 + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2tr));
415 if (lastP2tr.address != address) {
416 addressesMap[lastP2tr.address] = 'P2TR';
417 } else {
@@ -415,7 +419,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
419 }
420
421 final lastP2wsh = _addresses.firstWhere(
418 - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wsh));
422 + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wsh));
423 if (lastP2wsh.address != address) {
424 addressesMap[lastP2wsh.address] = 'P2WSH';
425 } else {
@@ -440,7 +444,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
444 void addLitecoinAddressTypes() {
445 final lastP2wpkh = _addresses
446 .where((addressRecord) =>
443 - _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.p2wpkh))
447 + _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.p2wpkh))
448 .toList()
449 .last;
450 if (lastP2wpkh.address != address) {
@@ -450,7 +454,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
454 }
455
456 final lastMweb = _addresses.firstWhere(
453 - (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddresType.mweb));
457 + (addressRecord) => _isUnusedReceiveAddressByType(addressRecord, SegwitAddressType.mweb));
458 if (lastMweb.address != address) {
459 addressesMap[lastMweb.address] = 'MWEB';
460 } else {
@@ -560,14 +564,14 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
564 addressRecord.isHidden &&
565 !addressRecord.isUsed &&
566 // TODO: feature to change change address type. For now fixed to p2wpkh, the cheapest type
563 - (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddresType.p2wpkh));
567 + (walletInfo.type != WalletType.bitcoin || addressRecord.type == SegwitAddressType.p2wpkh));
568 changeAddresses.addAll(newAddresses);
569 }
570
571 @action
572 Future<void> discoverAddresses(List<BitcoinAddressRecord> addressList, bool isHidden,
573 Future<String?> Function(BitcoinAddressRecord) getAddressHistory,
570 - {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
574 + {BitcoinAddressType type = SegwitAddressType.p2wpkh}) async {
575 final newAddresses = await _createNewAddresses(gap,
576 startIndex: addressList.length, isHidden: isHidden, type: type);
577 addAddresses(newAddresses);
@@ -581,7 +585,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
585 }
586
587 Future<void> _generateInitialAddresses(
584 - {BitcoinAddressType type = SegwitAddresType.p2wpkh}) async {
588 + {BitcoinAddressType type = SegwitAddressType.p2wpkh}) async {
589 var countOfReceiveAddresses = 0;
590 var countOfHiddenAddresses = 0;
591
@@ -658,7 +662,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
662
663 void _validateAddresses() {
664 _addresses.forEach((element) async {
661 - if (element.type == SegwitAddresType.mweb) {
665 + if (element.type == SegwitAddressType.mweb) {
666 // this would add a ton of startup lag for mweb addresses since we have 1000 of them
667 return;
668 }
cw_bitcoin/lib/electrum_wallet_snapshot.dart
+4 -4
@@ -87,8 +87,8 @@ class ElectrumWalletSnapshot {
87
88 final balance = ElectrumBalance.fromJSON(data['balance'] as String?) ??
89 ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
90 - var regularAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
91 - var changeAddressIndexByType = {SegwitAddresType.p2wpkh.toString(): 0};
90 + var regularAddressIndexByType = {SegwitAddressType.p2wpkh.toString(): 0};
91 + var changeAddressIndexByType = {SegwitAddressType.p2wpkh.toString(): 0};
92 var silentAddressIndex = 0;
93
94 final derivationType = DerivationType
@@ -97,10 +97,10 @@ class ElectrumWalletSnapshot {
97
98 try {
99 regularAddressIndexByType = {
100 - SegwitAddresType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0')
100 + SegwitAddressType.p2wpkh.toString(): int.parse(data['account_index'] as String? ?? '0')
101 };
102 changeAddressIndexByType = {
103 - SegwitAddresType.p2wpkh.toString():
103 + SegwitAddressType.p2wpkh.toString():
104 int.parse(data['change_address_index'] as String? ?? '0')
105 };
106 silentAddressIndex = int.parse(data['silent_address_index'] as String? ?? '0');
cw_bitcoin/lib/litecoin_wallet.dart
+9 -8
@@ -16,7 +16,6 @@ import 'package:fixnum/fixnum.dart';
16 import 'package:bip39/bip39.dart' as bip39;
17 import 'package:bitcoin_base/bitcoin_base.dart';
18 import 'package:blockchain_utils/blockchain_utils.dart';
19 -import 'package:blockchain_utils/signer/ecdsa_signing_key.dart';
19 import 'package:cw_bitcoin/bitcoin_address_record.dart';
20 import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
21 import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
@@ -971,9 +970,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
970 List<ECPrivateInfo>? inputPrivKeyInfos,
971 List<Outpoint>? vinOutpoints,
972 }) async {
974 - bool spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddresType.mweb);
973 + bool spendsMweb = utxos.any((utxo) => utxo.utxo.scriptType == SegwitAddressType.mweb);
974 bool paysToMweb = outputs
976 - .any((output) => output.toOutput.scriptPubKey.getAddressType() == SegwitAddresType.mweb);
975 + .any((output) => output.toOutput.scriptPubKey.getAddressType() == SegwitAddressType.mweb);
976
977 bool isRegular = !spendsMweb && !paysToMweb;
978 bool isMweb = spendsMweb || paysToMweb;
@@ -1064,9 +1063,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
1063 tx.isMweb = mwebEnabled;
1064
1065 if (!mwebEnabled) {
1067 - tx.changeAddressOverride =
1068 - (await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb))
1069 - .address;
1066 + tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses)
1067 + .getChangeAddress(coinTypeToSpendFrom: UnspentCoinType.nonMweb))
1068 + .address;
1069 return tx;
1070 }
1071 await waitForMwebAddresses();
@@ -1108,7 +1107,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
1107
1108 // check if mweb inputs are used:
1109 for (final utxo in tx.utxos) {
1111 - if (utxo.utxo.scriptType == SegwitAddresType.mweb) {
1110 + if (utxo.utxo.scriptType == SegwitAddressType.mweb) {
1111 hasMwebInput = true;
1112 }
1113 }
@@ -1119,7 +1118,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
1118 bool isRegular = !hasMwebInput && !hasMwebOutput;
1119 bool shouldNotUseMwebChange = isPegIn || isRegular || !hasMwebInput;
1120 tx.changeAddressOverride = (await (walletAddresses as LitecoinWalletAddresses)
1122 - .getChangeAddress(coinTypeToSpendFrom: shouldNotUseMwebChange ? UnspentCoinType.nonMweb : UnspentCoinType.any))
1121 + .getChangeAddress(
1122 + coinTypeToSpendFrom:
1123 + shouldNotUseMwebChange ? UnspentCoinType.nonMweb : UnspentCoinType.any))
1124 .address;
1125 if (isRegular) {
1126 tx.isMweb = false;
cw_bitcoin/lib/litecoin_wallet_addresses.dart
+5 -5
@@ -106,7 +106,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
106 .map((e) => BitcoinAddressRecord(
107 e.value,
108 index: e.key,
109 - type: SegwitAddresType.mweb,
109 + type: SegwitAddressType.mweb,
110 network: network,
111 ))
112 .toList();
@@ -128,7 +128,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
128 required Bip32Slip10Secp256k1 hd,
129 BitcoinAddressType? addressType,
130 }) {
131 - if (addressType == SegwitAddresType.mweb) {
131 + if (addressType == SegwitAddressType.mweb) {
132 return hd == sideHd ? mwebAddrs[0] : mwebAddrs[index + 1];
133 }
134 return generateP2WPKHAddress(hd: hd, index: index, network: network);
@@ -140,7 +140,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
140 required Bip32Slip10Secp256k1 hd,
141 BitcoinAddressType? addressType,
142 }) async {
143 - if (addressType == SegwitAddresType.mweb) {
143 + if (addressType == SegwitAddressType.mweb) {
144 await ensureMwebAddressUpToIndexExists(index);
145 }
146 return getAddress(index: index, hd: hd, addressType: addressType);
@@ -195,7 +195,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
195 return BitcoinAddressRecord(
196 mwebAddrs[0],
197 index: 0,
198 - type: SegwitAddresType.mweb,
198 + type: SegwitAddressType.mweb,
199 network: network,
200 );
201 }
@@ -207,7 +207,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
207 String get addressForExchange {
208 // don't use mweb addresses for exchange refund address:
209 final addresses = receiveAddresses
210 - .where((element) => element.type == SegwitAddresType.p2wpkh && !element.isUsed);
210 + .where((element) => element.type == SegwitAddressType.p2wpkh && !element.isUsed);
211 return addresses.first.address;
212 }
213 }
cw_bitcoin/lib/payjoin/manager.dart
+10 -18
@@ -31,8 +31,8 @@ class PayjoinManager {
31 'https://ohttp.cakewallet.com',
32 ];
33
34 - static Future<PayjoinUri.Url> randomOhttpRelayUrl() => PayjoinUri.Url.fromStr(
35 - ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]);
34 + static Future<PayjoinUri.Url> randomOhttpRelayUrl() =>
35 + PayjoinUri.Url.fromStr(ohttpRelayUrls[Random.secure().nextInt(ohttpRelayUrls.length)]);
36
37 static const payjoinDirectoryUrl = 'https://payjo.in';
38
@@ -59,8 +59,7 @@ class PayjoinManager {
59 Future<Sender> initSender(
60 String pjUriString, String originalPsbt, int networkFeesSatPerVb) async {
61 try {
62 - final pjUri =
63 - (await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported();
62 + final pjUri = (await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported();
63 final minFeeRateSatPerKwu = BigInt.from(networkFeesSatPerVb * 250);
64 final senderBuilder = await SenderBuilder.fromPsbtAndUri(
65 psbtBase64: originalPsbt,
@@ -79,8 +78,7 @@ class PayjoinManager {
78 bool isTestnet = false,
79 }) async {
80 final pjUri = Uri.parse(pjUrl).queryParameters['pj']!;
82 - await _payjoinStorage.insertSenderSession(
83 - sender, pjUri, _wallet.id, amount);
81 + await _payjoinStorage.insertSenderSession(sender, pjUri, _wallet.id, amount);
82
83 return _spawnSender(isTestnet: isTestnet, sender: sender, pjUri: pjUri);
84 }
@@ -140,11 +138,9 @@ class PayjoinManager {
138 return completer.future;
139 }
140
143 - Future<Receiver> initReceiver(String address,
144 - [bool isTestnet = false]) async {
141 + Future<Receiver> initReceiver(String address, [bool isTestnet = false]) async {
142 try {
146 - final payjoinDirectory =
147 - await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
143 + final payjoinDirectory = await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
144
145 final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
146 ohttpRelay: await randomOhttpRelayUrl(),
@@ -199,8 +195,7 @@ class PayjoinManager {
195 _payjoinStorage.markReceiverSessionInProgress(receiver.id());
196
197 final inputScript = message['input_script'] as Uint8List;
202 - final isOwned =
203 - _wallet.isMine(Script.fromRaw(byteData: inputScript));
198 + final isOwned = _wallet.isMine(Script.fromRaw(bytes: inputScript));
199 mainToIsolateSendPort?.send({
200 'requestId': message['requestId'],
201 'result': isOwned,
@@ -209,8 +204,7 @@ class PayjoinManager {
204
205 case PayjoinReceiverRequestTypes.checkIsReceiverOutput:
206 final outputScript = message['output_script'] as Uint8List;
212 - final isReceiverOutput =
213 - _wallet.isMine(Script.fromRaw(byteData: outputScript));
207 + final isReceiverOutput = _wallet.isMine(Script.fromRaw(bytes: outputScript));
208 mainToIsolateSendPort?.send({
209 'requestId': message['requestId'],
210 'result': isReceiverOutput,
@@ -243,15 +237,13 @@ class PayjoinManager {
237 }
238 } catch (e) {
239 _cleanupSession(receiver.id());
246 - await _payjoinStorage.markReceiverSessionUnrecoverable(
247 - receiver.id(), e.toString());
240 + await _payjoinStorage.markReceiverSessionUnrecoverable(receiver.id(), e.toString());
241 completer.completeError(e);
242 }
243 } else if (message is PayjoinSessionError) {
244 _cleanupSession(receiver.id());
245 if (message is UnrecoverableError) {
253 - await _payjoinStorage.markReceiverSessionUnrecoverable(
254 - receiver.id(), message.message);
246 + await _payjoinStorage.markReceiverSessionUnrecoverable(receiver.id(), message.message);
247 completer.complete();
248 } else if (message is RecoverableError) {
249 completer.complete();
cw_bitcoin/lib/psbt/signer.dart
+29 -49
@@ -40,8 +40,7 @@ extension PsbtSigner on PsbtV2 {
40 return tx.buffer();
41 }
42
43 - Future<void> signWithUTXO(
44 - List<UtxoWithPrivateKey> utxos, UTXOSignerCallBack signer,
43 + Future<void> signWithUTXO(List<UtxoWithPrivateKey> utxos, UTXOSignerCallBack signer,
44 [UTXOGetterCallBack? getTaprootPair]) async {
45 final raw = BytesUtils.toHexString(extractUnsignedTX(getSegwit: false));
46 final tx = BtcTransaction.fromRaw(raw);
@@ -51,10 +50,10 @@ extension PsbtSigner on PsbtV2 {
50 List<BigInt> taprootAmounts = [];
51 List<Script> taprootScripts = [];
52
54 - if (utxos.any((e) => e.utxo.isP2tr())) {
53 + if (utxos.any((e) => e.utxo.isP2tr)) {
54 for (final input in tx.inputs) {
56 - final utxo = utxos.firstWhereOrNull(
57 - (u) => u.utxo.txHash == input.txId && u.utxo.vout == input.txIndex);
55 + final utxo = utxos
56 + .firstWhereOrNull((u) => u.utxo.txHash == input.txId && u.utxo.vout == input.txIndex);
57
58 if (utxo == null) {
59 final trPair = await getTaprootPair!.call(input.txId, input.txIndex);
@@ -76,37 +75,29 @@ extension PsbtSigner on PsbtV2 {
75 /// We receive the owner's ScriptPubKey
76 final script = _findLockingScript(utxo, false);
77
79 - final int sighash = utxo.utxo.isP2tr()
80 - ? BitcoinOpCodeConst.TAPROOT_SIGHASH_ALL
81 - : BitcoinOpCodeConst.SIGHASH_ALL;
78 + final int sighash =
79 + utxo.utxo.isP2tr ? BitcoinOpCodeConst.sighashDefault : BitcoinOpCodeConst.sighashAll;
80
81 /// We generate transaction digest for current input
84 - final digest = _generateTransactionDigest(
85 - script, i, utxo.utxo, tx, taprootAmounts, taprootScripts);
82 + final digest =
83 + _generateTransactionDigest(script, i, utxo.utxo, tx, taprootAmounts, taprootScripts);
84
85 /// now we need sign the transaction digest
86 final sig = signer(digest, utxo, utxo.privateKey, sighash);
87
90 - if (utxo.utxo.isP2tr()) {
88 + if (utxo.utxo.isP2tr) {
89 setInputTapKeySig(i, Uint8List.fromList(BytesUtils.fromHexString(sig)));
90 } else {
93 - setInputPartialSig(
94 - i,
95 - Uint8List.fromList(BytesUtils.fromHexString(utxo.public().toHex())),
91 + setInputPartialSig(i, Uint8List.fromList(BytesUtils.fromHexString(utxo.public().toHex())),
92 Uint8List.fromList(BytesUtils.fromHexString(sig)));
93 }
94 }
95 }
96
101 - List<int> _generateTransactionDigest(
102 - Script scriptPubKeys,
103 - int input,
104 - BitcoinUtxo utxo,
105 - BtcTransaction transaction,
106 - List<BigInt> taprootAmounts,
107 - List<Script> tapRootPubKeys) {
108 - if (utxo.isSegwit()) {
109 - if (utxo.isP2tr()) {
97 + List<int> _generateTransactionDigest(Script scriptPubKeys, int input, BitcoinUtxo utxo,
98 + BtcTransaction transaction, List<BigInt> taprootAmounts, List<Script> tapRootPubKeys) {
99 + if (utxo.isSegwit) {
100 + if (utxo.isP2tr) {
101 return transaction.getTransactionTaprootDigset(
102 txIndex: input,
103 scriptPubKeys: tapRootPubKeys,
@@ -116,8 +107,7 @@ extension PsbtSigner on PsbtV2 {
107 return transaction.getTransactionSegwitDigit(
108 txInIndex: input, script: scriptPubKeys, amount: utxo.value);
109 }
119 - return transaction.getTransactionDigest(
120 - txInIndex: input, script: scriptPubKeys);
110 + return transaction.getTransactionDigest(txInIndex: input, script: scriptPubKeys);
111 }
112
113 Script _findLockingScript(UtxoWithAddress utxo, bool isTaproot) {
@@ -129,23 +119,23 @@ extension PsbtSigner on PsbtV2 {
119 switch (utxo.utxo.scriptType) {
120 case PubKeyAddressType.p2pk:
121 return senderPub.toRedeemScript();
132 - case SegwitAddresType.p2wsh:
122 + case SegwitAddressType.p2wsh:
123 if (isTaproot) {
124 return senderPub.toP2wshAddress().toScriptPubKey();
125 }
126 return senderPub.toP2wshRedeemScript();
127 case P2pkhAddressType.p2pkh:
128 return senderPub.toP2pkhAddress().toScriptPubKey();
139 - case SegwitAddresType.p2wpkh:
129 + case SegwitAddressType.p2wpkh:
130 if (isTaproot) {
131 return senderPub.toP2wpkhAddress().toScriptPubKey();
132 }
133 return senderPub.toP2pkhAddress().toScriptPubKey();
144 - case SegwitAddresType.p2tr:
134 + case SegwitAddressType.p2tr:
135 return senderPub
136 .toTaprootAddress(tweak: utxo.utxo.isSilentPayment != true)
137 .toScriptPubKey();
148 - case SegwitAddresType.mweb:
138 + case SegwitAddressType.mweb:
139 return Script(script: []);
140 case P2shAddressType.p2pkhInP2sh:
141 if (isTaproot) {
@@ -172,11 +162,10 @@ extension PsbtSigner on PsbtV2 {
162 }
163 }
164
175 -typedef UTXOSignerCallBack = String Function(List<int> trDigest,
176 - UtxoWithAddress utxo, ECPrivate privateKey, int sighash);
165 +typedef UTXOSignerCallBack = String Function(
166 + List<int> trDigest, UtxoWithAddress utxo, ECPrivate privateKey, int sighash);
167
178 -typedef UTXOGetterCallBack = Future<TaprootAmountScriptPair> Function(
179 - String txId, int vout);
168 +typedef UTXOGetterCallBack = Future<TaprootAmountScriptPair> Function(String txId, int vout);
169
170 class TaprootAmountScriptPair {
171 final BigInt value;
@@ -216,23 +205,17 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
205 }
206
207 return UtxoWithPrivateKey(
219 - utxo: input.utxo,
220 - ownerDetails: input.ownerDetails,
221 - privateKey: key.privkey);
208 + utxo: input.utxo, ownerDetails: input.ownerDetails, privateKey: key.privkey);
209 }
210
224 - factory UtxoWithPrivateKey.fromUnspent(
225 - BitcoinUnspent input, BitcoinWalletBase wallet) {
226 - final address =
227 - RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);
211 + factory UtxoWithPrivateKey.fromUnspent(BitcoinUnspent input, BitcoinWalletBase wallet) {
212 + final address = RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);
213
229 - final newHd =
230 - input.bitcoinAddressRecord.isHidden ? wallet.sideHd : wallet.hd;
214 + final newHd = input.bitcoinAddressRecord.isHidden ? wallet.sideHd : wallet.hd;
215
216 ECPrivate privkey;
217 if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
234 - final unspentAddress =
235 - input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
218 + final unspentAddress = input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
219 privkey = wallet.walletAddresses.silentAddress!.b_spend.tweakAdd(
220 BigintUtils.fromBytes(
221 BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
@@ -240,9 +223,7 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
223 );
224 } else {
225 privkey = generateECPrivate(
243 - hd: newHd,
244 - index: input.bitcoinAddressRecord.index,
245 - network: BitcoinNetwork.mainnet);
226 + hd: newHd, index: input.bitcoinAddressRecord.index, network: BitcoinNetwork.mainnet);
227 }
228
229 return UtxoWithPrivateKey(
@@ -251,8 +232,7 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
232 value: BigInt.from(input.value),
233 vout: input.vout,
234 scriptType: input.bitcoinAddressRecord.type,
254 - isSilentPayment:
255 - input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
235 + isSilentPayment: input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
236 ),
237 ownerDetails: UtxoAddressDetails(
238 publicKey: privkey.getPublic().toHex(),
cw_bitcoin/lib/psbt/transaction_builder.dart
+15 -19
@@ -9,7 +9,9 @@ class PSBTTransactionBuild {
9 final PsbtV2 psbt = PsbtV2();
10
11 PSBTTransactionBuild(
12 - {required List<PSBTReadyUtxoWithAddress> inputs, required List<BitcoinBaseOutput> outputs, bool enableRBF = true}) {
12 + {required List<PSBTReadyUtxoWithAddress> inputs,
13 + required List<BitcoinBaseOutput> outputs,
14 + bool enableRBF = true}) {
15 psbt.setGlobalTxVersion(2);
16 psbt.setGlobalInputCount(inputs.length);
17 psbt.setGlobalOutputCount(outputs.length);
@@ -17,20 +19,20 @@ class PSBTTransactionBuild {
19 for (var i = 0; i < inputs.length; i++) {
20 final input = inputs[i];
21
20 - printV(input.utxo.isP2tr());
21 - printV(input.utxo.isSegwit());
22 - printV(input.utxo.isP2shSegwit());
22 + printV(input.utxo.isP2tr);
23 + printV(input.utxo.isSegwit);
24 + printV(input.utxo.isP2shSegwit);
25
24 - psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
26 + psbt.setInputPreviousTxId(
27 + i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
28 psbt.setInputOutputIndex(i, input.utxo.vout);
29 psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff);
30
28 -
29 - if (input.utxo.isSegwit()) {
31 + if (input.utxo.isSegwit) {
32 setInputSegwit(i, input);
31 - } else if (input.utxo.isP2shSegwit()) {
33 + } else if (input.utxo.isP2shSegwit) {
34 setInputP2shSegwit(i, input);
33 - } else if (input.utxo.isP2tr()) {
35 + } else if (input.utxo.isP2tr) {
36 // ToDo: (Konsti) Handle Taproot Inputs
37 } else {
38 setInputP2pkh(i, input);
@@ -49,20 +51,14 @@ class PSBTTransactionBuild {
51
52 void setInputP2pkh(int i, PSBTReadyUtxoWithAddress input) {
53 psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx)));
52 - psbt.setInputBip32Derivation(
53 - i,
54 - Uint8List.fromList(hex.decode(input.ownerPublicKey)),
55 - input.ownerMasterFingerprint,
56 - BIPPath.fromString(input.ownerDerivationPath).toPathArray());
54 + psbt.setInputBip32Derivation(i, Uint8List.fromList(hex.decode(input.ownerPublicKey)),
55 + input.ownerMasterFingerprint, BIPPath.fromString(input.ownerDerivationPath).toPathArray());
56 }
57
58 void setInputSegwit(int i, PSBTReadyUtxoWithAddress input) {
59 psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx)));
61 - psbt.setInputBip32Derivation(
62 - i,
63 - Uint8List.fromList(hex.decode(input.ownerPublicKey)),
64 - input.ownerMasterFingerprint,
65 - BIPPath.fromString(input.ownerDerivationPath).toPathArray());
60 + psbt.setInputBip32Derivation(i, Uint8List.fromList(hex.decode(input.ownerPublicKey)),
61 + input.ownerMasterFingerprint, BIPPath.fromString(input.ownerDerivationPath).toPathArray());
62
63 psbt.setInputWitnessUtxo(i, Uint8List.fromList(bigIntToUint64LE(input.utxo.value)),
64 Uint8List.fromList(input.ownerDetails.address.toScriptPubKey().toBytes()));
cw_bitcoin/lib/psbt/utils.dart
+1 -1
@@ -21,7 +21,7 @@ String getOutputAmountFromPsbt(String psbtV0, BitcoinWalletBase wallet) {
21 int amount = 0;
22 for (var i = 0; i < psbt.getGlobalOutputCount(); i++) {
23 final script = psbt.getOutputScript(i);
24 - if (wallet.isMine(Script.fromRaw(byteData: script))) {
24 + if (wallet.isMine(Script.fromRaw(bytes: script))) {
25 amount += psbt.getOutputAmount(i);
26 }
27 }
cw_bitcoin/pubspec.lock
+11 -11
@@ -79,20 +79,20 @@ packages:
79 dependency: "direct overridden"
80 description:
81 path: "."
82 - ref: cake-update-v9
83 - resolved-ref: "86969a14e337383e14965f5fb45a72a63e5009bc"
82 + ref: cake-update-v15
83 + resolved-ref: "29160733cbc4ef2c7b8c8fe9ed0297c9bffecfe2"
84 url: "https://github.com/cake-tech/bitcoin_base"
85 source: git
86 - version: "4.7.0"
86 + version: "6.1.0"
87 blockchain_utils:
88 dependency: "direct main"
89 description:
90 path: "."
91 - ref: cake-update-v2
92 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
91 + ref: cake-update-v4
92 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
93 url: "https://github.com/cake-tech/blockchain_utils"
94 source: git
95 - version: "3.3.0"
95 + version: "4.3.0"
96 bluez:
97 dependency: transitive
98 description:
@@ -681,11 +681,11 @@ packages:
681 dependency: transitive
682 description:
683 path: "."
684 - ref: cake-update-v2
685 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
684 + ref: cake-update-v4
685 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
686 url: "https://github.com/cake-tech/on_chain.git"
687 source: git
688 - version: "3.7.0"
688 + version: "6.2.0"
689 package_config:
690 dependency: transitive
691 description:
@@ -968,8 +968,8 @@ packages:
968 dependency: "direct main"
969 description:
970 path: "."
971 - ref: "sp_v4.0.0"
972 - resolved-ref: "2554cb8bd3ee1d026bc63e76a30d1226960c7cb4"
971 + ref: cake-update-v4
972 + resolved-ref: f3c172a7dc5155f5e745e4630b05f197e098a5cd
973 url: "https://github.com/cake-tech/sp_scanner"
974 source: git
975 version: "0.0.1"
cw_bitcoin/pubspec.yaml
+3 -3
@@ -29,14 +29,14 @@ dependencies:
29 blockchain_utils:
30 git:
31 url: https://github.com/cake-tech/blockchain_utils
32 - ref: cake-update-v2
32 + ref: cake-update-v4
33 cw_mweb:
34 path: ../cw_mweb
35 grpc: ^4.0.1
36 sp_scanner:
37 git:
38 url: https://github.com/cake-tech/sp_scanner
39 - ref: sp_v4.0.0
39 + ref: cake-update-v4
40 bech32:
41 git:
42 url: https://github.com/cake-tech/bech32.git
@@ -69,7 +69,7 @@ dependency_overrides:
69 bitcoin_base:
70 git:
71 url: https://github.com/cake-tech/bitcoin_base
72 - ref: cake-update-v9
72 + ref: cake-update-v15
73 pointycastle: 3.7.4
74 ffi: 2.1.0
75
cw_bitcoin_cash/pubspec.yaml
+2 -2
@@ -28,7 +28,7 @@ dependencies:
28 blockchain_utils:
29 git:
30 url: https://github.com/cake-tech/blockchain_utils
31 - ref: cake-update-v2
31 + ref: cake-update-v4
32
33 dev_dependencies:
34 flutter_test:
@@ -42,7 +42,7 @@ dependency_overrides:
42 bitcoin_base:
43 git:
44 url: https://github.com/cake-tech/bitcoin_base
45 - ref: cake-update-v9
45 + ref: cake-update-v15
46
47 # For information on the generic Dart part of this file, see the
48 # following page: https://dart.dev/tools/pub/pubspec
cw_core/lib/solana_rpc_http_service.dart
+20 -13
@@ -1,26 +1,33 @@
1 -import 'dart:convert';
1 import 'package:http/http.dart';
2 import 'package:on_chain/solana/solana.dart';
3
5 -class SolanaRPCHTTPService implements SolanaJSONRPCService {
4 +class SolanaRPCHTTPService implements SolanaServiceProvider {
5 SolanaRPCHTTPService(
6 {required this.url, Client? client, this.defaultRequestTimeout = const Duration(seconds: 30)})
7 : client = client ?? Client();
9 - @override
8 +
9 final String url;
10 final Client client;
11 final Duration defaultRequestTimeout;
12
13 @override
15 - Future<Map<String, dynamic>> call(SolanaRequestDetails params, [Duration? timeout]) async {
16 - final response = await client.post(
17 - Uri.parse(url),
18 - body: params.toRequestBody(),
19 - headers: {
20 - 'Content-Type': 'application/json',
21 - },
22 - ).timeout(timeout ?? defaultRequestTimeout);
23 - final data = json.decode(response.body) as Map<String, dynamic>;
24 - return data;
14 + Future<SolanaServiceResponse<T>> doRequest<T>(SolanaRequestDetails params,
15 + {Duration? timeout}) async {
16 + if (!params.type.isPostRequest) {
17 + final response = await client.get(
18 + params.toUri(url),
19 + headers: {'Content-Type': 'application/json'},
20 + ).timeout(timeout ?? defaultRequestTimeout);
21 + return params.toResponse(response.bodyBytes, response.statusCode);
22 + }
23 +
24 + final response = await client
25 + .post(
26 + params.toUri(url),
27 + headers: {'Content-Type': 'application/json'},
28 + body: params.body(),
29 + )
30 + .timeout(timeout ?? defaultRequestTimeout);
31 + return params.toResponse(response.bodyBytes, response.statusCode);
32 }
33 }
cw_core/pubspec.lock
+6 -6
@@ -50,11 +50,11 @@ packages:
50 dependency: transitive
51 description:
52 path: "."
53 - ref: cake-update-v2
54 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
53 + ref: cake-update-v4
54 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
55 url: "https://github.com/cake-tech/blockchain_utils"
56 source: git
57 - version: "3.3.0"
57 + version: "4.3.0"
58 boolean_selector:
59 dependency: transitive
60 description:
@@ -478,11 +478,11 @@ packages:
478 dependency: "direct main"
479 description:
480 path: "."
481 - ref: cake-update-v2
482 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
481 + ref: cake-update-v4
482 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
483 url: "https://github.com/cake-tech/on_chain.git"
484 source: git
485 - version: "3.7.0"
485 + version: "6.2.0"
486 package_config:
487 dependency: transitive
488 description:
cw_core/pubspec.yaml
+1 -1
@@ -30,7 +30,7 @@ dependencies:
30 on_chain:
31 git:
32 url: https://github.com/cake-tech/on_chain.git
33 - ref: cake-update-v2
33 + ref: cake-update-v4
34 # tor:
35 # git:
36 # url: https://github.com/cake-tech/tor.git
cw_decred/pubspec.lock
+6 -6
@@ -50,11 +50,11 @@ packages:
50 dependency: transitive
51 description:
52 path: "."
53 - ref: cake-update-v2
54 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
53 + ref: cake-update-v4
54 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
55 url: "https://github.com/cake-tech/blockchain_utils"
56 source: git
57 - version: "3.3.0"
57 + version: "4.3.0"
58 boolean_selector:
59 dependency: transitive
60 description:
@@ -501,11 +501,11 @@ packages:
501 dependency: transitive
502 description:
503 path: "."
504 - ref: cake-update-v2
505 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
504 + ref: cake-update-v4
505 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
506 url: "https://github.com/cake-tech/on_chain.git"
507 source: git
508 - version: "3.7.0"
508 + version: "6.2.0"
509 package_config:
510 dependency: transitive
511 description:
cw_monero/pubspec.lock
+6 -6
@@ -66,11 +66,11 @@ packages:
66 dependency: transitive
67 description:
68 path: "."
69 - ref: cake-update-v2
70 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
69 + ref: cake-update-v4
70 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
71 url: "https://github.com/cake-tech/blockchain_utils"
72 source: git
73 - version: "3.3.0"
73 + version: "4.3.0"
74 bluez:
75 dependency: transitive
76 description:
@@ -598,11 +598,11 @@ packages:
598 dependency: transitive
599 description:
600 path: "."
601 - ref: cake-update-v2
602 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
601 + ref: cake-update-v4
602 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
603 url: "https://github.com/cake-tech/on_chain.git"
604 source: git
605 - version: "3.7.0"
605 + version: "6.2.0"
606 package_config:
607 dependency: transitive
608 description:
cw_nano/pubspec.lock
+6 -6
@@ -61,11 +61,11 @@ packages:
61 dependency: transitive
62 description:
63 path: "."
64 - ref: cake-update-v2
65 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
64 + ref: cake-update-v4
65 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
66 url: "https://github.com/cake-tech/blockchain_utils"
67 source: git
68 - version: "3.3.0"
68 + version: "4.3.0"
69 boolean_selector:
70 dependency: transitive
71 description:
@@ -550,11 +550,11 @@ packages:
550 dependency: transitive
551 description:
552 path: "."
553 - ref: cake-update-v2
554 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
553 + ref: cake-update-v4
554 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
555 url: "https://github.com/cake-tech/on_chain.git"
556 source: git
557 - version: "3.7.0"
557 + version: "6.2.0"
558 package_config:
559 dependency: transitive
560 description:
cw_solana/lib/solana_client.dart
+16 -16
@@ -19,7 +19,7 @@ import '.secrets.g.dart' as secrets;
19
20 class SolanaWalletClient {
21 final httpClient = http.Client();
22 - SolanaRPC? _provider;
22 + SolanaProvider? _provider;
23
24 bool connect(Node node) {
25 try {
@@ -38,7 +38,7 @@ class SolanaWalletClient {
38 formattedUrl = '$protocolUsed://${node.uriRaw}';
39 }
40
41 - _provider = SolanaRPC(SolanaRPCHTTPService(url: formattedUrl));
41 + _provider = SolanaProvider(SolanaRPCHTTPService(url: formattedUrl));
42
43 return true;
44 } catch (e) {
@@ -49,7 +49,7 @@ class SolanaWalletClient {
49 Future<double> getBalance(String walletAddress) async {
50 try {
51 final balance = await _provider!.requestWithContext(
52 - SolanaRPCGetBalance(
52 + SolanaRequestGetBalance(
53 account: SolAddress(walletAddress),
54 ),
55 );
@@ -68,11 +68,11 @@ class SolanaWalletClient {
68 String mintAddress, String publicKey) async {
69 try {
70 final result = await _provider!.request(
71 - SolanaRPCGetTokenAccountsByOwner(
71 + SolanaRequestGetTokenAccountsByOwner(
72 account: SolAddress(publicKey),
73 mint: SolAddress(mintAddress),
74 commitment: Commitment.confirmed,
75 - encoding: SolanaRPCEncoding.base64,
75 + encoding: SolanaRequestEncoding.base64,
76 ),
77 );
78
@@ -96,7 +96,7 @@ class SolanaWalletClient {
96
97 for (var tokenAccount in tokenAccounts) {
98 final tokenAmountResult = await _provider!.request(
99 - SolanaRPCGetTokenAccountBalance(account: tokenAccount.pubkey),
99 + SolanaRequestGetTokenAccountBalance(account: tokenAccount.pubkey),
100 );
101
102 final balance = tokenAmountResult.uiAmountString;
@@ -112,7 +112,7 @@ class SolanaWalletClient {
112 Future<double> getFeeForMessage(String message, Commitment commitment) async {
113 try {
114 final feeForMessage = await _provider!.request(
115 - SolanaRPCGetFeeForMessage(
115 + SolanaRequestGetFeeForMessage(
116 encodedMessage: message,
117 commitment: commitment,
118 ),
@@ -342,7 +342,7 @@ class SolanaWalletClient {
342 List<SolanaTransactionModel> transactions = [];
343 try {
344 final signatures = await _provider!.request(
345 - SolanaRPCGetSignaturesForAddress(
345 + SolanaRequestGetSignaturesForAddress(
346 account: address,
347 commitment: commitment,
348 ),
@@ -357,9 +357,9 @@ class SolanaWalletClient {
357 final batchResponses = await Future.wait(batch.map((signature) async {
358 try {
359 return await _provider!.request(
360 - SolanaRPCGetTransaction(
360 + SolanaRequestGetTransaction(
361 transactionSignature: signature['signature'],
362 - encoding: SolanaRPCEncoding.jsonParsed,
362 + encoding: SolanaRequestEncoding.jsonParsed,
363 maxSupportedTransactionVersion: 0,
364 ),
365 );
@@ -482,7 +482,7 @@ class SolanaWalletClient {
482
483 void stop() {}
484
485 - SolanaRPC? get getSolanaProvider => _provider;
485 + SolanaProvider? get getSolanaProvider => _provider;
486
487 Future<PendingSolanaTransaction> signSolanaTransaction({
488 required String tokenTitle,
@@ -523,7 +523,7 @@ class SolanaWalletClient {
523
524 Future<SolAddress> _getLatestBlockhash(Commitment commitment) async {
525 final latestBlockhash = await _provider!.request(
526 - const SolanaRPCGetLatestBlockhash(),
526 + const SolanaRequestGetLatestBlockhash(),
527 );
528
529 return latestBlockhash.blockhash;
@@ -599,7 +599,7 @@ class SolanaWalletClient {
599 required double fee,
600 }) async {
601 final rent = await _provider!.request(
602 - SolanaRPCGetMinimumBalanceForRentExemption(
602 + SolanaRequestGetMinimumBalanceForRentExemption(
603 size: SolanaTokenAccountUtils.accountSize,
604 ),
605 );
@@ -732,7 +732,7 @@ class SolanaWalletClient {
732 SolanaAccountInfo? accountInfo;
733 try {
734 accountInfo = await _provider!.request(
735 - SolanaRPCGetAccountInfo(account: associatedTokenAccount.address),
735 + SolanaRequestGetAccountInfo(account: associatedTokenAccount.address),
736 );
737 } catch (e) {
738 accountInfo = null;
@@ -890,7 +890,7 @@ class SolanaWalletClient {
890 }) async {
891 /// Sign the transaction with the owner's private key.
892 final ownerSignature = ownerPrivateKey.sign(transaction.serializeMessage());
893 -
893 +
894 transaction.addSignature(ownerPrivateKey.publicKey().toAddress(), ownerSignature);
895
896 /// Serialize the transaction.
@@ -906,7 +906,7 @@ class SolanaWalletClient {
906 try {
907 /// Send the transaction to the Solana network.
908 final signature = await _provider!.request(
909 - SolanaRPCSendTransaction(
909 + SolanaRequestSendTransaction(
910 encodedTransaction: serializedTransaction,
911 commitment: commitment,
912 ),
cw_solana/lib/solana_wallet.dart
+1 -1
@@ -611,7 +611,7 @@ abstract class SolanaWalletBase
611 );
612 }
613
614 - SolanaRPC? get solanaProvider => _client.getSolanaProvider;
614 + SolanaProvider? get solanaProvider => _client.getSolanaProvider;
615
616 @override
617 String get password => _password;
cw_solana/pubspec.yaml
+2 -2
@@ -23,11 +23,11 @@ dependencies:
23 on_chain:
24 git:
25 url: https://github.com/cake-tech/on_chain.git
26 - ref: cake-update-v2
26 + ref: cake-update-v4
27 blockchain_utils:
28 git:
29 url: https://github.com/cake-tech/blockchain_utils
30 - ref: cake-update-v2
30 + ref: cake-update-v4
31
32 dev_dependencies:
33 flutter_test:
cw_tron/lib/tron_client.dart
+4 -4
@@ -235,7 +235,7 @@ class TronClient {
235 String contractAddress = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
236 String constantAmount =
237 '0'; // We're using 0 as the base amount here as we get an error when balance is zero i.e for new wallets.
238 - final contract = ContractABI.fromJson(trc20Abi, isTron: true);
238 + final contract = ContractABI.fromJson(trc20Abi);
239
240 final function = contract.functionFromName("transfer");
241
@@ -405,7 +405,7 @@ class TronClient {
405 String contractAddress,
406 BigInt tronBalance,
407 ) async {
408 - final contract = ContractABI.fromJson(trc20Abi, isTron: true);
408 + final contract = ContractABI.fromJson(trc20Abi);
409
410 final function = contract.functionFromName("transfer");
411
@@ -483,7 +483,7 @@ class TronClient {
483
484 final tokenAddress = TronAddress(contractAddress);
485
486 - final contract = ContractABI.fromJson(trc20Abi, isTron: true);
486 + final contract = ContractABI.fromJson(trc20Abi);
487
488 final function = contract.functionFromName("balanceOf");
489
@@ -510,7 +510,7 @@ class TronClient {
510
511 final ownerAddress = TronAddress(userAddress);
512
513 - final contract = ContractABI.fromJson(trc20Abi, isTron: true);
513 + final contract = ContractABI.fromJson(trc20Abi);
514
515 final name =
516 (await getTokenDetail(contract, "name", ownerAddress, tokenAddress) as String?) ?? '';
cw_tron/lib/tron_http_provider.dart
+25 -24
@@ -1,8 +1,6 @@
1 -import 'dart:convert';
2 -
1 import 'package:http/http.dart' as http;
4 -import 'package:on_chain/tron/tron.dart';
2 import '.secrets.g.dart' as secrets;
3 +import 'package:on_chain/tron/tron.dart';
4
5 class TronHTTPProvider implements TronServiceProvider {
6 TronHTTPProvider(
@@ -10,34 +8,37 @@ class TronHTTPProvider implements TronServiceProvider {
8 http.Client? client,
9 this.defaultRequestTimeout = const Duration(seconds: 30)})
10 : client = client ?? http.Client();
13 - @override
11 +
12 final String url;
13 final http.Client client;
14 final Duration defaultRequestTimeout;
15
16 @override
19 - Future<Map<String, dynamic>> get(TronRequestDetails params, [Duration? timeout]) async {
20 - final response = await client.get(Uri.parse(params.url(url)), headers: {
21 - 'Content-Type': 'application/json',
22 - if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
23 - if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey,
24 - }).timeout(timeout ?? defaultRequestTimeout);
25 - final data = json.decode(response.body) as Map<String, dynamic>;
26 - return data;
27 - }
17 + Future<TronServiceResponse<T>> doRequest<T>(TronRequestDetails params,
18 + {Duration? timeout}) async {
19 + if (!params.type.isPostRequest) {
20 + final response = await client.get(
21 + params.toUri(url),
22 + headers: {
23 + 'Content-Type': 'application/json',
24 + if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
25 + if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey,
26 + },
27 + ).timeout(timeout ?? defaultRequestTimeout);
28 + return params.toResponse(response.bodyBytes, response.statusCode);
29 + }
30
29 - @override
30 - Future<Map<String, dynamic>> post(TronRequestDetails params, [Duration? timeout]) async {
31 final response = await client
32 - .post(Uri.parse(params.url(url)),
33 - headers: {
34 - 'Content-Type': 'application/json',
35 - if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
36 - if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey,
37 - },
38 - body: params.toRequestBody())
32 + .post(
33 + params.toUri(url),
34 + headers: {
35 + 'Content-Type': 'application/json',
36 + if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
37 + if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey,
38 + },
39 + body: params.body(),
40 + )
41 .timeout(timeout ?? defaultRequestTimeout);
40 - final data = json.decode(response.body) as Map<String, dynamic>;
41 - return data;
42 + return params.toResponse(response.bodyBytes, response.statusCode);
43 }
44 }
cw_tron/lib/tron_transaction_model.dart
+2 -1
@@ -1,5 +1,6 @@
1 import 'package:blockchain_utils/hex/hex.dart';
2 import 'package:on_chain/on_chain.dart';
3 +import 'package:on_chain/solidity/address/core.dart';
4
5 class TronTRC20TransactionModel extends TronTransactionModel {
6 String? transactionId;
@@ -188,7 +189,7 @@ class Value {
189 output = output.replaceFirst('0x', '').substring(8);
190 final abiCoder = ABICoder.fromType('address');
191 final decoded = abiCoder.decode(AbiParameter.bytes, hex.decode(output));
191 - final tronAddress = TronAddress.fromEthAddress((decoded.result as ETHAddress).toBytes());
192 + final tronAddress = TronAddress.fromEthAddress((decoded.result as SolidityAddress).toBytes());
193
194 return tronAddress.toString();
195 }
cw_tron/lib/tron_wallet.dart
+23 -20
@@ -31,7 +31,7 @@ import 'package:cw_tron/tron_transaction_info.dart';
31 import 'package:cw_tron/tron_wallet_addresses.dart';
32 import 'package:hive/hive.dart';
33 import 'package:mobx/mobx.dart';
34 -import 'package:on_chain/on_chain.dart';
34 +import 'package:on_chain/on_chain.dart' as on_chain;
35
36 part 'tron_wallet.g.dart';
37
@@ -74,13 +74,13 @@ abstract class TronWalletBase
74
75 late final Box<TronToken> tronTokensBox;
76
77 - late final TronPrivateKey _tronPrivateKey;
77 + late final on_chain.TronPrivateKey _tronPrivateKey;
78
79 - late final TronPublicKey _tronPublicKey;
79 + late final on_chain.TronPublicKey _tronPublicKey;
80
81 - TronPublicKey get tronPublicKey => _tronPublicKey;
81 + on_chain.TronPublicKey get tronPublicKey => _tronPublicKey;
82
83 - TronPrivateKey get tronPrivateKey => _tronPrivateKey;
83 + on_chain.TronPrivateKey get tronPrivateKey => _tronPrivateKey;
84
85 late String _tronAddress;
86
@@ -190,7 +190,7 @@ abstract class TronWalletBase
190
191 String idFor(String name, WalletType type) => '${walletTypeToString(type).toLowerCase()}_$name';
192
193 - Future<TronPrivateKey> getPrivateKey({
193 + Future<on_chain.TronPrivateKey> getPrivateKey({
194 String? mnemonic,
195 String? privateKey,
196 required String password,
@@ -198,7 +198,7 @@ abstract class TronWalletBase
198 }) async {
199 assert(mnemonic != null || privateKey != null);
200
201 - if (privateKey != null) return TronPrivateKey(privateKey);
201 + if (privateKey != null) return on_chain.TronPrivateKey(privateKey);
202
203 final seed = bip39.mnemonicToSeed(mnemonic!, passphrase: passphrase ?? '');
204
@@ -207,7 +207,7 @@ abstract class TronWalletBase
207
208 final childKey = bip44.deriveDefaultPath;
209
210 - return TronPrivateKey.fromBytes(childKey.privateKey.raw);
210 + return on_chain.TronPrivateKey.fromBytes(childKey.privateKey.raw);
211 }
212
213 @override
@@ -242,10 +242,10 @@ abstract class TronWalletBase
242
243 Future<void> _getEstimatedFees() async {
244 final nativeFee = await _getNativeTxFee();
245 - nativeTxEstimatedFee = TronHelper.fromSun(BigInt.from(nativeFee));
245 + nativeTxEstimatedFee = on_chain.TronHelper.fromSun(BigInt.from(nativeFee));
246
247 final trc20Fee = await _getTrc20TxFee();
248 - trc20EstimatedFee = TronHelper.fromSun(BigInt.from(trc20Fee));
248 + trc20EstimatedFee = on_chain.TronHelper.fromSun(BigInt.from(trc20Fee));
249
250 log('Native Estimated Fee: $nativeTxEstimatedFee');
251 log('TRC20 Estimated Fee: $trc20EstimatedFee');
@@ -323,7 +323,7 @@ abstract class TronWalletBase
323 totalAmount = walletBalanceForCurrency;
324 } else {
325 final totalOriginalAmount = double.parse(output.cryptoAmount ?? '0.0');
326 - totalAmount = TronHelper.toSun(totalOriginalAmount.toString());
326 + totalAmount = on_chain.TronHelper.toSun(totalOriginalAmount.toString());
327 }
328
329 if (walletBalanceForCurrency < totalAmount || totalAmount < BigInt.zero) {
@@ -338,7 +338,7 @@ abstract class TronWalletBase
338 toAddress: tronCredentials.outputs.first.isParsedAddress
339 ? tronCredentials.outputs.first.extractedAddress!
340 : tronCredentials.outputs.first.address,
341 - amount: TronHelper.fromSun(totalAmount),
341 + amount: on_chain.TronHelper.fromSun(totalAmount),
342 currency: transactionCurrency,
343 tronBalance: tronBalance,
344 sendAll: shouldSendAll,
@@ -355,9 +355,9 @@ abstract class TronWalletBase
355
356 final Map<String, TronTransactionInfo> result = {};
357
358 - final contract = ContractABI.fromJson(trc20Abi, isTron: true);
358 + final contract = on_chain.ContractABI.fromJson(trc20Abi);
359
360 - final ownerAddress = TronAddress(_tronAddress);
360 + final ownerAddress = on_chain.TronAddress(_tronAddress);
361
362 for (var transactionModel in transactions) {
363 if (transactionModel.isError) {
@@ -371,7 +371,7 @@ abstract class TronWalletBase
371
372 String? tokenSymbol;
373 if (transactionModel.contractAddress != null) {
374 - final tokenAddress = TronAddress(transactionModel.contractAddress!);
374 + final tokenAddress = on_chain.TronAddress(transactionModel.contractAddress!);
375
376 tokenSymbol = (await _client.getTokenDetail(
377 contract,
@@ -385,9 +385,10 @@ abstract class TronWalletBase
385 result[transactionModel.hash] = TronTransactionInfo(
386 id: transactionModel.hash,
387 tronAmount: transactionModel.amount ?? BigInt.zero,
388 - direction: TronAddress(transactionModel.from!, visible: false).toAddress() == address
389 - ? TransactionDirection.outgoing
390 - : TransactionDirection.incoming,
388 + direction:
389 + on_chain.TronAddress(transactionModel.from!, visible: false).toAddress() == address
390 + ? TransactionDirection.outgoing
391 + : TransactionDirection.incoming,
392 blockTime: transactionModel.date,
393 txFee: transactionModel.fee,
394 tokenSymbol: tokenSymbol ?? "TRX",
@@ -604,11 +605,13 @@ abstract class TronWalletBase
605 if (address == null) {
606 return false;
607 }
607 - TronPublicKey pubKey = TronPublicKey.fromPersonalSignature(ascii.encode(message), signature)!;
608 + on_chain.TronPublicKey pubKey =
609 + on_chain.TronPublicKey.fromPersonalSignature(ascii.encode(message), signature)!;
610 return pubKey.toAddress().toString() == address;
611 }
612
611 - String getTronBase58AddressFromHex(String hexAddress) => TronAddress(hexAddress).toAddress();
613 + String getTronBase58AddressFromHex(String hexAddress) =>
614 + on_chain.TronAddress(hexAddress).toAddress();
615
616 void updateScanProviderUsageState(bool isEnabled) {
617 if (isEnabled) {
cw_tron/pubspec.yaml
+2 -2
@@ -18,11 +18,11 @@ dependencies:
18 on_chain:
19 git:
20 url: https://github.com/cake-tech/on_chain.git
21 - ref: cake-update-v2
21 + ref: cake-update-v4
22 blockchain_utils:
23 git:
24 url: https://github.com/cake-tech/blockchain_utils
25 - ref: cake-update-v2
25 + ref: cake-update-v4
26 mobx: ^2.3.0+1
27 bip39: ^1.0.6
28 hive: ^2.2.3
cw_wownero/pubspec.lock
+6 -6
@@ -45,11 +45,11 @@ packages:
45 dependency: transitive
46 description:
47 path: "."
48 - ref: cake-update-v2
49 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
48 + ref: cake-update-v4
49 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
50 url: "https://github.com/cake-tech/blockchain_utils"
51 source: git
52 - version: "3.3.0"
52 + version: "4.3.0"
53 boolean_selector:
54 dependency: transitive
55 description:
@@ -505,11 +505,11 @@ packages:
505 dependency: transitive
506 description:
507 path: "."
508 - ref: cake-update-v2
509 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
508 + ref: cake-update-v4
509 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
510 url: "https://github.com/cake-tech/on_chain.git"
511 source: git
512 - version: "3.7.0"
512 + version: "6.2.0"
513 package_config:
514 dependency: transitive
515 description:
cw_zano/pubspec.lock
+6 -6
@@ -45,11 +45,11 @@ packages:
45 dependency: transitive
46 description:
47 path: "."
48 - ref: cake-update-v2
49 - resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
48 + ref: cake-update-v4
49 + resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
50 url: "https://github.com/cake-tech/blockchain_utils"
51 source: git
52 - version: "3.3.0"
52 + version: "4.3.0"
53 boolean_selector:
54 dependency: transitive
55 description:
@@ -502,11 +502,11 @@ packages:
502 dependency: transitive
503 description:
504 path: "."
505 - ref: cake-update-v2
506 - resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2"
505 + ref: cake-update-v4
506 + resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
507 url: "https://github.com/cake-tech/on_chain.git"
508 source: git
509 - version: "3.7.0"
509 + version: "6.2.0"
510 package_config:
511 dependency: transitive
512 description:
lib/bitcoin/cw_bitcoin.dart
+9 -9
@@ -213,9 +213,9 @@ class CWBitcoin extends Bitcoin {
213 return bitcoinWallet.unspentCoins.where((element) {
214 switch (coinTypeToSpendFrom) {
215 case UnspentCoinType.mweb:
216 - return element.bitcoinAddressRecord.type == SegwitAddresType.mweb;
216 + return element.bitcoinAddressRecord.type == SegwitAddressType.mweb;
217 case UnspentCoinType.nonMweb:
218 - return element.bitcoinAddressRecord.type != SegwitAddresType.mweb;
218 + return element.bitcoinAddressRecord.type != SegwitAddressType.mweb;
219 case UnspentCoinType.any:
220 return true;
221 }
@@ -296,14 +296,14 @@ class CWBitcoin extends Bitcoin {
296 case BitcoinReceivePageOption.p2sh:
297 return P2shAddressType.p2wpkhInP2sh;
298 case BitcoinReceivePageOption.p2tr:
299 - return SegwitAddresType.p2tr;
299 + return SegwitAddressType.p2tr;
300 case BitcoinReceivePageOption.p2wsh:
301 - return SegwitAddresType.p2wsh;
301 + return SegwitAddressType.p2wsh;
302 case BitcoinReceivePageOption.mweb:
303 - return SegwitAddresType.mweb;
303 + return SegwitAddressType.mweb;
304 case BitcoinReceivePageOption.p2wpkh:
305 default:
306 - return SegwitAddresType.p2wpkh;
306 + return SegwitAddressType.p2wpkh;
307 }
308 }
309
@@ -527,7 +527,7 @@ class CWBitcoin extends Bitcoin {
527 List<ElectrumSubAddress> getSilentPaymentAddresses(Object wallet) {
528 final bitcoinWallet = wallet as ElectrumWallet;
529 return bitcoinWallet.walletAddresses.silentAddresses
530 - .where((addr) => addr.type != SegwitAddresType.p2tr)
530 + .where((addr) => addr.type != SegwitAddressType.p2tr)
531 .map((addr) => ElectrumSubAddress(
532 id: addr.index,
533 name: addr.name,
@@ -542,7 +542,7 @@ class CWBitcoin extends Bitcoin {
542 List<ElectrumSubAddress> getSilentPaymentReceivedAddresses(Object wallet) {
543 final bitcoinWallet = wallet as ElectrumWallet;
544 return bitcoinWallet.walletAddresses.silentAddresses
545 - .where((addr) => addr.type == SegwitAddresType.p2tr)
545 + .where((addr) => addr.type == SegwitAddressType.p2tr)
546 .map((addr) => ElectrumSubAddress(
547 id: addr.index,
548 name: addr.name,
@@ -712,7 +712,7 @@ class CWBitcoin extends Bitcoin {
712 try {
713 final electrumWallet = wallet as ElectrumWallet;
714 final segwitAddress = electrumWallet.walletAddresses.allAddresses
715 - .firstWhere((element) => !element.isUsed && element.type == SegwitAddresType.p2wpkh);
715 + .firstWhere((element) => !element.isUsed && element.type == SegwitAddressType.p2wpkh);
716 return segwitAddress.address;
717 } catch (_) {
718 return null;
pubspec_base.yaml
+3 -3
@@ -115,12 +115,12 @@ dependencies:
115 on_chain:
116 git:
117 url: https://github.com/cake-tech/on_chain.git
118 - ref: cake-update-v2
118 + ref: cake-update-v4
119 reown_walletkit: ^1.1.2
120 blockchain_utils:
121 git:
122 url: https://github.com/cake-tech/blockchain_utils
123 - ref: cake-update-v2
123 + ref: cake-update-v4
124 flutter_daemon:
125 git:
126 url: https://github.com/MrCyjaneK/flutter_daemon
@@ -160,7 +160,7 @@ dependency_overrides:
160 bitcoin_base:
161 git:
162 url: https://github.com/cake-tech/bitcoin_base
163 - ref: cake-update-v9
163 + ref: cake-update-v15
164 ffi: 2.1.0
165 ledger_flutter_plus:
166 git:
tool/download_moneroc_prebuilds.py new
+76
@@ -0,0 +1,76 @@
1 +#!/usr/bin/env python3
2 +
3 +import os
4 +import subprocess
5 +import requests
6 +import lzma
7 +import shutil
8 +
9 +
10 +
11 +# Define triplets list
12 +triplets = [
13 + "x86_64-linux-gnu",
14 + "x86_64-linux-android",
15 + "aarch64-linux-android",
16 + "armv7a-linux-androideabi",
17 + # "x86_64-w64-mingw32",
18 + # "aarch64-apple-darwin",
19 + # "x86_64-apple-darwin",
20 + "aarch64-host-apple-darwin",
21 + # "aarch64-apple-ios",
22 + # "aarch64-apple-iossimulator",
23 +]
24 +
25 +
26 +def main():
27 + # Get the latest release data
28 + resp = requests.get("https://api.github.com/repos/mrcyjanek/monero_c/releases")
29 + data = resp.json()[0]
30 + tag_name = data["tag_name"]
31 + print(f"Downloading artifacts for: {tag_name}")
32 +
33 + assets = data["assets"]
34 + for asset in assets:
35 + for triplet in triplets:
36 + filename = asset["name"]
37 + if triplet not in filename:
38 + continue
39 +
40 + coin = filename.split("_")[0]
41 + local_filename = filename.replace(f"{coin}_{triplet}_", "")
42 + local_filename = (
43 + f"scripts/monero_c/release/{coin}/{triplet}_{local_filename}"
44 + )
45 +
46 + # Create directory if it doesn't exist
47 + os.makedirs(os.path.dirname(local_filename), exist_ok=True)
48 +
49 + url = asset["browser_download_url"]
50 + print(f"- downloading {local_filename}")
51 +
52 + # Download the file
53 + response = requests.get(url)
54 + with open(local_filename, "wb") as f:
55 + f.write(response.content)
56 +
57 + # Extract if it's an .xz file
58 + if local_filename.endswith(".xz"):
59 + print(f" extracting {local_filename}")
60 + with lzma.open(local_filename) as f_in:
61 + with open(local_filename.replace(".xz", ""), "wb") as f_out:
62 + shutil.copyfileobj(f_in, f_out)
63 +
64 + # Generate iOS framework if on macOS
65 + if os.uname().sysname == "Darwin": # Check if on macOS
66 + print("Generating ios framework")
67 + result = subprocess.run(
68 + ["bash", "-c", "cd scripts/ios && ./gen_framework.sh && cd ../.."],
69 + capture_output=True,
70 + text=True,
71 + )
72 + print(result.stdout.strip() + result.stderr.strip())
73 +
74 +
75 +if __name__ == "__main__":
76 + main()