From bbba41396d32b0fde52b6d676ee310c9fa26f639 Mon Sep 17 00:00:00 2001 From: Rafael Date: Sun, 11 Aug 2024 20:49:45 -0300 Subject: [PATCH] Fixes node connection, and sp, and electrum (#1577) * refactor: remove bitcoin_flutter, update deps, electrs node improvements * feat: connecting/disconnecting improvements, fix rescan by date, scanning message * chore: print * Update pubspec.yaml * Update pubspec.yaml * handle null sockets, retry connection on connect failure * fix imports * fix transaction history * fix RBF * minor fixes/readability enhancements [skip ci] --------- Co-authored-by: Omar Hatem Co-authored-by: Matthew Fosse --- .../lib/bitcoin_hardware_wallet_service.dart | 5 +- cw_bitcoin/lib/bitcoin_wallet.dart | 18 +- cw_bitcoin/lib/bitcoin_wallet_addresses.dart | 5 +- cw_bitcoin/lib/electrum.dart | 111 ++++--- cw_bitcoin/lib/electrum_transaction_info.dart | 4 +- cw_bitcoin/lib/electrum_wallet.dart | 295 +++++++++++------- cw_bitcoin/lib/electrum_wallet_addresses.dart | 30 +- cw_bitcoin/lib/litecoin_network.dart | 9 - cw_bitcoin/lib/litecoin_wallet.dart | 6 +- cw_bitcoin/lib/litecoin_wallet_addresses.dart | 6 +- cw_bitcoin/lib/utils.dart | 72 ++--- cw_bitcoin/pubspec.lock | 79 ++--- cw_bitcoin/pubspec.yaml | 12 +- .../lib/src/bitcoin_cash_wallet.dart | 26 +- .../src/bitcoin_cash_wallet_addresses.dart | 6 +- .../lib/src/bitcoin_cash_wallet_service.dart | 12 +- cw_bitcoin_cash/lib/src/mnemonic.dart | 2 +- cw_bitcoin_cash/pubspec.yaml | 8 +- cw_core/lib/get_height_by_date.dart | 7 +- cw_core/lib/node.dart | 9 +- cw_core/lib/sync_status.dart | 5 + cw_core/lib/transaction_info.dart | 5 +- cw_haven/pubspec.lock | 16 +- cw_monero/pubspec.lock | 4 +- cw_nano/pubspec.lock | 54 ++-- cw_nano/pubspec.yaml | 1 + cw_tron/pubspec.yaml | 4 +- cw_wownero/pubspec.lock | 20 +- ios/Podfile.lock | 12 +- lib/bitcoin/cw_bitcoin.dart | 50 +-- lib/core/sync_status_title.dart | 4 + .../cake_pay_confirm_purchase_card_page.dart | 48 +-- pubspec_base.yaml | 6 +- res/values/strings_ar.arb | 1 + res/values/strings_bg.arb | 1 + res/values/strings_cs.arb | 1 + res/values/strings_de.arb | 1 + res/values/strings_en.arb | 1 + res/values/strings_es.arb | 1 + res/values/strings_fr.arb | 1 + res/values/strings_ha.arb | 1 + res/values/strings_hi.arb | 1 + res/values/strings_hr.arb | 1 + res/values/strings_id.arb | 1 + res/values/strings_it.arb | 1 + res/values/strings_ja.arb | 1 + res/values/strings_ko.arb | 1 + res/values/strings_my.arb | 1 + res/values/strings_nl.arb | 1 + res/values/strings_pl.arb | 1 + res/values/strings_pt.arb | 1 + res/values/strings_ru.arb | 1 + res/values/strings_th.arb | 1 + res/values/strings_tl.arb | 1 + res/values/strings_tr.arb | 1 + res/values/strings_uk.arb | 1 + res/values/strings_ur.arb | 1 + res/values/strings_yo.arb | 1 + res/values/strings_zh.arb | 1 + tool/configure.dart | 3 +- 60 files changed, 525 insertions(+), 455 deletions(-) delete mode 100644 cw_bitcoin/lib/litecoin_network.dart diff --git a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart index 345d645d1..de339175d 100644 --- a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart @@ -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); diff --git a/cw_bitcoin/lib/bitcoin_wallet.dart b/cw_bitcoin/lib/bitcoin_wallet.dart index ce3e2caa8..7b8250541 100644 --- a/cw_bitcoin/lib/bitcoin_wallet.dart +++ b/cw_bitcoin/lib/bitcoin_wallet.dart @@ -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/bitcoin_wallet_addresses.dart'; @@ -51,11 +50,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, @@ -76,10 +75,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((_) { @@ -253,7 +251,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 diff --git a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart index 486e69b11..697719894 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_addresses.dart @@ -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); diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index e3925ca74..69b07d7c1 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -8,6 +8,8 @@ import 'package:cw_bitcoin/script_hash.dart'; import 'package:flutter/foundation.dart'; import 'package:rxdart/rxdart.dart'; +enum ConnectionStatus { connected, disconnected, connecting, failed } + String jsonrpcparams(List params) { final _params = params.map((val) => '"${val.toString()}"').join(','); return '[$_params]'; @@ -41,7 +43,7 @@ class ElectrumClient { bool get isConnected => _isConnected; Socket? socket; - void Function(bool?)? onConnectionStatusChange; + void Function(ConnectionStatus)? onConnectionStatusChange; int _id; final Map _tasks; Map get tasks => _tasks; @@ -60,17 +62,33 @@ class ElectrumClient { } Future connect({required String host, required int port, bool? useSSL}) async { + _setConnectionStatus(ConnectionStatus.connecting); + try { await socket?.close(); } catch (_) {} - if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) { - socket = await Socket.connect(host, port, timeout: connectionTimeout); - } else { - socket = await SecureSocket.connect(host, port, - timeout: connectionTimeout, onBadCertificate: (_) => true); + try { + if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) { + socket = await Socket.connect(host, port, timeout: connectionTimeout); + } else { + socket = await SecureSocket.connect( + host, + port, + timeout: connectionTimeout, + onBadCertificate: (_) => true, + ); + } + } catch (_) { + _setConnectionStatus(ConnectionStatus.failed); + return; } - _setIsConnected(true); + + if (socket == null) { + _setConnectionStatus(ConnectionStatus.failed); + return; + } + _setConnectionStatus(ConnectionStatus.connected); socket!.listen((Uint8List event) { try { @@ -86,13 +104,20 @@ class ElectrumClient { print(e.toString()); } }, onError: (Object error) { - print(error.toString()); + final errorMsg = error.toString(); + print(errorMsg); unterminatedString = ''; - _setIsConnected(false); + + final currentHost = socket?.address.host; + final isErrorForCurrentHost = errorMsg.contains(" ${currentHost} "); + + if (currentHost != null && isErrorForCurrentHost) + _setConnectionStatus(ConnectionStatus.failed); }, onDone: () { unterminatedString = ''; - _setIsConnected(null); + if (host == socket?.address.host) _setConnectionStatus(ConnectionStatus.disconnected); }); + keepAlive(); } @@ -144,9 +169,9 @@ class ElectrumClient { Future ping() async { try { await callWithTimeout(method: 'server.ping'); - _setIsConnected(true); + _setConnectionStatus(ConnectionStatus.connected); } on RequestFailedTimeoutException catch (_) { - _setIsConnected(null); + _setConnectionStatus(ConnectionStatus.disconnected); } } @@ -236,37 +261,39 @@ class ElectrumClient { return []; }); - Future> getTransactionRaw({required String hash}) async { + Future getTransaction({required String hash, required bool verbose}) async { try { final result = await callWithTimeout( - method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000); + method: 'blockchain.transaction.get', params: [hash, verbose], timeout: 10000); if (result is Map) { return result; } } on RequestFailedTimeoutException catch (_) { return {}; } catch (e) { - print("getTransactionRaw: ${e.toString()}"); + print("getTransaction: ${e.toString()}"); return {}; } return {}; } - Future getTransactionHex({required String hash}) async { - try { - final result = await callWithTimeout( - method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000); - if (result is String) { - return result; - } - } on RequestFailedTimeoutException catch (_) { - return ''; - } catch (e) { - print("getTransactionHex: ${e.toString()}"); - return ''; - } - return ''; - } + Future> getTransactionVerbose({required String hash}) => + getTransaction(hash: hash, verbose: true).then((dynamic result) { + if (result is Map) { + return result; + } + + return {}; + }); + + Future getTransactionHex({required String hash}) => + getTransaction(hash: hash, verbose: false).then((dynamic result) { + if (result is String) { + return result; + } + + return ''; + }); Future broadcastTransaction( {required String transactionRaw, @@ -348,7 +375,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(); @@ -398,6 +425,10 @@ class ElectrumClient { BehaviorSubject? subscribe( {required String id, required String method, List params = const []}) { try { + if (socket == null) { + _setConnectionStatus(ConnectionStatus.failed); + return null; + } final subscription = BehaviorSubject(); _regisrySubscription(id, subscription); socket!.write(jsonrpc(method: method, id: _id, params: params)); @@ -411,6 +442,10 @@ class ElectrumClient { Future call( {required String method, List params = const [], Function(int)? idCallback}) async { + if (socket == null) { + _setConnectionStatus(ConnectionStatus.failed); + return null; + } final completer = Completer(); _id += 1; final id = _id; @@ -424,6 +459,10 @@ class ElectrumClient { Future callWithTimeout( {required String method, List params = const [], int timeout = 4000}) async { try { + if (socket == null) { + _setConnectionStatus(ConnectionStatus.failed); + return null; + } final completer = Completer(); _id += 1; final id = _id; @@ -445,6 +484,7 @@ class ElectrumClient { _aliveTimer?.cancel(); try { await socket?.close(); + socket = null; } catch (_) {} onConnectionStatusChange = null; } @@ -493,12 +533,9 @@ class ElectrumClient { } } - void _setIsConnected(bool? isConnected) { - if (_isConnected != isConnected) { - onConnectionStatusChange?.call(isConnected); - } - - _isConnected = isConnected ?? false; + void _setConnectionStatus(ConnectionStatus status) { + onConnectionStatusChange?.call(status); + _isConnected = status == ConnectionStatus.connected; } void _handleResponse(Map response) { diff --git a/cw_bitcoin/lib/electrum_transaction_info.dart b/cw_bitcoin/lib/electrum_transaction_info.dart index d06cfe9de..ea4a3de33 100644 --- a/cw_bitcoin/lib/electrum_transaction_info.dart +++ b/cw_bitcoin/lib/electrum_transaction_info.dart @@ -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? inputAddresses, @@ -99,7 +99,7 @@ class ElectrumTransactionInfo extends TransactionInfo { factory ElectrumTransactionInfo.fromElectrumBundle( ElectrumTransactionBundle bundle, WalletType type, BasedUtxoNetwork network, - {required Set addresses, required int height}) { + {required Set addresses, int? height}) { final date = bundle.time != null ? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000) : DateTime.now(); diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index e55e5ed0e..e1b038beb 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -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'; @@ -42,7 +40,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'; @@ -60,7 +57,7 @@ abstract class ElectrumWalletBase required String password, required WalletInfo walletInfo, required Box unspentCoinsInfo, - required this.networkType, + required this.network, String? xpub, String? mnemonic, Uint8List? seedBytes, @@ -71,7 +68,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 = [], @@ -90,8 +87,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(); @@ -101,12 +97,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"); @@ -115,25 +107,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 @@ -165,7 +158,7 @@ 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; @@ -174,7 +167,6 @@ abstract class ElectrumWalletBase WalletKeysData get walletKeysData => WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase); - bitcoin.NetworkType networkType; BasedUtxoNetwork network; @override @@ -190,24 +182,21 @@ abstract class ElectrumWalletBase bool _isTryingToConnect = false; @action - Future setSilentPaymentsScanning(bool active, bool usingElectrs) async { + Future setSilentPaymentsScanning(bool active) async { silentPaymentsScanningActive = active; if (active) { - syncStatus = AttemptingSyncStatus(); + syncStatus = StartingScanSyncStatus(); final tip = await getUpdatedChainTip(); if (tip == walletInfo.restoreHeight) { syncStatus = SyncedTipSyncStatus(tip); + return; } if (tip > walletInfo.restoreHeight) { - _setListeners( - walletInfo.restoreHeight, - chainTipParam: _currentChainTip, - usingElectrs: usingElectrs, - ); + _setListeners(walletInfo.restoreHeight, chainTipParam: _currentChainTip); } } else { alwaysScan = false; @@ -245,8 +234,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 unspentCoins; @@ -278,7 +270,7 @@ abstract class ElectrumWalletBase int height, { int? chainTipParam, bool? doSingleScan, - bool? usingElectrs, + bool? usingSupportedNode, }) async { final chainTip = chainTipParam ?? await getUpdatedChainTip(); @@ -287,7 +279,7 @@ abstract class ElectrumWalletBase return; } - syncStatus = AttemptingSyncStatus(); + syncStatus = StartingScanSyncStatus(); if (_isolate != null) { final runningIsolate = await _isolate!; @@ -305,7 +297,9 @@ abstract class ElectrumWalletBase chainTip: chainTip, electrumClient: ElectrumClient(), transactionHistoryIds: transactionHistory.transactions.keys.toList(), - node: usingElectrs == true ? ScanNode(node!.uri, node!.useSSL) : null, + node: (await getNodeSupportsSilentPayments()) == true + ? ScanNode(node!.uri, node!.useSSL) + : null, labels: walletAddresses.labels, labelIndexes: walletAddresses.silentAddresses .where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.index >= 1) @@ -393,7 +387,7 @@ abstract class ElectrumWalletBase BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)), ) : silentAddress.B_spend, - hrp: silentAddress.hrp, + network: network, ); final addressRecord = walletAddresses.silentAddresses @@ -422,8 +416,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 { @@ -446,6 +438,58 @@ abstract class ElectrumWalletBase Node? node; + Future getNodeIsElectrs() async { + if (node == null) { + return false; + } + + final version = await electrumClient.version(); + + if (version.isNotEmpty) { + 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 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 connectToNode({required Node node}) async { @@ -507,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; @@ -530,6 +567,7 @@ abstract class ElectrumWalletBase } vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout)); + String pubKeyHex; if (privkey != null) { inputPrivKeyInfos.add(ECPrivateInfo( @@ -537,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( @@ -1127,10 +1175,9 @@ abstract class ElectrumWalletBase int? chainTip, ScanData? scanData, bool? doSingleScan, - bool? usingElectrs, }) async { silentPaymentsScanningActive = true; - _setListeners(height, doSingleScan: doSingleScan, usingElectrs: usingElectrs); + _setListeners(height, doSingleScan: doSingleScan); } @override @@ -1228,7 +1275,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; @@ -1283,9 +1330,17 @@ abstract class ElectrumWalletBase } Future canReplaceByFee(String hash) async { - final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash); - final confirmations = verboseTransaction['confirmations'] as int? ?? 0; - final transactionHex = verboseTransaction['hex'] as String?; + final verboseTransaction = await electrumClient.getTransactionVerbose(hash: hash); + + final String? transactionHex; + int confirmations = 0; + + if (verboseTransaction.isEmpty) { + transactionHex = await electrumClient.getTransactionHex(hash: hash); + } else { + confirmations = verboseTransaction['confirmations'] as int? ?? 0; + transactionHex = verboseTransaction['hex'] as String?; + } if (confirmations > 0) return false; @@ -1293,10 +1348,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 isChangeSufficientForFee(String txId, int newFee) async { @@ -1455,50 +1507,73 @@ abstract class ElectrumWalletBase } } - Future getTransactionExpanded({required String hash}) async { + Future 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); final ins = []; for (final vin in original.inputs) { - ins.add(BtcTransaction.fromRaw(await electrumClient.getTransactionHex(hash: vin.txId))); + final verboseTransaction = await electrumClient.getTransactionVerbose(hash: vin.txId); + + final String inputTransactionHex; + + if (verboseTransaction.isEmpty) { + inputTransactionHex = await electrumClient.getTransactionHex(hash: hash); + } else { + inputTransactionHex = verboseTransaction['hex'] as String; + } + + ins.add(BtcTransaction.fromRaw(inputTransactionHex)); } return ElectrumTransactionBundle( original, ins: ins, time: time, - confirmations: confirmations, + confirmations: confirmations ?? 0, ); } Future 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)); @@ -1649,8 +1724,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; } }); @@ -1766,8 +1841,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 _setInitialHeight() async { @@ -1793,43 +1872,42 @@ 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); @action - void _onConnectionStatusChange(bool? isConnected) { - if (syncStatus is SyncingSyncStatus) return; + void _onConnectionStatusChange(ConnectionStatus status) { + switch (status) { + case ConnectionStatus.connected: + if (syncStatus is NotConnectedSyncStatus || + syncStatus is LostConnectionSyncStatus || + syncStatus is ConnectingSyncStatus) { + syncStatus = AttemptingSyncStatus(); + startSync(); + } - if (isConnected == true && syncStatus is! SyncedSyncStatus) { - syncStatus = ConnectedSyncStatus(); - } else if (isConnected == false) { - syncStatus = LostConnectionSyncStatus(); - } else if (isConnected != true && syncStatus is! ConnectingSyncStatus) { - syncStatus = NotConnectedSyncStatus(); + break; + case ConnectionStatus.disconnected: + syncStatus = NotConnectedSyncStatus(); + break; + case ConnectionStatus.failed: + syncStatus = LostConnectionSyncStatus(); + // wait for 5 seconds and then try to reconnect: + Future.delayed(Duration(seconds: 5), () { + electrumClient.connectToUri( + node!.uri, + useSSL: node!.useSSL ?? false, + ); + }); + break; + case ConnectionStatus.connecting: + syncStatus = ConnectingSyncStatus(); + break; + default: } } void _syncStatusReaction(SyncStatus syncStatus) async { - if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus) { - silentPaymentsScanningActive = syncStatus is SyncingSyncStatus; - } - if (syncStatus is NotConnectedSyncStatus) { // Needs to re-subscribe to all scripthashes when reconnected _scripthashesUpdateSubject = {}; @@ -1950,8 +2028,8 @@ Future startRefresh(ScanData scanData) async { final tweaks = t as Map; 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; } @@ -2180,3 +2258,4 @@ class UtxoDetails { required this.spendsUnconfirmedTX, }); } + diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index b39821dbb..a0424c934 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -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? initialChangeAddressIndex, List? initialSilentAddresses, int initialSilentAddressIndex = 0, - bitcoin.HDWallet? masterHd, + Bip32Slip10Secp256k1? masterHd, BitcoinAddressType? initialAddressPageType, }) : _addresses = ObservableList.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 changeAddresses; final ObservableList 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() { _addresses.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; diff --git a/cw_bitcoin/lib/litecoin_network.dart b/cw_bitcoin/lib/litecoin_network.dart deleted file mode 100644 index d7ad2f837..000000000 --- a/cw_bitcoin/lib/litecoin_network.dart +++ /dev/null @@ -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); diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index bfb9a1b16..64e53ca5d 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -1,12 +1,12 @@ import 'package:bip39/bip39.dart' as bip39; import 'package:bitcoin_base/bitcoin_base.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/bitcoin_transaction_priority.dart'; import 'package:cw_bitcoin/electrum_balance.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/electrum_wallet_snapshot.dart'; -import 'package:cw_bitcoin/litecoin_network.dart'; import 'package:cw_bitcoin/litecoin_wallet_addresses.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/transaction_priority.dart'; @@ -38,7 +38,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, @@ -49,7 +49,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((_) { diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index 99b7445fc..6945db445 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -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); } diff --git a/cw_bitcoin/lib/utils.dart b/cw_bitcoin/lib/utils.dart index e3ebc00db..29d7a9bf3 100644 --- a/cw_bitcoin/lib/utils.dart +++ b/cw_bitcoin/lib/utils.dart @@ -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); diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index 15f7cdb43..be7862e26 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -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: "574486bfcdbbaf978dcd006b46fc8716f880da29" 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: "59fdf29d72068e0522a96a8953ed7272833a9f57" url: "https://github.com/cake-tech/blockchain_utils" source: git - version: "2.1.2" + version: "3.3.0" boolean_selector: dependency: transitive description: @@ -411,10 +393,10 @@ packages: dependency: "direct main" description: name: http - sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -499,11 +481,12 @@ packages: ledger_flutter: dependency: "direct main" description: - name: ledger_flutter - sha256: f1680060ed6ff78f275837e0024ccaf667715a59ba7aa29fa7354bc7752e71c8 - url: "https://pub.dev" - source: hosted - version: "1.0.1" + path: "." + ref: cake-v3 + resolved-ref: "66469ff9dffe2417c70ae7287c9d76d2fe7157a4" + url: "https://github.com/cake-tech/ledger-flutter.git" + source: git + version: "1.0.2" ledger_usb: dependency: transitive description: @@ -596,10 +579,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" path_provider_android: dependency: transitive description: @@ -636,18 +619,18 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -700,10 +683,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" quiver: dependency: transitive description: @@ -761,10 +744,10 @@ packages: dependency: transitive description: name: socks5_proxy - sha256: "045cbba84f6e2b01c1c77634a63e926352bf110ef5f07fc462c6d43bbd4b6a83" + sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" url: "https://pub.dev" source: hosted - version: "1.0.5+dev.2" + version: "1.0.6" source_gen: dependency: transitive description: @@ -793,9 +776,9 @@ packages: dependency: "direct main" description: path: "." - ref: "sp_v2.0.0" - resolved-ref: "62c152b9086cd968019128845371072f7e1168de" - url: "https://github.com/cake-tech/sp_scanner" + ref: "sp_v4.0.0" + resolved-ref: "3b8ae38592c0584f53560071dc18bc570758fe13" + url: "https://github.com/rafael-xmr/sp_scanner" source: git version: "0.0.1" stack_trace: @@ -910,14 +893,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.5" - win32: - dependency: transitive - description: - name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" - url: "https://pub.dev" - source: hosted - version: "5.5.0" xdg_directories: dependency: transitive description: diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index 69ff3d29b..449833220 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -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: diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart index f15eed10d..8323c01a8 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet.dart @@ -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'; @@ -40,7 +38,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, @@ -51,7 +49,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, ); @@ -77,7 +75,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, @@ -136,15 +134,17 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store { } }).toList(), initialBalance: snp?.balance, - seedBytes: await Mnemonic.toSeed(keysData.mnemonic!), + seedBytes: await MnemonicBip39.toSeed(keysData.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; @@ -190,7 +190,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)); } } diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart index d543e944c..7342dc7f5 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_addresses.dart @@ -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); } diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart index 01ae8ace3..002e52c4f 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart @@ -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 { +class BitcoinCashWalletService extends WalletService< + BitcoinCashNewWalletCredentials, + BitcoinCashRestoreWalletFromSeedCredentials, + BitcoinCashRestoreWalletFromWIFCredentials, + BitcoinCashNewWalletCredentials> { BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource); final Box walletInfoSource; @@ -30,7 +33,7 @@ class BitcoinCashWalletService extends WalletService 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 diff --git a/cw_bitcoin_cash/lib/src/mnemonic.dart b/cw_bitcoin_cash/lib/src/mnemonic.dart index b1f1ee984..7aac1d5c4 100644 --- a/cw_bitcoin_cash/lib/src/mnemonic.dart +++ b/cw_bitcoin_cash/lib/src/mnemonic.dart @@ -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); diff --git a/cw_bitcoin_cash/pubspec.yaml b/cw_bitcoin_cash/pubspec.yaml index a0ce889c1..3728bafc5 100644 --- a/cw_bitcoin_cash/pubspec.yaml +++ b/cw_bitcoin_cash/pubspec.yaml @@ -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: diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 6f1b4078b..204f03d62 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -245,6 +245,8 @@ Future 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; -} \ No newline at end of file +} + diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index f35ea589f..85c61de15 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -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; diff --git a/cw_core/lib/sync_status.dart b/cw_core/lib/sync_status.dart index 55c31877f..ea015340c 100644 --- a/cw_core/lib/sync_status.dart +++ b/cw_core/lib/sync_status.dart @@ -3,6 +3,11 @@ abstract class SyncStatus { double progress(); } +class StartingScanSyncStatus extends SyncStatus { + @override + double progress() => 0.0; +} + class SyncingSyncStatus extends SyncStatus { SyncingSyncStatus(this.blocksLeft, this.ptc); diff --git a/cw_core/lib/transaction_info.dart b/cw_core/lib/transaction_info.dart index e363d88db..971e4ecdb 100644 --- a/cw_core/lib/transaction_info.dart +++ b/cw_core/lib/transaction_info.dart @@ -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 additionalInfo; -} \ No newline at end of file +} + diff --git a/cw_haven/pubspec.lock b/cw_haven/pubspec.lock index b8583d219..c34e164f4 100644 --- a/cw_haven/pubspec.lock +++ b/cw_haven/pubspec.lock @@ -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: diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 838f7224c..38299b2dc 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -438,8 +438,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b" - resolved-ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b" + ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b + resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index 70f2f6f0b..c3d4b26b6 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -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: @@ -114,7 +114,7 @@ packages: source: hosted version: "2.4.9" build_runner_core: - dependency: transitive + dependency: "direct overridden" description: name: build_runner_core sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e" @@ -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" diff --git a/cw_nano/pubspec.yaml b/cw_nano/pubspec.yaml index 768c1bb4e..6fae6a895 100644 --- a/cw_nano/pubspec.yaml +++ b/cw_nano/pubspec.yaml @@ -38,6 +38,7 @@ dev_dependencies: dependency_overrides: watcher: ^1.1.0 + build_runner_core: 7.2.7+1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/cw_tron/pubspec.yaml b/cw_tron/pubspec.yaml index f27e1b460..e69fd7ca0 100644 --- a/cw_tron/pubspec.yaml +++ b/cw_tron/pubspec.yaml @@ -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 diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index d91922ac9..737743925 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -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: @@ -438,8 +438,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b" - resolved-ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b" + ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b + resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" @@ -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: diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fddf6e24f..fb6dc4ecf 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -94,6 +94,8 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - sp_scanner (0.0.1): + - Flutter - SwiftProtobuf (1.26.0) - SwiftyGif (5.4.5) - Toast (4.1.1) @@ -132,6 +134,7 @@ DEPENDENCIES: - sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sp_scanner (from `.symlinks/plugins/sp_scanner/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`) - UnstoppableDomainsResolution (~> 4.0.0) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -197,6 +200,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sp_scanner: + :path: ".symlinks/plugins/sp_scanner/ios" uni_links: :path: ".symlinks/plugins/uni_links/ios" url_launcher_ios: @@ -227,7 +232,7 @@ SPEC CHECKSUMS: MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 - package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2 @@ -235,15 +240,16 @@ SPEC CHECKSUMS: reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 - share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12 SwiftProtobuf: 5e8349171e7c2f88f5b9e683cb3cb79d1dc780b3 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e uni_links: d97da20c7701486ba192624d99bffaaffcfc298a UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 + wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 PODFILE CHECKSUM: a2fe518be61cdbdc5b0e2da085ab543d556af2d3 diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index a92aaad74..edfc77acb 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -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; @@ -515,10 +510,7 @@ class CWBitcoin extends Bitcoin { @override Future setScanningActive(Object wallet, bool active) async { final bitcoinWallet = wallet as ElectrumWallet; - bitcoinWallet.setSilentPaymentsScanning( - active, - active && (await getNodeIsElectrsSPEnabled(wallet)), - ); + bitcoinWallet.setSilentPaymentsScanning(active); } @override @@ -536,44 +528,10 @@ class CWBitcoin extends Bitcoin { bitcoinWallet.rescan(height: height, doSingleScan: doSingleScan); } - Future 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 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 diff --git a/lib/core/sync_status_title.dart b/lib/core/sync_status_title.dart index c4cc3929f..465211f23 100644 --- a/lib/core/sync_status_title.dart +++ b/lib/core/sync_status_title.dart @@ -52,5 +52,9 @@ String syncStatusTitle(SyncStatus syncStatus) { return S.current.sync_status_syncronizing; } + if (syncStatus is StartingScanSyncStatus) { + return S.current.sync_status_starting_scan; + } + return ''; } diff --git a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart index fd8dce103..02ddf037d 100644 --- a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart @@ -34,7 +34,7 @@ class CakePayBuyCardDetailPage extends BasePage { @override Widget? middle(BuildContext context) { - return Text( + return Text( title, textAlign: TextAlign.center, maxLines: 2, @@ -359,7 +359,7 @@ class CakePayBuyCardDetailPage extends BasePage { reaction((_) => cakePayPurchaseViewModel.sendViewModel.state, (ExecutionState state) { if (state is FailureState) { WidgetsBinding.instance.addPostFrameCallback((_) { - showStateAlert(context, S.of(context).error, state.error); + if (context.mounted) showStateAlert(context, S.of(context).error, state.error); }); } @@ -381,31 +381,35 @@ class CakePayBuyCardDetailPage extends BasePage { } void showStateAlert(BuildContext context, String title, String content) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: title, - alertContent: content, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); + if (context.mounted) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: title, + alertContent: content, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + } } Future showSentAlert(BuildContext context) async { + if (!context.mounted) { + return; + } final order = cakePayPurchaseViewModel.order!.orderId; final isCopy = await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertTitle: S.of(context).transaction_sent, - alertContent: - S.of(context).cake_pay_save_order + '\n${order}', - leftButtonText: S.of(context).ignor, - rightButtonText: S.of(context).copy, - actionLeftButton: () => Navigator.of(context).pop(false), - actionRightButton: () => Navigator.of(context).pop(true)); - }) ?? + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: S.of(context).transaction_sent, + alertContent: S.of(context).cake_pay_save_order + '\n${order}', + leftButtonText: S.of(context).ignor, + rightButtonText: S.of(context).copy, + actionLeftButton: () => Navigator.of(context).pop(false), + actionRightButton: () => Navigator.of(context).pop(true)); + }) ?? false; if (isCopy) { diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 463c04988..90072a7c1 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -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 diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index d543706fc..4cf9509f8 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "يتم التوصيل", "sync_status_failed_connect": "انقطع الاتصال", "sync_status_not_connected": "غير متصل", + "sync_status_starting_scan": "بدء المسح", "sync_status_starting_sync": "بدء المزامنة", "sync_status_syncronized": "متزامن", "sync_status_syncronizing": "يتم المزامنة", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index ede60567d..b76401cf4 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "СВЪРЗВАНЕ", "sync_status_failed_connect": "НЕУСПЕШНО СВЪРЗВАНЕ", "sync_status_not_connected": "НЯМА ВРЪЗКА", + "sync_status_starting_scan": "Стартово сканиране", "sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ", "sync_status_syncronized": "СИНХРОНИЗИРАНО", "sync_status_syncronizing": "СИНХРОНИЗИРАНЕ", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 8f2cda1e0..c5d374dd0 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "PŘIPOJOVÁNÍ", "sync_status_failed_connect": "ODPOJENO", "sync_status_not_connected": "NEPŘIPOJENO", + "sync_status_starting_scan": "Počáteční skenování", "sync_status_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE", "sync_status_syncronized": "SYNCHRONIZOVÁNO", "sync_status_syncronizing": "SYNCHRONIZUJI", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 59a23222c..7b6613dd6 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "VERBINDEN", "sync_status_failed_connect": "GETRENNT", "sync_status_not_connected": "NICHT VERBUNDEN", + "sync_status_starting_scan": "Scan beginnen", "sync_status_starting_sync": "STARTE SYNCHRONISIERUNG", "sync_status_syncronized": "SYNCHRONISIERT", "sync_status_syncronizing": "SYNCHRONISIERE", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 1bd3fc241..35712a780 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "CONNECTING", "sync_status_failed_connect": "DISCONNECTED", "sync_status_not_connected": "NOT CONNECTED", + "sync_status_starting_scan": "STARTING SCAN", "sync_status_starting_sync": "STARTING SYNC", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONIZING", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index dc8aa3b95..31a6e6865 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "CONECTANDO", "sync_status_failed_connect": "DESCONECTADO", "sync_status_not_connected": "NO CONECTADO", + "sync_status_starting_scan": "Escaneo inicial", "sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index f7c45f7ef..03d4a73dd 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "CONNEXION EN COURS", "sync_status_failed_connect": "DÉCONNECTÉ", "sync_status_not_connected": "NON CONNECTÉ", + "sync_status_starting_scan": "Démarrage", "sync_status_starting_sync": "DÉBUT DE SYNCHRO", "sync_status_syncronized": "SYNCHRONISÉ", "sync_status_syncronizing": "SYNCHRONISATION EN COURS", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index a5805bbb8..922f9a51b 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -697,6 +697,7 @@ "sync_status_connecting": "HADA", "sync_status_failed_connect": "BABU INTERNET", "sync_status_not_connected": "BABU INTERNET", + "sync_status_starting_scan": "Fara scan", "sync_status_starting_sync": "KWAFI", "sync_status_syncronized": "KYAU", "sync_status_syncronizing": "KWAFI", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 4ab8e7534..db6940e8b 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -697,6 +697,7 @@ "sync_status_connecting": "कनेक्ट", "sync_status_failed_connect": "डिस्कनेक्ट किया गया", "sync_status_not_connected": "जुड़े नहीं हैं", + "sync_status_starting_scan": "स्कैन शुरू करना", "sync_status_starting_sync": "सिताज़ा करना", "sync_status_syncronized": "सिंक्रनाइज़", "sync_status_syncronizing": "सिंक्रनाइज़ करने", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 67095ba8f..57cf1361e 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "SPAJANJE", "sync_status_failed_connect": "ISKLJUČENO", "sync_status_not_connected": "NIJE POVEZANO", + "sync_status_starting_scan": "Početno skeniranje", "sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE", "sync_status_syncronized": "SINKRONIZIRANO", "sync_status_syncronizing": "SINKRONIZIRANJE", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 939b938fe..97a4afd3f 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -698,6 +698,7 @@ "sync_status_connecting": "MENGHUBUNGKAN", "sync_status_failed_connect": "GAGAL TERHUBUNG", "sync_status_not_connected": "TIDAK TERHUBUNG", + "sync_status_starting_scan": "Mulai pindai", "sync_status_starting_sync": "MULAI SINKRONISASI", "sync_status_syncronized": "SUDAH TERSINKRONISASI", "sync_status_syncronizing": "SEDANG SINKRONISASI", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 29a142d1e..42c2e628d 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -697,6 +697,7 @@ "sync_status_connecting": "CONNESSIONE", "sync_status_failed_connect": "DISCONNESSO", "sync_status_not_connected": "NON CONNESSO", + "sync_status_starting_scan": "Scansione di partenza", "sync_status_starting_sync": "INIZIO SINC", "sync_status_syncronized": "SINCRONIZZATO", "sync_status_syncronizing": "SINCRONIZZAZIONE", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 3009aa115..72b1f7d09 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "接続中", "sync_status_failed_connect": "切断されました", "sync_status_not_connected": "接続されていません", + "sync_status_starting_scan": "スキャンを開始します", "sync_status_starting_sync": "同期の開始", "sync_status_syncronized": "同期された", "sync_status_syncronizing": "同期", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 53b3cc875..b8cfee1b5 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "연결 중", "sync_status_failed_connect": "연결 해제", "sync_status_not_connected": "연결되지 않은", + "sync_status_starting_scan": "스캔 시작", "sync_status_starting_sync": "동기화 시작", "sync_status_syncronized": "동기화", "sync_status_syncronizing": "동기화", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 64a7a1ad1..52fe72ea6 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "ချိတ်ဆက်ခြင်း။", "sync_status_failed_connect": "အဆက်အသွယ်ဖြတ်ထားသည်။", "sync_status_not_connected": "မချိတ်ဆက်ပါ။", + "sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှု", "sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။", "sync_status_syncronized": "ထပ်တူပြုထားသည်။", "sync_status_syncronizing": "ထပ်တူပြုခြင်း။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 86f6b8c0b..cde10506f 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "AANSLUITING", "sync_status_failed_connect": "LOSGEKOPPELD", "sync_status_not_connected": "NIET VERBONDEN", + "sync_status_starting_scan": "Startscan", "sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN", "sync_status_syncronized": "SYNCHRONIZED", "sync_status_syncronizing": "SYNCHRONISEREN", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 34a8d57fe..a22034c96 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "ŁĄCZENIE", "sync_status_failed_connect": "POŁĄCZENIE NIEUDANE", "sync_status_not_connected": "NIE POŁĄCZONY", + "sync_status_starting_scan": "Rozpoczęcie skanowania", "sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI", "sync_status_syncronized": "ZSYNCHRONIZOWANO", "sync_status_syncronizing": "SYNCHRONIZACJA", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 67d68988f..8f87ca59f 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -697,6 +697,7 @@ "sync_status_connecting": "CONECTANDO", "sync_status_failed_connect": "DESCONECTADO", "sync_status_not_connected": "DESCONECTADO", + "sync_status_starting_scan": "Diretor inicial", "sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO", "sync_status_syncronized": "SINCRONIZADO", "sync_status_syncronizing": "SINCRONIZANDO", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 521cda83d..9f360137f 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "ПОДКЛЮЧЕНИЕ", "sync_status_failed_connect": "ОТКЛЮЧЕНО", "sync_status_not_connected": "НЕ ПОДКЛЮЧЁН", + "sync_status_starting_scan": "Начальное сканирование", "sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ", "sync_status_syncronized": "СИНХРОНИЗИРОВАН", "sync_status_syncronizing": "СИНХРОНИЗАЦИЯ", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 996472f47..a178d2452 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "กำลังเชื่อมต่อ", "sync_status_failed_connect": "การเชื่อมต่อล้มเหลว", "sync_status_not_connected": "ไม่ได้เชื่อมต่อ", + "sync_status_starting_scan": "เริ่มการสแกน", "sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์", "sync_status_syncronized": "ซิงโครไนซ์แล้ว", "sync_status_syncronizing": "กำลังซิงโครไนซ์", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 27e4974bb..f49d3ddee 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "Pagkonekta", "sync_status_failed_connect": "Naka -disconnect", "sync_status_not_connected": "HINDI KONEKTADO", + "sync_status_starting_scan": "Simula sa pag -scan", "sync_status_starting_sync": "Simula sa pag -sync", "sync_status_syncronized": "Naka -synchronize", "sync_status_syncronizing": "Pag -synchronize", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 74b72581e..c73765f64 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "BAĞLANILIYOR", "sync_status_failed_connect": "BAĞLANTI KESİLDİ", "sync_status_not_connected": "BAĞLI DEĞİL", + "sync_status_starting_scan": "Başlangıç ​​taraması", "sync_status_starting_sync": "SENKRONİZE BAŞLATILIYOR", "sync_status_syncronized": "SENKRONİZE EDİLDİ", "sync_status_syncronizing": "SENKRONİZE EDİLİYOR", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 74b2e4703..d088dd1b2 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "ПІДКЛЮЧЕННЯ", "sync_status_failed_connect": "ВІДКЛЮЧЕНО", "sync_status_not_connected": "НЕ ПІДКЛЮЧЕННИЙ", + "sync_status_starting_scan": "Початок сканування", "sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ", "sync_status_syncronized": "СИНХРОНІЗОВАНИЙ", "sync_status_syncronizing": "СИНХРОНІЗАЦІЯ", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 35d024188..0694463de 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -697,6 +697,7 @@ "sync_status_connecting": "جڑ رہا ہے۔", "sync_status_failed_connect": "منقطع", "sync_status_not_connected": "منسلک نہیں", + "sync_status_starting_scan": "اسکین شروع کرنا", "sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔", "sync_status_syncronized": "مطابقت پذیر", "sync_status_syncronizing": "مطابقت پذیری", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 29b8d9b71..87df87aca 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -696,6 +696,7 @@ "sync_status_connecting": "Ń DÁRAPỌ̀ MỌ́", "sync_status_failed_connect": "ÌKÀNPỌ̀ TI KÚ", "sync_status_not_connected": "KÒ TI DÁRAPỌ̀ MỌ́ Ọ", + "sync_status_starting_scan": "Bibẹrẹ ọlọjẹ", "sync_status_starting_sync": "Ń BẸ̀RẸ̀ RẸ́", "sync_status_syncronized": "TI MÚDỌ́GBA", "sync_status_syncronizing": "Ń MÚDỌ́GBA", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index a30acad70..89eca2073 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -695,6 +695,7 @@ "sync_status_connecting": "连接中", "sync_status_failed_connect": "断线", "sync_status_not_connected": "未连接", + "sync_status_starting_scan": "开始扫描", "sync_status_starting_sync": "开始同步", "sync_status_syncronized": "已同步", "sync_status_syncronizing": "正在同步", diff --git a/tool/configure.dart b/tool/configure.dart index 8b5af92b2..c37946476 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -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';