refactor: remove bitcoin_flutter, update deps, electrs node improvements

This commit is contained in:
Rafael Saes 2024-08-02 18:07:51 -03:00
parent 1b109ac702
commit 0523cecc79
29 changed files with 321 additions and 358 deletions

View file

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/hardware/hardware_account_data.dart';
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
@ -25,7 +25,8 @@ class BitcoinHardwareWalletService {
for (final i in indexRange) {
final derivationPath = "m/84'/0'/$i'";
final xpub = await bitcoinLedgerApp.getXPubKey(device, derivationPath: derivationPath);
HDWallet hd = HDWallet.fromBase58(xpub).derive(0);
Bip32Slip10Secp256k1 hd =
Bip32Slip10Secp256k1.fromExtendedKey(xpub).childKey(Bip32KeyIndex(0));
final address = generateP2WPKHAddress(hd: hd, index: 0, network: BitcoinNetwork.mainnet);

View file

@ -2,8 +2,7 @@ import 'dart:convert';
import 'package:bip39/bip39.dart' as bip39;
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:convert/convert.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
@ -50,11 +49,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: networkParam == null
? bitcoin.bitcoin
network: networkParam == null
? BitcoinNetwork.mainnet
: networkParam == BitcoinNetwork.mainnet
? bitcoin.bitcoin
: bitcoin.testnet,
? BitcoinNetwork.mainnet
: BitcoinNetwork.testnet,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: seedBytes,
@ -75,10 +74,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
initialSilentAddresses: initialSilentAddresses,
initialSilentAddressIndex: initialSilentAddressIndex,
mainHd: hd,
sideHd: accountHD.derive(1),
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
network: networkParam ?? network,
masterHd:
seedBytes != null ? bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) : null,
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
);
autorun((_) {
@ -235,7 +233,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
return BtcTransaction.fromRaw(hex.encode(rawHex));
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
}
@override
@ -249,8 +247,8 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
final accountPath = walletInfo.derivationInfo?.derivationPath;
final derivationPath = accountPath != null ? "$accountPath/$isChange/$index" : null;
final signature = await _bitcoinLedgerApp!
.signMessage(_ledgerDevice!, message: ascii.encode(message), signDerivationPath: derivationPath);
final signature = await _bitcoinLedgerApp!.signMessage(_ledgerDevice!,
message: ascii.encode(message), signDerivationPath: derivationPath);
return base64Encode(signature);
}

View file

@ -1,5 +1,5 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart';
import 'package:blockchain_utils/bip/bip/bip32/bip32.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/wallet_info.dart';
@ -24,7 +24,8 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
}) : super(walletInfo);
@override
String getAddress({required int index, required HDWallet hd, BitcoinAddressType? addressType}) {
String getAddress(
{required int index, required Bip32Slip10Secp256k1 hd, BitcoinAddressType? addressType}) {
if (addressType == P2pkhAddressType.p2pkh)
return generateP2PKHAddress(hd: hd, index: index, network: network);

View file

@ -236,9 +236,12 @@ class ElectrumClient {
return [];
});
Future<Map<String, dynamic>> getTransactionRaw({required String hash}) async =>
callWithTimeout(method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000)
.then((dynamic result) {
Future<dynamic> getTransaction({required String hash, required bool verbose}) async =>
callWithTimeout(
method: 'blockchain.transaction.get', params: [hash, verbose], timeout: 10000);
Future<Map<String, dynamic>> getTransactionVerbose({required String hash}) =>
getTransaction(hash: hash, verbose: true).then((dynamic result) {
if (result is Map<String, dynamic>) {
return result;
}
@ -246,9 +249,8 @@ class ElectrumClient {
return <String, dynamic>{};
});
Future<String> getTransactionHex({required String hash}) async =>
callWithTimeout(method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000)
.then((dynamic result) {
Future<String> getTransactionHex({required String hash}) =>
getTransaction(hash: hash, verbose: false).then((dynamic result) {
if (result is String) {
return result;
}
@ -336,7 +338,7 @@ class ElectrumClient {
try {
final topDoubleString = await estimatefee(p: 1);
final middleDoubleString = await estimatefee(p: 5);
final bottomDoubleString = await estimatefee(p: 100);
final bottomDoubleString = await estimatefee(p: 10);
final top = (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000).round();
final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();

View file

@ -22,7 +22,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
ElectrumTransactionInfo(this.type,
{required String id,
required int height,
int? height,
required int amount,
int? fee,
List<String>? inputAddresses,
@ -99,7 +99,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
factory ElectrumTransactionInfo.fromElectrumBundle(
ElectrumTransactionBundle bundle, WalletType type, BasedUtxoNetwork network,
{required Set<String> addresses, required int height}) {
{required Set<String> addresses, int? height}) {
final date = bundle.time != null
? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
: DateTime.now();

View file

@ -5,7 +5,6 @@ import 'dart:isolate';
import 'dart:math';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:collection/collection.dart';
import 'package:cw_bitcoin/address_from_output.dart';
@ -22,7 +21,6 @@ import 'package:cw_bitcoin/electrum_transaction_history.dart';
import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_bitcoin/exceptions.dart';
import 'package:cw_bitcoin/litecoin_network.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
import 'package:cw_bitcoin/script_hash.dart';
import 'package:cw_bitcoin/utils.dart';
@ -41,7 +39,6 @@ import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/get_height_by_date.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
import 'package:mobx/mobx.dart';
import 'package:rxdart/subjects.dart';
import 'package:sp_scanner/sp_scanner.dart';
@ -59,7 +56,7 @@ abstract class ElectrumWalletBase
required String password,
required WalletInfo walletInfo,
required Box<UnspentCoinsInfo> unspentCoinsInfo,
required this.networkType,
required this.network,
String? xpub,
String? mnemonic,
Uint8List? seedBytes,
@ -70,7 +67,7 @@ abstract class ElectrumWalletBase
CryptoCurrency? currency,
this.alwaysScan,
}) : accountHD =
getAccountHDWallet(currency, networkType, seedBytes, xpub, walletInfo.derivationInfo),
getAccountHDWallet(currency, network, seedBytes, xpub, walletInfo.derivationInfo),
syncStatus = NotConnectedSyncStatus(),
_password = password,
_feeRates = <int>[],
@ -89,8 +86,7 @@ abstract class ElectrumWalletBase
}
: {}),
this.unspentCoinsInfo = unspentCoinsInfo,
this.network = _getNetwork(networkType, currency),
this.isTestnet = networkType == bitcoin.testnet,
this.isTestnet = network == BitcoinNetwork.testnet,
this._mnemonic = mnemonic,
super(walletInfo) {
this.electrumClient = electrumClient ?? ElectrumClient();
@ -100,12 +96,8 @@ abstract class ElectrumWalletBase
reaction((_) => syncStatus, _syncStatusReaction);
}
static bitcoin.HDWallet getAccountHDWallet(
CryptoCurrency? currency,
bitcoin.NetworkType networkType,
Uint8List? seedBytes,
String? xpub,
DerivationInfo? derivationInfo) {
static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network,
Uint8List? seedBytes, String? xpub, DerivationInfo? derivationInfo) {
if (seedBytes == null && xpub == null) {
throw Exception(
"To create a Wallet you need either a seed or an xpub. This should not happen");
@ -114,25 +106,26 @@ abstract class ElectrumWalletBase
if (seedBytes != null) {
return currency == CryptoCurrency.bch
? bitcoinCashHDWallet(seedBytes)
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
.derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
: Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(
_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path))
as Bip32Slip10Secp256k1;
}
return bitcoin.HDWallet.fromBase58(xpub!);
return Bip32Slip10Secp256k1.fromExtendedKey(xpub!);
}
static bitcoin.HDWallet bitcoinCashHDWallet(Uint8List seedBytes) =>
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'");
static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) =>
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'") as Bip32Slip10Secp256k1;
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
inputsCount * 68 + outputsCounts * 34 + 10;
bool? alwaysScan;
final bitcoin.HDWallet accountHD;
final Bip32Slip10Secp256k1 accountHD;
final String? _mnemonic;
bitcoin.HDWallet get hd => accountHD.derive(0);
Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
final String? passphrase;
@override
@ -164,12 +157,11 @@ abstract class ElectrumWalletBase
.map((addr) => scriptHash(addr.address, network: network))
.toList();
String get xpub => accountHD.base58!;
String get xpub => accountHD.publicKey.toExtended;
@override
String? get seed => _mnemonic;
bitcoin.NetworkType networkType;
BasedUtxoNetwork network;
@override
@ -195,6 +187,7 @@ abstract class ElectrumWalletBase
if (tip == walletInfo.restoreHeight) {
syncStatus = SyncedTipSyncStatus(tip);
return;
}
if (tip > walletInfo.restoreHeight) {
@ -240,8 +233,11 @@ abstract class ElectrumWalletBase
}
@override
BitcoinWalletKeys get keys =>
BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!);
BitcoinWalletKeys get keys => BitcoinWalletKeys(
wif: WifEncoder.encode(hd.privateKey.raw, netVer: network.wifNetVer),
privateKey: hd.privateKey.toHex(),
publicKey: hd.publicKey.toHex(),
);
String _password;
List<BitcoinUnspent> unspentCoins;
@ -388,7 +384,7 @@ abstract class ElectrumWalletBase
BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)),
)
: silentAddress.B_spend,
hrp: silentAddress.hrp,
network: network,
);
final addressRecord = walletAddresses.silentAddresses
@ -417,8 +413,6 @@ abstract class ElectrumWalletBase
await updateAllUnspents();
await updateBalance();
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
if (alwaysScan == true) {
_setListeners(walletInfo.restoreHeight);
} else {
@ -441,6 +435,61 @@ abstract class ElectrumWalletBase
Node? node;
Future<bool> getNodeIsElectrs() async {
if (node == null) {
return false;
}
final version = await electrumClient.version();
if (version.isEmpty) {
node!.isElectrs = false;
node!.save();
return node!.isElectrs!;
}
final server = version[0];
if (server.toLowerCase().contains('electrs')) {
node!.isElectrs = true;
node!.save();
return node!.isElectrs!;
}
node!.isElectrs = false;
node!.save();
return node!.isElectrs!;
}
Future<bool> getNodeSupportsSilentPayments() async {
// As of today (august 2024), only ElectrumRS supports silent payments
if (!(await getNodeIsElectrs())) {
return false;
}
if (node == null) {
return false;
}
try {
final tweaksResponse = await electrumClient.getTweaks(height: 0);
if (tweaksResponse != null) {
node!.supportsSilentPayments = true;
node!.save();
return node!.supportsSilentPayments!;
}
} on RequestFailedTimeoutException catch (_) {
node!.supportsSilentPayments = false;
node!.save();
return node!.supportsSilentPayments!;
} catch (_) {}
node!.supportsSilentPayments = false;
node!.save();
return node!.supportsSilentPayments!;
}
@action
@override
Future<void> connectToNode({required Node node}) async {
@ -502,13 +551,6 @@ abstract class ElectrumWalletBase
final hd =
utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd;
final derivationPath =
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}"
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
"/${utx.bitcoinAddressRecord.index}";
final pubKeyHex = hd.derive(utx.bitcoinAddressRecord.index).pubKey!;
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
if (utx.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
@ -525,6 +567,7 @@ abstract class ElectrumWalletBase
}
vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout));
String pubKeyHex;
if (privkey != null) {
inputPrivKeyInfos.add(ECPrivateInfo(
@ -532,8 +575,18 @@ abstract class ElectrumWalletBase
address.type == SegwitAddresType.p2tr,
tweak: !isSilentPayment,
));
pubKeyHex = privkey.getPublic().toHex();
} else {
pubKeyHex = hd.childKey(Bip32KeyIndex(utx.bitcoinAddressRecord.index)).publicKey.toHex();
}
final derivationPath =
"${_hardenedDerivationPath(walletInfo.derivationInfo?.derivationPath ?? "m/0'")}"
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
"/${utx.bitcoinAddressRecord.index}";
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
utxos.add(
UtxoWithAddress(
utxo: BitcoinUtxo(
@ -1220,7 +1273,7 @@ abstract class ElectrumWalletBase
await Future.wait(unspents.map((unspent) async {
try {
final coin = BitcoinUnspent.fromJSON(address, unspent);
final tx = await fetchTransactionInfo(hash: coin.hash, height: 0);
final tx = await fetchTransactionInfo(hash: coin.hash);
coin.isChange = address.isHidden;
coin.confirmations = tx?.confirmations;
@ -1275,7 +1328,8 @@ abstract class ElectrumWalletBase
}
Future<bool> canReplaceByFee(String hash) async {
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
// TODO: not every node supports verbose
final verboseTransaction = await electrumClient.getTransactionVerbose(hash: hash);
final confirmations = verboseTransaction['confirmations'] as int? ?? 0;
final transactionHex = verboseTransaction['hex'] as String?;
@ -1285,10 +1339,7 @@ abstract class ElectrumWalletBase
return false;
}
final original = bitcoin.Transaction.fromHex(transactionHex);
return original.ins
.any((element) => element.sequence != null && element.sequence! < 4294967293);
return BtcTransaction.fromRaw(transactionHex).canReplaceByFee;
}
Future<bool> isChangeSufficientForFee(String txId, int newFee) async {
@ -1447,27 +1498,36 @@ abstract class ElectrumWalletBase
}
}
Future<ElectrumTransactionBundle> getTransactionExpanded({required String hash}) async {
Future<ElectrumTransactionBundle> getTransactionExpanded(
{required String hash, int? height}) async {
String transactionHex;
// TODO: time is not always available, and calculating it from height is not always accurate.
// Add settings to choose API provider and use and http server instead of electrum for this.
int? time;
int confirmations = 0;
if (network == BitcoinNetwork.testnet) {
// Testnet public electrum server does not support verbose transaction fetching
int? confirmations;
final verboseTransaction = await electrumClient.getTransactionVerbose(hash: hash);
if (verboseTransaction.isEmpty) {
transactionHex = await electrumClient.getTransactionHex(hash: hash);
final status = json.decode(
(await http.get(Uri.parse("https://blockstream.info/testnet/api/tx/$hash/status"))).body);
time = status["block_time"] as int?;
final height = status["block_height"] as int? ?? 0;
final tip = await getUpdatedChainTip();
if (tip > 0) confirmations = height > 0 ? tip - height + 1 : 0;
} else {
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
transactionHex = verboseTransaction['hex'] as String;
time = verboseTransaction['time'] as int?;
confirmations = verboseTransaction['confirmations'] as int? ?? 0;
confirmations = verboseTransaction['confirmations'] as int?;
}
if (height != null) {
if (time == null) {
time = (getDateByBitcoinHeight(height).millisecondsSinceEpoch / 1000).round();
}
if (confirmations == null) {
final tip = await getUpdatedChainTip();
if (tip > 0 && height > 0) {
// Add one because the block itself is the first confirmation
confirmations = tip - height + 1;
}
}
}
final original = BtcTransaction.fromRaw(transactionHex);
@ -1481,16 +1541,20 @@ abstract class ElectrumWalletBase
original,
ins: ins,
time: time,
confirmations: confirmations,
confirmations: confirmations ?? 0,
);
}
Future<ElectrumTransactionInfo?> fetchTransactionInfo(
{required String hash, required int height, bool? retryOnFailure}) async {
{required String hash, int? height, bool? retryOnFailure}) async {
try {
return ElectrumTransactionInfo.fromElectrumBundle(
await getTransactionExpanded(hash: hash), walletInfo.type, network,
addresses: addressesSet, height: height);
await getTransactionExpanded(hash: hash, height: height),
walletInfo.type,
network,
addresses: addressesSet,
height: height,
);
} catch (e) {
if (e is FormatException && retryOnFailure == true) {
await Future.delayed(const Duration(seconds: 2));
@ -1641,8 +1705,8 @@ abstract class ElectrumWalletBase
await getCurrentChainTip();
transactionHistory.transactions.values.forEach((tx) async {
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height > 0) {
tx.confirmations = await getCurrentChainTip() - tx.height + 1;
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height != null && tx.height! > 0) {
tx.confirmations = await getCurrentChainTip() - tx.height! + 1;
}
});
@ -1758,8 +1822,12 @@ abstract class ElectrumWalletBase
final index = address != null
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
: null;
final HD = index == null ? hd : hd.derive(index);
return base64Encode(HD.signMessage(message));
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
final priv = ECPrivate.fromWif(
WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer),
netVersion: network.wifNetVer,
);
return priv.signMessage(StringUtils.encode(message));
}
Future<void> _setInitialHeight() async {
@ -1785,22 +1853,6 @@ abstract class ElectrumWalletBase
});
}
static BasedUtxoNetwork _getNetwork(bitcoin.NetworkType networkType, CryptoCurrency? currency) {
if (networkType == bitcoin.bitcoin && currency == CryptoCurrency.bch) {
return BitcoinCashNetwork.mainnet;
}
if (networkType == litecoinNetwork) {
return LitecoinNetwork.mainnet;
}
if (networkType == bitcoin.testnet) {
return BitcoinNetwork.testnet;
}
return BitcoinNetwork.mainnet;
}
static String _hardenedDerivationPath(String derivationPath) =>
derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
@ -1813,6 +1865,7 @@ abstract class ElectrumWalletBase
} else if (isConnected == false) {
syncStatus = LostConnectionSyncStatus();
} else if (isConnected != true && syncStatus is! ConnectingSyncStatus) {
// TODO: fix this
syncStatus = NotConnectedSyncStatus();
}
}
@ -1942,8 +1995,8 @@ Future<void> startRefresh(ScanData scanData) async {
final tweaks = t as Map<String, dynamic>;
if (tweaks["message"] != null) {
// re-subscribe to continue receiving messages
electrumClient.tweaksSubscribe(height: syncHeight, count: count);
// re-subscribe to continue receiving messages, starting from the next unscanned height
electrumClient.tweaksSubscribe(height: syncHeight + 1, count: count);
return;
}

View file

@ -1,5 +1,4 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_core/wallet_addresses.dart';
@ -30,7 +29,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
Map<String, int>? initialChangeAddressIndex,
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
int initialSilentAddressIndex = 0,
bitcoin.HDWallet? masterHd,
Bip32Slip10Secp256k1? masterHd,
BitcoinAddressType? initialAddressPageType,
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
addressesByReceiveType =
@ -53,9 +52,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
super(walletInfo) {
if (masterHd != null) {
silentAddress = SilentPaymentOwner.fromPrivateKeys(
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privKey!),
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privKey!),
hrp: network == BitcoinNetwork.testnet ? 'tsp' : 'sp');
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()),
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()),
network: network,
);
if (silentAddresses.length == 0) {
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
@ -92,8 +92,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
final ObservableList<BitcoinAddressRecord> changeAddresses;
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
final BasedUtxoNetwork network;
final bitcoin.HDWallet mainHd;
final bitcoin.HDWallet sideHd;
final Bip32Slip10Secp256k1 mainHd;
final Bip32Slip10Secp256k1 sideHd;
@observable
SilentPaymentOwner? silentAddress;
@ -318,7 +318,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
}
String getAddress(
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
{required int index,
required Bip32Slip10Secp256k1 hd,
BitcoinAddressType? addressType}) =>
'';
@override
@ -540,11 +542,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
void _validateAddresses() {
allAddresses.forEach((element) {
if (!element.isHidden && element.address !=
getAddress(index: element.index, hd: mainHd, addressType: element.type)) {
if (!element.isHidden &&
element.address !=
getAddress(index: element.index, hd: mainHd, addressType: element.type)) {
element.isHidden = true;
} else if (element.isHidden && element.address !=
getAddress(index: element.index, hd: sideHd, addressType: element.type)) {
} else if (element.isHidden &&
element.address !=
getAddress(index: element.index, hd: sideHd, addressType: element.type)) {
element.isHidden = false;
}
});
@ -562,7 +566,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
return _isAddressByType(addressRecord, addressPageType);
}
bitcoin.HDWallet _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
Bip32Slip10Secp256k1 _getHd(bool isHidden) => isHidden ? sideHd : mainHd;
bool _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
!addr.isHidden && !addr.isUsed && addr.type == type;

View file

@ -1,9 +0,0 @@
import 'package:bitcoin_flutter/bitcoin_flutter.dart';
final litecoinNetwork = NetworkType(
messagePrefix: '\x19Litecoin Signed Message:\n',
bech32: 'ltc',
bip32: Bip32Type(public: 0x0488b21e, private: 0x0488ade4),
pubKeyHash: 0x30,
scriptHash: 0x32,
wif: 0xb0);

View file

@ -1,4 +1,5 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_core/crypto_currency.dart';
@ -13,7 +14,6 @@ import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
import 'package:cw_bitcoin/electrum_wallet.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
import 'package:cw_bitcoin/litecoin_network.dart';
import 'package:bip39/bip39.dart' as bip39;
part 'litecoin_wallet.g.dart';
@ -37,7 +37,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: litecoinNetwork,
network: LitecoinNetwork.mainnet,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: seedBytes,
@ -48,7 +48,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: accountHD.derive(1),
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
network: network,
);
autorun((_) {

View file

@ -1,5 +1,5 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_core/wallet_info.dart';
@ -22,6 +22,8 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
@override
String getAddress(
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
{required int index,
required Bip32Slip10Secp256k1 hd,
BitcoinAddressType? addressType}) =>
generateP2WPKHAddress(hd: hd, index: index, network: network);
}

View file

@ -1,68 +1,54 @@
import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:flutter/foundation.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bitcoin_flutter/src/payments/index.dart' show PaymentData;
import 'package:hex/hex.dart';
bitcoin.PaymentData generatePaymentData({
required bitcoin.HDWallet hd,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return PaymentData(pubkey: Uint8List.fromList(HEX.decode(pubKey)));
}
import 'package:blockchain_utils/blockchain_utils.dart';
ECPrivate generateECPrivate({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final wif = hd.derive(index).wif!;
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
}
}) =>
ECPrivate(hd.childKey(Bip32KeyIndex(index)).privateKey);
String generateP2WPKHAddress({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
}
}) =>
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
.toP2wpkhAddress()
.toAddress(network);
String generateP2SHAddress({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
}
}) =>
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
.toP2wshInP2sh()
.toAddress(network);
String generateP2WSHAddress({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
}
}) =>
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
.toP2wshAddress()
.toAddress(network);
String generateP2PKHAddress({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
}
}) =>
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
.toP2pkhAddress()
.toAddress(network);
String generateP2TRAddress({
required bitcoin.HDWallet hd,
required Bip32Slip10Secp256k1 hd,
required BasedUtxoNetwork network,
required int index,
}) {
final pubKey = hd.derive(index).pubKey!;
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
}
}) =>
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
.toTaprootAddress()
.toAddress(network);

View file

@ -41,15 +41,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
bech32:
dependency: transitive
description:
path: "."
ref: "cake-0.2.2"
resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
url: "https://github.com/cake-tech/bech32.git"
source: git
version: "0.2.2"
bip32:
dependency: transitive
description:
@ -79,29 +70,20 @@ packages:
dependency: "direct main"
description:
path: "."
ref: cake-update-v3
resolved-ref: cc99eedb1d28ee9376dda0465ef72aa627ac6149
ref: cake-update-v4
resolved-ref: "593d9cebc0c132d96e4df7a183ded585203361f5"
url: "https://github.com/cake-tech/bitcoin_base"
source: git
version: "4.2.1"
bitcoin_flutter:
dependency: "direct main"
description:
path: "."
ref: cake-update-v4
resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
url: "https://github.com/cake-tech/bitcoin_flutter.git"
source: git
version: "2.1.0"
version: "4.7.0"
blockchain_utils:
dependency: "direct main"
description:
path: "."
ref: cake-update-v1
resolved-ref: cabd7e0e16c4da9920338c76eff3aeb8af0211f3
ref: cake-update-v2
resolved-ref: "2767a54ed2b0a23494e4e96a3fe5b5022b834b70"
url: "https://github.com/cake-tech/blockchain_utils"
source: git
version: "2.1.2"
version: "3.3.0"
boolean_selector:
dependency: transitive
description:
@ -792,11 +774,9 @@ packages:
sp_scanner:
dependency: "direct main"
description:
path: "."
ref: "sp_v2.0.0"
resolved-ref: "62c152b9086cd968019128845371072f7e1168de"
url: "https://github.com/cake-tech/sp_scanner"
source: git
path: "/home/rafael/Working/sp_scanner"
relative: false
source: path
version: "0.0.1"
stack_trace:
dependency: transitive

View file

@ -19,10 +19,6 @@ dependencies:
intl: ^0.18.0
cw_core:
path: ../cw_core
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v4
bitbox:
git:
url: https://github.com/cake-tech/bitbox-flutter.git
@ -32,19 +28,19 @@ dependencies:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
ref: cake-update-v3
ref: cake-update-v4
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v1
ref: cake-update-v2
ledger_flutter: ^1.0.1
ledger_bitcoin:
git:
url: https://github.com/cake-tech/ledger-bitcoin
sp_scanner:
git:
url: https://github.com/cake-tech/sp_scanner
ref: sp_v2.0.0
url: https://github.com/rafael-xmr/sp_scanner
ref: sp_v4.0.0
dev_dependencies:

View file

@ -1,8 +1,6 @@
import 'dart:convert';
import 'package:bitbox/bitbox.dart' as bitbox;
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_bitcoin/electrum_balance.dart';
@ -39,7 +37,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
password: password,
walletInfo: walletInfo,
unspentCoinsInfo: unspentCoinsInfo,
networkType: bitcoin.bitcoin,
network: BitcoinCashNetwork.mainnet,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: seedBytes,
@ -50,7 +48,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
mainHd: hd,
sideHd: accountHD.derive(1),
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
network: network,
initialAddressPageType: addressPageType,
);
@ -76,7 +74,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
unspentCoinsInfo: unspentCoinsInfo,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
seedBytes: await Mnemonic.toSeed(mnemonic),
seedBytes: await MnemonicBip39.toSeed(mnemonic),
initialRegularAddressIndex: initialRegularAddressIndex,
initialChangeAddressIndex: initialChangeAddressIndex,
addressPageType: P2pkhAddressType.p2pkh,
@ -117,15 +115,17 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
}
}).toList(),
initialBalance: snp.balance,
seedBytes: await Mnemonic.toSeed(snp.mnemonic!),
seedBytes: await MnemonicBip39.toSeed(snp.mnemonic!),
initialRegularAddressIndex: snp.regularAddressIndex,
initialChangeAddressIndex: snp.changeAddressIndex,
addressPageType: P2pkhAddressType.p2pkh,
);
}
bitbox.ECPair generateKeyPair({required bitcoin.HDWallet hd, required int index}) =>
bitbox.ECPair.fromWIF(hd.derive(index).wif!);
bitbox.ECPair generateKeyPair({required Bip32Slip10Secp256k1 hd, required int index}) =>
bitbox.ECPair.fromPrivateKey(
Uint8List.fromList(hd.childKey(Bip32KeyIndex(index)).privateKey.raw),
);
int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount, int? size}) {
int inputsCount = 0;
@ -171,7 +171,11 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
.index
: null;
final HD = index == null ? hd : hd.derive(index);
return base64Encode(HD.signMessage(message));
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
final priv = ECPrivate.fromWif(
WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer),
netVersion: network.wifNetVer,
);
return priv.signMessage(StringUtils.encode(message));
}
}

View file

@ -1,5 +1,5 @@
import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_core/wallet_info.dart';
@ -23,6 +23,8 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
@override
String getAddress(
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
{required int index,
required Bip32Slip10Secp256k1 hd,
BitcoinAddressType? addressType}) =>
generateP2PKHAddress(hd: hd, index: index, network: network);
}

View file

@ -11,8 +11,11 @@ import 'package:cw_core/wallet_type.dart';
import 'package:collection/collection.dart';
import 'package:hive/hive.dart';
class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredentials,
BitcoinCashRestoreWalletFromSeedCredentials, BitcoinCashRestoreWalletFromWIFCredentials, BitcoinCashNewWalletCredentials> {
class BitcoinCashWalletService extends WalletService<
BitcoinCashNewWalletCredentials,
BitcoinCashRestoreWalletFromSeedCredentials,
BitcoinCashRestoreWalletFromWIFCredentials,
BitcoinCashNewWalletCredentials> {
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
final Box<WalletInfo> walletInfoSource;
@ -30,7 +33,7 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
final wallet = await BitcoinCashWalletBase.create(
mnemonic: await Mnemonic.generate(strength: strength),
mnemonic: await MnemonicBip39.generate(strength: strength),
password: credentials.password!,
walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource);
@ -95,7 +98,8 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
@override
Future<BitcoinCashWallet> restoreFromHardwareWallet(BitcoinCashNewWalletCredentials credentials) {
throw UnimplementedError("Restoring a Bitcoin Cash wallet from a hardware wallet is not yet supported!");
throw UnimplementedError(
"Restoring a Bitcoin Cash wallet from a hardware wallet is not yet supported!");
}
@override

View file

@ -2,7 +2,7 @@ import 'dart:typed_data';
import 'package:bip39/bip39.dart' as bip39;
class Mnemonic {
class MnemonicBip39 {
/// Generate bip39 mnemonic
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);

View file

@ -21,10 +21,6 @@ dependencies:
path: ../cw_core
cw_bitcoin:
path: ../cw_bitcoin
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v4
bitbox:
git:
url: https://github.com/cake-tech/bitbox-flutter.git
@ -32,11 +28,11 @@ dependencies:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
ref: cake-update-v3
ref: cake-update-v4
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v1
ref: cake-update-v2
dev_dependencies:
flutter_test:

View file

@ -245,6 +245,8 @@ Future<int> getHavenCurrentHeight() async {
// Data taken from https://timechaincalendar.com/
const bitcoinDates = {
"2024-08": 854889,
"2024-07": 850182,
"2024-06": 846005,
"2024-05": 841590,
"2024-04": 837182,
@ -371,7 +373,8 @@ const wowDates = {
int getWowneroHeightByDate({required DateTime date}) {
String closestKey =
wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
return wowDates[closestKey] ?? 0;
}
}

View file

@ -11,7 +11,8 @@ import 'package:http/io_client.dart' as ioc;
part 'node.g.dart';
Uri createUriFromElectrumAddress(String address, String path) => Uri.tryParse('tcp://$address$path')!;
Uri createUriFromElectrumAddress(String address, String path) =>
Uri.tryParse('tcp://$address$path')!;
@HiveType(typeId: Node.typeId)
class Node extends HiveObject with Keyable {
@ -72,6 +73,12 @@ class Node extends HiveObject with Keyable {
@HiveField(7, defaultValue: '')
String? path;
@HiveField(8)
bool? isElectrs;
@HiveField(9)
bool? supportsSilentPayments;
bool get isSSL => useSSL ?? false;
bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;

View file

@ -9,7 +9,7 @@ abstract class TransactionInfo extends Object with Keyable {
late TransactionDirection direction;
late bool isPending;
late DateTime date;
late int height;
int? height;
late int confirmations;
String amountFormatted();
String fiatAmount();
@ -25,4 +25,5 @@ abstract class TransactionInfo extends Object with Keyable {
dynamic get keyIndex => id;
late Map<String, dynamic> additionalInfo;
}
}

View file

@ -254,10 +254,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
graphs:
dependency: transitive
description:
@ -514,14 +514,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
name: process
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
pub_semver:
dependency: transitive
description:
@ -707,10 +699,10 @@ packages:
dependency: transitive
description:
name: xdg_directories
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "0.2.0+3"
version: "1.0.4"
yaml:
dependency: transitive
description:

View file

@ -254,10 +254,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
graphs:
dependency: transitive
description:
@ -555,14 +555,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
name: process
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
pub_semver:
dependency: transitive
description:
@ -748,10 +740,10 @@ packages:
dependency: transitive
description:
name: xdg_directories
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "0.2.0+3"
version: "1.0.4"
yaml:
dependency: transitive
description:

View file

@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: b74e3842a52c61f8819a1ec8444b4de5419b41a7465e69d4aa681445377398b0
sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.5.3"
async:
dependency: transitive
description:
@ -117,10 +117,10 @@ packages:
dependency: transitive
description:
name: build_runner_core
sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e"
sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
url: "https://pub.dev"
source: hosted
version: "7.2.7+1"
version: "7.2.7"
built_collection:
dependency: transitive
description:
@ -133,10 +133,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166"
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
url: "https://pub.dev"
source: hosted
version: "8.6.1"
version: "8.9.2"
characters:
dependency: transitive
description:
@ -165,10 +165,10 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189"
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
url: "https://pub.dev"
source: hosted
version: "4.5.0"
version: "4.10.0"
collection:
dependency: transitive
description:
@ -220,10 +220,10 @@ packages:
dependency: "direct main"
description:
name: ed25519_hd_key
sha256: "326608234e986ea826a5db4cf4cd6826058d860875a3fff7926c0725fe1a604d"
sha256: c5c9f11a03f5789bf9dcd9ae88d641571c802640851f1cacdb13123f171b3a26
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.2.1"
encrypt:
dependency: transitive
description:
@ -244,10 +244,10 @@ packages:
dependency: transitive
description:
name: ffi
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.1.2"
file:
dependency: transitive
description:
@ -475,10 +475,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "0afcf88b3ee9d6819890bf16c11a727fc8c62cf736fda8e5d3b9b4eace4e62ea"
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.3.3+2"
mobx_codegen:
dependency: "direct dev"
description:
@ -572,10 +572,10 @@ packages:
dependency: transitive
description:
name: pinenacl
sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327"
url: "https://pub.dev"
source: hosted
version: "0.3.4"
version: "0.5.1"
platform:
dependency: transitive
description:
@ -588,10 +588,10 @@ packages:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd"
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
version: "2.1.8"
pointycastle:
dependency: transitive
description:
@ -652,10 +652,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833"
url: "https://pub.dev"
source: hosted
version: "2.3.4"
version: "2.5.0"
shared_preferences_linux:
dependency: transitive
description:
@ -668,10 +668,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
version: "2.4.1"
shared_preferences_web:
dependency: transitive
description:
@ -849,18 +849,18 @@ packages:
dependency: transitive
description:
name: win32
sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
url: "https://pub.dev"
source: hosted
version: "4.1.4"
version: "5.5.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.4"
yaml:
dependency: transitive
description:
@ -870,5 +870,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.2.0-0 <4.0.0"
flutter: ">=3.7.0"
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.16.6"

View file

@ -18,11 +18,11 @@ dependencies:
on_chain:
git:
url: https://github.com/cake-tech/On_chain
ref: cake-update-v1
ref: cake-update-v2
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v1
ref: cake-update-v2
mobx: ^2.3.0+1
bip39: ^1.0.6
hive: ^2.2.3

View file

@ -254,10 +254,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
graphs:
dependency: transitive
description:
@ -555,14 +555,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process:
dependency: transitive
description:
name: process
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
url: "https://pub.dev"
source: hosted
version: "4.2.4"
pub_semver:
dependency: transitive
description:
@ -748,10 +740,10 @@ packages:
dependency: transitive
description:
name: xdg_directories
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "0.2.0+3"
version: "1.0.4"
yaml:
dependency: transitive
description:

View file

@ -302,16 +302,13 @@ class CWBitcoin extends Bitcoin {
await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
late BasedUtxoNetwork network;
btc.NetworkType networkType;
switch (node.type) {
case WalletType.litecoin:
network = LitecoinNetwork.mainnet;
networkType = litecoinNetwork;
break;
case WalletType.bitcoin:
default:
network = BitcoinNetwork.mainnet;
networkType = btc.bitcoin;
break;
}
@ -341,10 +338,8 @@ class CWBitcoin extends Bitcoin {
balancePath += "/0";
}
final hd = btc.HDWallet.fromSeed(
seedBytes,
network: networkType,
).derivePath(balancePath);
final hd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(balancePath)
as Bip32Slip10Secp256k1;
// derive address at index 0:
String? address;
@ -510,7 +505,7 @@ class CWBitcoin extends Bitcoin {
final bitcoinWallet = wallet as ElectrumWallet;
bitcoinWallet.setSilentPaymentsScanning(
active,
active && (await getNodeIsElectrsSPEnabled(wallet)),
active && (await bitcoinWallet.getNodeSupportsSilentPayments()),
);
}
@ -529,44 +524,10 @@ class CWBitcoin extends Bitcoin {
bitcoinWallet.rescan(height: height, doSingleScan: doSingleScan);
}
Future<bool> getNodeIsElectrs(Object wallet) async {
final bitcoinWallet = wallet as ElectrumWallet;
final version = await bitcoinWallet.electrumClient.version();
if (version.isEmpty) {
return false;
}
final server = version[0];
if (server.toLowerCase().contains('electrs')) {
return true;
}
return false;
}
@override
Future<bool> getNodeIsElectrsSPEnabled(Object wallet) async {
if (!(await getNodeIsElectrs(wallet))) {
return false;
}
final bitcoinWallet = wallet as ElectrumWallet;
try {
final tweaksResponse = await bitcoinWallet.electrumClient.getTweaks(height: 0);
if (tweaksResponse != null) {
return true;
}
} on RequestFailedTimeoutException catch (_) {
return false;
} catch (_) {
rethrow;
}
return false;
return bitcoinWallet.getNodeSupportsSilentPayments();
}
@override

View file

@ -87,10 +87,6 @@ dependencies:
git:
url: https://github.com/cake-tech/ens_dart.git
ref: main
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v4
fluttertoast: 8.1.4
# tor:
# git:
@ -104,7 +100,7 @@ dependencies:
bitcoin_base:
git:
url: https://github.com/cake-tech/bitcoin_base
ref: cake-update-v3
ref: cake-update-v4
ledger_flutter: ^1.0.1
hashlib: 1.12.0

View file

@ -94,12 +94,11 @@ import 'package:cw_core/wallet_service.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
import 'package:ledger_flutter/ledger_flutter.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as btc;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:bip39/bip39.dart' as bip39;
""";
const bitcoinCWHeaders = """
import 'package:cw_bitcoin/utils.dart';
import 'package:cw_bitcoin/litecoin_network.dart';
import 'package:cw_bitcoin/electrum_derivations.dart';
import 'package:cw_bitcoin/electrum.dart';
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';