mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Mweb enhancements 3 (#1744)
* version 4.20.0 * update build numbers * UI updates and script fix for ios bundle identifier * disable mweb for desktop * change hardcoded ltc server ip address electrum connection enhancement * MWEB enhancements 2.0 (#1735) * additional logging and minor fixes * additional logging and minor fixes * addresses pt.1 * Allow Wallet Group Names to be the same as Wallet Names (#1730) * fix: Issues with imaging * fix: Allow group names to be the same as wallet names * fix: Bug with wallet grouping when a wallet is minimized * fix: Bug with wallet grouping when a wallet is minimized * logs of fixes and experimental changes, close wallet before opening next * save * fix icon * fixes * [skip ci] updates * [skip ci] updates * updates * minor optimizations * fix for when switching between wallets * [skip ci] updates * [skip ci] updates * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * Update cw_bitcoin/lib/litecoin_wallet.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * mobx * mostly logging * stream fix pt.1 [skip ci] * updates * some fixes and enhancements * [skip ci] minor * potential partial fix for streamsink closed * fix stream sink closed errors * fix mweb logo colors * save * minor enhancements [skip ci] * save * experimental * minor * minor [skip ci] --------- Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com> Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> * fix menu list removing from original list * detach sync status from mwebsyncstatus * minor * keep sync status in sync where necessary * minor * wip * appears to work? * updates * prevent mwebd from submitting non mweb transactions * fix unspent coins info not persisting for mweb coins + other minor fixes * [skip ci] minor * Polish MWEB card UI * make sure current chain tip is updated correctly [skip ci] * [skip ci] review fixes * [skip ci] detect mweb outputs more thoroughly (fix peg-in commit error) * fix change address on send ui * fix qr code scan issue * get segwit address for pegout even if mweb is selected on the receive screen [skip ci] * - Fix adding nodes twice - Fix mempool API parsing error * (potentially) fix duplicate tx history bug * [skip ci] fix bc1 address * don't show contacts prompt on pegin/out + potential unconfirmed balance fixes * [skip ci] minor cleanup * fix mweb input detection * fix showing mweb address for non-mweb transactions --------- Co-authored-by: OmarHatem <omarh.ismail1@gmail.com> Co-authored-by: David Adegoke <64401859+Blazebrain@users.noreply.github.com> Co-authored-by: tuxpizza <tuxsudo@tux.pizza>
This commit is contained in:
parent
7faca38cfa
commit
50825a62c1
13 changed files with 266 additions and 140 deletions
|
@ -68,8 +68,8 @@ class ElectrumClient {
|
|||
|
||||
try {
|
||||
await socket?.close();
|
||||
socket = null;
|
||||
} catch (_) {}
|
||||
socket = null;
|
||||
|
||||
try {
|
||||
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) {
|
||||
|
@ -102,7 +102,8 @@ class ElectrumClient {
|
|||
return;
|
||||
}
|
||||
|
||||
_setConnectionStatus(ConnectionStatus.connected);
|
||||
// use ping to determine actual connection status since we could've just not timed out yet:
|
||||
// _setConnectionStatus(ConnectionStatus.connected);
|
||||
|
||||
socket!.listen(
|
||||
(Uint8List event) {
|
||||
|
@ -128,7 +129,7 @@ class ElectrumClient {
|
|||
print("SOCKET CLOSED!!!!!");
|
||||
unterminatedString = '';
|
||||
try {
|
||||
if (host == socket?.address.host) {
|
||||
if (host == socket?.address.host || socket == null) {
|
||||
_setConnectionStatus(ConnectionStatus.disconnected);
|
||||
socket?.destroy();
|
||||
}
|
||||
|
@ -178,7 +179,7 @@ class ElectrumClient {
|
|||
unterminatedString = '';
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("parse $e");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +192,7 @@ class ElectrumClient {
|
|||
try {
|
||||
await callWithTimeout(method: 'server.ping');
|
||||
_setConnectionStatus(ConnectionStatus.connected);
|
||||
} on RequestFailedTimeoutException catch (_) {
|
||||
} catch (_) {
|
||||
_setConnectionStatus(ConnectionStatus.disconnected);
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +432,7 @@ class ElectrumClient {
|
|||
|
||||
return subscription;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("subscribe $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -470,7 +471,8 @@ class ElectrumClient {
|
|||
|
||||
return completer.future;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("callWithTimeout $e");
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,6 +539,12 @@ class ElectrumClient {
|
|||
onConnectionStatusChange?.call(status);
|
||||
_connectionStatus = status;
|
||||
_isConnected = status == ConnectionStatus.connected;
|
||||
if (!_isConnected) {
|
||||
try {
|
||||
socket?.destroy();
|
||||
} catch (_) {}
|
||||
socket = null;
|
||||
}
|
||||
}
|
||||
|
||||
void _handleResponse(Map<String, dynamic> response) {
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||
import 'dart:isolate';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cw_core/encryption_file_utils.dart';
|
||||
import 'package:blockchain_utils/blockchain_utils.dart';
|
||||
|
@ -249,7 +250,7 @@ abstract class ElectrumWalletBase
|
|||
int? _currentChainTip;
|
||||
|
||||
Future<int> getCurrentChainTip() async {
|
||||
if (_currentChainTip != null) {
|
||||
if ((_currentChainTip ?? 0) > 0) {
|
||||
return _currentChainTip!;
|
||||
}
|
||||
_currentChainTip = await electrumClient.getCurrentBlockChainTip() ?? 0;
|
||||
|
@ -301,6 +302,7 @@ abstract class ElectrumWalletBase
|
|||
|
||||
@action
|
||||
Future<void> _setListeners(int height, {int? chainTipParam, bool? doSingleScan}) async {
|
||||
if (this is! BitcoinWallet) return;
|
||||
final chainTip = chainTipParam ?? await getUpdatedChainTip();
|
||||
|
||||
if (chainTip == height) {
|
||||
|
@ -467,7 +469,7 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
} catch (e, stacktrace) {
|
||||
print(stacktrace);
|
||||
print(e.toString());
|
||||
print("startSync $e");
|
||||
syncStatus = FailedSyncStatus();
|
||||
}
|
||||
}
|
||||
|
@ -479,10 +481,10 @@ abstract class ElectrumWalletBase
|
|||
final response =
|
||||
await http.get(Uri.parse("http://mempool.cakewallet.com:8999/api/v1/fees/recommended"));
|
||||
|
||||
final result = json.decode(response.body) as Map<String, num>;
|
||||
final slowFee = result['economyFee']?.toInt() ?? 0;
|
||||
int mediumFee = result['hourFee']?.toInt() ?? 0;
|
||||
int fastFee = result['fastestFee']?.toInt() ?? 0;
|
||||
final result = json.decode(response.body) as Map<String, dynamic>;
|
||||
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
|
||||
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
|
||||
int fastFee = (result['fastestFee'] as num?)?.toInt() ?? 0;
|
||||
if (slowFee == mediumFee) {
|
||||
mediumFee++;
|
||||
}
|
||||
|
@ -491,7 +493,9 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
_feeRates = [slowFee, mediumFee, fastFee];
|
||||
return;
|
||||
} catch (_) {}
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
final feeRates = await electrumClient.feeRates(network: network);
|
||||
|
@ -571,7 +575,7 @@ abstract class ElectrumWalletBase
|
|||
await electrumClient.connectToUri(node.uri, useSSL: node.useSSL);
|
||||
} catch (e, stacktrace) {
|
||||
print(stacktrace);
|
||||
print(e.toString());
|
||||
print("connectToNode $e");
|
||||
syncStatus = FailedSyncStatus();
|
||||
}
|
||||
}
|
||||
|
@ -826,8 +830,8 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
|
||||
final changeAddress = await walletAddresses.getChangeAddress(
|
||||
inputs: utxoDetails.availableInputs,
|
||||
outputs: updatedOutputs,
|
||||
utxoDetails: utxoDetails,
|
||||
);
|
||||
final address = RegexUtils.addressTypeFromStr(changeAddress, network);
|
||||
updatedOutputs.add(BitcoinOutput(
|
||||
|
@ -1181,6 +1185,7 @@ abstract class ElectrumWalletBase
|
|||
hasChange: estimatedTx.hasChange,
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
)..addListener((transaction) async {
|
||||
transactionHistory.addOne(transaction);
|
||||
if (estimatedTx.spendsSilentPayment) {
|
||||
|
@ -1370,7 +1375,7 @@ abstract class ElectrumWalletBase
|
|||
});
|
||||
}
|
||||
|
||||
// Set the balance of all non-silent payment addresses to 0 before updating
|
||||
// Set the balance of all non-silent payment and non-mweb addresses to 0 before updating
|
||||
walletAddresses.allAddresses
|
||||
.where((element) => element.type != SegwitAddresType.mweb)
|
||||
.forEach((addr) {
|
||||
|
@ -1487,7 +1492,7 @@ abstract class ElectrumWalletBase
|
|||
await unspentCoinsInfo.deleteAll(keys);
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("refreshUnspentCoinsInfo $e");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1831,7 +1836,7 @@ abstract class ElectrumWalletBase
|
|||
|
||||
return historiesWithDetails;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("fetchTransactions $e");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
@ -1905,7 +1910,9 @@ abstract class ElectrumWalletBase
|
|||
if (height > 0) {
|
||||
storedTx.height = height;
|
||||
// the tx's block itself is the first confirmation so add 1
|
||||
if (currentHeight != null) storedTx.confirmations = currentHeight - height + 1;
|
||||
if ((currentHeight ?? 0) > 0) {
|
||||
storedTx.confirmations = currentHeight! - height + 1;
|
||||
}
|
||||
storedTx.isPending = storedTx.confirmations == 0;
|
||||
}
|
||||
|
||||
|
@ -1946,9 +1953,13 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
await getCurrentChainTip();
|
||||
|
||||
transactionHistory.transactions.values.forEach((tx) async {
|
||||
if (tx.unspents != null && tx.unspents!.isNotEmpty && tx.height != null && tx.height! > 0) {
|
||||
tx.confirmations = await getCurrentChainTip() - tx.height! + 1;
|
||||
transactionHistory.transactions.values.forEach((tx) {
|
||||
if (tx.unspents != null &&
|
||||
tx.unspents!.isNotEmpty &&
|
||||
tx.height != null &&
|
||||
tx.height! > 0 &&
|
||||
(_currentChainTip ?? 0) > 0) {
|
||||
tx.confirmations = _currentChainTip! - tx.height! + 1;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1973,9 +1984,17 @@ abstract class ElectrumWalletBase
|
|||
await Future.wait(unsubscribedScriptHashes.map((address) async {
|
||||
final sh = address.getScriptHash(network);
|
||||
if (!(_scripthashesUpdateSubject[sh]?.isClosed ?? true)) {
|
||||
try {
|
||||
await _scripthashesUpdateSubject[sh]?.close();
|
||||
} catch (e) {
|
||||
print("failed to close: $e");
|
||||
}
|
||||
}
|
||||
try {
|
||||
_scripthashesUpdateSubject[sh] = await electrumClient.scripthashUpdate(sh);
|
||||
} catch (e) {
|
||||
print("failed scripthashUpdate: $e");
|
||||
}
|
||||
_scripthashesUpdateSubject[sh]?.listen((event) async {
|
||||
try {
|
||||
await updateUnspentsForAddress(address);
|
||||
|
@ -2171,6 +2190,7 @@ abstract class ElectrumWalletBase
|
|||
|
||||
@action
|
||||
void _onConnectionStatusChange(ConnectionStatus status) {
|
||||
|
||||
switch (status) {
|
||||
case ConnectionStatus.connected:
|
||||
if (syncStatus is NotConnectedSyncStatus ||
|
||||
|
@ -2182,19 +2202,26 @@ abstract class ElectrumWalletBase
|
|||
|
||||
break;
|
||||
case ConnectionStatus.disconnected:
|
||||
if (syncStatus is! NotConnectedSyncStatus) {
|
||||
syncStatus = NotConnectedSyncStatus();
|
||||
}
|
||||
break;
|
||||
case ConnectionStatus.failed:
|
||||
if (syncStatus is! LostConnectionSyncStatus) {
|
||||
syncStatus = LostConnectionSyncStatus();
|
||||
}
|
||||
break;
|
||||
case ConnectionStatus.connecting:
|
||||
if (syncStatus is! ConnectingSyncStatus) {
|
||||
syncStatus = ConnectingSyncStatus();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
void _syncStatusReaction(SyncStatus syncStatus) async {
|
||||
print("SYNC_STATUS_CHANGE: ${syncStatus}");
|
||||
if (syncStatus is SyncingSyncStatus) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:io' show Platform;
|
|||
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/electrum_wallet.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_unspent.dart';
|
||||
import 'package:cw_core/wallet_addresses.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -267,7 +267,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
}
|
||||
|
||||
@action
|
||||
Future<String> getChangeAddress({List<BitcoinOutput>? outputs, UtxoDetails? utxoDetails}) async {
|
||||
Future<String> getChangeAddress({List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||
updateChangeAddresses();
|
||||
|
||||
if (changeAddresses.isEmpty) {
|
||||
|
@ -478,7 +478,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
|
|||
|
||||
await saveAddressesInBox();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
print("updateAddresses $e");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
|
||||
import 'package:cw_core/cake_hive.dart';
|
||||
import 'package:cw_core/mweb_utxo.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:cw_mweb/mwebd.pbgrpc.dart';
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
|
@ -95,6 +96,36 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
autorun((_) {
|
||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||
});
|
||||
reaction((_) => mwebSyncStatus, (status) async {
|
||||
if (mwebSyncStatus is FailedSyncStatus) {
|
||||
// we failed to connect to mweb, check if we are connected to the litecoin node:
|
||||
late int nodeHeight;
|
||||
try {
|
||||
nodeHeight = await electrumClient.getCurrentBlockChainTip() ?? 0;
|
||||
} catch (_) {
|
||||
nodeHeight = 0;
|
||||
}
|
||||
|
||||
if (nodeHeight == 0) {
|
||||
// we aren't connected to the litecoin node, so the current electrum_wallet reactions will take care of this case for us
|
||||
} else {
|
||||
// we're connected to the litecoin node, but we failed to connect to mweb, try again after a few seconds:
|
||||
await CwMweb.stop();
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
startSync();
|
||||
}
|
||||
} else if (mwebSyncStatus is SyncingSyncStatus) {
|
||||
syncStatus = mwebSyncStatus;
|
||||
} else if (mwebSyncStatus is SyncronizingSyncStatus) {
|
||||
if (syncStatus is! SyncronizingSyncStatus) {
|
||||
syncStatus = mwebSyncStatus;
|
||||
}
|
||||
} else if (mwebSyncStatus is SyncedSyncStatus) {
|
||||
if (syncStatus is! SyncedSyncStatus) {
|
||||
syncStatus = mwebSyncStatus;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
late final Bip32Slip10Secp256k1 mwebHd;
|
||||
late final Box<MwebUtxo> mwebUtxosBox;
|
||||
|
@ -105,6 +136,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
late bool mwebEnabled;
|
||||
bool processingUtxos = false;
|
||||
|
||||
@observable
|
||||
SyncStatus mwebSyncStatus = NotConnectedSyncStatus();
|
||||
|
||||
List<int> get scanSecret => mwebHd.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw;
|
||||
List<int> get spendSecret => mwebHd.childKey(Bip32KeyIndex(0x80000001)).privateKey.privKey.raw;
|
||||
|
||||
|
@ -244,13 +278,24 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
@override
|
||||
Future<void> startSync() async {
|
||||
print("startSync() called!");
|
||||
if (syncStatus is SyncronizingSyncStatus) {
|
||||
print("STARTING SYNC - MWEB ENABLED: $mwebEnabled");
|
||||
if (!mwebEnabled) {
|
||||
try {
|
||||
// in case we're switching from a litecoin wallet that had mweb enabled
|
||||
CwMweb.stop();
|
||||
} catch (_) {}
|
||||
super.startSync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mwebSyncStatus is SyncronizingSyncStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
print("STARTING SYNC - MWEB ENABLED: $mwebEnabled");
|
||||
_syncTimer?.cancel();
|
||||
try {
|
||||
syncStatus = SyncronizingSyncStatus();
|
||||
mwebSyncStatus = SyncronizingSyncStatus();
|
||||
try {
|
||||
await subscribeForUpdates();
|
||||
} catch (e) {
|
||||
|
@ -261,45 +306,32 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
_feeRatesTimer =
|
||||
Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates());
|
||||
|
||||
if (!mwebEnabled) {
|
||||
try {
|
||||
// in case we're switching from a litecoin wallet that had mweb enabled
|
||||
CwMweb.stop();
|
||||
} catch (_) {}
|
||||
try {
|
||||
await updateAllUnspents();
|
||||
await updateTransactions();
|
||||
await updateBalance();
|
||||
syncStatus = SyncedSyncStatus();
|
||||
} catch (e, s) {
|
||||
print(e);
|
||||
print(s);
|
||||
syncStatus = FailedSyncStatus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
print("START SYNC FUNCS");
|
||||
await waitForMwebAddresses();
|
||||
await processMwebUtxos();
|
||||
await updateTransactions();
|
||||
await updateUnspent();
|
||||
await updateBalance();
|
||||
} catch (e) {
|
||||
print("failed to start mweb sync: $e");
|
||||
syncStatus = FailedSyncStatus(error: "failed to start");
|
||||
print("DONE SYNC FUNCS");
|
||||
} catch (e, s) {
|
||||
print("mweb sync failed: $e $s");
|
||||
mwebSyncStatus = FailedSyncStatus(error: "mweb sync failed: $e");
|
||||
return;
|
||||
}
|
||||
|
||||
_syncTimer = Timer.periodic(const Duration(milliseconds: 3000), (timer) async {
|
||||
if (syncStatus is FailedSyncStatus) return;
|
||||
if (mwebSyncStatus is FailedSyncStatus) {
|
||||
_syncTimer?.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
final nodeHeight =
|
||||
await electrumClient.getCurrentBlockChainTip() ?? 0; // current block height of our node
|
||||
|
||||
if (nodeHeight == 0) {
|
||||
// we aren't connected to the ltc node yet
|
||||
if (syncStatus is! NotConnectedSyncStatus) {
|
||||
syncStatus = FailedSyncStatus(error: "Failed to connect to Litecoin node");
|
||||
if (mwebSyncStatus is! NotConnectedSyncStatus) {
|
||||
mwebSyncStatus = FailedSyncStatus(error: "litecoin node isn't connected");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -309,12 +341,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
try {
|
||||
if (resp.blockHeaderHeight < nodeHeight) {
|
||||
int h = resp.blockHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
mwebSyncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebHeaderHeight < nodeHeight) {
|
||||
int h = resp.mwebHeaderHeight;
|
||||
syncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
mwebSyncStatus = SyncingSyncStatus(nodeHeight - h, h / nodeHeight);
|
||||
} else if (resp.mwebUtxosHeight < nodeHeight) {
|
||||
syncStatus = SyncingSyncStatus(1, 0.999);
|
||||
mwebSyncStatus = SyncingSyncStatus(1, 0.999);
|
||||
} else {
|
||||
if (resp.mwebUtxosHeight > walletInfo.restoreHeight) {
|
||||
await walletInfo.updateRestoreHeight(resp.mwebUtxosHeight);
|
||||
|
@ -325,6 +357,9 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
int txHeight = transaction.height ?? resp.mwebUtxosHeight;
|
||||
final confirmations = (resp.mwebUtxosHeight - txHeight) + 1;
|
||||
if (transaction.confirmations == confirmations) continue;
|
||||
if (transaction.confirmations == 0) {
|
||||
updateBalance();
|
||||
}
|
||||
transaction.confirmations = confirmations;
|
||||
transactionHistory.addOne(transaction);
|
||||
}
|
||||
|
@ -332,17 +367,17 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
|
||||
// prevent unnecessary reaction triggers:
|
||||
if (syncStatus is! SyncedSyncStatus) {
|
||||
if (mwebSyncStatus is! SyncedSyncStatus) {
|
||||
// mwebd is synced, but we could still be processing incoming utxos:
|
||||
if (!processingUtxos) {
|
||||
syncStatus = SyncedSyncStatus();
|
||||
mwebSyncStatus = SyncedSyncStatus();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
print("error syncing: $e");
|
||||
syncStatus = FailedSyncStatus(error: e.toString());
|
||||
mwebSyncStatus = FailedSyncStatus(error: e.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -512,8 +547,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
_utxoStream = responseStream.listen((Utxo sUtxo) async {
|
||||
// we're processing utxos, so our balance could still be innacurate:
|
||||
if (syncStatus is! SyncronizingSyncStatus && syncStatus is! SyncingSyncStatus) {
|
||||
syncStatus = SyncronizingSyncStatus();
|
||||
if (mwebSyncStatus is! SyncronizingSyncStatus && mwebSyncStatus is! SyncingSyncStatus) {
|
||||
mwebSyncStatus = SyncronizingSyncStatus();
|
||||
processingUtxos = true;
|
||||
_processingTimer?.cancel();
|
||||
_processingTimer = Timer.periodic(const Duration(seconds: 2), (timer) async {
|
||||
|
@ -530,10 +565,18 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
value: sUtxo.value.toInt(),
|
||||
);
|
||||
|
||||
// if (mwebUtxosBox.containsKey(utxo.outputId)) {
|
||||
// // we've already stored this utxo, skip it:
|
||||
// return;
|
||||
// }
|
||||
if (mwebUtxosBox.containsKey(utxo.outputId)) {
|
||||
// we've already stored this utxo, skip it:
|
||||
// but do update the utxo height if it's somehow different:
|
||||
final existingUtxo = mwebUtxosBox.get(utxo.outputId);
|
||||
if (existingUtxo!.height != utxo.height) {
|
||||
print(
|
||||
"updating utxo height for $utxo.outputId: ${existingUtxo.height} -> ${utxo.height}");
|
||||
existingUtxo.height = utxo.height;
|
||||
await mwebUtxosBox.put(utxo.outputId, existingUtxo);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await updateUnspent();
|
||||
await updateBalance();
|
||||
|
@ -579,7 +622,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
final height = await electrumClient.getCurrentBlockChainTip();
|
||||
if (height == null || status.blockHeaderHeight != height) return;
|
||||
if (status.mwebUtxosHeight != height) return; // we aren't synced
|
||||
|
||||
int amount = 0;
|
||||
Set<String> inputAddresses = {};
|
||||
var output = convert.AccumulatorSink<Digest>();
|
||||
|
@ -673,10 +715,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
@override
|
||||
@action
|
||||
Future<void> updateAllUnspents() async {
|
||||
// get ltc unspents:
|
||||
await super.updateAllUnspents();
|
||||
|
||||
if (!mwebEnabled) {
|
||||
await super.updateAllUnspents();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -712,6 +752,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
}
|
||||
mwebUnspentCoins.add(unspent);
|
||||
});
|
||||
|
||||
// copy coin control attributes to mwebCoins:
|
||||
await updateCoins(mwebUnspentCoins);
|
||||
// get regular ltc unspents (this resets unspentCoins):
|
||||
await super.updateAllUnspents();
|
||||
// add the mwebCoins:
|
||||
unspentCoins.addAll(mwebUnspentCoins);
|
||||
}
|
||||
|
||||
|
@ -890,6 +936,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
tx.isMweb = mwebEnabled;
|
||||
|
||||
if (!mwebEnabled) {
|
||||
tx.changeAddressOverride =
|
||||
await (walletAddresses as LitecoinWalletAddresses).getChangeAddress(isPegIn: false);
|
||||
return tx;
|
||||
}
|
||||
await waitForMwebAddresses();
|
||||
|
@ -913,12 +961,23 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
hasMwebOutput = true;
|
||||
break;
|
||||
}
|
||||
if (output.address.toLowerCase().contains("mweb")) {
|
||||
hasMwebOutput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tx2.mwebBytes != null && tx2.mwebBytes!.isNotEmpty) {
|
||||
// check if mweb inputs are used:
|
||||
for (final utxo in tx.utxos) {
|
||||
if (utxo.utxo.scriptType == SegwitAddresType.mweb) {
|
||||
hasMwebInput = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool isPegIn = !hasMwebInput && hasMwebOutput;
|
||||
bool isRegular = !hasMwebInput && !hasMwebOutput;
|
||||
tx.changeAddressOverride = await (walletAddresses as LitecoinWalletAddresses)
|
||||
.getChangeAddress(isPegIn: isPegIn || isRegular);
|
||||
if (!hasMwebInput && !hasMwebOutput) {
|
||||
tx.isMweb = false;
|
||||
return tx;
|
||||
|
@ -971,7 +1030,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
final addresses = <String>{};
|
||||
transaction.inputAddresses?.forEach((id) async {
|
||||
final utxo = mwebUtxosBox.get(id);
|
||||
// await mwebUtxosBox.delete(id);// gets deleted in checkMwebUtxosSpent
|
||||
await mwebUtxosBox.delete(id); // gets deleted in checkMwebUtxosSpent
|
||||
if (utxo == null) return;
|
||||
final addressRecord = walletAddresses.allAddresses
|
||||
.firstWhere((addressRecord) => addressRecord.address == utxo.address);
|
||||
|
@ -990,6 +1049,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
print(e);
|
||||
print(s);
|
||||
if (e.toString().contains("commit failed")) {
|
||||
print(e);
|
||||
throw Exception("Transaction commit failed (no peers responded), please try again.");
|
||||
}
|
||||
rethrow;
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:typed_data';
|
|||
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_unspent.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:cw_bitcoin/utils.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_addresses.dart';
|
||||
|
@ -142,14 +143,15 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
|
||||
@action
|
||||
@override
|
||||
Future<String> getChangeAddress({List<BitcoinOutput>? outputs, UtxoDetails? utxoDetails}) async {
|
||||
Future<String> getChangeAddress(
|
||||
{List<BitcoinUnspent>? inputs, List<BitcoinOutput>? outputs, bool isPegIn = false}) async {
|
||||
// use regular change address on peg in, otherwise use mweb for change address:
|
||||
|
||||
if (!mwebEnabled) {
|
||||
if (!mwebEnabled || isPegIn) {
|
||||
return super.getChangeAddress();
|
||||
}
|
||||
|
||||
if (outputs != null && utxoDetails != null) {
|
||||
if (inputs != null && outputs != null) {
|
||||
// check if this is a PEGIN:
|
||||
bool outputsToMweb = false;
|
||||
bool comesFromMweb = false;
|
||||
|
@ -161,14 +163,18 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
|
|||
outputsToMweb = true;
|
||||
}
|
||||
}
|
||||
// TODO: this doesn't respect coin control because it doesn't know which available inputs are selected
|
||||
utxoDetails.availableInputs.forEach((element) {
|
||||
|
||||
inputs.forEach((element) {
|
||||
if (!element.isSending || element.isFrozen) {
|
||||
return;
|
||||
}
|
||||
if (element.address.contains("mweb")) {
|
||||
comesFromMweb = true;
|
||||
}
|
||||
});
|
||||
|
||||
bool isPegIn = !comesFromMweb && outputsToMweb;
|
||||
|
||||
if (isPegIn && mwebEnabled) {
|
||||
return super.getChangeAddress();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ class PendingBitcoinTransaction with PendingTransaction {
|
|||
this.isSendAll = false,
|
||||
this.hasTaprootInputs = false,
|
||||
this.isMweb = false,
|
||||
this.utxos = const [],
|
||||
}) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];
|
||||
|
||||
final WalletType type;
|
||||
|
@ -36,7 +37,9 @@ class PendingBitcoinTransaction with PendingTransaction {
|
|||
final bool isSendAll;
|
||||
final bool hasChange;
|
||||
final bool hasTaprootInputs;
|
||||
List<UtxoWithAddress> utxos;
|
||||
bool isMweb;
|
||||
String? changeAddressOverride;
|
||||
String? idOverride;
|
||||
String? hexOverride;
|
||||
List<String>? outputAddresses;
|
||||
|
@ -63,6 +66,9 @@ class PendingBitcoinTransaction with PendingTransaction {
|
|||
PendingChange? get change {
|
||||
try {
|
||||
final change = _tx.outputs.firstWhere((out) => out.isChange);
|
||||
if (changeAddressOverride != null) {
|
||||
return PendingChange(changeAddressOverride!, BtcUtils.fromSatoshi(change.amount));
|
||||
}
|
||||
return PendingChange(change.scriptPubKey.toAddress(), BtcUtils.fromSatoshi(change.amount));
|
||||
} catch (_) {
|
||||
return null;
|
||||
|
|
|
@ -40,7 +40,7 @@ class CwMweb {
|
|||
}
|
||||
|
||||
static Future<void> _initializeClient() async {
|
||||
print("initialize client called!");
|
||||
print("_initializeClient() called!");
|
||||
final appDir = await getApplicationSupportDirectory();
|
||||
const ltcNodeUri = "ltc-electrum.cakewallet.com:9333";
|
||||
|
||||
|
@ -54,7 +54,7 @@ class CwMweb {
|
|||
log("Attempting to connect to server on port: $_port");
|
||||
|
||||
// wait for the server to finish starting up before we try to connect to it:
|
||||
await Future.delayed(const Duration(seconds: 5));
|
||||
await Future.delayed(const Duration(seconds: 8));
|
||||
|
||||
_clientChannel = ClientChannel('127.0.0.1', port: _port!, channelShutdownHandler: () {
|
||||
_rpcClient = null;
|
||||
|
@ -83,10 +83,13 @@ class CwMweb {
|
|||
log("Attempt $i failed: $e");
|
||||
log('Caught grpc error: ${e.message}');
|
||||
_rpcClient = null;
|
||||
// necessary if the database isn't open:
|
||||
await stop();
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
} catch (e) {
|
||||
log("Attempt $i failed: $e");
|
||||
_rpcClient = null;
|
||||
await stop();
|
||||
await Future.delayed(const Duration(seconds: 3));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ class CWBitcoin extends Bitcoin {
|
|||
{UnspentCoinType coinTypeToSpendFrom = UnspentCoinType.any}) {
|
||||
final bitcoinWallet = wallet as ElectrumWallet;
|
||||
return bitcoinWallet.unspentCoins.where((element) {
|
||||
switch(coinTypeToSpendFrom) {
|
||||
switch (coinTypeToSpendFrom) {
|
||||
case UnspentCoinType.mweb:
|
||||
return element.bitcoinAddressRecord.type == SegwitAddresType.mweb;
|
||||
case UnspentCoinType.nonMweb:
|
||||
|
@ -216,7 +216,6 @@ class CWBitcoin extends Bitcoin {
|
|||
case UnspentCoinType.any:
|
||||
return true;
|
||||
}
|
||||
|
||||
}).toList();
|
||||
}
|
||||
|
||||
|
@ -399,19 +398,21 @@ class CWBitcoin extends Bitcoin {
|
|||
final history = await electrumClient.getHistory(sh);
|
||||
|
||||
final balance = await electrumClient.getBalance(sh);
|
||||
dInfoCopy.balance = balance.entries.first.value.toString();
|
||||
dInfoCopy.balance = balance.entries.firstOrNull?.value.toString() ?? "0";
|
||||
dInfoCopy.address = address;
|
||||
dInfoCopy.transactionsCount = history.length;
|
||||
|
||||
list.add(dInfoCopy);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
} catch (e, s) {
|
||||
print("derivationInfoError: $e");
|
||||
print("derivationInfoStack: $s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort the list such that derivations with the most transactions are first:
|
||||
list.sort((a, b) => b.transactionsCount.compareTo(a.transactionsCount));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -682,4 +683,15 @@ class CWBitcoin extends Bitcoin {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? getUnusedSegwitAddress(Object wallet) {
|
||||
try {
|
||||
final electrumWallet = wallet as ElectrumWallet;
|
||||
final segwitAddress = electrumWallet.walletAddresses.allAddresses
|
||||
.firstWhere((element) => !element.isUsed && element.type == SegwitAddresType.p2wpkh);
|
||||
return segwitAddress.address;
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -899,7 +899,9 @@ Future<void> changeDefaultBitcoinNode(
|
|||
final newCakeWalletBitcoinNode =
|
||||
Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: false);
|
||||
|
||||
if (!nodeSource.values.any((element) => element.uriRaw == newCakeWalletBitcoinUri)) {
|
||||
await nodeSource.add(newCakeWalletBitcoinNode);
|
||||
}
|
||||
|
||||
if (needToReplaceCurrentBitcoinNode) {
|
||||
await sharedPreferences.setInt(
|
||||
|
@ -931,6 +933,10 @@ Future<void> _addBitcoinNode({
|
|||
bool replaceExisting = false,
|
||||
bool useSSL = false,
|
||||
}) async {
|
||||
bool isNodeExists = nodeSource.values.any((element) => element.uriRaw == nodeUri);
|
||||
if (isNodeExists) {
|
||||
return;
|
||||
}
|
||||
const cakeWalletBitcoinNodeUriPattern = '.cakewallet.com';
|
||||
final currentBitcoinNodeId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);
|
||||
|
|
|
@ -17,7 +17,6 @@ import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
|||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
|
@ -843,7 +842,7 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
|
||||
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
|
||||
child: Stack(
|
||||
children: [
|
||||
if (currency == CryptoCurrency.ltc)
|
||||
|
@ -851,17 +850,15 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 16, top: 16),
|
||||
padding: EdgeInsets.only(right: 16, top: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: ImageIcon(
|
||||
AssetImage('assets/images/mweb_logo.png'),
|
||||
color: Color.fromARGB(255, 11, 70, 129),
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
|
@ -889,7 +886,6 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
Text(
|
||||
'${secondAvailableBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
|
@ -907,9 +903,9 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
AutoSizeText(
|
||||
secondAvailableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontSize: 24,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
|
@ -918,15 +914,15 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
SizedBox(height: 6),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${secondAvailableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.textColor,
|
||||
|
@ -1019,7 +1015,6 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
paymentRequest =
|
||||
PaymentRequest.fromUri(Uri.parse("litecoin:${mwebAddress}"));
|
||||
}
|
||||
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.send,
|
||||
|
@ -1030,11 +1025,10 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor
|
||||
backgroundColor: Colors.grey.shade400
|
||||
.withAlpha(50),
|
||||
side: BorderSide(color: Colors.grey.shade400, width: 0),
|
||||
side: BorderSide(color: Colors.grey.shade400
|
||||
.withAlpha(50), width: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
|
@ -1058,7 +1052,7 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -1074,13 +1068,12 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
final litecoinAddress =
|
||||
bitcoin!.getAddress(dashboardViewModel.wallet);
|
||||
bitcoin!.getUnusedSegwitAddress(dashboardViewModel.wallet);
|
||||
PaymentRequest? paymentRequest = null;
|
||||
if (litecoinAddress.isNotEmpty) {
|
||||
if ((litecoinAddress?.isNotEmpty ?? false)) {
|
||||
paymentRequest = PaymentRequest.fromUri(
|
||||
Uri.parse("litecoin:${litecoinAddress}"));
|
||||
}
|
||||
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.send,
|
||||
|
@ -1091,11 +1084,10 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor
|
||||
backgroundColor: Colors.grey.shade400
|
||||
.withAlpha(50),
|
||||
side: BorderSide(color: Colors.grey.shade400, width: 0),
|
||||
side: BorderSide(color: Colors.grey.shade400
|
||||
.withAlpha(50), width: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
|
@ -1119,7 +1111,7 @@ class BalanceRowWidget extends StatelessWidget {
|
|||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -28,6 +28,7 @@ import 'package:cake_wallet/utils/request_review_handler.dart';
|
|||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
|
||||
|
@ -509,6 +510,10 @@ class SendPage extends BasePage {
|
|||
newContactAddress =
|
||||
newContactAddress ?? sendViewModel.newContactAddress();
|
||||
|
||||
if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) {
|
||||
newContactAddress = null;
|
||||
}
|
||||
|
||||
final successMessage = S.of(_dialogContext).send_success(
|
||||
sendViewModel.selectedCryptoCurrency.toString());
|
||||
|
||||
|
|
|
@ -115,7 +115,9 @@ abstract class WalletCreationVMBase with Store {
|
|||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
_appStore.authenticationStore.allowed();
|
||||
state = ExecutedSuccessfullyState();
|
||||
} catch (e, _) {
|
||||
} catch (e, s) {
|
||||
print("error: $e");
|
||||
print("stack: $s");
|
||||
state = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
@ -198,16 +200,14 @@ abstract class WalletCreationVMBase with Store {
|
|||
switch (walletType) {
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
|
||||
final derivationList = await bitcoin!.getDerivationsFromMnemonic(
|
||||
mnemonic: restoreWallet.mnemonicSeed!,
|
||||
node: node,
|
||||
passphrase: restoreWallet.passphrase,
|
||||
);
|
||||
|
||||
|
||||
if (derivationList.first.transactionsCount == 0 && derivationList.length > 1) return [];
|
||||
|
||||
if (derivationList.firstOrNull?.transactionsCount == 0 && derivationList.length > 1)
|
||||
return [];
|
||||
return derivationList;
|
||||
|
||||
case WalletType.nano:
|
||||
|
|
|
@ -231,6 +231,7 @@ abstract class Bitcoin {
|
|||
Future<void> setMwebEnabled(Object wallet, bool enabled);
|
||||
bool getMwebEnabled(Object wallet);
|
||||
String? getUnusedMwebAddress(Object wallet);
|
||||
String? getUnusedSegwitAddress(Object wallet);
|
||||
}
|
||||
""";
|
||||
|
||||
|
|
Loading…
Reference in a new issue