apply wallet cache mixin to rest of coin wallets and clean up hive code

This commit is contained in:
julian 2023-01-12 15:32:25 -06:00
parent 5c70cf7967
commit 8c67901c28
8 changed files with 1598 additions and 1772 deletions

View file

@ -12,7 +12,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -146,7 +145,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -163,22 +162,14 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite") bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
}
@override @override
Coin get coin => _coin; Coin get coin => _coin;
@ -245,25 +236,18 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: "storedChainHeight", value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -688,10 +672,10 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
await DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -912,11 +896,6 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
unawaited(updateStoredChainHeight(newHeight: currentHeight));
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await _checkChangeAddressForTransactions(); await _checkChangeAddressForTransactions();
@ -1154,7 +1133,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -1168,9 +1147,8 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: walletId), updateCachedId(walletId),
DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
]); ]);
} }
@ -1179,7 +1157,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1242,7 +1220,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1279,6 +1257,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1810,7 +1789,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1818,48 +1797,9 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list)
// /// and checks for the txid associated with the utxo being blocked and marks it accordingly.
// /// Now also checks for output labeling.
// Future<void> _sortOutputs(List<UtxoObject> utxos) async {
// final blockedHashArray =
// DB.instance.get<dynamic>(boxName: walletId, key: 'blocked_tx_hashes')
// as List<dynamic>?;
// final List<String> lst = [];
// if (blockedHashArray != null) {
// for (var hash in blockedHashArray) {
// lst.add(hash as String);
// }
// }
// final labels =
// DB.instance.get<dynamic>(boxName: walletId, key: 'labels') as Map? ??
// {};
//
// outputsList = [];
//
// for (var i = 0; i < utxos.length; i++) {
// if (labels[utxos[i].txid] != null) {
// utxos[i].txName = labels[utxos[i].txid] as String? ?? "";
// } else {
// utxos[i].txName = 'Output #$i';
// }
//
// if (utxos[i].status.confirmed == false) {
// outputsList.add(utxos[i]);
// } else {
// if (lst.contains(utxos[i].txid)) {
// utxos[i].blocked = true;
// outputsList.add(utxos[i]);
// } else if (!lst.contains(utxos[i].txid)) {
// outputsList.add(utxos[i]);
// }
// }
// }
// }
Future<int> getTxCount({required String address}) async { Future<int> getTxCount({required String address}) async {
String? scripthash; String? scripthash;
try { try {
@ -3075,7 +3015,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
// back up data // back up data
await _rescanBackup(); // await _rescanBackup();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
@ -3104,7 +3044,7 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
// restore from backup // restore from backup
await _rescanRestore(); // await _rescanRestore();
longMutex = false; longMutex = false;
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
@ -3113,345 +3053,345 @@ class BitcoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
} }
Future<void> _rescanRestore() async { // Future<void> _rescanRestore() async {
Logging.instance.log("starting rescan restore", level: LogLevel.Info); // Logging.instance.log("starting rescan restore", level: LogLevel.Info);
//
// restore from backup // // restore from backup
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
final tempReceivingIndexP2PKH = DB.instance // final tempReceivingIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
final tempChangeIndexP2PKH = DB.instance // final tempChangeIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH', // key: 'receivingAddressesP2PKH',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH', // key: 'changeAddressesP2PKH',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH', // key: 'receivingIndexP2PKH',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH', // key: 'changeIndexP2PKH',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
//
// p2Sh // // p2Sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP');
final tempChangeAddressesP2SH = DB.instance // final tempChangeAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP');
final tempReceivingIndexP2SH = DB.instance // final tempReceivingIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP');
final tempChangeIndexP2SH = DB.instance // final tempChangeIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH', // key: 'receivingAddressesP2SH',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH', // key: 'changeAddressesP2SH',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH', // key: 'receivingIndexP2SH',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH); // boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2SH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>( // final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>(
boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP'); // boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP');
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP');
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP');
final tempChangeIndexP2WPKH = DB.instance // final tempChangeIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH', // key: 'receivingAddressesP2WPKH',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH', // key: 'changeAddressesP2WPKH',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH', // key: 'receivingIndexP2WPKH',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH', // key: 'changeIndexP2WPKH',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = await _secureStore.read( // final p2pkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
final p2pkhChangeDerivationsString = await _secureStore.read( // final p2pkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH", // key: "${walletId}_receiveDerivationsP2PKH",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH", // key: "${walletId}_changeDerivationsP2PKH",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = await _secureStore.read( // final p2shReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // key: "${walletId}_receiveDerivationsP2SH_BACKUP");
final p2shChangeDerivationsString = await _secureStore.read( // final p2shChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2SH_BACKUP"); // key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH", // key: "${walletId}_receiveDerivationsP2SH",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH", // key: "${walletId}_changeDerivationsP2SH",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = await _secureStore.read( // final p2wpkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
final p2wpkhChangeDerivationsString = await _secureStore.read( // final p2wpkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH", // key: "${walletId}_receiveDerivationsP2WPKH",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH", // key: "${walletId}_changeDerivationsP2WPKH",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
// UTXOs // // UTXOs
final utxoData = DB.instance // final utxoData = DB.instance
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model', value: utxoData); // boxName: walletId, key: 'latest_utxo_model', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
//
Logging.instance.log("rescan restore complete", level: LogLevel.Info); // Logging.instance.log("rescan restore complete", level: LogLevel.Info);
} // }
//
Future<void> _rescanBackup() async { // Future<void> _rescanBackup() async {
Logging.instance.log("starting rescan backup", level: LogLevel.Info); // Logging.instance.log("starting rescan backup", level: LogLevel.Info);
//
// backup current and clear data // // backup current and clear data
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH_BACKUP', // key: 'receivingAddressesP2PKH_BACKUP',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
//
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH_BACKUP', // key: 'changeAddressesP2PKH_BACKUP',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
//
final tempReceivingIndexP2PKH = // final tempReceivingIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH_BACKUP', // key: 'receivingIndexP2PKH_BACKUP',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
//
final tempChangeIndexP2PKH = // final tempChangeIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH_BACKUP', // key: 'changeIndexP2PKH_BACKUP',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
//
// p2sh // // p2sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH_BACKUP', // key: 'receivingAddressesP2SH_BACKUP',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId);
//
final tempChangeAddressesP2SH = // final tempChangeAddressesP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH_BACKUP', // key: 'changeAddressesP2SH_BACKUP',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId);
//
final tempReceivingIndexP2SH = // final tempReceivingIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH_BACKUP', // key: 'receivingIndexP2SH_BACKUP',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId);
//
final tempChangeIndexP2SH = // final tempChangeIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2SH_BACKUP', // key: 'changeIndexP2SH_BACKUP',
value: tempChangeIndexP2SH); // value: tempChangeIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance // final tempReceivingAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH_BACKUP', // key: 'receivingAddressesP2WPKH_BACKUP',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId);
//
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH_BACKUP', // key: 'changeAddressesP2WPKH_BACKUP',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId);
//
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH_BACKUP', // key: 'receivingIndexP2WPKH_BACKUP',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId);
//
final tempChangeIndexP2WPKH = // final tempChangeIndexP2WPKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH_BACKUP', // key: 'changeIndexP2WPKH_BACKUP',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = // final p2pkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
final p2pkhChangeDerivationsString = // final p2pkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP", // key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH_BACKUP", // key: "${walletId}_changeDerivationsP2PKH_BACKUP",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = // final p2shReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH");
final p2shChangeDerivationsString = // final p2shChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2SH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH_BACKUP", // key: "${walletId}_receiveDerivationsP2SH_BACKUP",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH_BACKUP", // key: "${walletId}_changeDerivationsP2SH_BACKUP",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = // final p2wpkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH");
final p2wpkhChangeDerivationsString = // final p2wpkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP", // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP", // key: "${walletId}_changeDerivationsP2WPKH_BACKUP",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH");
//
// UTXOs // // UTXOs
final utxoData = // final utxoData =
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model'); // DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); // boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
//
Logging.instance.log("rescan backup complete", level: LogLevel.Info); // Logging.instance.log("rescan backup complete", level: LogLevel.Info);
} // }
bool isActive = false; bool isActive = false;

View file

@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/address/address.dart'; import 'package:stackwallet/models/isar/models/address/address.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
@ -133,7 +132,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -213,25 +212,18 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: DBKeys.storedChainHeight) as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: DBKeys.storedChainHeight, value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -621,10 +613,10 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: DBKeys.id, value: _walletId); updateCachedId(walletId),
await DB.instance.put<dynamic>( updateCachedIsFavorite(false),
boxName: walletId, key: DBKeys.isFavorite, value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -853,11 +845,6 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
await updateStoredChainHeight(newHeight: currentHeight);
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await _checkChangeAddressForTransactions(); await _checkChangeAddressForTransactions();
@ -1075,7 +1062,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.id)) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -1088,10 +1075,8 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance updateCachedId(walletId),
.put<dynamic>(boxName: walletId, key: DBKeys.id, value: _walletId), updateCachedIsFavorite(false),
DB.instance.put<dynamic>(
boxName: walletId, key: DBKeys.isFavorite, value: false),
]); ]);
} }
@ -1100,7 +1085,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.id)) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1190,7 +1175,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1226,6 +1211,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1675,7 +1661,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1683,7 +1669,7 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
Future<int> getTxCount({required String address}) async { Future<int> getTxCount({required String address}) async {
@ -2825,22 +2811,14 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: DBKeys.isFavorite, value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.isFavorite) bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
}
@override @override
bool get isRefreshing => refreshMutex; bool get isRefreshing => refreshMutex;

View file

@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -131,7 +130,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -212,25 +211,18 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: "storedChainHeight", value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -535,10 +527,10 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
await DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -758,11 +750,6 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
unawaited(updateStoredChainHeight(newHeight: currentHeight));
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await checkChangeAddressForTransactions(); await checkChangeAddressForTransactions();
@ -980,7 +967,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -992,10 +979,10 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
level: LogLevel.Fatal); level: LogLevel.Fatal);
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: _walletId), updateCachedId(walletId),
DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
]); ]);
} }
@ -1004,7 +991,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1067,7 +1054,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1103,6 +1090,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1552,7 +1540,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1560,7 +1548,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) // /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list)
@ -2436,7 +2424,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
// back up data // back up data
await _rescanBackup(); // await _rescanBackup();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
@ -2465,7 +2453,7 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
// restore from backup // restore from backup
await _rescanRestore(); // await _rescanRestore();
longMutex = false; longMutex = false;
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
@ -2474,158 +2462,150 @@ class DogecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
} }
Future<void> _rescanRestore() async { // Future<void> _rescanRestore() async {
Logging.instance.log("starting rescan restore", level: LogLevel.Info); // Logging.instance.log("starting rescan restore", level: LogLevel.Info);
//
// restore from backup // // restore from backup
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
final tempReceivingIndexP2PKH = DB.instance // final tempReceivingIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
final tempChangeIndexP2PKH = DB.instance // final tempChangeIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH', // key: 'receivingAddressesP2PKH',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH', // key: 'changeAddressesP2PKH',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH', // key: 'receivingIndexP2PKH',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH', // key: 'changeIndexP2PKH',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = await _secureStore.read( // final p2pkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
final p2pkhChangeDerivationsString = await _secureStore.read( // final p2pkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH", // key: "${walletId}_receiveDerivationsP2PKH",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH", // key: "${walletId}_changeDerivationsP2PKH",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
// UTXOs // // UTXOs
final utxoData = DB.instance // final utxoData = DB.instance
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model', value: utxoData); // boxName: walletId, key: 'latest_utxo_model', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
//
Logging.instance.log("rescan restore complete", level: LogLevel.Info); // Logging.instance.log("rescan restore complete", level: LogLevel.Info);
} // }
//
Future<void> _rescanBackup() async { // Future<void> _rescanBackup() async {
Logging.instance.log("starting rescan backup", level: LogLevel.Info); // Logging.instance.log("starting rescan backup", level: LogLevel.Info);
//
// backup current and clear data // // backup current and clear data
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH_BACKUP', // key: 'receivingAddressesP2PKH_BACKUP',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
//
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH_BACKUP', // key: 'changeAddressesP2PKH_BACKUP',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
//
final tempReceivingIndexP2PKH = // final tempReceivingIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH_BACKUP', // key: 'receivingIndexP2PKH_BACKUP',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
//
final tempChangeIndexP2PKH = // final tempChangeIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH_BACKUP', // key: 'changeIndexP2PKH_BACKUP',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = // final p2pkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
final p2pkhChangeDerivationsString = // final p2pkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP", // key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH_BACKUP", // key: "${walletId}_changeDerivationsP2PKH_BACKUP",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
//
// UTXOs // // UTXOs
final utxoData = // final utxoData =
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model'); // DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); // boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
//
Logging.instance.log("rescan backup complete", level: LogLevel.Info); // Logging.instance.log("rescan backup complete", level: LogLevel.Info);
} // }
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite") bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
}
@override @override
bool get isRefreshing => refreshMutex; bool get isRefreshing => refreshMutex;

View file

@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -145,7 +144,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -162,22 +161,14 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite") bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
}
@override @override
Coin get coin => _coin; Coin get coin => _coin;
@ -244,25 +235,18 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: "storedChainHeight", value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -705,10 +689,10 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
await DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -929,11 +913,6 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
unawaited(updateStoredChainHeight(newHeight: currentHeight));
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await _checkChangeAddressForTransactions(); await _checkChangeAddressForTransactions();
@ -1171,7 +1150,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -1184,10 +1163,10 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
level: LogLevel.Fatal); level: LogLevel.Fatal);
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: walletId), updateCachedId(walletId),
DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
]); ]);
} }
@ -1196,7 +1175,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1258,7 +1237,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1294,6 +1273,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1796,7 +1776,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1804,7 +1784,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) // /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list)
@ -3127,7 +3107,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
// back up data // back up data
await _rescanBackup(); // await _rescanBackup();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
@ -3156,7 +3136,7 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
// restore from backup // restore from backup
await _rescanRestore(); // await _rescanRestore();
longMutex = false; longMutex = false;
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
@ -3165,345 +3145,345 @@ class LitecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
} }
Future<void> _rescanRestore() async { // Future<void> _rescanRestore() async {
Logging.instance.log("starting rescan restore", level: LogLevel.Info); // Logging.instance.log("starting rescan restore", level: LogLevel.Info);
//
// restore from backup // // restore from backup
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
final tempReceivingIndexP2PKH = DB.instance // final tempReceivingIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
final tempChangeIndexP2PKH = DB.instance // final tempChangeIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH', // key: 'receivingAddressesP2PKH',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH', // key: 'changeAddressesP2PKH',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH', // key: 'receivingIndexP2PKH',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH', // key: 'changeIndexP2PKH',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
//
// p2Sh // // p2Sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP');
final tempChangeAddressesP2SH = DB.instance // final tempChangeAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP');
final tempReceivingIndexP2SH = DB.instance // final tempReceivingIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP');
final tempChangeIndexP2SH = DB.instance // final tempChangeIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH', // key: 'receivingAddressesP2SH',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH', // key: 'changeAddressesP2SH',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH', // key: 'receivingIndexP2SH',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH); // boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2SH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>( // final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>(
boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP'); // boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP');
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP');
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP');
final tempChangeIndexP2WPKH = DB.instance // final tempChangeIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH', // key: 'receivingAddressesP2WPKH',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH', // key: 'changeAddressesP2WPKH',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH', // key: 'receivingIndexP2WPKH',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH', // key: 'changeIndexP2WPKH',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = await _secureStore.read( // final p2pkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
final p2pkhChangeDerivationsString = await _secureStore.read( // final p2pkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH", // key: "${walletId}_receiveDerivationsP2PKH",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH", // key: "${walletId}_changeDerivationsP2PKH",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = await _secureStore.read( // final p2shReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // key: "${walletId}_receiveDerivationsP2SH_BACKUP");
final p2shChangeDerivationsString = await _secureStore.read( // final p2shChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2SH_BACKUP"); // key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH", // key: "${walletId}_receiveDerivationsP2SH",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH", // key: "${walletId}_changeDerivationsP2SH",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = await _secureStore.read( // final p2wpkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
final p2wpkhChangeDerivationsString = await _secureStore.read( // final p2wpkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH", // key: "${walletId}_receiveDerivationsP2WPKH",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH", // key: "${walletId}_changeDerivationsP2WPKH",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
// UTXOs // // UTXOs
final utxoData = DB.instance // final utxoData = DB.instance
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model', value: utxoData); // boxName: walletId, key: 'latest_utxo_model', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
//
Logging.instance.log("rescan restore complete", level: LogLevel.Info); // Logging.instance.log("rescan restore complete", level: LogLevel.Info);
} // }
//
Future<void> _rescanBackup() async { // Future<void> _rescanBackup() async {
Logging.instance.log("starting rescan backup", level: LogLevel.Info); // Logging.instance.log("starting rescan backup", level: LogLevel.Info);
//
// backup current and clear data // // backup current and clear data
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH_BACKUP', // key: 'receivingAddressesP2PKH_BACKUP',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
//
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH_BACKUP', // key: 'changeAddressesP2PKH_BACKUP',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
//
final tempReceivingIndexP2PKH = // final tempReceivingIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH_BACKUP', // key: 'receivingIndexP2PKH_BACKUP',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
//
final tempChangeIndexP2PKH = // final tempChangeIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH_BACKUP', // key: 'changeIndexP2PKH_BACKUP',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
//
// p2sh // // p2sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH_BACKUP', // key: 'receivingAddressesP2SH_BACKUP',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId);
//
final tempChangeAddressesP2SH = // final tempChangeAddressesP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH_BACKUP', // key: 'changeAddressesP2SH_BACKUP',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId);
//
final tempReceivingIndexP2SH = // final tempReceivingIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH_BACKUP', // key: 'receivingIndexP2SH_BACKUP',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId);
//
final tempChangeIndexP2SH = // final tempChangeIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2SH_BACKUP', // key: 'changeIndexP2SH_BACKUP',
value: tempChangeIndexP2SH); // value: tempChangeIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance // final tempReceivingAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH_BACKUP', // key: 'receivingAddressesP2WPKH_BACKUP',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId);
//
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH_BACKUP', // key: 'changeAddressesP2WPKH_BACKUP',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId);
//
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH_BACKUP', // key: 'receivingIndexP2WPKH_BACKUP',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId);
//
final tempChangeIndexP2WPKH = // final tempChangeIndexP2WPKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH_BACKUP', // key: 'changeIndexP2WPKH_BACKUP',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = // final p2pkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
final p2pkhChangeDerivationsString = // final p2pkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP", // key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH_BACKUP", // key: "${walletId}_changeDerivationsP2PKH_BACKUP",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = // final p2shReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH");
final p2shChangeDerivationsString = // final p2shChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2SH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH_BACKUP", // key: "${walletId}_receiveDerivationsP2SH_BACKUP",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH_BACKUP", // key: "${walletId}_changeDerivationsP2SH_BACKUP",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = // final p2wpkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH");
final p2wpkhChangeDerivationsString = // final p2wpkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP", // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP", // key: "${walletId}_changeDerivationsP2WPKH_BACKUP",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH");
//
// UTXOs // // UTXOs
final utxoData = // final utxoData =
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model'); // DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); // boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
//
Logging.instance.log("rescan backup complete", level: LogLevel.Info); // Logging.instance.log("rescan backup complete", level: LogLevel.Info);
} // }
bool isActive = false; bool isActive = false;

View file

@ -50,12 +50,13 @@ import 'package:stackwallet/utilities/stack_file_system.dart';
const int MINIMUM_CONFIRMATIONS = 10; const int MINIMUM_CONFIRMATIONS = 10;
class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB { class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
final String _walletId; late final String _walletId;
final Coin _coin; late final Coin _coin;
final SecureStorageInterface _secureStorage; late final SecureStorageInterface _secureStorage;
final Prefs _prefs; late final Prefs _prefs;
late String _walletName;
String _walletName;
bool _shouldAutoSync = false; bool _shouldAutoSync = false;
bool _isConnected = false; bool _isConnected = false;
bool _hasCalledExit = false; bool _hasCalledExit = false;
@ -81,31 +82,26 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
required Coin coin, required Coin coin,
required SecureStorageInterface secureStorage, required SecureStorageInterface secureStorage,
Prefs? prefs, Prefs? prefs,
}) : _walletId = walletId, }) {
_walletName = walletName, _walletId = walletId;
_coin = coin, _walletName = walletName;
_secureStorage = secureStorage, _coin = coin;
_prefs = prefs ?? Prefs.instance; _secureStorage = secureStorage;
_prefs = prefs ?? Prefs.instance;
@override initCache(walletId, coin);
bool get isFavorite {
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite")
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
} }
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override
bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
bool? _isFavorite;
@override @override
bool get shouldAutoSync => _shouldAutoSync; bool get shouldAutoSync => _shouldAutoSync;
@ -260,7 +256,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
level: LogLevel.Info, level: LogLevel.Info,
); );
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -382,10 +378,10 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
node: Node(uri: "$host:${node.port}", type: WalletType.monero)); node: Node(uri: "$host:${node.port}", type: WalletType.monero));
await walletBase!.startSync(); await walletBase!.startSync();
await DB.instance await DB.instance
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); .put<dynamic>(boxName: walletId, key: DBKeys.id, value: _walletId);
await DB.instance await DB.instance
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); .put<dynamic>(boxName: walletId, key: DBKeys.isFavorite, value: false);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialReceivingAddress = await _generateAddressForChain(0, 0); final initialReceivingAddress = await _generateAddressForChain(0, 0);
@ -593,11 +589,10 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
// walletBase!.onNewTransaction = onNewTransaction; // walletBase!.onNewTransaction = onNewTransaction;
// walletBase!.syncStatusChanged = syncStatusChanged; // walletBase!.syncStatusChanged = syncStatusChanged;
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
updateCachedIsFavorite(false),
await DB.instance ]);
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
} catch (e, s) { } catch (e, s) {
debugPrint(e.toString()); debugPrint(e.toString());
debugPrint(s.toString()); debugPrint(s.toString());
@ -734,7 +729,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: 0, blockedTotal: 0,
pendingSpendable: total - available, pendingSpendable: total - available,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} }
Future<int> get _availableBalance async { Future<int> get _availableBalance async {
@ -1215,7 +1210,7 @@ class MoneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
int get storedChainHeight => throw UnimplementedError(); int get storedChainHeight => throw UnimplementedError();
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
@override @override

View file

@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -142,7 +141,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -157,22 +156,14 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite") bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
}
@override @override
Coin get coin => _coin; Coin get coin => _coin;
@ -239,25 +230,18 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: "storedChainHeight", value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -695,10 +679,10 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
await DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -919,11 +903,6 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
unawaited(updateStoredChainHeight(newHeight: currentHeight));
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await _checkChangeAddressForTransactions(); await _checkChangeAddressForTransactions();
@ -1161,7 +1140,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -1175,9 +1154,8 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: walletId), updateCachedId(walletId),
DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
]); ]);
} }
@ -1186,7 +1164,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1248,7 +1226,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1284,6 +1262,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1776,7 +1755,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1784,7 +1763,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) // /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list)
@ -3118,7 +3097,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
// back up data // back up data
await _rescanBackup(); // await _rescanBackup();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
@ -3147,7 +3126,7 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
// restore from backup // restore from backup
await _rescanRestore(); // await _rescanRestore();
longMutex = false; longMutex = false;
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
@ -3156,345 +3135,345 @@ class NamecoinWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
} }
Future<void> _rescanRestore() async { // Future<void> _rescanRestore() async {
Logging.instance.log("starting rescan restore", level: LogLevel.Info); // Logging.instance.log("starting rescan restore", level: LogLevel.Info);
//
// restore from backup // // restore from backup
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
final tempReceivingIndexP2PKH = DB.instance // final tempReceivingIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
final tempChangeIndexP2PKH = DB.instance // final tempChangeIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH', // key: 'receivingAddressesP2PKH',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH', // key: 'changeAddressesP2PKH',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH', // key: 'receivingIndexP2PKH',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH', // key: 'changeIndexP2PKH',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
//
// p2Sh // // p2Sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP');
final tempChangeAddressesP2SH = DB.instance // final tempChangeAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP');
final tempReceivingIndexP2SH = DB.instance // final tempReceivingIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP');
final tempChangeIndexP2SH = DB.instance // final tempChangeIndexP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH', // key: 'receivingAddressesP2SH',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH', // key: 'changeAddressesP2SH',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH', // key: 'receivingIndexP2SH',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH); // boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2SH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>( // final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>(
boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP'); // boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP');
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP');
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP');
final tempChangeIndexP2WPKH = DB.instance // final tempChangeIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH', // key: 'receivingAddressesP2WPKH',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH', // key: 'changeAddressesP2WPKH',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH', // key: 'receivingIndexP2WPKH',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH', // key: 'changeIndexP2WPKH',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = await _secureStore.read( // final p2pkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
final p2pkhChangeDerivationsString = await _secureStore.read( // final p2pkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH", // key: "${walletId}_receiveDerivationsP2PKH",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH", // key: "${walletId}_changeDerivationsP2PKH",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = await _secureStore.read( // final p2shReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // key: "${walletId}_receiveDerivationsP2SH_BACKUP");
final p2shChangeDerivationsString = await _secureStore.read( // final p2shChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2SH_BACKUP"); // key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH", // key: "${walletId}_receiveDerivationsP2SH",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH", // key: "${walletId}_changeDerivationsP2SH",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = await _secureStore.read( // final p2wpkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
final p2wpkhChangeDerivationsString = await _secureStore.read( // final p2wpkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH", // key: "${walletId}_receiveDerivationsP2WPKH",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH", // key: "${walletId}_changeDerivationsP2WPKH",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
// UTXOs // // UTXOs
final utxoData = DB.instance // final utxoData = DB.instance
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model', value: utxoData); // boxName: walletId, key: 'latest_utxo_model', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
//
Logging.instance.log("rescan restore complete", level: LogLevel.Info); // Logging.instance.log("rescan restore complete", level: LogLevel.Info);
} // }
//
Future<void> _rescanBackup() async { // Future<void> _rescanBackup() async {
Logging.instance.log("starting rescan backup", level: LogLevel.Info); // Logging.instance.log("starting rescan backup", level: LogLevel.Info);
//
// backup current and clear data // // backup current and clear data
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH_BACKUP', // key: 'receivingAddressesP2PKH_BACKUP',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
//
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH_BACKUP', // key: 'changeAddressesP2PKH_BACKUP',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
//
final tempReceivingIndexP2PKH = // final tempReceivingIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH_BACKUP', // key: 'receivingIndexP2PKH_BACKUP',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
//
final tempChangeIndexP2PKH = // final tempChangeIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH_BACKUP', // key: 'changeIndexP2PKH_BACKUP',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
//
// p2sh // // p2sh
final tempReceivingAddressesP2SH = DB.instance // final tempReceivingAddressesP2SH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2SH_BACKUP', // key: 'receivingAddressesP2SH_BACKUP',
value: tempReceivingAddressesP2SH); // value: tempReceivingAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId);
//
final tempChangeAddressesP2SH = // final tempChangeAddressesP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2SH_BACKUP', // key: 'changeAddressesP2SH_BACKUP',
value: tempChangeAddressesP2SH); // value: tempChangeAddressesP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId);
//
final tempReceivingIndexP2SH = // final tempReceivingIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2SH_BACKUP', // key: 'receivingIndexP2SH_BACKUP',
value: tempReceivingIndexP2SH); // value: tempReceivingIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId);
//
final tempChangeIndexP2SH = // final tempChangeIndexP2SH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2SH_BACKUP', // key: 'changeIndexP2SH_BACKUP',
value: tempChangeIndexP2SH); // value: tempChangeIndexP2SH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance // final tempReceivingAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH_BACKUP', // key: 'receivingAddressesP2WPKH_BACKUP',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId);
//
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH_BACKUP', // key: 'changeAddressesP2WPKH_BACKUP',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId);
//
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH_BACKUP', // key: 'receivingIndexP2WPKH_BACKUP',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId);
//
final tempChangeIndexP2WPKH = // final tempChangeIndexP2WPKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH_BACKUP', // key: 'changeIndexP2WPKH_BACKUP',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = // final p2pkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
final p2pkhChangeDerivationsString = // final p2pkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP", // key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH_BACKUP", // key: "${walletId}_changeDerivationsP2PKH_BACKUP",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
//
// P2SH derivations // // P2SH derivations
final p2shReceiveDerivationsString = // final p2shReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH");
final p2shChangeDerivationsString = // final p2shChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2SH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2SH_BACKUP", // key: "${walletId}_receiveDerivationsP2SH_BACKUP",
value: p2shReceiveDerivationsString); // value: p2shReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2SH_BACKUP", // key: "${walletId}_changeDerivationsP2SH_BACKUP",
value: p2shChangeDerivationsString); // value: p2shChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = // final p2wpkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH");
final p2wpkhChangeDerivationsString = // final p2wpkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP", // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP", // key: "${walletId}_changeDerivationsP2WPKH_BACKUP",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH");
//
// UTXOs // // UTXOs
final utxoData = // final utxoData =
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model'); // DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); // boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
//
Logging.instance.log("rescan backup complete", level: LogLevel.Info); // Logging.instance.log("rescan backup complete", level: LogLevel.Info);
} // }
bool isActive = false; bool isActive = false;

View file

@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart'; import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart'; import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/hive/db.dart';
import 'package:stackwallet/models/balance.dart'; import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models; import 'package:stackwallet/models/isar/models/isar_models.dart' as isar_models;
import 'package:stackwallet/models/paymint/fee_object_model.dart'; import 'package:stackwallet/models/paymint/fee_object_model.dart';
@ -138,7 +137,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
final _prefs = Prefs.instance; final _prefs = Prefs.instance;
Timer? timer; Timer? timer;
late Coin _coin; late final Coin _coin;
late final TransactionNotificationTracker txTracker; late final TransactionNotificationTracker txTracker;
@ -153,21 +152,14 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override @override
bool get isFavorite { bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite") bool? _isFavorite;
as bool;
} catch (e, s) {
Logging.instance
.log("isFavorite fetch failed: $e\n$s", level: LogLevel.Error);
rethrow;
}
}
@override @override
Coin get coin => _coin; Coin get coin => _coin;
@ -234,25 +226,18 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<int> get chainHeight async { Future<int> get chainHeight async {
try { try {
final result = await _electrumXClient.getBlockHeadTip(); final result = await _electrumXClient.getBlockHeadTip();
return result["height"] as int; final height = result["height"] as int;
await updateCachedChainHeight(height);
return height;
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Exception caught in chainHeight: $e\n$s", Logging.instance.log("Exception caught in chainHeight: $e\n$s",
level: LogLevel.Error); level: LogLevel.Error);
return -1; return storedChainHeight;
} }
} }
@override @override
int get storedChainHeight { int get storedChainHeight => getCachedChainHeight();
final storedHeight = DB.instance
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
return storedHeight ?? 0;
}
Future<void> updateStoredChainHeight({required int newHeight}) async {
await DB.instance.put<dynamic>(
boxName: walletId, key: "storedChainHeight", value: newHeight);
}
DerivePathType addressType({required String address}) { DerivePathType addressType({required String address}) {
Uint8List? decodeBase58; Uint8List? decodeBase58;
@ -627,10 +612,10 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _updateUTXOs(); await _updateUTXOs();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
await DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false); ]);
longMutex = false; longMutex = false;
} catch (e, s) { } catch (e, s) {
@ -851,11 +836,6 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
.log("cached height: $storedHeight", level: LogLevel.Info); .log("cached height: $storedHeight", level: LogLevel.Info);
if (currentHeight != storedHeight) { if (currentHeight != storedHeight) {
if (currentHeight != -1) {
// -1 failed to fetch current height
unawaited(updateStoredChainHeight(newHeight: currentHeight));
}
GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId)); GlobalEventBus.instance.fire(RefreshPercentChangedEvent(0.2, walletId));
await _checkChangeAddressForTransactions(); await _checkChangeAddressForTransactions();
@ -1090,7 +1070,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance Logging.instance
.log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info); .log("Generating new ${coin.prettyName} wallet.", level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) != null) { if (getCachedId() != null) {
throw Exception( throw Exception(
"Attempted to initialize a new wallet using an existing wallet ID!"); "Attempted to initialize a new wallet using an existing wallet ID!");
} }
@ -1104,9 +1084,8 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
rethrow; rethrow;
} }
await Future.wait([ await Future.wait([
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: walletId), updateCachedId(walletId),
DB.instance updateCachedIsFavorite(false),
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
]); ]);
} }
@ -1115,7 +1094,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
Logging.instance.log("Opening existing ${coin.prettyName} wallet.", Logging.instance.log("Opening existing ${coin.prettyName} wallet.",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
throw Exception( throw Exception(
"Attempted to initialize an existing wallet using an unknown wallet ID!"); "Attempted to initialize an existing wallet using an unknown wallet ID!");
} }
@ -1178,7 +1157,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override @override
String get walletId => _walletId; String get walletId => _walletId;
late String _walletId; late final String _walletId;
@override @override
String get walletName => _walletName; String get walletName => _walletName;
@ -1214,6 +1193,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
_electrumXClient = client; _electrumXClient = client;
_cachedElectrumXClient = cachedClient; _cachedElectrumXClient = cachedClient;
_secureStore = secureStore; _secureStore = secureStore;
initCache(walletId, coin);
} }
@override @override
@ -1665,7 +1645,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: satoshiBalanceBlocked, blockedTotal: satoshiBalanceBlocked,
pendingSpendable: satoshiBalancePending, pendingSpendable: satoshiBalancePending,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} catch (e, s) { } catch (e, s) {
Logging.instance Logging.instance
.log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error); .log("Output fetch unsuccessful: $e\n$s", level: LogLevel.Error);
@ -1673,7 +1653,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
// /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list) // /// Takes in a list of UtxoObjects and adds a name (dependent on object index within list)
@ -2989,7 +2969,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin); await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
// back up data // back up data
await _rescanBackup(); // await _rescanBackup();
try { try {
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic'); final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
@ -3018,7 +2998,7 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
); );
// restore from backup // restore from backup
await _rescanRestore(); // await _rescanRestore();
longMutex = false; longMutex = false;
Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s", Logging.instance.log("Exception rethrown from fullRescan(): $e\n$s",
@ -3027,244 +3007,244 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
} }
} }
Future<void> _rescanRestore() async { // Future<void> _rescanRestore() async {
Logging.instance.log("starting rescan restore", level: LogLevel.Info); // Logging.instance.log("starting rescan restore", level: LogLevel.Info);
//
// restore from backup // // restore from backup
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
final tempReceivingIndexP2PKH = DB.instance // final tempReceivingIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
final tempChangeIndexP2PKH = DB.instance // final tempChangeIndexP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH', // key: 'receivingAddressesP2PKH',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH', // key: 'changeAddressesP2PKH',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH', // key: 'receivingIndexP2PKH',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH', // key: 'changeIndexP2PKH',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>( // final tempReceivingAddressesP2WPKH = DB.instance.get<dynamic>(
boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP'); // boxName: walletId, key: 'receivingAddressesP2WPKH_BACKUP');
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH_BACKUP');
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH_BACKUP');
final tempChangeIndexP2WPKH = DB.instance // final tempChangeIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH', // key: 'receivingAddressesP2WPKH',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH', // key: 'changeAddressesP2WPKH',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH', // key: 'receivingIndexP2WPKH',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH', // key: 'changeIndexP2WPKH',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'receivingAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance.delete<dynamic>( // await DB.instance.delete<dynamic>(
key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId); // key: 'changeAddressesP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH_BACKUP', boxName: walletId);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH_BACKUP', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = await _secureStore.read( // final p2pkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
final p2pkhChangeDerivationsString = await _secureStore.read( // final p2pkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH", // key: "${walletId}_receiveDerivationsP2PKH",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH", // key: "${walletId}_changeDerivationsP2PKH",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = await _secureStore.read( // final p2wpkhReceiveDerivationsString = await _secureStore.read(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
final p2wpkhChangeDerivationsString = await _secureStore.read( // final p2wpkhChangeDerivationsString = await _secureStore.read(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH", // key: "${walletId}_receiveDerivationsP2WPKH",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH", // key: "${walletId}_changeDerivationsP2WPKH",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP"); // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP");
await _secureStore.delete( // await _secureStore.delete(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP"); // key: "${walletId}_changeDerivationsP2WPKH_BACKUP");
//
// UTXOs // // UTXOs
final utxoData = DB.instance // final utxoData = DB.instance
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP'); // .get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model', value: utxoData); // boxName: walletId, key: 'latest_utxo_model', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
//
Logging.instance.log("rescan restore complete", level: LogLevel.Info); // Logging.instance.log("rescan restore complete", level: LogLevel.Info);
} // }
//
Future<void> _rescanBackup() async { // Future<void> _rescanBackup() async {
Logging.instance.log("starting rescan backup", level: LogLevel.Info); // Logging.instance.log("starting rescan backup", level: LogLevel.Info);
//
// backup current and clear data // // backup current and clear data
// p2pkh // // p2pkh
final tempReceivingAddressesP2PKH = DB.instance // final tempReceivingAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2PKH_BACKUP', // key: 'receivingAddressesP2PKH_BACKUP',
value: tempReceivingAddressesP2PKH); // value: tempReceivingAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
//
final tempChangeAddressesP2PKH = DB.instance // final tempChangeAddressesP2PKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2PKH_BACKUP', // key: 'changeAddressesP2PKH_BACKUP',
value: tempChangeAddressesP2PKH); // value: tempChangeAddressesP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
//
final tempReceivingIndexP2PKH = // final tempReceivingIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2PKH_BACKUP', // key: 'receivingIndexP2PKH_BACKUP',
value: tempReceivingIndexP2PKH); // value: tempReceivingIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
//
final tempChangeIndexP2PKH = // final tempChangeIndexP2PKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2PKH_BACKUP', // key: 'changeIndexP2PKH_BACKUP',
value: tempChangeIndexP2PKH); // value: tempChangeIndexP2PKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
//
// p2wpkh // // p2wpkh
final tempReceivingAddressesP2WPKH = DB.instance // final tempReceivingAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingAddressesP2WPKH_BACKUP', // key: 'receivingAddressesP2WPKH_BACKUP',
value: tempReceivingAddressesP2WPKH); // value: tempReceivingAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingAddressesP2WPKH', boxName: walletId);
//
final tempChangeAddressesP2WPKH = DB.instance // final tempChangeAddressesP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'changeAddressesP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeAddressesP2WPKH_BACKUP', // key: 'changeAddressesP2WPKH_BACKUP',
value: tempChangeAddressesP2WPKH); // value: tempChangeAddressesP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeAddressesP2WPKH', boxName: walletId);
//
final tempReceivingIndexP2WPKH = DB.instance // final tempReceivingIndexP2WPKH = DB.instance
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH'); // .get<dynamic>(boxName: walletId, key: 'receivingIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'receivingIndexP2WPKH_BACKUP', // key: 'receivingIndexP2WPKH_BACKUP',
value: tempReceivingIndexP2WPKH); // value: tempReceivingIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'receivingIndexP2WPKH', boxName: walletId);
//
final tempChangeIndexP2WPKH = // final tempChangeIndexP2WPKH =
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH'); // DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2WPKH');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, // boxName: walletId,
key: 'changeIndexP2WPKH_BACKUP', // key: 'changeIndexP2WPKH_BACKUP',
value: tempChangeIndexP2WPKH); // value: tempChangeIndexP2WPKH);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId); // .delete<dynamic>(key: 'changeIndexP2WPKH', boxName: walletId);
//
// P2PKH derivations // // P2PKH derivations
final p2pkhReceiveDerivationsString = // final p2pkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
final p2pkhChangeDerivationsString = // final p2pkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2PKH_BACKUP", // key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
value: p2pkhReceiveDerivationsString); // value: p2pkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2PKH_BACKUP", // key: "${walletId}_changeDerivationsP2PKH_BACKUP",
value: p2pkhChangeDerivationsString); // value: p2pkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
//
// P2WPKH derivations // // P2WPKH derivations
final p2wpkhReceiveDerivationsString = // final p2wpkhReceiveDerivationsString =
await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_receiveDerivationsP2WPKH");
final p2wpkhChangeDerivationsString = // final p2wpkhChangeDerivationsString =
await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.read(key: "${walletId}_changeDerivationsP2WPKH");
//
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_receiveDerivationsP2WPKH_BACKUP", // key: "${walletId}_receiveDerivationsP2WPKH_BACKUP",
value: p2wpkhReceiveDerivationsString); // value: p2wpkhReceiveDerivationsString);
await _secureStore.write( // await _secureStore.write(
key: "${walletId}_changeDerivationsP2WPKH_BACKUP", // key: "${walletId}_changeDerivationsP2WPKH_BACKUP",
value: p2wpkhChangeDerivationsString); // value: p2wpkhChangeDerivationsString);
//
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_receiveDerivationsP2WPKH");
await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH"); // await _secureStore.delete(key: "${walletId}_changeDerivationsP2WPKH");
//
// UTXOs // // UTXOs
final utxoData = // final utxoData =
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model'); // DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
await DB.instance.put<dynamic>( // await DB.instance.put<dynamic>(
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData); // boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
await DB.instance // await DB.instance
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId); // .delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
//
Logging.instance.log("rescan backup complete", level: LogLevel.Info); // Logging.instance.log("rescan backup complete", level: LogLevel.Info);
} // }
bool isActive = false; bool isActive = false;

View file

@ -52,12 +52,13 @@ import 'package:stackwallet/utilities/stack_file_system.dart';
const int MINIMUM_CONFIRMATIONS = 10; const int MINIMUM_CONFIRMATIONS = 10;
class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB { class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
final String _walletId; late final String _walletId;
final Coin _coin; late final Coin _coin;
final SecureStorageInterface _secureStorage; late final SecureStorageInterface _secureStorage;
final Prefs _prefs; late final Prefs _prefs;
late String _walletName;
String _walletName;
bool _shouldAutoSync = false; bool _shouldAutoSync = false;
bool _isConnected = false; bool _isConnected = false;
bool _hasCalledExit = false; bool _hasCalledExit = false;
@ -83,31 +84,26 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
required Coin coin, required Coin coin,
required SecureStorageInterface secureStorage, required SecureStorageInterface secureStorage,
Prefs? prefs, Prefs? prefs,
}) : _walletId = walletId, }) {
_walletName = walletName, _walletId = walletId;
_coin = coin, _walletName = walletName;
_secureStorage = secureStorage, _coin = coin;
_prefs = prefs ?? Prefs.instance; _secureStorage = secureStorage;
_prefs = prefs ?? Prefs.instance;
@override initCache(walletId, coin);
bool get isFavorite {
try {
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite")
as bool;
} catch (e, s) {
Logging.instance.log(
"isFavorite fetch failed (returning false by default): $e\n$s",
level: LogLevel.Error);
return false;
}
} }
@override @override
set isFavorite(bool markFavorite) { set isFavorite(bool markFavorite) {
DB.instance.put<dynamic>( _isFavorite = markFavorite;
boxName: walletId, key: "isFavorite", value: markFavorite); updateCachedIsFavorite(markFavorite);
} }
@override
bool get isFavorite => _isFavorite ??= getCachedIsFavorite();
bool? _isFavorite;
@override @override
bool get shouldAutoSync => _shouldAutoSync; bool get shouldAutoSync => _shouldAutoSync;
@ -282,7 +278,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
"Opening existing ${coin.prettyName} wallet $walletName...", "Opening existing ${coin.prettyName} wallet $walletName...",
level: LogLevel.Info); level: LogLevel.Info);
if ((DB.instance.get<dynamic>(boxName: walletId, key: "id")) == null) { if (getCachedId() == null) {
//todo: check if print needed //todo: check if print needed
// debugPrint("Exception was thrown"); // debugPrint("Exception was thrown");
throw Exception( throw Exception(
@ -390,11 +386,10 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
await walletBase?.connectToNode( await walletBase?.connectToNode(
node: Node(uri: "$host:${node.port}", type: WalletType.wownero)); node: Node(uri: "$host:${node.port}", type: WalletType.wownero));
await walletBase?.startSync(); await walletBase?.startSync();
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
updateCachedIsFavorite(false),
await DB.instance ]);
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
// Generate and add addresses to relevant arrays // Generate and add addresses to relevant arrays
final initialReceivingAddress = await _generateAddressForChain(0, 0); final initialReceivingAddress = await _generateAddressForChain(0, 0);
@ -605,11 +600,10 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
walletBase?.close(); walletBase?.close();
walletBase = wallet as WowneroWalletBase; walletBase = wallet as WowneroWalletBase;
await DB.instance await Future.wait([
.put<dynamic>(boxName: walletId, key: "id", value: _walletId); updateCachedId(walletId),
updateCachedIsFavorite(false),
await DB.instance ]);
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
} catch (e, s) { } catch (e, s) {
//todo: come back to this //todo: come back to this
debugPrint(e.toString()); debugPrint(e.toString());
@ -744,7 +738,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
blockedTotal: 0, blockedTotal: 0,
pendingSpendable: total - available, pendingSpendable: total - available,
); );
await updateCachedBalance(walletId, _balance!); await updateCachedBalance(_balance!);
} }
Future<int> get _availableBalance async { Future<int> get _availableBalance async {
@ -1285,7 +1279,7 @@ class WowneroWallet extends CoinServiceAPI with WalletCache, WalletDB {
int get storedChainHeight => throw UnimplementedError(); int get storedChainHeight => throw UnimplementedError();
@override @override
Balance get balance => _balance ??= getCachedBalance(walletId, coin); Balance get balance => _balance ??= getCachedBalance();
Balance? _balance; Balance? _balance;
@override @override