mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-22 11:29:23 +00:00
639 lines
20 KiB
Dart
639 lines
20 KiB
Dart
/*
|
|
* This file is part of Stack Wallet.
|
|
*
|
|
* Copyright (c) 2023 Cypher Stack
|
|
* All Rights Reserved.
|
|
* The code is distributed under GPLv3 license, see LICENSE file for details.
|
|
* Generated by Cypher Stack on 2023-05-26
|
|
*
|
|
*/
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:compat/compat.dart' as lib_monero_compat;
|
|
import 'package:isar/isar.dart';
|
|
|
|
import '../app_config.dart';
|
|
import '../db/hive/db.dart';
|
|
import '../db/isar/main_db.dart';
|
|
import '../utilities/enums/sync_type_enum.dart';
|
|
import '../utilities/flutter_secure_storage_interface.dart';
|
|
import '../utilities/logger.dart';
|
|
import '../utilities/prefs.dart';
|
|
import '../utilities/stack_file_system.dart';
|
|
import '../wallets/crypto_currency/crypto_currency.dart';
|
|
import '../wallets/isar/models/wallet_info.dart';
|
|
import '../wallets/wallet/impl/epiccash_wallet.dart';
|
|
import '../wallets/wallet/intermediate/lib_monero_wallet.dart';
|
|
import '../wallets/wallet/wallet.dart';
|
|
import 'event_bus/events/wallet_added_event.dart';
|
|
import 'event_bus/global_event_bus.dart';
|
|
import 'node_service.dart';
|
|
import 'notifications_service.dart';
|
|
import 'trade_sent_from_stack_service.dart';
|
|
|
|
class Wallets {
|
|
Wallets._private();
|
|
|
|
static final Wallets _sharedInstance = Wallets._private();
|
|
static Wallets get sharedInstance => _sharedInstance;
|
|
|
|
late NodeService nodeService;
|
|
late MainDB mainDB;
|
|
|
|
List<Wallet> get wallets => _wallets.values.toList();
|
|
|
|
static bool hasLoaded = false;
|
|
|
|
final Map<String, Wallet> _wallets = {};
|
|
|
|
Wallet getWallet(String walletId) {
|
|
if (_wallets[walletId] != null) {
|
|
return _wallets[walletId]!;
|
|
} else {
|
|
throw Exception("Wallet with id $walletId not found");
|
|
}
|
|
}
|
|
|
|
void addWallet(Wallet wallet) {
|
|
if (_wallets[wallet.walletId] != null) {
|
|
throw Exception(
|
|
"Tried to add wallet that already exists, according to it's wallet Id!",
|
|
);
|
|
}
|
|
_wallets[wallet.walletId] = wallet;
|
|
GlobalEventBus.instance.fire(WalletAddedEvent());
|
|
}
|
|
|
|
Future<void> deleteWallet(
|
|
WalletInfo info,
|
|
SecureStorageInterface secureStorage,
|
|
) async {
|
|
final walletId = info.walletId;
|
|
Logging.instance.log(
|
|
"deleteWallet called with walletId=$walletId",
|
|
level: LogLevel.Warning,
|
|
);
|
|
|
|
final wallet = _wallets[walletId];
|
|
_wallets.remove(walletId);
|
|
await wallet?.exit();
|
|
|
|
await secureStorage.delete(key: Wallet.mnemonicKey(walletId: walletId));
|
|
await secureStorage.delete(
|
|
key: Wallet.mnemonicPassphraseKey(walletId: walletId),
|
|
);
|
|
await secureStorage.delete(key: Wallet.privateKeyKey(walletId: walletId));
|
|
await secureStorage.delete(
|
|
key: Wallet.getViewOnlyWalletDataSecStoreKey(walletId: walletId),
|
|
);
|
|
|
|
if (info.coin is Wownero) {
|
|
await lib_monero_compat.deleteWalletFiles(
|
|
name: walletId,
|
|
type: lib_monero_compat.WalletType.wownero,
|
|
appRoot: await StackFileSystem.applicationRootDirectory(),
|
|
);
|
|
Logging.instance
|
|
.log("monero wallet: $walletId deleted", level: LogLevel.Info);
|
|
} else if (info.coin is Monero) {
|
|
await lib_monero_compat.deleteWalletFiles(
|
|
name: walletId,
|
|
type: lib_monero_compat.WalletType.monero,
|
|
appRoot: await StackFileSystem.applicationRootDirectory(),
|
|
);
|
|
Logging.instance
|
|
.log("monero wallet: $walletId deleted", level: LogLevel.Info);
|
|
} else if (info.coin is Epiccash) {
|
|
final deleteResult = await deleteEpicWallet(
|
|
walletId: walletId,
|
|
secureStore: secureStorage,
|
|
);
|
|
Logging.instance.log(
|
|
"epic wallet: $walletId deleted with result: $deleteResult",
|
|
level: LogLevel.Info,
|
|
);
|
|
}
|
|
|
|
// delete wallet data in main db
|
|
await MainDB.instance.deleteWalletBlockchainData(walletId);
|
|
await MainDB.instance.deleteAddressLabels(walletId);
|
|
await MainDB.instance.deleteTransactionNotes(walletId);
|
|
|
|
// box data may currently still be read/written to if wallet was refreshing
|
|
// when delete was requested so instead of deleting now we mark the wallet
|
|
// as needs delete by adding it's id to a list which gets checked on app start
|
|
await DB.instance.add<String>(
|
|
boxName: DB.boxNameWalletsToDeleteOnStart,
|
|
value: walletId,
|
|
);
|
|
|
|
final lookupService = TradeSentFromStackService();
|
|
for (final lookup in lookupService.all) {
|
|
if (lookup.walletIds.contains(walletId)) {
|
|
// update lookup data to reflect deleted wallet
|
|
await lookupService.save(
|
|
tradeWalletLookup: lookup.copyWith(
|
|
walletIds: lookup.walletIds.where((id) => id != walletId).toList(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// delete notifications tied to deleted wallet
|
|
for (final notification in NotificationsService.instance.notifications) {
|
|
if (notification.walletId == walletId) {
|
|
await NotificationsService.instance.delete(notification, false);
|
|
}
|
|
}
|
|
|
|
await mainDB.isar.writeTxn(() async {
|
|
await mainDB.isar.walletInfo.deleteByWalletId(walletId);
|
|
});
|
|
}
|
|
|
|
Future<void> load(Prefs prefs, MainDB mainDB) async {
|
|
// return await _loadV1(prefs, mainDB);
|
|
// return await _loadV2(prefs, mainDB);
|
|
return await _loadV3(prefs, mainDB);
|
|
}
|
|
|
|
Future<void> _loadV1(Prefs prefs, MainDB mainDB) async {
|
|
if (hasLoaded) {
|
|
return;
|
|
}
|
|
hasLoaded = true;
|
|
|
|
// clear out any wallet hive boxes where the wallet was deleted in previous app run
|
|
for (final walletId in DB.instance
|
|
.values<String>(boxName: DB.boxNameWalletsToDeleteOnStart)) {
|
|
await mainDB.isar.writeTxn(
|
|
() async => await mainDB.isar.walletInfo
|
|
.where()
|
|
.walletIdEqualTo(walletId)
|
|
.deleteAll(),
|
|
);
|
|
}
|
|
// clear list
|
|
await DB.instance
|
|
.deleteAll<String>(boxName: DB.boxNameWalletsToDeleteOnStart);
|
|
|
|
final walletInfoList = await mainDB.isar.walletInfo.where().findAll();
|
|
if (walletInfoList.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final List<Future<void>> walletInitFutures = [];
|
|
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
|
[];
|
|
|
|
final List<String> walletIdsToEnableAutoSync = [];
|
|
bool shouldAutoSyncAll = false;
|
|
switch (prefs.syncType) {
|
|
case SyncingType.currentWalletOnly:
|
|
// do nothing as this will be set when going into a wallet from the main screen
|
|
break;
|
|
case SyncingType.selectedWalletsAtStartup:
|
|
walletIdsToEnableAutoSync.addAll(prefs.walletIdsSyncOnStartup);
|
|
break;
|
|
case SyncingType.allWalletsOnStartup:
|
|
shouldAutoSyncAll = true;
|
|
break;
|
|
}
|
|
|
|
for (final walletInfo in walletInfoList) {
|
|
try {
|
|
final isVerified = await walletInfo.isMnemonicVerified(mainDB.isar);
|
|
Logging.instance.log(
|
|
"LOADING WALLET: ${walletInfo.name}:${walletInfo.walletId} "
|
|
"IS VERIFIED: $isVerified",
|
|
level: LogLevel.Info,
|
|
);
|
|
|
|
if (isVerified) {
|
|
// TODO: integrate this into the new wallets somehow?
|
|
// requires some thinking
|
|
// final txTracker =
|
|
// TransactionNotificationTracker(walletId: walletInfo.walletId);
|
|
|
|
final wallet = await Wallet.load(
|
|
walletId: walletInfo.walletId,
|
|
mainDB: mainDB,
|
|
secureStorageInterface: nodeService.secureStorageInterface,
|
|
nodeService: nodeService,
|
|
prefs: prefs,
|
|
);
|
|
|
|
final shouldSetAutoSync = shouldAutoSyncAll ||
|
|
walletIdsToEnableAutoSync.contains(walletInfo.walletId);
|
|
|
|
if (wallet is LibMoneroWallet) {
|
|
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
|
} else {
|
|
walletInitFutures.add(
|
|
wallet.init().then((_) {
|
|
if (shouldSetAutoSync) {
|
|
wallet.shouldAutoSync = true;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
|
|
_wallets[wallet.walletId] = wallet;
|
|
} else {
|
|
// wallet creation was not completed by user so we remove it completely
|
|
await _deleteWallet(walletInfo.walletId);
|
|
// await walletsService.deleteWallet(walletInfo.name, false);
|
|
}
|
|
} catch (e, s) {
|
|
Logging.instance.log("$e $s", level: LogLevel.Fatal);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) {
|
|
await Future.wait([
|
|
_initLinearly(walletsToInitLinearly),
|
|
...walletInitFutures,
|
|
]);
|
|
} else if (walletInitFutures.isNotEmpty) {
|
|
await Future.wait(walletInitFutures);
|
|
} else if (walletsToInitLinearly.isNotEmpty) {
|
|
await _initLinearly(walletsToInitLinearly);
|
|
}
|
|
}
|
|
|
|
/// should be fastest but big ui performance hit
|
|
Future<void> _loadV2(Prefs prefs, MainDB mainDB) async {
|
|
if (hasLoaded) {
|
|
return;
|
|
}
|
|
hasLoaded = true;
|
|
|
|
// clear out any wallet hive boxes where the wallet was deleted in previous app run
|
|
for (final walletId in DB.instance
|
|
.values<String>(boxName: DB.boxNameWalletsToDeleteOnStart)) {
|
|
await mainDB.isar.writeTxn(
|
|
() async => await mainDB.isar.walletInfo
|
|
.where()
|
|
.walletIdEqualTo(walletId)
|
|
.deleteAll(),
|
|
);
|
|
}
|
|
// clear list
|
|
await DB.instance
|
|
.deleteAll<String>(boxName: DB.boxNameWalletsToDeleteOnStart);
|
|
|
|
final walletInfoList = await mainDB.isar.walletInfo.where().findAll();
|
|
if (walletInfoList.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final List<Future<String>> walletIDInitFutures = [];
|
|
final List<Future<void>> deleteFutures = [];
|
|
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
|
[];
|
|
|
|
final List<String> walletIdsToEnableAutoSync = [];
|
|
bool shouldAutoSyncAll = false;
|
|
switch (prefs.syncType) {
|
|
case SyncingType.currentWalletOnly:
|
|
// do nothing as this will be set when going into a wallet from the main screen
|
|
break;
|
|
case SyncingType.selectedWalletsAtStartup:
|
|
walletIdsToEnableAutoSync.addAll(prefs.walletIdsSyncOnStartup);
|
|
break;
|
|
case SyncingType.allWalletsOnStartup:
|
|
shouldAutoSyncAll = true;
|
|
break;
|
|
}
|
|
|
|
for (final walletInfo in walletInfoList) {
|
|
try {
|
|
final isVerified = await walletInfo.isMnemonicVerified(mainDB.isar);
|
|
Logging.instance.log(
|
|
"LOADING WALLET: ${walletInfo.name}:${walletInfo.walletId} "
|
|
"IS VERIFIED: $isVerified",
|
|
level: LogLevel.Info,
|
|
);
|
|
|
|
if (isVerified) {
|
|
// TODO: integrate this into the new wallets somehow?
|
|
// requires some thinking
|
|
// final txTracker =
|
|
// TransactionNotificationTracker(walletId: walletInfo.walletId);
|
|
|
|
final walletIdCompleter = Completer<String>();
|
|
|
|
walletIDInitFutures.add(walletIdCompleter.future);
|
|
|
|
await Wallet.load(
|
|
walletId: walletInfo.walletId,
|
|
mainDB: mainDB,
|
|
secureStorageInterface: nodeService.secureStorageInterface,
|
|
nodeService: nodeService,
|
|
prefs: prefs,
|
|
).then((wallet) {
|
|
if (wallet is LibMoneroWallet) {
|
|
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
|
|
|
walletIdCompleter.complete("dummy_ignore");
|
|
} else {
|
|
walletIdCompleter.complete(wallet.walletId);
|
|
}
|
|
|
|
_wallets[wallet.walletId] = wallet;
|
|
});
|
|
} else {
|
|
// wallet creation was not completed by user so we remove it completely
|
|
deleteFutures.add(_deleteWallet(walletInfo.walletId));
|
|
}
|
|
} catch (e, s) {
|
|
Logging.instance.log("$e $s", level: LogLevel.Fatal);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
final asyncWalletIds = await Future.wait(walletIDInitFutures);
|
|
asyncWalletIds.removeWhere((e) => e == "dummy_ignore");
|
|
|
|
final List<Future<void>> walletInitFutures = asyncWalletIds
|
|
.map(
|
|
(id) => _wallets[id]!.init().then(
|
|
(_) {
|
|
if (shouldAutoSyncAll || walletIdsToEnableAutoSync.contains(id)) {
|
|
_wallets[id]!.shouldAutoSync = true;
|
|
}
|
|
},
|
|
),
|
|
)
|
|
.toList();
|
|
|
|
if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) {
|
|
unawaited(
|
|
Future.wait([
|
|
_initLinearly(walletsToInitLinearly),
|
|
...walletInitFutures,
|
|
]),
|
|
);
|
|
} else if (walletInitFutures.isNotEmpty) {
|
|
unawaited(Future.wait(walletInitFutures));
|
|
} else if (walletsToInitLinearly.isNotEmpty) {
|
|
unawaited(_initLinearly(walletsToInitLinearly));
|
|
}
|
|
|
|
// finally await any deletions that haven't completed yet
|
|
await Future.wait(deleteFutures);
|
|
}
|
|
|
|
/// should be best performance
|
|
Future<void> _loadV3(Prefs prefs, MainDB mainDB) async {
|
|
if (hasLoaded) {
|
|
return;
|
|
}
|
|
hasLoaded = true;
|
|
|
|
// clear out any wallet hive boxes where the wallet was deleted in previous app run
|
|
for (final walletId in DB.instance
|
|
.values<String>(boxName: DB.boxNameWalletsToDeleteOnStart)) {
|
|
await mainDB.isar.writeTxn(
|
|
() async => await mainDB.isar.walletInfo
|
|
.where()
|
|
.walletIdEqualTo(walletId)
|
|
.deleteAll(),
|
|
);
|
|
}
|
|
// clear list
|
|
await DB.instance
|
|
.deleteAll<String>(boxName: DB.boxNameWalletsToDeleteOnStart);
|
|
|
|
final walletInfoList = await mainDB.isar.walletInfo
|
|
.where()
|
|
.filter()
|
|
.anyOf<String, CryptoCurrency>(
|
|
AppConfig.coins.map((e) => e.identifier),
|
|
(q, element) => q.coinNameMatches(element),
|
|
)
|
|
.findAll();
|
|
if (walletInfoList.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final List<Future<String>> walletIDInitFutures = [];
|
|
final List<Future<void>> deleteFutures = [];
|
|
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
|
[];
|
|
|
|
final List<String> walletIdsToSyncOnceOnStartup = [];
|
|
bool shouldSyncAllOnceOnStartup = false;
|
|
switch (prefs.syncType) {
|
|
case SyncingType.currentWalletOnly:
|
|
// do nothing as this will be set when going into a wallet from the main screen
|
|
break;
|
|
case SyncingType.selectedWalletsAtStartup:
|
|
walletIdsToSyncOnceOnStartup.addAll(prefs.walletIdsSyncOnStartup);
|
|
break;
|
|
case SyncingType.allWalletsOnStartup:
|
|
shouldSyncAllOnceOnStartup = true;
|
|
break;
|
|
}
|
|
|
|
for (final walletInfo in walletInfoList) {
|
|
try {
|
|
final isVerified = await walletInfo.isMnemonicVerified(mainDB.isar);
|
|
Logging.instance.log(
|
|
"LOADING WALLET: ${walletInfo.name}:${walletInfo.walletId} "
|
|
"IS VERIFIED: $isVerified",
|
|
level: LogLevel.Info,
|
|
);
|
|
|
|
if (isVerified) {
|
|
// TODO: integrate this into the new wallets somehow?
|
|
// requires some thinking
|
|
// final txTracker =
|
|
// TransactionNotificationTracker(walletId: walletInfo.walletId);
|
|
|
|
final walletIdCompleter = Completer<String>();
|
|
|
|
walletIDInitFutures.add(walletIdCompleter.future);
|
|
|
|
await Wallet.load(
|
|
walletId: walletInfo.walletId,
|
|
mainDB: mainDB,
|
|
secureStorageInterface: nodeService.secureStorageInterface,
|
|
nodeService: nodeService,
|
|
prefs: prefs,
|
|
).then((wallet) {
|
|
if (wallet is LibMoneroWallet) {
|
|
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
|
|
|
walletIdCompleter.complete("dummy_ignore");
|
|
} else {
|
|
walletIdCompleter.complete(wallet.walletId);
|
|
}
|
|
|
|
_wallets[wallet.walletId] = wallet;
|
|
});
|
|
} else {
|
|
// wallet creation was not completed by user so we remove it completely
|
|
deleteFutures.add(_deleteWallet(walletInfo.walletId));
|
|
}
|
|
} catch (e, s) {
|
|
Logging.instance.log("$e $s", level: LogLevel.Fatal);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
final asyncWalletIds = await Future.wait(walletIDInitFutures);
|
|
asyncWalletIds.removeWhere((e) => e == "dummy_ignore");
|
|
|
|
final List<String> idsToRefresh = [];
|
|
final List<Future<void>> walletInitFutures = asyncWalletIds
|
|
.map(
|
|
(id) => _wallets[id]!.init().then(
|
|
(_) {
|
|
if (shouldSyncAllOnceOnStartup ||
|
|
walletIdsToSyncOnceOnStartup.contains(id)) {
|
|
idsToRefresh.add(id);
|
|
}
|
|
},
|
|
),
|
|
)
|
|
.toList();
|
|
|
|
Future<void> _refreshFutures(List<String> idsToRefresh) async {
|
|
final start = DateTime.now();
|
|
Logging.instance.log(
|
|
"Initial refresh start: ${start.toUtc()}",
|
|
level: LogLevel.Warning,
|
|
);
|
|
const groupCount = 3;
|
|
for (int i = 0; i < idsToRefresh.length; i += groupCount) {
|
|
final List<Future<void>> futures = [];
|
|
for (int j = 0; j < groupCount; j++) {
|
|
if (i + j >= idsToRefresh.length) {
|
|
break;
|
|
}
|
|
futures.add(
|
|
_wallets[idsToRefresh[i + j]]!.refresh(),
|
|
);
|
|
}
|
|
await Future.wait(futures);
|
|
}
|
|
Logging.instance.log(
|
|
"Initial refresh duration: ${DateTime.now().difference(start)}",
|
|
level: LogLevel.Warning,
|
|
);
|
|
}
|
|
|
|
if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) {
|
|
unawaited(
|
|
Future.wait([
|
|
_initLinearly(walletsToInitLinearly),
|
|
...walletInitFutures,
|
|
]).then(
|
|
(value) => _refreshFutures(idsToRefresh),
|
|
),
|
|
);
|
|
} else if (walletInitFutures.isNotEmpty) {
|
|
unawaited(
|
|
Future.wait(walletInitFutures).then(
|
|
(value) => _refreshFutures(idsToRefresh),
|
|
),
|
|
);
|
|
} else if (walletsToInitLinearly.isNotEmpty) {
|
|
unawaited(_initLinearly(walletsToInitLinearly));
|
|
}
|
|
|
|
// finally await any deletions that haven't completed yet
|
|
await Future.wait(deleteFutures);
|
|
}
|
|
|
|
Future<void> loadAfterStackRestore(
|
|
Prefs prefs,
|
|
List<Wallet> wallets,
|
|
bool isDesktop,
|
|
) async {
|
|
final List<Future<void>> walletInitFutures = [];
|
|
final List<({Wallet wallet, bool shouldAutoSync})> walletsToInitLinearly =
|
|
[];
|
|
|
|
final List<String> walletIdsToEnableAutoSync = [];
|
|
bool shouldAutoSyncAll = false;
|
|
switch (prefs.syncType) {
|
|
case SyncingType.currentWalletOnly:
|
|
// do nothing as this will be set when going into a wallet from the main screen
|
|
break;
|
|
case SyncingType.selectedWalletsAtStartup:
|
|
walletIdsToEnableAutoSync.addAll(prefs.walletIdsSyncOnStartup);
|
|
break;
|
|
case SyncingType.allWalletsOnStartup:
|
|
shouldAutoSyncAll = true;
|
|
break;
|
|
}
|
|
|
|
for (final wallet in wallets) {
|
|
final isVerified = await wallet.info.isMnemonicVerified(mainDB.isar);
|
|
Logging.instance.log(
|
|
"LOADING WALLET: ${wallet.info.name}:${wallet.walletId} IS VERIFIED: $isVerified",
|
|
level: LogLevel.Info,
|
|
);
|
|
|
|
if (isVerified) {
|
|
final shouldSetAutoSync = shouldAutoSyncAll ||
|
|
walletIdsToEnableAutoSync.contains(wallet.walletId);
|
|
|
|
if (isDesktop) {
|
|
if (wallet is LibMoneroWallet) {
|
|
// walletsToInitLinearly.add(Tuple2(manager, shouldSetAutoSync));
|
|
} else {
|
|
walletInitFutures.add(
|
|
wallet.init().then((_) {
|
|
// if (shouldSetAutoSync) {
|
|
// wallet.shouldAutoSync = true;
|
|
// }
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
_wallets[wallet.walletId] = wallet;
|
|
} else {
|
|
// wallet creation was not completed by user so we remove it completely
|
|
await _deleteWallet(wallet.walletId);
|
|
// await walletsService.deleteWallet(walletInfo.name, false);
|
|
}
|
|
}
|
|
|
|
if (isDesktop) {
|
|
if (walletInitFutures.isNotEmpty && walletsToInitLinearly.isNotEmpty) {
|
|
await Future.wait([
|
|
_initLinearly(walletsToInitLinearly),
|
|
...walletInitFutures,
|
|
]);
|
|
} else if (walletInitFutures.isNotEmpty) {
|
|
await Future.wait(walletInitFutures);
|
|
} else if (walletsToInitLinearly.isNotEmpty) {
|
|
await _initLinearly(walletsToInitLinearly);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _initLinearly(
|
|
List<({Wallet wallet, bool shouldAutoSync})> dataList,
|
|
) async {
|
|
for (final data in dataList) {
|
|
await data.wallet.init();
|
|
if (data.shouldAutoSync && !data.wallet.shouldAutoSync) {
|
|
data.wallet.shouldAutoSync = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _deleteWallet(String walletId) async {
|
|
// TODO proper clean up of other wallet data in addition to the following
|
|
await mainDB.isar.writeTxn(
|
|
() async => await mainDB.isar.walletInfo.deleteByWalletId(walletId),
|
|
);
|
|
}
|
|
}
|