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()