mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-16 17:27:37 +00:00
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 <omarh.ismail1@gmail.com> Co-authored-by: Matthew Fosse <matt@fosse.co>
This commit is contained in:
parent
96baf460f3
commit
bbba41396d
60 changed files with 525 additions and 455 deletions
|
@ -1,7 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/hardware/hardware_account_data.dart';
|
import 'package:cw_core/hardware/hardware_account_data.dart';
|
||||||
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
import 'package:ledger_bitcoin/ledger_bitcoin.dart';
|
||||||
|
@ -25,7 +25,8 @@ class BitcoinHardwareWalletService {
|
||||||
for (final i in indexRange) {
|
for (final i in indexRange) {
|
||||||
final derivationPath = "m/84'/0'/$i'";
|
final derivationPath = "m/84'/0'/$i'";
|
||||||
final xpub = await bitcoinLedgerApp.getXPubKey(device, derivationPath: derivationPath);
|
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);
|
final address = generateP2WPKHAddress(hd: hd, index: 0, network: BitcoinNetwork.mainnet);
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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:convert/convert.dart';
|
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||||
|
@ -51,11 +50,11 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: networkParam == null
|
network: networkParam == null
|
||||||
? bitcoin.bitcoin
|
? BitcoinNetwork.mainnet
|
||||||
: networkParam == BitcoinNetwork.mainnet
|
: networkParam == BitcoinNetwork.mainnet
|
||||||
? bitcoin.bitcoin
|
? BitcoinNetwork.mainnet
|
||||||
: bitcoin.testnet,
|
: BitcoinNetwork.testnet,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
|
@ -76,10 +75,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialSilentAddresses: initialSilentAddresses,
|
initialSilentAddresses: initialSilentAddresses,
|
||||||
initialSilentAddressIndex: initialSilentAddressIndex,
|
initialSilentAddressIndex: initialSilentAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.derive(1),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: networkParam ?? network,
|
network: networkParam ?? network,
|
||||||
masterHd:
|
masterHd: seedBytes != null ? Bip32Slip10Secp256k1.fromSeed(seedBytes) : null,
|
||||||
seedBytes != null ? bitcoin.HDWallet.fromSeed(seedBytes, network: networkType) : null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
|
@ -253,7 +251,7 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
|
||||||
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
PSBTTransactionBuild(inputs: psbtReadyInputs, outputs: outputs, enableRBF: enableRBF);
|
||||||
|
|
||||||
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
final rawHex = await _bitcoinLedgerApp!.signPsbt(_ledgerDevice!, psbt: psbt.psbt);
|
||||||
return BtcTransaction.fromRaw(hex.encode(rawHex));
|
return BtcTransaction.fromRaw(BytesUtils.toHexString(rawHex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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/electrum_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -24,7 +24,8 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||||
}) : super(walletInfo);
|
}) : super(walletInfo);
|
||||||
|
|
||||||
@override
|
@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)
|
if (addressType == P2pkhAddressType.p2pkh)
|
||||||
return generateP2PKHAddress(hd: hd, index: index, network: network);
|
return generateP2PKHAddress(hd: hd, index: index, network: network);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import 'package:cw_bitcoin/script_hash.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
|
enum ConnectionStatus { connected, disconnected, connecting, failed }
|
||||||
|
|
||||||
String jsonrpcparams(List<Object> params) {
|
String jsonrpcparams(List<Object> params) {
|
||||||
final _params = params.map((val) => '"${val.toString()}"').join(',');
|
final _params = params.map((val) => '"${val.toString()}"').join(',');
|
||||||
return '[$_params]';
|
return '[$_params]';
|
||||||
|
@ -41,7 +43,7 @@ class ElectrumClient {
|
||||||
|
|
||||||
bool get isConnected => _isConnected;
|
bool get isConnected => _isConnected;
|
||||||
Socket? socket;
|
Socket? socket;
|
||||||
void Function(bool?)? onConnectionStatusChange;
|
void Function(ConnectionStatus)? onConnectionStatusChange;
|
||||||
int _id;
|
int _id;
|
||||||
final Map<String, SocketTask> _tasks;
|
final Map<String, SocketTask> _tasks;
|
||||||
Map<String, SocketTask> get tasks => _tasks;
|
Map<String, SocketTask> get tasks => _tasks;
|
||||||
|
@ -60,17 +62,33 @@ class ElectrumClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> connect({required String host, required int port, bool? useSSL}) async {
|
Future<void> connect({required String host, required int port, bool? useSSL}) async {
|
||||||
|
_setConnectionStatus(ConnectionStatus.connecting);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await socket?.close();
|
await socket?.close();
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
|
try {
|
||||||
socket = await Socket.connect(host, port, timeout: connectionTimeout);
|
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
|
||||||
} else {
|
socket = await Socket.connect(host, port, timeout: connectionTimeout);
|
||||||
socket = await SecureSocket.connect(host, port,
|
} else {
|
||||||
timeout: connectionTimeout, onBadCertificate: (_) => true);
|
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) {
|
socket!.listen((Uint8List event) {
|
||||||
try {
|
try {
|
||||||
|
@ -86,13 +104,20 @@ class ElectrumClient {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
}
|
}
|
||||||
}, onError: (Object error) {
|
}, onError: (Object error) {
|
||||||
print(error.toString());
|
final errorMsg = error.toString();
|
||||||
|
print(errorMsg);
|
||||||
unterminatedString = '';
|
unterminatedString = '';
|
||||||
_setIsConnected(false);
|
|
||||||
|
final currentHost = socket?.address.host;
|
||||||
|
final isErrorForCurrentHost = errorMsg.contains(" ${currentHost} ");
|
||||||
|
|
||||||
|
if (currentHost != null && isErrorForCurrentHost)
|
||||||
|
_setConnectionStatus(ConnectionStatus.failed);
|
||||||
}, onDone: () {
|
}, onDone: () {
|
||||||
unterminatedString = '';
|
unterminatedString = '';
|
||||||
_setIsConnected(null);
|
if (host == socket?.address.host) _setConnectionStatus(ConnectionStatus.disconnected);
|
||||||
});
|
});
|
||||||
|
|
||||||
keepAlive();
|
keepAlive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,9 +169,9 @@ class ElectrumClient {
|
||||||
Future<void> ping() async {
|
Future<void> ping() async {
|
||||||
try {
|
try {
|
||||||
await callWithTimeout(method: 'server.ping');
|
await callWithTimeout(method: 'server.ping');
|
||||||
_setIsConnected(true);
|
_setConnectionStatus(ConnectionStatus.connected);
|
||||||
} on RequestFailedTimeoutException catch (_) {
|
} on RequestFailedTimeoutException catch (_) {
|
||||||
_setIsConnected(null);
|
_setConnectionStatus(ConnectionStatus.disconnected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,37 +261,39 @@ class ElectrumClient {
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getTransactionRaw({required String hash}) async {
|
Future<dynamic> getTransaction({required String hash, required bool verbose}) async {
|
||||||
try {
|
try {
|
||||||
final result = await callWithTimeout(
|
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<String, dynamic>) {
|
if (result is Map<String, dynamic>) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} on RequestFailedTimeoutException catch (_) {
|
} on RequestFailedTimeoutException catch (_) {
|
||||||
return <String, dynamic>{};
|
return <String, dynamic>{};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("getTransactionRaw: ${e.toString()}");
|
print("getTransaction: ${e.toString()}");
|
||||||
return <String, dynamic>{};
|
return <String, dynamic>{};
|
||||||
}
|
}
|
||||||
return <String, dynamic>{};
|
return <String, dynamic>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getTransactionHex({required String hash}) async {
|
Future<Map<String, dynamic>> getTransactionVerbose({required String hash}) =>
|
||||||
try {
|
getTransaction(hash: hash, verbose: true).then((dynamic result) {
|
||||||
final result = await callWithTimeout(
|
if (result is Map<String, dynamic>) {
|
||||||
method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000);
|
return result;
|
||||||
if (result is String) {
|
}
|
||||||
return result;
|
|
||||||
}
|
return <String, dynamic>{};
|
||||||
} on RequestFailedTimeoutException catch (_) {
|
});
|
||||||
return '';
|
|
||||||
} catch (e) {
|
Future<String> getTransactionHex({required String hash}) =>
|
||||||
print("getTransactionHex: ${e.toString()}");
|
getTransaction(hash: hash, verbose: false).then((dynamic result) {
|
||||||
return '';
|
if (result is String) {
|
||||||
}
|
return result;
|
||||||
return '';
|
}
|
||||||
}
|
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
Future<String> broadcastTransaction(
|
Future<String> broadcastTransaction(
|
||||||
{required String transactionRaw,
|
{required String transactionRaw,
|
||||||
|
@ -348,7 +375,7 @@ class ElectrumClient {
|
||||||
try {
|
try {
|
||||||
final topDoubleString = await estimatefee(p: 1);
|
final topDoubleString = await estimatefee(p: 1);
|
||||||
final middleDoubleString = await estimatefee(p: 5);
|
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 top = (stringDoubleToBitcoinAmount(topDoubleString.toString()) / 1000).round();
|
||||||
final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
|
final middle = (stringDoubleToBitcoinAmount(middleDoubleString.toString()) / 1000).round();
|
||||||
final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();
|
final bottom = (stringDoubleToBitcoinAmount(bottomDoubleString.toString()) / 1000).round();
|
||||||
|
@ -398,6 +425,10 @@ class ElectrumClient {
|
||||||
BehaviorSubject<T>? subscribe<T>(
|
BehaviorSubject<T>? subscribe<T>(
|
||||||
{required String id, required String method, List<Object> params = const []}) {
|
{required String id, required String method, List<Object> params = const []}) {
|
||||||
try {
|
try {
|
||||||
|
if (socket == null) {
|
||||||
|
_setConnectionStatus(ConnectionStatus.failed);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final subscription = BehaviorSubject<T>();
|
final subscription = BehaviorSubject<T>();
|
||||||
_regisrySubscription(id, subscription);
|
_regisrySubscription(id, subscription);
|
||||||
socket!.write(jsonrpc(method: method, id: _id, params: params));
|
socket!.write(jsonrpc(method: method, id: _id, params: params));
|
||||||
|
@ -411,6 +442,10 @@ class ElectrumClient {
|
||||||
|
|
||||||
Future<dynamic> call(
|
Future<dynamic> call(
|
||||||
{required String method, List<Object> params = const [], Function(int)? idCallback}) async {
|
{required String method, List<Object> params = const [], Function(int)? idCallback}) async {
|
||||||
|
if (socket == null) {
|
||||||
|
_setConnectionStatus(ConnectionStatus.failed);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final completer = Completer<dynamic>();
|
final completer = Completer<dynamic>();
|
||||||
_id += 1;
|
_id += 1;
|
||||||
final id = _id;
|
final id = _id;
|
||||||
|
@ -424,6 +459,10 @@ class ElectrumClient {
|
||||||
Future<dynamic> callWithTimeout(
|
Future<dynamic> callWithTimeout(
|
||||||
{required String method, List<Object> params = const [], int timeout = 4000}) async {
|
{required String method, List<Object> params = const [], int timeout = 4000}) async {
|
||||||
try {
|
try {
|
||||||
|
if (socket == null) {
|
||||||
|
_setConnectionStatus(ConnectionStatus.failed);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
final completer = Completer<dynamic>();
|
final completer = Completer<dynamic>();
|
||||||
_id += 1;
|
_id += 1;
|
||||||
final id = _id;
|
final id = _id;
|
||||||
|
@ -445,6 +484,7 @@ class ElectrumClient {
|
||||||
_aliveTimer?.cancel();
|
_aliveTimer?.cancel();
|
||||||
try {
|
try {
|
||||||
await socket?.close();
|
await socket?.close();
|
||||||
|
socket = null;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
onConnectionStatusChange = null;
|
onConnectionStatusChange = null;
|
||||||
}
|
}
|
||||||
|
@ -493,12 +533,9 @@ class ElectrumClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setIsConnected(bool? isConnected) {
|
void _setConnectionStatus(ConnectionStatus status) {
|
||||||
if (_isConnected != isConnected) {
|
onConnectionStatusChange?.call(status);
|
||||||
onConnectionStatusChange?.call(isConnected);
|
_isConnected = status == ConnectionStatus.connected;
|
||||||
}
|
|
||||||
|
|
||||||
_isConnected = isConnected ?? false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleResponse(Map<String, dynamic> response) {
|
void _handleResponse(Map<String, dynamic> response) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
|
|
||||||
ElectrumTransactionInfo(this.type,
|
ElectrumTransactionInfo(this.type,
|
||||||
{required String id,
|
{required String id,
|
||||||
required int height,
|
int? height,
|
||||||
required int amount,
|
required int amount,
|
||||||
int? fee,
|
int? fee,
|
||||||
List<String>? inputAddresses,
|
List<String>? inputAddresses,
|
||||||
|
@ -99,7 +99,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
|
||||||
|
|
||||||
factory ElectrumTransactionInfo.fromElectrumBundle(
|
factory ElectrumTransactionInfo.fromElectrumBundle(
|
||||||
ElectrumTransactionBundle bundle, WalletType type, BasedUtxoNetwork network,
|
ElectrumTransactionBundle bundle, WalletType type, BasedUtxoNetwork network,
|
||||||
{required Set<String> addresses, required int height}) {
|
{required Set<String> addresses, int? height}) {
|
||||||
final date = bundle.time != null
|
final date = bundle.time != null
|
||||||
? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
|
? DateTime.fromMillisecondsSinceEpoch(bundle.time! * 1000)
|
||||||
: DateTime.now();
|
: DateTime.now();
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'dart:isolate';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:cw_bitcoin/address_from_output.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_transaction_info.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/exceptions.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/pending_bitcoin_transaction.dart';
|
||||||
import 'package:cw_bitcoin/script_hash.dart';
|
import 'package:cw_bitcoin/script_hash.dart';
|
||||||
import 'package:cw_bitcoin/utils.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:cw_core/get_height_by_date.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:rxdart/subjects.dart';
|
import 'package:rxdart/subjects.dart';
|
||||||
import 'package:sp_scanner/sp_scanner.dart';
|
import 'package:sp_scanner/sp_scanner.dart';
|
||||||
|
@ -60,7 +57,7 @@ abstract class ElectrumWalletBase
|
||||||
required String password,
|
required String password,
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||||
required this.networkType,
|
required this.network,
|
||||||
String? xpub,
|
String? xpub,
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
Uint8List? seedBytes,
|
Uint8List? seedBytes,
|
||||||
|
@ -71,7 +68,7 @@ abstract class ElectrumWalletBase
|
||||||
CryptoCurrency? currency,
|
CryptoCurrency? currency,
|
||||||
this.alwaysScan,
|
this.alwaysScan,
|
||||||
}) : accountHD =
|
}) : accountHD =
|
||||||
getAccountHDWallet(currency, networkType, seedBytes, xpub, walletInfo.derivationInfo),
|
getAccountHDWallet(currency, network, seedBytes, xpub, walletInfo.derivationInfo),
|
||||||
syncStatus = NotConnectedSyncStatus(),
|
syncStatus = NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_feeRates = <int>[],
|
_feeRates = <int>[],
|
||||||
|
@ -90,8 +87,7 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
this.unspentCoinsInfo = unspentCoinsInfo,
|
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||||
this.network = _getNetwork(networkType, currency),
|
this.isTestnet = network == BitcoinNetwork.testnet,
|
||||||
this.isTestnet = networkType == bitcoin.testnet,
|
|
||||||
this._mnemonic = mnemonic,
|
this._mnemonic = mnemonic,
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.electrumClient = electrumClient ?? ElectrumClient();
|
this.electrumClient = electrumClient ?? ElectrumClient();
|
||||||
|
@ -101,12 +97,8 @@ abstract class ElectrumWalletBase
|
||||||
reaction((_) => syncStatus, _syncStatusReaction);
|
reaction((_) => syncStatus, _syncStatusReaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bitcoin.HDWallet getAccountHDWallet(
|
static Bip32Slip10Secp256k1 getAccountHDWallet(CryptoCurrency? currency, BasedUtxoNetwork network,
|
||||||
CryptoCurrency? currency,
|
Uint8List? seedBytes, String? xpub, DerivationInfo? derivationInfo) {
|
||||||
bitcoin.NetworkType networkType,
|
|
||||||
Uint8List? seedBytes,
|
|
||||||
String? xpub,
|
|
||||||
DerivationInfo? derivationInfo) {
|
|
||||||
if (seedBytes == null && xpub == null) {
|
if (seedBytes == null && xpub == null) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"To create a Wallet you need either a seed or an xpub. This should not happen");
|
"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) {
|
if (seedBytes != null) {
|
||||||
return currency == CryptoCurrency.bch
|
return currency == CryptoCurrency.bch
|
||||||
? bitcoinCashHDWallet(seedBytes)
|
? bitcoinCashHDWallet(seedBytes)
|
||||||
: bitcoin.HDWallet.fromSeed(seedBytes, network: networkType)
|
: Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(
|
||||||
.derivePath(_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path));
|
_hardenedDerivationPath(derivationInfo?.derivationPath ?? electrum_path))
|
||||||
|
as Bip32Slip10Secp256k1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bitcoin.HDWallet.fromBase58(xpub!);
|
return Bip32Slip10Secp256k1.fromExtendedKey(xpub!);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bitcoin.HDWallet bitcoinCashHDWallet(Uint8List seedBytes) =>
|
static Bip32Slip10Secp256k1 bitcoinCashHDWallet(Uint8List seedBytes) =>
|
||||||
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'");
|
Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath("m/44'/145'/0'") as Bip32Slip10Secp256k1;
|
||||||
|
|
||||||
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
||||||
inputsCount * 68 + outputsCounts * 34 + 10;
|
inputsCount * 68 + outputsCounts * 34 + 10;
|
||||||
|
|
||||||
bool? alwaysScan;
|
bool? alwaysScan;
|
||||||
|
|
||||||
final bitcoin.HDWallet accountHD;
|
final Bip32Slip10Secp256k1 accountHD;
|
||||||
final String? _mnemonic;
|
final String? _mnemonic;
|
||||||
|
|
||||||
bitcoin.HDWallet get hd => accountHD.derive(0);
|
Bip32Slip10Secp256k1 get hd => accountHD.childKey(Bip32KeyIndex(0));
|
||||||
final String? passphrase;
|
final String? passphrase;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -165,7 +158,7 @@ abstract class ElectrumWalletBase
|
||||||
.map((addr) => scriptHash(addr.address, network: network))
|
.map((addr) => scriptHash(addr.address, network: network))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
String get xpub => accountHD.base58!;
|
String get xpub => accountHD.publicKey.toExtended;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get seed => _mnemonic;
|
String? get seed => _mnemonic;
|
||||||
|
@ -174,7 +167,6 @@ abstract class ElectrumWalletBase
|
||||||
WalletKeysData get walletKeysData =>
|
WalletKeysData get walletKeysData =>
|
||||||
WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase);
|
WalletKeysData(mnemonic: _mnemonic, xPub: xpub, passphrase: passphrase);
|
||||||
|
|
||||||
bitcoin.NetworkType networkType;
|
|
||||||
BasedUtxoNetwork network;
|
BasedUtxoNetwork network;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -190,24 +182,21 @@ abstract class ElectrumWalletBase
|
||||||
bool _isTryingToConnect = false;
|
bool _isTryingToConnect = false;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> setSilentPaymentsScanning(bool active, bool usingElectrs) async {
|
Future<void> setSilentPaymentsScanning(bool active) async {
|
||||||
silentPaymentsScanningActive = active;
|
silentPaymentsScanningActive = active;
|
||||||
|
|
||||||
if (active) {
|
if (active) {
|
||||||
syncStatus = AttemptingSyncStatus();
|
syncStatus = StartingScanSyncStatus();
|
||||||
|
|
||||||
final tip = await getUpdatedChainTip();
|
final tip = await getUpdatedChainTip();
|
||||||
|
|
||||||
if (tip == walletInfo.restoreHeight) {
|
if (tip == walletInfo.restoreHeight) {
|
||||||
syncStatus = SyncedTipSyncStatus(tip);
|
syncStatus = SyncedTipSyncStatus(tip);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tip > walletInfo.restoreHeight) {
|
if (tip > walletInfo.restoreHeight) {
|
||||||
_setListeners(
|
_setListeners(walletInfo.restoreHeight, chainTipParam: _currentChainTip);
|
||||||
walletInfo.restoreHeight,
|
|
||||||
chainTipParam: _currentChainTip,
|
|
||||||
usingElectrs: usingElectrs,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
alwaysScan = false;
|
alwaysScan = false;
|
||||||
|
@ -245,8 +234,11 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
BitcoinWalletKeys get keys =>
|
BitcoinWalletKeys get keys => BitcoinWalletKeys(
|
||||||
BitcoinWalletKeys(wif: hd.wif!, privateKey: hd.privKey!, publicKey: hd.pubKey!);
|
wif: WifEncoder.encode(hd.privateKey.raw, netVer: network.wifNetVer),
|
||||||
|
privateKey: hd.privateKey.toHex(),
|
||||||
|
publicKey: hd.publicKey.toHex(),
|
||||||
|
);
|
||||||
|
|
||||||
String _password;
|
String _password;
|
||||||
List<BitcoinUnspent> unspentCoins;
|
List<BitcoinUnspent> unspentCoins;
|
||||||
|
@ -278,7 +270,7 @@ abstract class ElectrumWalletBase
|
||||||
int height, {
|
int height, {
|
||||||
int? chainTipParam,
|
int? chainTipParam,
|
||||||
bool? doSingleScan,
|
bool? doSingleScan,
|
||||||
bool? usingElectrs,
|
bool? usingSupportedNode,
|
||||||
}) async {
|
}) async {
|
||||||
final chainTip = chainTipParam ?? await getUpdatedChainTip();
|
final chainTip = chainTipParam ?? await getUpdatedChainTip();
|
||||||
|
|
||||||
|
@ -287,7 +279,7 @@ abstract class ElectrumWalletBase
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
syncStatus = AttemptingSyncStatus();
|
syncStatus = StartingScanSyncStatus();
|
||||||
|
|
||||||
if (_isolate != null) {
|
if (_isolate != null) {
|
||||||
final runningIsolate = await _isolate!;
|
final runningIsolate = await _isolate!;
|
||||||
|
@ -305,7 +297,9 @@ abstract class ElectrumWalletBase
|
||||||
chainTip: chainTip,
|
chainTip: chainTip,
|
||||||
electrumClient: ElectrumClient(),
|
electrumClient: ElectrumClient(),
|
||||||
transactionHistoryIds: transactionHistory.transactions.keys.toList(),
|
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,
|
labels: walletAddresses.labels,
|
||||||
labelIndexes: walletAddresses.silentAddresses
|
labelIndexes: walletAddresses.silentAddresses
|
||||||
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.index >= 1)
|
.where((addr) => addr.type == SilentPaymentsAddresType.p2sp && addr.index >= 1)
|
||||||
|
@ -393,7 +387,7 @@ abstract class ElectrumWalletBase
|
||||||
BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)),
|
BigintUtils.fromBytes(BytesUtils.fromHexString(unspent.silentPaymentLabel!)),
|
||||||
)
|
)
|
||||||
: silentAddress.B_spend,
|
: silentAddress.B_spend,
|
||||||
hrp: silentAddress.hrp,
|
network: network,
|
||||||
);
|
);
|
||||||
|
|
||||||
final addressRecord = walletAddresses.silentAddresses
|
final addressRecord = walletAddresses.silentAddresses
|
||||||
|
@ -422,8 +416,6 @@ abstract class ElectrumWalletBase
|
||||||
await updateAllUnspents();
|
await updateAllUnspents();
|
||||||
await updateBalance();
|
await updateBalance();
|
||||||
|
|
||||||
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
|
|
||||||
|
|
||||||
if (alwaysScan == true) {
|
if (alwaysScan == true) {
|
||||||
_setListeners(walletInfo.restoreHeight);
|
_setListeners(walletInfo.restoreHeight);
|
||||||
} else {
|
} else {
|
||||||
|
@ -446,6 +438,58 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
Node? node;
|
Node? node;
|
||||||
|
|
||||||
|
Future<bool> 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<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
|
@action
|
||||||
@override
|
@override
|
||||||
Future<void> connectToNode({required Node node}) async {
|
Future<void> connectToNode({required Node node}) async {
|
||||||
|
@ -507,13 +551,6 @@ abstract class ElectrumWalletBase
|
||||||
|
|
||||||
final hd =
|
final hd =
|
||||||
utx.bitcoinAddressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd;
|
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) {
|
if (utx.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
|
||||||
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
final unspentAddress = utx.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
|
||||||
|
@ -530,6 +567,7 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout));
|
vinOutpoints.add(Outpoint(txid: utx.hash, index: utx.vout));
|
||||||
|
String pubKeyHex;
|
||||||
|
|
||||||
if (privkey != null) {
|
if (privkey != null) {
|
||||||
inputPrivKeyInfos.add(ECPrivateInfo(
|
inputPrivKeyInfos.add(ECPrivateInfo(
|
||||||
|
@ -537,8 +575,18 @@ abstract class ElectrumWalletBase
|
||||||
address.type == SegwitAddresType.p2tr,
|
address.type == SegwitAddresType.p2tr,
|
||||||
tweak: !isSilentPayment,
|
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(
|
utxos.add(
|
||||||
UtxoWithAddress(
|
UtxoWithAddress(
|
||||||
utxo: BitcoinUtxo(
|
utxo: BitcoinUtxo(
|
||||||
|
@ -1127,10 +1175,9 @@ abstract class ElectrumWalletBase
|
||||||
int? chainTip,
|
int? chainTip,
|
||||||
ScanData? scanData,
|
ScanData? scanData,
|
||||||
bool? doSingleScan,
|
bool? doSingleScan,
|
||||||
bool? usingElectrs,
|
|
||||||
}) async {
|
}) async {
|
||||||
silentPaymentsScanningActive = true;
|
silentPaymentsScanningActive = true;
|
||||||
_setListeners(height, doSingleScan: doSingleScan, usingElectrs: usingElectrs);
|
_setListeners(height, doSingleScan: doSingleScan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -1228,7 +1275,7 @@ abstract class ElectrumWalletBase
|
||||||
await Future.wait(unspents.map((unspent) async {
|
await Future.wait(unspents.map((unspent) async {
|
||||||
try {
|
try {
|
||||||
final coin = BitcoinUnspent.fromJSON(address, unspent);
|
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.isChange = address.isHidden;
|
||||||
coin.confirmations = tx?.confirmations;
|
coin.confirmations = tx?.confirmations;
|
||||||
|
|
||||||
|
@ -1283,9 +1330,17 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> canReplaceByFee(String hash) async {
|
Future<bool> canReplaceByFee(String hash) async {
|
||||||
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
|
final verboseTransaction = await electrumClient.getTransactionVerbose(hash: hash);
|
||||||
final confirmations = verboseTransaction['confirmations'] as int? ?? 0;
|
|
||||||
final transactionHex = verboseTransaction['hex'] as String?;
|
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;
|
if (confirmations > 0) return false;
|
||||||
|
|
||||||
|
@ -1293,10 +1348,7 @@ abstract class ElectrumWalletBase
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final original = bitcoin.Transaction.fromHex(transactionHex);
|
return BtcTransaction.fromRaw(transactionHex).canReplaceByFee;
|
||||||
|
|
||||||
return original.ins
|
|
||||||
.any((element) => element.sequence != null && element.sequence! < 4294967293);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> isChangeSufficientForFee(String txId, int newFee) async {
|
Future<bool> isChangeSufficientForFee(String txId, int newFee) async {
|
||||||
|
@ -1455,50 +1507,73 @@ abstract class ElectrumWalletBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ElectrumTransactionBundle> getTransactionExpanded({required String hash}) async {
|
Future<ElectrumTransactionBundle> getTransactionExpanded(
|
||||||
|
{required String hash, int? height}) async {
|
||||||
String transactionHex;
|
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? time;
|
||||||
int confirmations = 0;
|
int? confirmations;
|
||||||
if (network == BitcoinNetwork.testnet) {
|
|
||||||
// Testnet public electrum server does not support verbose transaction fetching
|
final verboseTransaction = await electrumClient.getTransactionVerbose(hash: hash);
|
||||||
|
|
||||||
|
if (verboseTransaction.isEmpty) {
|
||||||
transactionHex = await electrumClient.getTransactionHex(hash: hash);
|
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 {
|
} else {
|
||||||
final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
|
|
||||||
|
|
||||||
transactionHex = verboseTransaction['hex'] as String;
|
transactionHex = verboseTransaction['hex'] as String;
|
||||||
time = verboseTransaction['time'] as int?;
|
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 original = BtcTransaction.fromRaw(transactionHex);
|
||||||
final ins = <BtcTransaction>[];
|
final ins = <BtcTransaction>[];
|
||||||
|
|
||||||
for (final vin in original.inputs) {
|
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(
|
return ElectrumTransactionBundle(
|
||||||
original,
|
original,
|
||||||
ins: ins,
|
ins: ins,
|
||||||
time: time,
|
time: time,
|
||||||
confirmations: confirmations,
|
confirmations: confirmations ?? 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ElectrumTransactionInfo?> fetchTransactionInfo(
|
Future<ElectrumTransactionInfo?> fetchTransactionInfo(
|
||||||
{required String hash, required int height, bool? retryOnFailure}) async {
|
{required String hash, int? height, bool? retryOnFailure}) async {
|
||||||
try {
|
try {
|
||||||
return ElectrumTransactionInfo.fromElectrumBundle(
|
return ElectrumTransactionInfo.fromElectrumBundle(
|
||||||
await getTransactionExpanded(hash: hash), walletInfo.type, network,
|
await getTransactionExpanded(hash: hash, height: height),
|
||||||
addresses: addressesSet, height: height);
|
walletInfo.type,
|
||||||
|
network,
|
||||||
|
addresses: addressesSet,
|
||||||
|
height: height,
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e is FormatException && retryOnFailure == true) {
|
if (e is FormatException && retryOnFailure == true) {
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
@ -1649,8 +1724,8 @@ abstract class ElectrumWalletBase
|
||||||
await getCurrentChainTip();
|
await getCurrentChainTip();
|
||||||
|
|
||||||
transactionHistory.transactions.values.forEach((tx) async {
|
transactionHistory.transactions.values.forEach((tx) async {
|
||||||
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height > 0) {
|
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height != null && tx.height! > 0) {
|
||||||
tx.confirmations = await getCurrentChainTip() - tx.height + 1;
|
tx.confirmations = await getCurrentChainTip() - tx.height! + 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1766,8 +1841,12 @@ abstract class ElectrumWalletBase
|
||||||
final index = address != null
|
final index = address != null
|
||||||
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
|
? walletAddresses.allAddresses.firstWhere((element) => element.address == address).index
|
||||||
: null;
|
: null;
|
||||||
final HD = index == null ? hd : hd.derive(index);
|
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
|
||||||
return base64Encode(HD.signMessage(message));
|
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 {
|
Future<void> _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) =>
|
static String _hardenedDerivationPath(String derivationPath) =>
|
||||||
derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
|
derivationPath.substring(0, derivationPath.lastIndexOf("'") + 1);
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void _onConnectionStatusChange(bool? isConnected) {
|
void _onConnectionStatusChange(ConnectionStatus status) {
|
||||||
if (syncStatus is SyncingSyncStatus) return;
|
switch (status) {
|
||||||
|
case ConnectionStatus.connected:
|
||||||
|
if (syncStatus is NotConnectedSyncStatus ||
|
||||||
|
syncStatus is LostConnectionSyncStatus ||
|
||||||
|
syncStatus is ConnectingSyncStatus) {
|
||||||
|
syncStatus = AttemptingSyncStatus();
|
||||||
|
startSync();
|
||||||
|
}
|
||||||
|
|
||||||
if (isConnected == true && syncStatus is! SyncedSyncStatus) {
|
break;
|
||||||
syncStatus = ConnectedSyncStatus();
|
case ConnectionStatus.disconnected:
|
||||||
} else if (isConnected == false) {
|
syncStatus = NotConnectedSyncStatus();
|
||||||
syncStatus = LostConnectionSyncStatus();
|
break;
|
||||||
} else if (isConnected != true && syncStatus is! ConnectingSyncStatus) {
|
case ConnectionStatus.failed:
|
||||||
syncStatus = NotConnectedSyncStatus();
|
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 {
|
void _syncStatusReaction(SyncStatus syncStatus) async {
|
||||||
if (syncStatus is! AttemptingSyncStatus && syncStatus is! SyncedTipSyncStatus) {
|
|
||||||
silentPaymentsScanningActive = syncStatus is SyncingSyncStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncStatus is NotConnectedSyncStatus) {
|
if (syncStatus is NotConnectedSyncStatus) {
|
||||||
// Needs to re-subscribe to all scripthashes when reconnected
|
// Needs to re-subscribe to all scripthashes when reconnected
|
||||||
_scripthashesUpdateSubject = {};
|
_scripthashesUpdateSubject = {};
|
||||||
|
@ -1950,8 +2028,8 @@ Future<void> startRefresh(ScanData scanData) async {
|
||||||
final tweaks = t as Map<String, dynamic>;
|
final tweaks = t as Map<String, dynamic>;
|
||||||
|
|
||||||
if (tweaks["message"] != null) {
|
if (tweaks["message"] != null) {
|
||||||
// re-subscribe to continue receiving messages
|
// re-subscribe to continue receiving messages, starting from the next unscanned height
|
||||||
electrumClient.tweaksSubscribe(height: syncHeight, count: count);
|
electrumClient.tweaksSubscribe(height: syncHeight + 1, count: count);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2180,3 +2258,4 @@ class UtxoDetails {
|
||||||
required this.spendsUnconfirmedTX,
|
required this.spendsUnconfirmedTX,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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:blockchain_utils/blockchain_utils.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||||
import 'package:cw_core/wallet_addresses.dart';
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
|
@ -30,7 +29,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
Map<String, int>? initialChangeAddressIndex,
|
Map<String, int>? initialChangeAddressIndex,
|
||||||
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
List<BitcoinSilentPaymentAddressRecord>? initialSilentAddresses,
|
||||||
int initialSilentAddressIndex = 0,
|
int initialSilentAddressIndex = 0,
|
||||||
bitcoin.HDWallet? masterHd,
|
Bip32Slip10Secp256k1? masterHd,
|
||||||
BitcoinAddressType? initialAddressPageType,
|
BitcoinAddressType? initialAddressPageType,
|
||||||
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
}) : _addresses = ObservableList<BitcoinAddressRecord>.of((initialAddresses ?? []).toSet()),
|
||||||
addressesByReceiveType =
|
addressesByReceiveType =
|
||||||
|
@ -53,9 +52,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
if (masterHd != null) {
|
if (masterHd != null) {
|
||||||
silentAddress = SilentPaymentOwner.fromPrivateKeys(
|
silentAddress = SilentPaymentOwner.fromPrivateKeys(
|
||||||
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privKey!),
|
b_scan: ECPrivate.fromHex(masterHd.derivePath(SCAN_PATH).privateKey.toHex()),
|
||||||
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privKey!),
|
b_spend: ECPrivate.fromHex(masterHd.derivePath(SPEND_PATH).privateKey.toHex()),
|
||||||
hrp: network == BitcoinNetwork.testnet ? 'tsp' : 'sp');
|
network: network,
|
||||||
|
);
|
||||||
|
|
||||||
if (silentAddresses.length == 0) {
|
if (silentAddresses.length == 0) {
|
||||||
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
silentAddresses.add(BitcoinSilentPaymentAddressRecord(
|
||||||
|
@ -92,8 +92,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
final ObservableList<BitcoinAddressRecord> changeAddresses;
|
||||||
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
|
final ObservableList<BitcoinSilentPaymentAddressRecord> silentAddresses;
|
||||||
final BasedUtxoNetwork network;
|
final BasedUtxoNetwork network;
|
||||||
final bitcoin.HDWallet mainHd;
|
final Bip32Slip10Secp256k1 mainHd;
|
||||||
final bitcoin.HDWallet sideHd;
|
final Bip32Slip10Secp256k1 sideHd;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
SilentPaymentOwner? silentAddress;
|
SilentPaymentOwner? silentAddress;
|
||||||
|
@ -318,7 +318,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
String getAddress(
|
String getAddress(
|
||||||
{required int index, required bitcoin.HDWallet hd, BitcoinAddressType? addressType}) =>
|
{required int index,
|
||||||
|
required Bip32Slip10Secp256k1 hd,
|
||||||
|
BitcoinAddressType? addressType}) =>
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -540,11 +542,13 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
|
||||||
void _validateAddresses() {
|
void _validateAddresses() {
|
||||||
_addresses.forEach((element) {
|
_addresses.forEach((element) {
|
||||||
if (!element.isHidden && element.address !=
|
if (!element.isHidden &&
|
||||||
getAddress(index: element.index, hd: mainHd, addressType: element.type)) {
|
element.address !=
|
||||||
|
getAddress(index: element.index, hd: mainHd, addressType: element.type)) {
|
||||||
element.isHidden = true;
|
element.isHidden = true;
|
||||||
} else if (element.isHidden && element.address !=
|
} else if (element.isHidden &&
|
||||||
getAddress(index: element.index, hd: sideHd, addressType: element.type)) {
|
element.address !=
|
||||||
|
getAddress(index: element.index, hd: sideHd, addressType: element.type)) {
|
||||||
element.isHidden = false;
|
element.isHidden = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -562,7 +566,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
||||||
return _isAddressByType(addressRecord, addressPageType);
|
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 _isAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) => addr.type == type;
|
||||||
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
bool _isUnusedReceiveAddressByType(BitcoinAddressRecord addr, BitcoinAddressType type) =>
|
||||||
!addr.isHidden && !addr.isUsed && addr.type == type;
|
!addr.isHidden && !addr.isUsed && addr.type == type;
|
||||||
|
|
|
@ -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);
|
|
|
@ -1,12 +1,12 @@
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.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_bitcoin/litecoin_wallet_addresses.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
@ -38,7 +38,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: litecoinNetwork,
|
network: LitecoinNetwork.mainnet,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
|
@ -49,7 +49,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.derive(1),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: network,
|
network: network,
|
||||||
);
|
);
|
||||||
autorun((_) {
|
autorun((_) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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/utils.dart';
|
||||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -22,6 +22,8 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAddress(
|
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);
|
generateP2WPKHAddress(hd: hd, index: index, network: network);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,68 +1,54 @@
|
||||||
import 'dart:typed_data';
|
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:blockchain_utils/blockchain_utils.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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ECPrivate generateECPrivate({
|
ECPrivate generateECPrivate({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final wif = hd.derive(index).wif!;
|
ECPrivate(hd.childKey(Bip32KeyIndex(index)).privateKey);
|
||||||
return ECPrivate.fromWif(wif, netVersion: network.wifNetVer);
|
|
||||||
}
|
|
||||||
|
|
||||||
String generateP2WPKHAddress({
|
String generateP2WPKHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final pubKey = hd.derive(index).pubKey!;
|
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||||
return ECPublic.fromHex(pubKey).toP2wpkhAddress().toAddress(network);
|
.toP2wpkhAddress()
|
||||||
}
|
.toAddress(network);
|
||||||
|
|
||||||
String generateP2SHAddress({
|
String generateP2SHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final pubKey = hd.derive(index).pubKey!;
|
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||||
return ECPublic.fromHex(pubKey).toP2wpkhInP2sh().toAddress(network);
|
.toP2wshInP2sh()
|
||||||
}
|
.toAddress(network);
|
||||||
|
|
||||||
String generateP2WSHAddress({
|
String generateP2WSHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final pubKey = hd.derive(index).pubKey!;
|
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||||
return ECPublic.fromHex(pubKey).toP2wshAddress().toAddress(network);
|
.toP2wshAddress()
|
||||||
}
|
.toAddress(network);
|
||||||
|
|
||||||
String generateP2PKHAddress({
|
String generateP2PKHAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final pubKey = hd.derive(index).pubKey!;
|
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||||
return ECPublic.fromHex(pubKey).toP2pkhAddress().toAddress(network);
|
.toP2pkhAddress()
|
||||||
}
|
.toAddress(network);
|
||||||
|
|
||||||
String generateP2TRAddress({
|
String generateP2TRAddress({
|
||||||
required bitcoin.HDWallet hd,
|
required Bip32Slip10Secp256k1 hd,
|
||||||
required BasedUtxoNetwork network,
|
required BasedUtxoNetwork network,
|
||||||
required int index,
|
required int index,
|
||||||
}) {
|
}) =>
|
||||||
final pubKey = hd.derive(index).pubKey!;
|
ECPublic.fromBip32(hd.childKey(Bip32KeyIndex(index)).publicKey)
|
||||||
return ECPublic.fromHex(pubKey).toTaprootAddress().toAddress(network);
|
.toTaprootAddress()
|
||||||
}
|
.toAddress(network);
|
||||||
|
|
|
@ -41,15 +41,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
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:
|
bip32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -79,29 +70,20 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
resolved-ref: cc99eedb1d28ee9376dda0465ef72aa627ac6149
|
resolved-ref: "574486bfcdbbaf978dcd006b46fc8716f880da29"
|
||||||
url: "https://github.com/cake-tech/bitcoin_base"
|
url: "https://github.com/cake-tech/bitcoin_base"
|
||||||
source: git
|
source: git
|
||||||
version: "4.2.1"
|
version: "4.7.0"
|
||||||
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"
|
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-update-v1
|
ref: cake-update-v2
|
||||||
resolved-ref: cabd7e0e16c4da9920338c76eff3aeb8af0211f3
|
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
|
||||||
url: "https://github.com/cake-tech/blockchain_utils"
|
url: "https://github.com/cake-tech/blockchain_utils"
|
||||||
source: git
|
source: git
|
||||||
version: "2.1.2"
|
version: "3.3.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -411,10 +393,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -499,11 +481,12 @@ packages:
|
||||||
ledger_flutter:
|
ledger_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: ledger_flutter
|
path: "."
|
||||||
sha256: f1680060ed6ff78f275837e0024ccaf667715a59ba7aa29fa7354bc7752e71c8
|
ref: cake-v3
|
||||||
url: "https://pub.dev"
|
resolved-ref: "66469ff9dffe2417c70ae7287c9d76d2fe7157a4"
|
||||||
source: hosted
|
url: "https://github.com/cake-tech/ledger-flutter.git"
|
||||||
version: "1.0.1"
|
source: git
|
||||||
|
version: "1.0.2"
|
||||||
ledger_usb:
|
ledger_usb:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -596,10 +579,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.3"
|
version: "2.1.4"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -636,18 +619,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_windows
|
name: path_provider_windows
|
||||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.1"
|
version: "2.3.0"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.4"
|
version: "3.1.5"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -700,10 +683,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
|
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.3"
|
version: "1.3.0"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -761,10 +744,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: socks5_proxy
|
name: socks5_proxy
|
||||||
sha256: "045cbba84f6e2b01c1c77634a63e926352bf110ef5f07fc462c6d43bbd4b6a83"
|
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5+dev.2"
|
version: "1.0.6"
|
||||||
source_gen:
|
source_gen:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -793,9 +776,9 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "sp_v2.0.0"
|
ref: "sp_v4.0.0"
|
||||||
resolved-ref: "62c152b9086cd968019128845371072f7e1168de"
|
resolved-ref: "3b8ae38592c0584f53560071dc18bc570758fe13"
|
||||||
url: "https://github.com/cake-tech/sp_scanner"
|
url: "https://github.com/rafael-xmr/sp_scanner"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
|
@ -910,14 +893,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5"
|
||||||
win32:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: win32
|
|
||||||
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.5.0"
|
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -19,10 +19,6 @@ dependencies:
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
bitcoin_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
|
||||||
ref: cake-update-v4
|
|
||||||
bitbox:
|
bitbox:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
|
@ -32,19 +28,19 @@ dependencies:
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v1
|
ref: cake-update-v2
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
ledger_bitcoin:
|
ledger_bitcoin:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ledger-bitcoin
|
url: https://github.com/cake-tech/ledger-bitcoin
|
||||||
sp_scanner:
|
sp_scanner:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/sp_scanner
|
url: https://github.com/rafael-xmr/sp_scanner
|
||||||
ref: sp_v2.0.0
|
ref: sp_v4.0.0
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:bitbox/bitbox.dart' as bitbox;
|
import 'package:bitbox/bitbox.dart' as bitbox;
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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_address_record.dart';
|
||||||
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
|
||||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||||
|
@ -40,7 +38,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
password: password,
|
password: password,
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
networkType: bitcoin.bitcoin,
|
network: BitcoinCashNetwork.mainnet,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: seedBytes,
|
seedBytes: seedBytes,
|
||||||
|
@ -51,7 +49,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
mainHd: hd,
|
mainHd: hd,
|
||||||
sideHd: accountHD.derive(1),
|
sideHd: accountHD.childKey(Bip32KeyIndex(1)),
|
||||||
network: network,
|
network: network,
|
||||||
initialAddressPageType: addressPageType,
|
initialAddressPageType: addressPageType,
|
||||||
);
|
);
|
||||||
|
@ -77,7 +75,7 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
unspentCoinsInfo: unspentCoinsInfo,
|
unspentCoinsInfo: unspentCoinsInfo,
|
||||||
initialAddresses: initialAddresses,
|
initialAddresses: initialAddresses,
|
||||||
initialBalance: initialBalance,
|
initialBalance: initialBalance,
|
||||||
seedBytes: await Mnemonic.toSeed(mnemonic),
|
seedBytes: await MnemonicBip39.toSeed(mnemonic),
|
||||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||||
addressPageType: P2pkhAddressType.p2pkh,
|
addressPageType: P2pkhAddressType.p2pkh,
|
||||||
|
@ -136,15 +134,17 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
}
|
}
|
||||||
}).toList(),
|
}).toList(),
|
||||||
initialBalance: snp?.balance,
|
initialBalance: snp?.balance,
|
||||||
seedBytes: await Mnemonic.toSeed(keysData.mnemonic!),
|
seedBytes: await MnemonicBip39.toSeed(keysData.mnemonic!),
|
||||||
initialRegularAddressIndex: snp?.regularAddressIndex,
|
initialRegularAddressIndex: snp?.regularAddressIndex,
|
||||||
initialChangeAddressIndex: snp?.changeAddressIndex,
|
initialChangeAddressIndex: snp?.changeAddressIndex,
|
||||||
addressPageType: P2pkhAddressType.p2pkh,
|
addressPageType: P2pkhAddressType.p2pkh,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitbox.ECPair generateKeyPair({required bitcoin.HDWallet hd, required int index}) =>
|
bitbox.ECPair generateKeyPair({required Bip32Slip10Secp256k1 hd, required int index}) =>
|
||||||
bitbox.ECPair.fromWIF(hd.derive(index).wif!);
|
bitbox.ECPair.fromPrivateKey(
|
||||||
|
Uint8List.fromList(hd.childKey(Bip32KeyIndex(index)).privateKey.raw),
|
||||||
|
);
|
||||||
|
|
||||||
int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount, int? size}) {
|
int calculateEstimatedFeeWithFeeRate(int feeRate, int? amount, {int? outputsCount, int? size}) {
|
||||||
int inputsCount = 0;
|
int inputsCount = 0;
|
||||||
|
@ -190,7 +190,11 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
|
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
|
||||||
.index
|
.index
|
||||||
: null;
|
: null;
|
||||||
final HD = index == null ? hd : hd.derive(index);
|
final HD = index == null ? hd : hd.childKey(Bip32KeyIndex(index));
|
||||||
return base64Encode(HD.signMessage(message));
|
final priv = ECPrivate.fromWif(
|
||||||
|
WifEncoder.encode(HD.privateKey.raw, netVer: network.wifNetVer),
|
||||||
|
netVersion: network.wifNetVer,
|
||||||
|
);
|
||||||
|
return priv.signMessage(StringUtils.encode(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
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/electrum_wallet_addresses.dart';
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
import 'package:cw_bitcoin/utils.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -23,6 +23,8 @@ abstract class BitcoinCashWalletAddressesBase extends ElectrumWalletAddresses wi
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getAddress(
|
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);
|
generateP2PKHAddress(hd: hd, index: index, network: network);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,11 @@ import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredentials,
|
class BitcoinCashWalletService extends WalletService<
|
||||||
BitcoinCashRestoreWalletFromSeedCredentials, BitcoinCashRestoreWalletFromWIFCredentials, BitcoinCashNewWalletCredentials> {
|
BitcoinCashNewWalletCredentials,
|
||||||
|
BitcoinCashRestoreWalletFromSeedCredentials,
|
||||||
|
BitcoinCashRestoreWalletFromWIFCredentials,
|
||||||
|
BitcoinCashNewWalletCredentials> {
|
||||||
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
BitcoinCashWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||||
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
@ -30,7 +33,7 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
|
||||||
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
|
||||||
|
|
||||||
final wallet = await BitcoinCashWalletBase.create(
|
final wallet = await BitcoinCashWalletBase.create(
|
||||||
mnemonic: await Mnemonic.generate(strength: strength),
|
mnemonic: await MnemonicBip39.generate(strength: strength),
|
||||||
password: credentials.password!,
|
password: credentials.password!,
|
||||||
walletInfo: credentials.walletInfo!,
|
walletInfo: credentials.walletInfo!,
|
||||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||||
|
@ -97,7 +100,8 @@ class BitcoinCashWalletService extends WalletService<BitcoinCashNewWalletCredent
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<BitcoinCashWallet> restoreFromHardwareWallet(BitcoinCashNewWalletCredentials credentials) {
|
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
|
@override
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:bip39/bip39.dart' as bip39;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
|
|
||||||
class Mnemonic {
|
class MnemonicBip39 {
|
||||||
/// Generate bip39 mnemonic
|
/// Generate bip39 mnemonic
|
||||||
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
|
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,6 @@ dependencies:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
cw_bitcoin:
|
cw_bitcoin:
|
||||||
path: ../cw_bitcoin
|
path: ../cw_bitcoin
|
||||||
bitcoin_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
|
||||||
ref: cake-update-v4
|
|
||||||
bitbox:
|
bitbox:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
|
@ -32,11 +28,11 @@ dependencies:
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v1
|
ref: cake-update-v2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -245,6 +245,8 @@ Future<int> getHavenCurrentHeight() async {
|
||||||
|
|
||||||
// Data taken from https://timechaincalendar.com/
|
// Data taken from https://timechaincalendar.com/
|
||||||
const bitcoinDates = {
|
const bitcoinDates = {
|
||||||
|
"2024-08": 854889,
|
||||||
|
"2024-07": 850182,
|
||||||
"2024-06": 846005,
|
"2024-06": 846005,
|
||||||
"2024-05": 841590,
|
"2024-05": 841590,
|
||||||
"2024-04": 837182,
|
"2024-04": 837182,
|
||||||
|
@ -371,7 +373,8 @@ const wowDates = {
|
||||||
|
|
||||||
int getWowneroHeightByDate({required DateTime date}) {
|
int getWowneroHeightByDate({required DateTime date}) {
|
||||||
String closestKey =
|
String closestKey =
|
||||||
wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
|
wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
|
||||||
|
|
||||||
return wowDates[closestKey] ?? 0;
|
return wowDates[closestKey] ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,8 @@ import 'package:http/io_client.dart' as ioc;
|
||||||
|
|
||||||
part 'node.g.dart';
|
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)
|
@HiveType(typeId: Node.typeId)
|
||||||
class Node extends HiveObject with Keyable {
|
class Node extends HiveObject with Keyable {
|
||||||
|
@ -72,6 +73,12 @@ class Node extends HiveObject with Keyable {
|
||||||
@HiveField(7, defaultValue: '')
|
@HiveField(7, defaultValue: '')
|
||||||
String? path;
|
String? path;
|
||||||
|
|
||||||
|
@HiveField(8)
|
||||||
|
bool? isElectrs;
|
||||||
|
|
||||||
|
@HiveField(9)
|
||||||
|
bool? supportsSilentPayments;
|
||||||
|
|
||||||
bool get isSSL => useSSL ?? false;
|
bool get isSSL => useSSL ?? false;
|
||||||
|
|
||||||
bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
|
bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
|
||||||
|
|
|
@ -3,6 +3,11 @@ abstract class SyncStatus {
|
||||||
double progress();
|
double progress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class StartingScanSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
|
double progress() => 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
class SyncingSyncStatus extends SyncStatus {
|
class SyncingSyncStatus extends SyncStatus {
|
||||||
SyncingSyncStatus(this.blocksLeft, this.ptc);
|
SyncingSyncStatus(this.blocksLeft, this.ptc);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ abstract class TransactionInfo extends Object with Keyable {
|
||||||
late TransactionDirection direction;
|
late TransactionDirection direction;
|
||||||
late bool isPending;
|
late bool isPending;
|
||||||
late DateTime date;
|
late DateTime date;
|
||||||
late int height;
|
int? height;
|
||||||
late int confirmations;
|
late int confirmations;
|
||||||
String amountFormatted();
|
String amountFormatted();
|
||||||
String fiatAmount();
|
String fiatAmount();
|
||||||
|
@ -26,3 +26,4 @@ abstract class TransactionInfo extends Object with Keyable {
|
||||||
|
|
||||||
late Map<String, dynamic> additionalInfo;
|
late Map<String, dynamic> additionalInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,10 +254,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -514,14 +514,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
process:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: process
|
|
||||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.4"
|
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -707,10 +699,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
|
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+3"
|
version: "1.0.4"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -438,8 +438,8 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "impls/monero.dart"
|
path: "impls/monero.dart"
|
||||||
ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b"
|
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||||
resolved-ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b"
|
resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||||
url: "https://github.com/mrcyjanek/monero_c"
|
url: "https://github.com/mrcyjanek/monero_c"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
|
|
@ -29,10 +29,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: asn1lib
|
name: asn1lib
|
||||||
sha256: b74e3842a52c61f8819a1ec8444b4de5419b41a7465e69d4aa681445377398b0
|
sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.5.3"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -114,7 +114,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.9"
|
version: "2.4.9"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e"
|
sha256: "0671ad4162ed510b70d0eb4ad6354c249f8429cab4ae7a4cec86bbc2886eb76e"
|
||||||
|
@ -133,10 +133,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "598a2a682e2a7a90f08ba39c0aaa9374c5112340f0a2e275f61b59389543d166"
|
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.6.1"
|
version: "8.9.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -165,10 +165,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
sha256: "4ad01d6e56db961d29661561effde45e519939fdaeb46c351275b182eac70189"
|
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.5.0"
|
version: "4.10.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -220,10 +220,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: ed25519_hd_key
|
name: ed25519_hd_key
|
||||||
sha256: "326608234e986ea826a5db4cf4cd6826058d860875a3fff7926c0725fe1a604d"
|
sha256: c5c9f11a03f5789bf9dcd9ae88d641571c802640851f1cacdb13123f171b3a26
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.1"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -244,10 +244,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
|
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.1.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -475,10 +475,10 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: mobx
|
name: mobx
|
||||||
sha256: "0afcf88b3ee9d6819890bf16c11a727fc8c62cf736fda8e5d3b9b4eace4e62ea"
|
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.3.3+2"
|
||||||
mobx_codegen:
|
mobx_codegen:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -572,10 +572,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pinenacl
|
name: pinenacl
|
||||||
sha256: e5fb0bce1717b7f136f35ee98b5c02b3e6383211f8a77ca882fa7812232a07b9
|
sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4"
|
version: "0.5.1"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -588,10 +588,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: plugin_platform_interface
|
name: plugin_platform_interface
|
||||||
sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd"
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.1.8"
|
||||||
pointycastle:
|
pointycastle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -652,10 +652,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_foundation
|
name: shared_preferences_foundation
|
||||||
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.4"
|
version: "2.5.0"
|
||||||
shared_preferences_linux:
|
shared_preferences_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -668,10 +668,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_platform_interface
|
name: shared_preferences_platform_interface
|
||||||
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.4.1"
|
||||||
shared_preferences_web:
|
shared_preferences_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -849,18 +849,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
|
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.4"
|
version: "5.5.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff
|
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.4"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -870,5 +870,5 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0-0 <4.0.0"
|
dart: ">=3.3.0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.16.6"
|
||||||
|
|
|
@ -38,6 +38,7 @@ dev_dependencies:
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
watcher: ^1.1.0
|
watcher: ^1.1.0
|
||||||
|
build_runner_core: 7.2.7+1
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
|
@ -18,11 +18,11 @@ dependencies:
|
||||||
on_chain:
|
on_chain:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/On_chain
|
url: https://github.com/cake-tech/On_chain
|
||||||
ref: cake-update-v1
|
ref: cake-update-v2
|
||||||
blockchain_utils:
|
blockchain_utils:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/blockchain_utils
|
url: https://github.com/cake-tech/blockchain_utils
|
||||||
ref: cake-update-v1
|
ref: cake-update-v2
|
||||||
mobx: ^2.3.0+1
|
mobx: ^2.3.0+1
|
||||||
bip39: ^1.0.6
|
bip39: ^1.0.6
|
||||||
hive: ^2.2.3
|
hive: ^2.2.3
|
||||||
|
|
|
@ -254,10 +254,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.2"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -438,8 +438,8 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "impls/monero.dart"
|
path: "impls/monero.dart"
|
||||||
ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b"
|
ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||||
resolved-ref: "bcb328a4956105dc182afd0ce2e48fe263f5f20b"
|
resolved-ref: bcb328a4956105dc182afd0ce2e48fe263f5f20b
|
||||||
url: "https://github.com/mrcyjanek/monero_c"
|
url: "https://github.com/mrcyjanek/monero_c"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
@ -555,14 +555,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
process:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: process
|
|
||||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.4"
|
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -748,10 +740,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
|
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+3"
|
version: "1.0.4"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -94,6 +94,8 @@ PODS:
|
||||||
- shared_preferences_foundation (0.0.1):
|
- shared_preferences_foundation (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- sp_scanner (0.0.1):
|
||||||
|
- Flutter
|
||||||
- SwiftProtobuf (1.26.0)
|
- SwiftProtobuf (1.26.0)
|
||||||
- SwiftyGif (5.4.5)
|
- SwiftyGif (5.4.5)
|
||||||
- Toast (4.1.1)
|
- Toast (4.1.1)
|
||||||
|
@ -132,6 +134,7 @@ DEPENDENCIES:
|
||||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- 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`)
|
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
@ -197,6 +200,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
|
sp_scanner:
|
||||||
|
:path: ".symlinks/plugins/sp_scanner/ios"
|
||||||
uni_links:
|
uni_links:
|
||||||
:path: ".symlinks/plugins/uni_links/ios"
|
:path: ".symlinks/plugins/uni_links/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
|
@ -227,7 +232,7 @@ SPEC CHECKSUMS:
|
||||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||||
Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2
|
Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2
|
||||||
|
@ -235,15 +240,16 @@ SPEC CHECKSUMS:
|
||||||
reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
|
reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
|
||||||
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
||||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
|
||||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
|
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
|
||||||
SwiftProtobuf: 5e8349171e7c2f88f5b9e683cb3cb79d1dc780b3
|
SwiftProtobuf: 5e8349171e7c2f88f5b9e683cb3cb79d1dc780b3
|
||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||||
|
|
||||||
PODFILE CHECKSUM: a2fe518be61cdbdc5b0e2da085ab543d556af2d3
|
PODFILE CHECKSUM: a2fe518be61cdbdc5b0e2da085ab543d556af2d3
|
||||||
|
|
|
@ -302,16 +302,13 @@ class CWBitcoin extends Bitcoin {
|
||||||
await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
|
await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
|
||||||
|
|
||||||
late BasedUtxoNetwork network;
|
late BasedUtxoNetwork network;
|
||||||
btc.NetworkType networkType;
|
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
network = LitecoinNetwork.mainnet;
|
network = LitecoinNetwork.mainnet;
|
||||||
networkType = litecoinNetwork;
|
|
||||||
break;
|
break;
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
default:
|
default:
|
||||||
network = BitcoinNetwork.mainnet;
|
network = BitcoinNetwork.mainnet;
|
||||||
networkType = btc.bitcoin;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,10 +338,8 @@ class CWBitcoin extends Bitcoin {
|
||||||
balancePath += "/0";
|
balancePath += "/0";
|
||||||
}
|
}
|
||||||
|
|
||||||
final hd = btc.HDWallet.fromSeed(
|
final hd = Bip32Slip10Secp256k1.fromSeed(seedBytes).derivePath(balancePath)
|
||||||
seedBytes,
|
as Bip32Slip10Secp256k1;
|
||||||
network: networkType,
|
|
||||||
).derivePath(balancePath);
|
|
||||||
|
|
||||||
// derive address at index 0:
|
// derive address at index 0:
|
||||||
String? address;
|
String? address;
|
||||||
|
@ -515,10 +510,7 @@ class CWBitcoin extends Bitcoin {
|
||||||
@override
|
@override
|
||||||
Future<void> setScanningActive(Object wallet, bool active) async {
|
Future<void> setScanningActive(Object wallet, bool active) async {
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
bitcoinWallet.setSilentPaymentsScanning(
|
bitcoinWallet.setSilentPaymentsScanning(active);
|
||||||
active,
|
|
||||||
active && (await getNodeIsElectrsSPEnabled(wallet)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -536,44 +528,10 @@ class CWBitcoin extends Bitcoin {
|
||||||
bitcoinWallet.rescan(height: height, doSingleScan: doSingleScan);
|
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
|
@override
|
||||||
Future<bool> getNodeIsElectrsSPEnabled(Object wallet) async {
|
Future<bool> getNodeIsElectrsSPEnabled(Object wallet) async {
|
||||||
if (!(await getNodeIsElectrs(wallet))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final bitcoinWallet = wallet as ElectrumWallet;
|
final bitcoinWallet = wallet as ElectrumWallet;
|
||||||
try {
|
return bitcoinWallet.getNodeSupportsSilentPayments();
|
||||||
final tweaksResponse = await bitcoinWallet.electrumClient.getTweaks(height: 0);
|
|
||||||
|
|
||||||
if (tweaksResponse != null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} on RequestFailedTimeoutException catch (_) {
|
|
||||||
return false;
|
|
||||||
} catch (_) {
|
|
||||||
rethrow;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -52,5 +52,9 @@ String syncStatusTitle(SyncStatus syncStatus) {
|
||||||
return S.current.sync_status_syncronizing;
|
return S.current.sync_status_syncronizing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (syncStatus is StartingScanSyncStatus) {
|
||||||
|
return S.current.sync_status_starting_scan;
|
||||||
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ class CakePayBuyCardDetailPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget? middle(BuildContext context) {
|
Widget? middle(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
title,
|
title,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
|
@ -359,7 +359,7 @@ class CakePayBuyCardDetailPage extends BasePage {
|
||||||
reaction((_) => cakePayPurchaseViewModel.sendViewModel.state, (ExecutionState state) {
|
reaction((_) => cakePayPurchaseViewModel.sendViewModel.state, (ExecutionState state) {
|
||||||
if (state is FailureState) {
|
if (state is FailureState) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
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) {
|
void showStateAlert(BuildContext context, String title, String content) {
|
||||||
showPopUp<void>(
|
if (context.mounted) {
|
||||||
context: context,
|
showPopUp<void>(
|
||||||
builder: (BuildContext context) {
|
context: context,
|
||||||
return AlertWithOneAction(
|
builder: (BuildContext context) {
|
||||||
alertTitle: title,
|
return AlertWithOneAction(
|
||||||
alertContent: content,
|
alertTitle: title,
|
||||||
buttonText: S.of(context).ok,
|
alertContent: content,
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
buttonText: S.of(context).ok,
|
||||||
});
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> showSentAlert(BuildContext context) async {
|
Future<void> showSentAlert(BuildContext context) async {
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final order = cakePayPurchaseViewModel.order!.orderId;
|
final order = cakePayPurchaseViewModel.order!.orderId;
|
||||||
final isCopy = await showPopUp<bool>(
|
final isCopy = await showPopUp<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertWithTwoActions(
|
return AlertWithTwoActions(
|
||||||
alertTitle: S.of(context).transaction_sent,
|
alertTitle: S.of(context).transaction_sent,
|
||||||
alertContent:
|
alertContent: S.of(context).cake_pay_save_order + '\n${order}',
|
||||||
S.of(context).cake_pay_save_order + '\n${order}',
|
leftButtonText: S.of(context).ignor,
|
||||||
leftButtonText: S.of(context).ignor,
|
rightButtonText: S.of(context).copy,
|
||||||
rightButtonText: S.of(context).copy,
|
actionLeftButton: () => Navigator.of(context).pop(false),
|
||||||
actionLeftButton: () => Navigator.of(context).pop(false),
|
actionRightButton: () => Navigator.of(context).pop(true));
|
||||||
actionRightButton: () => Navigator.of(context).pop(true));
|
}) ??
|
||||||
}) ??
|
|
||||||
false;
|
false;
|
||||||
|
|
||||||
if (isCopy) {
|
if (isCopy) {
|
||||||
|
|
|
@ -87,10 +87,6 @@ dependencies:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/ens_dart.git
|
url: https://github.com/cake-tech/ens_dart.git
|
||||||
ref: main
|
ref: main
|
||||||
bitcoin_flutter:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
|
||||||
ref: cake-update-v4
|
|
||||||
fluttertoast: 8.1.4
|
fluttertoast: 8.1.4
|
||||||
# tor:
|
# tor:
|
||||||
# git:
|
# git:
|
||||||
|
@ -104,7 +100,7 @@ dependencies:
|
||||||
bitcoin_base:
|
bitcoin_base:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_base
|
url: https://github.com/cake-tech/bitcoin_base
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
ledger_flutter: ^1.0.1
|
ledger_flutter: ^1.0.1
|
||||||
hashlib: 1.12.0
|
hashlib: 1.12.0
|
||||||
|
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "يتم التوصيل",
|
"sync_status_connecting": "يتم التوصيل",
|
||||||
"sync_status_failed_connect": "انقطع الاتصال",
|
"sync_status_failed_connect": "انقطع الاتصال",
|
||||||
"sync_status_not_connected": "غير متصل",
|
"sync_status_not_connected": "غير متصل",
|
||||||
|
"sync_status_starting_scan": "بدء المسح",
|
||||||
"sync_status_starting_sync": "بدء المزامنة",
|
"sync_status_starting_sync": "بدء المزامنة",
|
||||||
"sync_status_syncronized": "متزامن",
|
"sync_status_syncronized": "متزامن",
|
||||||
"sync_status_syncronizing": "يتم المزامنة",
|
"sync_status_syncronizing": "يتم المزامنة",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "СВЪРЗВАНЕ",
|
"sync_status_connecting": "СВЪРЗВАНЕ",
|
||||||
"sync_status_failed_connect": "НЕУСПЕШНО СВЪРЗВАНЕ",
|
"sync_status_failed_connect": "НЕУСПЕШНО СВЪРЗВАНЕ",
|
||||||
"sync_status_not_connected": "НЯМА ВРЪЗКА",
|
"sync_status_not_connected": "НЯМА ВРЪЗКА",
|
||||||
|
"sync_status_starting_scan": "Стартово сканиране",
|
||||||
"sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ",
|
"sync_status_starting_sync": "ЗАПОЧВАНЕ НА СИНХРОНИЗАЦИЯ",
|
||||||
"sync_status_syncronized": "СИНХРОНИЗИРАНО",
|
"sync_status_syncronized": "СИНХРОНИЗИРАНО",
|
||||||
"sync_status_syncronizing": "СИНХРОНИЗИРАНЕ",
|
"sync_status_syncronizing": "СИНХРОНИЗИРАНЕ",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "PŘIPOJOVÁNÍ",
|
"sync_status_connecting": "PŘIPOJOVÁNÍ",
|
||||||
"sync_status_failed_connect": "ODPOJENO",
|
"sync_status_failed_connect": "ODPOJENO",
|
||||||
"sync_status_not_connected": "NEPŘIPOJENO",
|
"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_starting_sync": "SPOUŠTĚNÍ SYNCHRONIZACE",
|
||||||
"sync_status_syncronized": "SYNCHRONIZOVÁNO",
|
"sync_status_syncronized": "SYNCHRONIZOVÁNO",
|
||||||
"sync_status_syncronizing": "SYNCHRONIZUJI",
|
"sync_status_syncronizing": "SYNCHRONIZUJI",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "VERBINDEN",
|
"sync_status_connecting": "VERBINDEN",
|
||||||
"sync_status_failed_connect": "GETRENNT",
|
"sync_status_failed_connect": "GETRENNT",
|
||||||
"sync_status_not_connected": "NICHT VERBUNDEN",
|
"sync_status_not_connected": "NICHT VERBUNDEN",
|
||||||
|
"sync_status_starting_scan": "Scan beginnen",
|
||||||
"sync_status_starting_sync": "STARTE SYNCHRONISIERUNG",
|
"sync_status_starting_sync": "STARTE SYNCHRONISIERUNG",
|
||||||
"sync_status_syncronized": "SYNCHRONISIERT",
|
"sync_status_syncronized": "SYNCHRONISIERT",
|
||||||
"sync_status_syncronizing": "SYNCHRONISIERE",
|
"sync_status_syncronizing": "SYNCHRONISIERE",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "CONNECTING",
|
"sync_status_connecting": "CONNECTING",
|
||||||
"sync_status_failed_connect": "DISCONNECTED",
|
"sync_status_failed_connect": "DISCONNECTED",
|
||||||
"sync_status_not_connected": "NOT CONNECTED",
|
"sync_status_not_connected": "NOT CONNECTED",
|
||||||
|
"sync_status_starting_scan": "STARTING SCAN",
|
||||||
"sync_status_starting_sync": "STARTING SYNC",
|
"sync_status_starting_sync": "STARTING SYNC",
|
||||||
"sync_status_syncronized": "SYNCHRONIZED",
|
"sync_status_syncronized": "SYNCHRONIZED",
|
||||||
"sync_status_syncronizing": "SYNCHRONIZING",
|
"sync_status_syncronizing": "SYNCHRONIZING",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "CONECTANDO",
|
"sync_status_connecting": "CONECTANDO",
|
||||||
"sync_status_failed_connect": "DESCONECTADO",
|
"sync_status_failed_connect": "DESCONECTADO",
|
||||||
"sync_status_not_connected": "NO CONECTADO",
|
"sync_status_not_connected": "NO CONECTADO",
|
||||||
|
"sync_status_starting_scan": "Escaneo inicial",
|
||||||
"sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR",
|
"sync_status_starting_sync": "EMPEZANDO A SINCRONIZAR",
|
||||||
"sync_status_syncronized": "SINCRONIZADO",
|
"sync_status_syncronized": "SINCRONIZADO",
|
||||||
"sync_status_syncronizing": "SINCRONIZANDO",
|
"sync_status_syncronizing": "SINCRONIZANDO",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "CONNEXION EN COURS",
|
"sync_status_connecting": "CONNEXION EN COURS",
|
||||||
"sync_status_failed_connect": "DÉCONNECTÉ",
|
"sync_status_failed_connect": "DÉCONNECTÉ",
|
||||||
"sync_status_not_connected": "NON CONNECTÉ",
|
"sync_status_not_connected": "NON CONNECTÉ",
|
||||||
|
"sync_status_starting_scan": "Démarrage",
|
||||||
"sync_status_starting_sync": "DÉBUT DE SYNCHRO",
|
"sync_status_starting_sync": "DÉBUT DE SYNCHRO",
|
||||||
"sync_status_syncronized": "SYNCHRONISÉ",
|
"sync_status_syncronized": "SYNCHRONISÉ",
|
||||||
"sync_status_syncronizing": "SYNCHRONISATION EN COURS",
|
"sync_status_syncronizing": "SYNCHRONISATION EN COURS",
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"sync_status_connecting": "HADA",
|
"sync_status_connecting": "HADA",
|
||||||
"sync_status_failed_connect": "BABU INTERNET",
|
"sync_status_failed_connect": "BABU INTERNET",
|
||||||
"sync_status_not_connected": "BABU INTERNET",
|
"sync_status_not_connected": "BABU INTERNET",
|
||||||
|
"sync_status_starting_scan": "Fara scan",
|
||||||
"sync_status_starting_sync": "KWAFI",
|
"sync_status_starting_sync": "KWAFI",
|
||||||
"sync_status_syncronized": "KYAU",
|
"sync_status_syncronized": "KYAU",
|
||||||
"sync_status_syncronizing": "KWAFI",
|
"sync_status_syncronizing": "KWAFI",
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"sync_status_connecting": "कनेक्ट",
|
"sync_status_connecting": "कनेक्ट",
|
||||||
"sync_status_failed_connect": "डिस्कनेक्ट किया गया",
|
"sync_status_failed_connect": "डिस्कनेक्ट किया गया",
|
||||||
"sync_status_not_connected": "जुड़े नहीं हैं",
|
"sync_status_not_connected": "जुड़े नहीं हैं",
|
||||||
|
"sync_status_starting_scan": "स्कैन शुरू करना",
|
||||||
"sync_status_starting_sync": "सिताज़ा करना",
|
"sync_status_starting_sync": "सिताज़ा करना",
|
||||||
"sync_status_syncronized": "सिंक्रनाइज़",
|
"sync_status_syncronized": "सिंक्रनाइज़",
|
||||||
"sync_status_syncronizing": "सिंक्रनाइज़ करने",
|
"sync_status_syncronizing": "सिंक्रनाइज़ करने",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "SPAJANJE",
|
"sync_status_connecting": "SPAJANJE",
|
||||||
"sync_status_failed_connect": "ISKLJUČENO",
|
"sync_status_failed_connect": "ISKLJUČENO",
|
||||||
"sync_status_not_connected": "NIJE POVEZANO",
|
"sync_status_not_connected": "NIJE POVEZANO",
|
||||||
|
"sync_status_starting_scan": "Početno skeniranje",
|
||||||
"sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE",
|
"sync_status_starting_sync": "ZAPOČINJEMO SINKRONIZIRANJE",
|
||||||
"sync_status_syncronized": "SINKRONIZIRANO",
|
"sync_status_syncronized": "SINKRONIZIRANO",
|
||||||
"sync_status_syncronizing": "SINKRONIZIRANJE",
|
"sync_status_syncronizing": "SINKRONIZIRANJE",
|
||||||
|
|
|
@ -698,6 +698,7 @@
|
||||||
"sync_status_connecting": "MENGHUBUNGKAN",
|
"sync_status_connecting": "MENGHUBUNGKAN",
|
||||||
"sync_status_failed_connect": "GAGAL TERHUBUNG",
|
"sync_status_failed_connect": "GAGAL TERHUBUNG",
|
||||||
"sync_status_not_connected": "TIDAK TERHUBUNG",
|
"sync_status_not_connected": "TIDAK TERHUBUNG",
|
||||||
|
"sync_status_starting_scan": "Mulai pindai",
|
||||||
"sync_status_starting_sync": "MULAI SINKRONISASI",
|
"sync_status_starting_sync": "MULAI SINKRONISASI",
|
||||||
"sync_status_syncronized": "SUDAH TERSINKRONISASI",
|
"sync_status_syncronized": "SUDAH TERSINKRONISASI",
|
||||||
"sync_status_syncronizing": "SEDANG SINKRONISASI",
|
"sync_status_syncronizing": "SEDANG SINKRONISASI",
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"sync_status_connecting": "CONNESSIONE",
|
"sync_status_connecting": "CONNESSIONE",
|
||||||
"sync_status_failed_connect": "DISCONNESSO",
|
"sync_status_failed_connect": "DISCONNESSO",
|
||||||
"sync_status_not_connected": "NON CONNESSO",
|
"sync_status_not_connected": "NON CONNESSO",
|
||||||
|
"sync_status_starting_scan": "Scansione di partenza",
|
||||||
"sync_status_starting_sync": "INIZIO SINC",
|
"sync_status_starting_sync": "INIZIO SINC",
|
||||||
"sync_status_syncronized": "SINCRONIZZATO",
|
"sync_status_syncronized": "SINCRONIZZATO",
|
||||||
"sync_status_syncronizing": "SINCRONIZZAZIONE",
|
"sync_status_syncronizing": "SINCRONIZZAZIONE",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "接続中",
|
"sync_status_connecting": "接続中",
|
||||||
"sync_status_failed_connect": "切断されました",
|
"sync_status_failed_connect": "切断されました",
|
||||||
"sync_status_not_connected": "接続されていません",
|
"sync_status_not_connected": "接続されていません",
|
||||||
|
"sync_status_starting_scan": "スキャンを開始します",
|
||||||
"sync_status_starting_sync": "同期の開始",
|
"sync_status_starting_sync": "同期の開始",
|
||||||
"sync_status_syncronized": "同期された",
|
"sync_status_syncronized": "同期された",
|
||||||
"sync_status_syncronizing": "同期",
|
"sync_status_syncronizing": "同期",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "연결 중",
|
"sync_status_connecting": "연결 중",
|
||||||
"sync_status_failed_connect": "연결 해제",
|
"sync_status_failed_connect": "연결 해제",
|
||||||
"sync_status_not_connected": "연결되지 않은",
|
"sync_status_not_connected": "연결되지 않은",
|
||||||
|
"sync_status_starting_scan": "스캔 시작",
|
||||||
"sync_status_starting_sync": "동기화 시작",
|
"sync_status_starting_sync": "동기화 시작",
|
||||||
"sync_status_syncronized": "동기화",
|
"sync_status_syncronized": "동기화",
|
||||||
"sync_status_syncronizing": "동기화",
|
"sync_status_syncronizing": "동기화",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "ချိတ်ဆက်ခြင်း။",
|
"sync_status_connecting": "ချိတ်ဆက်ခြင်း။",
|
||||||
"sync_status_failed_connect": "အဆက်အသွယ်ဖြတ်ထားသည်။",
|
"sync_status_failed_connect": "အဆက်အသွယ်ဖြတ်ထားသည်။",
|
||||||
"sync_status_not_connected": "မချိတ်ဆက်ပါ။",
|
"sync_status_not_connected": "မချိတ်ဆက်ပါ။",
|
||||||
|
"sync_status_starting_scan": "စကင်ဖတ်စစ်ဆေးမှု",
|
||||||
"sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။",
|
"sync_status_starting_sync": "စင့်ခ်လုပ်ခြင်း။",
|
||||||
"sync_status_syncronized": "ထပ်တူပြုထားသည်။",
|
"sync_status_syncronized": "ထပ်တူပြုထားသည်။",
|
||||||
"sync_status_syncronizing": "ထပ်တူပြုခြင်း။",
|
"sync_status_syncronizing": "ထပ်တူပြုခြင်း။",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "AANSLUITING",
|
"sync_status_connecting": "AANSLUITING",
|
||||||
"sync_status_failed_connect": "LOSGEKOPPELD",
|
"sync_status_failed_connect": "LOSGEKOPPELD",
|
||||||
"sync_status_not_connected": "NIET VERBONDEN",
|
"sync_status_not_connected": "NIET VERBONDEN",
|
||||||
|
"sync_status_starting_scan": "Startscan",
|
||||||
"sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN",
|
"sync_status_starting_sync": "BEGINNEN MET SYNCHRONISEREN",
|
||||||
"sync_status_syncronized": "SYNCHRONIZED",
|
"sync_status_syncronized": "SYNCHRONIZED",
|
||||||
"sync_status_syncronizing": "SYNCHRONISEREN",
|
"sync_status_syncronizing": "SYNCHRONISEREN",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "ŁĄCZENIE",
|
"sync_status_connecting": "ŁĄCZENIE",
|
||||||
"sync_status_failed_connect": "POŁĄCZENIE NIEUDANE",
|
"sync_status_failed_connect": "POŁĄCZENIE NIEUDANE",
|
||||||
"sync_status_not_connected": "NIE POŁĄCZONY",
|
"sync_status_not_connected": "NIE POŁĄCZONY",
|
||||||
|
"sync_status_starting_scan": "Rozpoczęcie skanowania",
|
||||||
"sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI",
|
"sync_status_starting_sync": "ROZPOCZĘCIE SYNCHRONIZACJI",
|
||||||
"sync_status_syncronized": "ZSYNCHRONIZOWANO",
|
"sync_status_syncronized": "ZSYNCHRONIZOWANO",
|
||||||
"sync_status_syncronizing": "SYNCHRONIZACJA",
|
"sync_status_syncronizing": "SYNCHRONIZACJA",
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"sync_status_connecting": "CONECTANDO",
|
"sync_status_connecting": "CONECTANDO",
|
||||||
"sync_status_failed_connect": "DESCONECTADO",
|
"sync_status_failed_connect": "DESCONECTADO",
|
||||||
"sync_status_not_connected": "DESCONECTADO",
|
"sync_status_not_connected": "DESCONECTADO",
|
||||||
|
"sync_status_starting_scan": "Diretor inicial",
|
||||||
"sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO",
|
"sync_status_starting_sync": "INICIANDO SINCRONIZAÇÃO",
|
||||||
"sync_status_syncronized": "SINCRONIZADO",
|
"sync_status_syncronized": "SINCRONIZADO",
|
||||||
"sync_status_syncronizing": "SINCRONIZANDO",
|
"sync_status_syncronizing": "SINCRONIZANDO",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "ПОДКЛЮЧЕНИЕ",
|
"sync_status_connecting": "ПОДКЛЮЧЕНИЕ",
|
||||||
"sync_status_failed_connect": "ОТКЛЮЧЕНО",
|
"sync_status_failed_connect": "ОТКЛЮЧЕНО",
|
||||||
"sync_status_not_connected": "НЕ ПОДКЛЮЧЁН",
|
"sync_status_not_connected": "НЕ ПОДКЛЮЧЁН",
|
||||||
|
"sync_status_starting_scan": "Начальное сканирование",
|
||||||
"sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ",
|
"sync_status_starting_sync": "НАЧАЛО СИНХРОНИЗАЦИИ",
|
||||||
"sync_status_syncronized": "СИНХРОНИЗИРОВАН",
|
"sync_status_syncronized": "СИНХРОНИЗИРОВАН",
|
||||||
"sync_status_syncronizing": "СИНХРОНИЗАЦИЯ",
|
"sync_status_syncronizing": "СИНХРОНИЗАЦИЯ",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "กำลังเชื่อมต่อ",
|
"sync_status_connecting": "กำลังเชื่อมต่อ",
|
||||||
"sync_status_failed_connect": "การเชื่อมต่อล้มเหลว",
|
"sync_status_failed_connect": "การเชื่อมต่อล้มเหลว",
|
||||||
"sync_status_not_connected": "ไม่ได้เชื่อมต่อ",
|
"sync_status_not_connected": "ไม่ได้เชื่อมต่อ",
|
||||||
|
"sync_status_starting_scan": "เริ่มการสแกน",
|
||||||
"sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์",
|
"sync_status_starting_sync": "กำลังเริ่มซิงโครไนซ์",
|
||||||
"sync_status_syncronized": "ซิงโครไนซ์แล้ว",
|
"sync_status_syncronized": "ซิงโครไนซ์แล้ว",
|
||||||
"sync_status_syncronizing": "กำลังซิงโครไนซ์",
|
"sync_status_syncronizing": "กำลังซิงโครไนซ์",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "Pagkonekta",
|
"sync_status_connecting": "Pagkonekta",
|
||||||
"sync_status_failed_connect": "Naka -disconnect",
|
"sync_status_failed_connect": "Naka -disconnect",
|
||||||
"sync_status_not_connected": "HINDI KONEKTADO",
|
"sync_status_not_connected": "HINDI KONEKTADO",
|
||||||
|
"sync_status_starting_scan": "Simula sa pag -scan",
|
||||||
"sync_status_starting_sync": "Simula sa pag -sync",
|
"sync_status_starting_sync": "Simula sa pag -sync",
|
||||||
"sync_status_syncronized": "Naka -synchronize",
|
"sync_status_syncronized": "Naka -synchronize",
|
||||||
"sync_status_syncronizing": "Pag -synchronize",
|
"sync_status_syncronizing": "Pag -synchronize",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "BAĞLANILIYOR",
|
"sync_status_connecting": "BAĞLANILIYOR",
|
||||||
"sync_status_failed_connect": "BAĞLANTI KESİLDİ",
|
"sync_status_failed_connect": "BAĞLANTI KESİLDİ",
|
||||||
"sync_status_not_connected": "BAĞLI DEĞİL",
|
"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_starting_sync": "SENKRONİZE BAŞLATILIYOR",
|
||||||
"sync_status_syncronized": "SENKRONİZE EDİLDİ",
|
"sync_status_syncronized": "SENKRONİZE EDİLDİ",
|
||||||
"sync_status_syncronizing": "SENKRONİZE EDİLİYOR",
|
"sync_status_syncronizing": "SENKRONİZE EDİLİYOR",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "ПІДКЛЮЧЕННЯ",
|
"sync_status_connecting": "ПІДКЛЮЧЕННЯ",
|
||||||
"sync_status_failed_connect": "ВІДКЛЮЧЕНО",
|
"sync_status_failed_connect": "ВІДКЛЮЧЕНО",
|
||||||
"sync_status_not_connected": "НЕ ПІДКЛЮЧЕННИЙ",
|
"sync_status_not_connected": "НЕ ПІДКЛЮЧЕННИЙ",
|
||||||
|
"sync_status_starting_scan": "Початок сканування",
|
||||||
"sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ",
|
"sync_status_starting_sync": "ПОЧАТОК СИНХРОНІЗАЦІЇ",
|
||||||
"sync_status_syncronized": "СИНХРОНІЗОВАНИЙ",
|
"sync_status_syncronized": "СИНХРОНІЗОВАНИЙ",
|
||||||
"sync_status_syncronizing": "СИНХРОНІЗАЦІЯ",
|
"sync_status_syncronizing": "СИНХРОНІЗАЦІЯ",
|
||||||
|
|
|
@ -697,6 +697,7 @@
|
||||||
"sync_status_connecting": "جڑ رہا ہے۔",
|
"sync_status_connecting": "جڑ رہا ہے۔",
|
||||||
"sync_status_failed_connect": "منقطع",
|
"sync_status_failed_connect": "منقطع",
|
||||||
"sync_status_not_connected": "منسلک نہیں",
|
"sync_status_not_connected": "منسلک نہیں",
|
||||||
|
"sync_status_starting_scan": "اسکین شروع کرنا",
|
||||||
"sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔",
|
"sync_status_starting_sync": "مطابقت پذیری شروع کر رہا ہے۔",
|
||||||
"sync_status_syncronized": "مطابقت پذیر",
|
"sync_status_syncronized": "مطابقت پذیر",
|
||||||
"sync_status_syncronizing": "مطابقت پذیری",
|
"sync_status_syncronizing": "مطابقت پذیری",
|
||||||
|
|
|
@ -696,6 +696,7 @@
|
||||||
"sync_status_connecting": "Ń DÁRAPỌ̀ MỌ́",
|
"sync_status_connecting": "Ń DÁRAPỌ̀ MỌ́",
|
||||||
"sync_status_failed_connect": "ÌKÀNPỌ̀ TI KÚ",
|
"sync_status_failed_connect": "ÌKÀNPỌ̀ TI KÚ",
|
||||||
"sync_status_not_connected": "KÒ TI DÁRAPỌ̀ MỌ́ Ọ",
|
"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_starting_sync": "Ń BẸ̀RẸ̀ RẸ́",
|
||||||
"sync_status_syncronized": "TI MÚDỌ́GBA",
|
"sync_status_syncronized": "TI MÚDỌ́GBA",
|
||||||
"sync_status_syncronizing": "Ń MÚDỌ́GBA",
|
"sync_status_syncronizing": "Ń MÚDỌ́GBA",
|
||||||
|
|
|
@ -695,6 +695,7 @@
|
||||||
"sync_status_connecting": "连接中",
|
"sync_status_connecting": "连接中",
|
||||||
"sync_status_failed_connect": "断线",
|
"sync_status_failed_connect": "断线",
|
||||||
"sync_status_not_connected": "未连接",
|
"sync_status_not_connected": "未连接",
|
||||||
|
"sync_status_starting_scan": "开始扫描",
|
||||||
"sync_status_starting_sync": "开始同步",
|
"sync_status_starting_sync": "开始同步",
|
||||||
"sync_status_syncronized": "已同步",
|
"sync_status_syncronized": "已同步",
|
||||||
"sync_status_syncronizing": "正在同步",
|
"sync_status_syncronizing": "正在同步",
|
||||||
|
|
|
@ -94,12 +94,11 @@ import 'package:cw_core/wallet_service.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:ledger_flutter/ledger_flutter.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;
|
import 'package:bip39/bip39.dart' as bip39;
|
||||||
""";
|
""";
|
||||||
const bitcoinCWHeaders = """
|
const bitcoinCWHeaders = """
|
||||||
import 'package:cw_bitcoin/utils.dart';
|
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_derivations.dart';
|
||||||
import 'package:cw_bitcoin/electrum.dart';
|
import 'package:cw_bitcoin/electrum.dart';
|
||||||
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
import 'package:cw_bitcoin/pending_bitcoin_transaction.dart';
|
||||||
|
|
Loading…
Reference in a new issue