small bug fixes and added WalletCache mixin to handle balance cache etc

This commit is contained in:
julian 2023-01-12 12:15:28 -06:00
parent e115ff1b41
commit ccb9f254bd
5 changed files with 88 additions and 348 deletions

View file

@ -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";
}

View file

@ -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,
);
}
} }

View file

@ -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(

View file

@ -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;

View 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(),
);
}
}