mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-30 22:25:54 +00:00
small bug fixes and added WalletCache mixin to handle balance cache etc
This commit is contained in:
parent
e115ff1b41
commit
ccb9f254bd
5 changed files with 88 additions and 348 deletions
|
@ -245,3 +245,10 @@ class DB {
|
||||||
Future<void> deleteBoxFromDisk({required String boxName}) async =>
|
Future<void> deleteBoxFromDisk({required String boxName}) async =>
|
||||||
await mutex.protect(() async => await Hive.deleteBoxFromDisk(boxName));
|
await mutex.protect(() async => await Hive.deleteBoxFromDisk(boxName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class DBKeys {
|
||||||
|
static const String cachedBalance = "cachedBalance";
|
||||||
|
static const String isFavorite = "isFavorite";
|
||||||
|
static const String id = "id";
|
||||||
|
static const String storedChainHeight = "storedChainHeight";
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
|
@ -36,4 +38,22 @@ class Balance {
|
||||||
blockedTotal,
|
blockedTotal,
|
||||||
coin: coin,
|
coin: coin,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
String toJsonIgnoreCoin() => jsonEncode({
|
||||||
|
"total": total,
|
||||||
|
"spendable": spendable,
|
||||||
|
"blockedTotal": blockedTotal,
|
||||||
|
"pendingSpendable": pendingSpendable,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Balance.fromJson(String json, Coin coin) {
|
||||||
|
final decoded = jsonDecode(json);
|
||||||
|
return Balance(
|
||||||
|
coin: coin,
|
||||||
|
total: decoded["total"] as int,
|
||||||
|
spendable: decoded["spendable"] as int,
|
||||||
|
blockedTotal: decoded["blockedTotal"] as int,
|
||||||
|
pendingSpendable: decoded["pendingSpendable"] as int,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import 'package:stackwallet/services/event_bus/events/global/refresh_percent_cha
|
||||||
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
|
||||||
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||||
|
import 'package:stackwallet/services/mixins/wallet_cache.dart';
|
||||||
import 'package:stackwallet/services/node_service.dart';
|
import 'package:stackwallet/services/node_service.dart';
|
||||||
import 'package:stackwallet/services/notifications_api.dart';
|
import 'package:stackwallet/services/notifications_api.dart';
|
||||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||||
|
@ -37,11 +38,10 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/prefs.dart';
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import '../../../utilities/stack_file_system.dart';
|
|
||||||
|
|
||||||
const int MINIMUM_CONFIRMATIONS = 1;
|
const int MINIMUM_CONFIRMATIONS = 1;
|
||||||
const int DUST_LIMIT = 546;
|
const int DUST_LIMIT = 546;
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ bip32.BIP32 getBip32RootWrapper(Tuple2<String, NetworkType> args) {
|
||||||
return getBip32Root(args.item1, args.item2);
|
return getBip32Root(args.item1, args.item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BitcoinCashWallet extends CoinServiceAPI {
|
class BitcoinCashWallet extends CoinServiceAPI with WalletCache {
|
||||||
static const integrationTestFlag =
|
static const integrationTestFlag =
|
||||||
bool.fromEnvironment("IS_INTEGRATION_TEST");
|
bool.fromEnvironment("IS_INTEGRATION_TEST");
|
||||||
final _prefs = Prefs.instance;
|
final _prefs = Prefs.instance;
|
||||||
|
@ -224,13 +224,13 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
@override
|
@override
|
||||||
int get storedChainHeight {
|
int get storedChainHeight {
|
||||||
final storedHeight = DB.instance
|
final storedHeight = DB.instance
|
||||||
.get<dynamic>(boxName: walletId, key: "storedChainHeight") as int?;
|
.get<dynamic>(boxName: walletId, key: DBKeys.storedChainHeight) as int?;
|
||||||
return storedHeight ?? 0;
|
return storedHeight ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> updateStoredChainHeight({required int newHeight}) async {
|
Future<void> updateStoredChainHeight({required int newHeight}) async {
|
||||||
await DB.instance.put<dynamic>(
|
await DB.instance.put<dynamic>(
|
||||||
boxName: walletId, key: "storedChainHeight", value: newHeight);
|
boxName: walletId, key: DBKeys.storedChainHeight, value: newHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
DerivePathType addressType({required String address}) {
|
DerivePathType addressType({required String address}) {
|
||||||
|
@ -622,9 +622,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
await _updateUTXOs();
|
await _updateUTXOs();
|
||||||
|
|
||||||
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>(
|
||||||
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
|
boxName: walletId, key: DBKeys.isFavorite, value: false);
|
||||||
|
|
||||||
longMutex = false;
|
longMutex = false;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -1075,7 +1075,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
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 ((DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.id)) != 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,9 +1088,10 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
DB.instance.put<dynamic>(boxName: walletId, key: "id", value: _walletId),
|
|
||||||
DB.instance
|
DB.instance
|
||||||
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false),
|
.put<dynamic>(boxName: walletId, key: DBKeys.id, value: _walletId),
|
||||||
|
DB.instance.put<dynamic>(
|
||||||
|
boxName: walletId, key: DBKeys.isFavorite, value: false),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1115,7 +1116,13 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
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) {
|
print("=============================================================");
|
||||||
|
for (final k in DB.instance.keys<dynamic>(boxName: walletId)) {
|
||||||
|
print("$k");
|
||||||
|
}
|
||||||
|
print("=============================================================");
|
||||||
|
|
||||||
|
if ((DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.id)) == 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!");
|
||||||
}
|
}
|
||||||
|
@ -1698,6 +1705,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
blockedTotal: satoshiBalanceBlocked,
|
blockedTotal: satoshiBalanceBlocked,
|
||||||
pendingSpendable: satoshiBalancePending,
|
pendingSpendable: satoshiBalancePending,
|
||||||
);
|
);
|
||||||
|
await updateCachedBalance(walletId, _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);
|
||||||
|
@ -1705,48 +1713,9 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Balance get balance => _balance!;
|
Balance get balance => _balance ??= getCachedBalance(walletId, coin);
|
||||||
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 {
|
||||||
|
@ -2013,47 +1982,6 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
final List<Map<String, dynamic>> allTxHashes =
|
final List<Map<String, dynamic>> allTxHashes =
|
||||||
await _fetchHistory([...receivingAddresses, ...changeAddresses]);
|
await _fetchHistory([...receivingAddresses, ...changeAddresses]);
|
||||||
|
|
||||||
// final cachedTransactions =
|
|
||||||
// DB.instance.get<dynamic>(boxName: walletId, key: 'latest_tx_model')
|
|
||||||
// as TransactionData?;
|
|
||||||
// int latestTxnBlockHeight =
|
|
||||||
// DB.instance.get<dynamic>(boxName: walletId, key: "storedTxnDataHeight")
|
|
||||||
// as int? ??
|
|
||||||
// 0;
|
|
||||||
|
|
||||||
// final unconfirmedCachedTransactions =
|
|
||||||
// cachedTransactions?.getAllTransactions() ?? {};
|
|
||||||
// unconfirmedCachedTransactions
|
|
||||||
// .removeWhere((key, value) => value.confirmedStatus);
|
|
||||||
|
|
||||||
// if (kDebugMode) {
|
|
||||||
// print("CACHED_TRANSACTIONS_IS $cachedTransactions");
|
|
||||||
// }
|
|
||||||
// if (cachedTransactions != null) {
|
|
||||||
// for (final tx in allTxHashes.toList(growable: false)) {
|
|
||||||
// final txHeight = tx["height"] as int;
|
|
||||||
// if (txHeight > 0 &&
|
|
||||||
// txHeight < latestTxnBlockHeight - MINIMUM_CONFIRMATIONS) {
|
|
||||||
// if (unconfirmedCachedTransactions[tx["tx_hash"] as String] == null) {
|
|
||||||
// if (kDebugMode) {
|
|
||||||
// print(
|
|
||||||
// cachedTransactions.findTransaction(tx["tx_hash"] as String));
|
|
||||||
// print(unconfirmedCachedTransactions[tx["tx_hash"] as String]);
|
|
||||||
// }
|
|
||||||
// final cachedTx =
|
|
||||||
// cachedTransactions.findTransaction(tx["tx_hash"] as String);
|
|
||||||
// if (!(cachedTx != null &&
|
|
||||||
// addressType(address: cachedTx.address) ==
|
|
||||||
// DerivePathType.bip44 &&
|
|
||||||
// bitbox.Address.detectFormat(cachedTx.address) ==
|
|
||||||
// bitbox.Address.formatLegacy)) {
|
|
||||||
// allTxHashes.remove(tx);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> allTransactions = [];
|
List<Map<String, dynamic>> allTransactions = [];
|
||||||
|
|
||||||
for (final txHash in allTxHashes) {
|
for (final txHash in allTxHashes) {
|
||||||
|
@ -2885,8 +2813,12 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
// clear cache
|
// clear cache
|
||||||
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
|
await _cachedElectrumXClient.clearSharedTransactionCache(coin: coin);
|
||||||
|
|
||||||
// back up data
|
// clear blockchain info
|
||||||
await _rescanBackup();
|
await isar.writeTxn(() async {
|
||||||
|
await isar.addresses.clear();
|
||||||
|
await isar.transactions.clear();
|
||||||
|
await isar.utxos.clear();
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
|
final mnemonic = await _secureStore.read(key: '${_walletId}_mnemonic');
|
||||||
|
@ -2914,9 +2846,6 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// restore from backup
|
|
||||||
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",
|
||||||
level: LogLevel.Error);
|
level: LogLevel.Error);
|
||||||
|
@ -2924,251 +2853,16 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _rescanRestore() async {
|
|
||||||
Logging.instance.log("starting rescan restore", level: LogLevel.Info);
|
|
||||||
|
|
||||||
// restore from backup
|
|
||||||
// p2pkh
|
|
||||||
final tempReceivingAddressesP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH_BACKUP');
|
|
||||||
final tempChangeAddressesP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH_BACKUP');
|
|
||||||
final tempReceivingIndexP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH_BACKUP');
|
|
||||||
final tempChangeIndexP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH_BACKUP');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingAddressesP2PKH',
|
|
||||||
value: tempReceivingAddressesP2PKH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeAddressesP2PKH',
|
|
||||||
value: tempChangeAddressesP2PKH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingIndexP2PKH',
|
|
||||||
value: tempReceivingIndexP2PKH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeIndexP2PKH',
|
|
||||||
value: tempChangeIndexP2PKH);
|
|
||||||
await DB.instance.delete<dynamic>(
|
|
||||||
key: 'receivingAddressesP2PKH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeAddressesP2PKH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingIndexP2PKH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeIndexP2PKH_BACKUP', boxName: walletId);
|
|
||||||
|
|
||||||
// p2Sh
|
|
||||||
final tempReceivingAddressesP2SH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH_BACKUP');
|
|
||||||
final tempChangeAddressesP2SH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH_BACKUP');
|
|
||||||
final tempReceivingIndexP2SH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH_BACKUP');
|
|
||||||
final tempChangeIndexP2SH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH_BACKUP');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingAddressesP2SH',
|
|
||||||
value: tempReceivingAddressesP2SH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeAddressesP2SH',
|
|
||||||
value: tempChangeAddressesP2SH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingIndexP2SH',
|
|
||||||
value: tempReceivingIndexP2SH);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId, key: 'changeIndexP2SH', value: tempChangeIndexP2SH);
|
|
||||||
await DB.instance.delete<dynamic>(
|
|
||||||
key: 'receivingAddressesP2SH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeAddressesP2SH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingIndexP2SH_BACKUP', boxName: walletId);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeIndexP2SH_BACKUP', boxName: walletId);
|
|
||||||
|
|
||||||
// P2PKH derivations
|
|
||||||
final p2pkhReceiveDerivationsString = await _secureStore.read(
|
|
||||||
key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
|
|
||||||
final p2pkhChangeDerivationsString = await _secureStore.read(
|
|
||||||
key: "${walletId}_changeDerivationsP2PKH_BACKUP");
|
|
||||||
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_receiveDerivationsP2PKH",
|
|
||||||
value: p2pkhReceiveDerivationsString);
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_changeDerivationsP2PKH",
|
|
||||||
value: p2pkhChangeDerivationsString);
|
|
||||||
|
|
||||||
await _secureStore.delete(
|
|
||||||
key: "${walletId}_receiveDerivationsP2PKH_BACKUP");
|
|
||||||
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH_BACKUP");
|
|
||||||
|
|
||||||
// P2SH derivations
|
|
||||||
final p2shReceiveDerivationsString = await _secureStore.read(
|
|
||||||
key: "${walletId}_receiveDerivationsP2SH_BACKUP");
|
|
||||||
final p2shChangeDerivationsString = await _secureStore.read(
|
|
||||||
key: "${walletId}_changeDerivationsP2SH_BACKUP");
|
|
||||||
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_receiveDerivationsP2SH",
|
|
||||||
value: p2shReceiveDerivationsString);
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_changeDerivationsP2SH",
|
|
||||||
value: p2shChangeDerivationsString);
|
|
||||||
|
|
||||||
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH_BACKUP");
|
|
||||||
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH_BACKUP");
|
|
||||||
|
|
||||||
// UTXOs
|
|
||||||
final utxoData = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'latest_utxo_model_BACKUP');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId, key: 'latest_utxo_model', value: utxoData);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'latest_utxo_model_BACKUP', boxName: walletId);
|
|
||||||
|
|
||||||
Logging.instance.log("rescan restore complete", level: LogLevel.Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _rescanBackup() async {
|
|
||||||
Logging.instance.log("starting rescan backup", level: LogLevel.Info);
|
|
||||||
|
|
||||||
// backup current and clear data
|
|
||||||
// p2pkh
|
|
||||||
final tempReceivingAddressesP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2PKH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingAddressesP2PKH_BACKUP',
|
|
||||||
value: tempReceivingAddressesP2PKH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingAddressesP2PKH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempChangeAddressesP2PKH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'changeAddressesP2PKH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeAddressesP2PKH_BACKUP',
|
|
||||||
value: tempChangeAddressesP2PKH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeAddressesP2PKH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempReceivingIndexP2PKH =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2PKH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingIndexP2PKH_BACKUP',
|
|
||||||
value: tempReceivingIndexP2PKH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingIndexP2PKH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempChangeIndexP2PKH =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2PKH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeIndexP2PKH_BACKUP',
|
|
||||||
value: tempChangeIndexP2PKH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeIndexP2PKH', boxName: walletId);
|
|
||||||
|
|
||||||
// p2sh
|
|
||||||
final tempReceivingAddressesP2SH = DB.instance
|
|
||||||
.get<dynamic>(boxName: walletId, key: 'receivingAddressesP2SH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingAddressesP2SH_BACKUP',
|
|
||||||
value: tempReceivingAddressesP2SH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingAddressesP2SH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempChangeAddressesP2SH =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'changeAddressesP2SH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeAddressesP2SH_BACKUP',
|
|
||||||
value: tempChangeAddressesP2SH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeAddressesP2SH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempReceivingIndexP2SH =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'receivingIndexP2SH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'receivingIndexP2SH_BACKUP',
|
|
||||||
value: tempReceivingIndexP2SH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'receivingIndexP2SH', boxName: walletId);
|
|
||||||
|
|
||||||
final tempChangeIndexP2SH =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'changeIndexP2SH');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'changeIndexP2SH_BACKUP',
|
|
||||||
value: tempChangeIndexP2SH);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'changeIndexP2SH', boxName: walletId);
|
|
||||||
|
|
||||||
// P2PKH derivations
|
|
||||||
final p2pkhReceiveDerivationsString =
|
|
||||||
await _secureStore.read(key: "${walletId}_receiveDerivationsP2PKH");
|
|
||||||
final p2pkhChangeDerivationsString =
|
|
||||||
await _secureStore.read(key: "${walletId}_changeDerivationsP2PKH");
|
|
||||||
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_receiveDerivationsP2PKH_BACKUP",
|
|
||||||
value: p2pkhReceiveDerivationsString);
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_changeDerivationsP2PKH_BACKUP",
|
|
||||||
value: p2pkhChangeDerivationsString);
|
|
||||||
|
|
||||||
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2PKH");
|
|
||||||
await _secureStore.delete(key: "${walletId}_changeDerivationsP2PKH");
|
|
||||||
|
|
||||||
// P2SH derivations
|
|
||||||
final p2shReceiveDerivationsString =
|
|
||||||
await _secureStore.read(key: "${walletId}_receiveDerivationsP2SH");
|
|
||||||
final p2shChangeDerivationsString =
|
|
||||||
await _secureStore.read(key: "${walletId}_changeDerivationsP2SH");
|
|
||||||
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_receiveDerivationsP2SH_BACKUP",
|
|
||||||
value: p2shReceiveDerivationsString);
|
|
||||||
await _secureStore.write(
|
|
||||||
key: "${walletId}_changeDerivationsP2SH_BACKUP",
|
|
||||||
value: p2shChangeDerivationsString);
|
|
||||||
|
|
||||||
await _secureStore.delete(key: "${walletId}_receiveDerivationsP2SH");
|
|
||||||
await _secureStore.delete(key: "${walletId}_changeDerivationsP2SH");
|
|
||||||
|
|
||||||
// UTXOs
|
|
||||||
final utxoData =
|
|
||||||
DB.instance.get<dynamic>(boxName: walletId, key: 'latest_utxo_model');
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId, key: 'latest_utxo_model_BACKUP', value: utxoData);
|
|
||||||
await DB.instance
|
|
||||||
.delete<dynamic>(key: 'latest_utxo_model', boxName: walletId);
|
|
||||||
|
|
||||||
Logging.instance.log("rescan backup complete", level: LogLevel.Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
set isFavorite(bool markFavorite) {
|
set isFavorite(bool markFavorite) {
|
||||||
DB.instance.put<dynamic>(
|
DB.instance.put<dynamic>(
|
||||||
boxName: walletId, key: "isFavorite", value: markFavorite);
|
boxName: walletId, key: DBKeys.isFavorite, value: markFavorite);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isFavorite {
|
bool get isFavorite {
|
||||||
try {
|
try {
|
||||||
return DB.instance.get<dynamic>(boxName: walletId, key: "isFavorite")
|
return DB.instance.get<dynamic>(boxName: walletId, key: DBKeys.isFavorite)
|
||||||
as bool;
|
as bool;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
|
|
|
@ -1082,19 +1082,6 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
await DB.instance.put<dynamic>(
|
await DB.instance.put<dynamic>(
|
||||||
boxName: walletId, key: "restoreHeight", value: bufferedCreateHeight);
|
boxName: walletId, key: "restoreHeight", value: bufferedCreateHeight);
|
||||||
|
|
||||||
await DB.instance
|
|
||||||
.put<dynamic>(boxName: walletId, key: "id", value: _walletId);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId, key: 'receivingAddresses', value: ["0"]);
|
|
||||||
await DB.instance
|
|
||||||
.put<dynamic>(boxName: walletId, key: "receivingIndex", value: 0);
|
|
||||||
await DB.instance
|
|
||||||
.put<dynamic>(boxName: walletId, key: "changeIndex", value: 0);
|
|
||||||
await DB.instance.put<dynamic>(
|
|
||||||
boxName: walletId,
|
|
||||||
key: 'blocked_tx_hashes',
|
|
||||||
value: ["0xdefault"],
|
|
||||||
); // A list of transaction hashes to represent frozen utxos in wallet
|
|
||||||
// initialize address book entries
|
// initialize address book entries
|
||||||
await DB.instance.put<dynamic>(
|
await DB.instance.put<dynamic>(
|
||||||
boxName: walletId,
|
boxName: walletId,
|
||||||
|
@ -1102,6 +1089,8 @@ class EpicCashWallet extends CoinServiceAPI {
|
||||||
value: <String, String>{});
|
value: <String, String>{});
|
||||||
await DB.instance
|
await DB.instance
|
||||||
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
|
.put<dynamic>(boxName: walletId, key: "isFavorite", value: false);
|
||||||
|
|
||||||
|
await _isarInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool refreshMutex = false;
|
bool refreshMutex = false;
|
||||||
|
|
30
lib/services/mixins/wallet_cache.dart
Normal file
30
lib/services/mixins/wallet_cache.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:stackwallet/hive/db.dart';
|
||||||
|
import 'package:stackwallet/models/balance.dart';
|
||||||
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
|
||||||
|
mixin WalletCache {
|
||||||
|
Balance getCachedBalance(String walletId, Coin coin) {
|
||||||
|
final jsonString = DB.instance.get<dynamic>(
|
||||||
|
boxName: walletId,
|
||||||
|
key: DBKeys.cachedBalance,
|
||||||
|
) as String?;
|
||||||
|
if (jsonString == null) {
|
||||||
|
return Balance(
|
||||||
|
coin: coin,
|
||||||
|
total: 0,
|
||||||
|
spendable: 0,
|
||||||
|
blockedTotal: 0,
|
||||||
|
pendingSpendable: 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Balance.fromJson(jsonString, coin);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateCachedBalance(String walletId, Balance balance) async {
|
||||||
|
await DB.instance.put<dynamic>(
|
||||||
|
boxName: walletId,
|
||||||
|
key: DBKeys.cachedBalance,
|
||||||
|
value: balance.toJsonIgnoreCoin(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue