2023-09-18 21:28:31 +00:00
|
|
|
import 'dart:convert';
|
|
|
|
|
2023-11-09 15:33:51 +00:00
|
|
|
import 'package:isar/isar.dart';
|
2024-05-23 17:05:30 +00:00
|
|
|
|
2024-05-23 00:37:06 +00:00
|
|
|
import '../app_config.dart';
|
|
|
|
import '../models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
|
|
|
import '../models/isar/models/isar_models.dart';
|
|
|
|
import '../utilities/flutter_secure_storage_interface.dart';
|
|
|
|
import '../wallets/crypto_currency/crypto_currency.dart';
|
|
|
|
import '../wallets/isar/models/token_wallet_info.dart';
|
|
|
|
import '../wallets/isar/models/wallet_info.dart';
|
|
|
|
import '../wallets/isar/models/wallet_info_meta.dart';
|
|
|
|
import '../wallets/wallet/supporting/epiccash_wallet_info_extension.dart';
|
2024-05-23 17:05:30 +00:00
|
|
|
import 'hive/db.dart';
|
|
|
|
import 'isar/main_db.dart';
|
2023-09-18 21:28:31 +00:00
|
|
|
|
2023-11-06 17:01:52 +00:00
|
|
|
Future<void> migrateWalletsToIsar({
|
2023-09-18 21:28:31 +00:00
|
|
|
required SecureStorageInterface secureStore,
|
|
|
|
}) async {
|
2023-12-20 00:34:20 +00:00
|
|
|
await MainDB.instance.initMainDB();
|
2024-01-14 19:03:07 +00:00
|
|
|
|
|
|
|
// ensure fresh
|
|
|
|
await MainDB.instance.isar
|
|
|
|
.writeTxn(() async => await MainDB.instance.isar.transactionV2s.clear());
|
|
|
|
|
2024-06-10 22:50:26 +00:00
|
|
|
final allWalletsBox =
|
|
|
|
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
2023-09-18 21:28:31 +00:00
|
|
|
|
|
|
|
final names = DB.instance
|
|
|
|
.get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
|
|
|
|
|
|
|
if (names == null) {
|
|
|
|
// no wallets to migrate
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Parse the old data from the Hive map into a nice list
|
|
|
|
//
|
|
|
|
final List<
|
|
|
|
({
|
2024-05-15 21:20:45 +00:00
|
|
|
String coinIdentifier,
|
2023-09-18 21:28:31 +00:00
|
|
|
String name,
|
|
|
|
String walletId,
|
|
|
|
})> oldInfo = Map<String, dynamic>.from(names).values.map((e) {
|
|
|
|
final map = e as Map;
|
|
|
|
return (
|
2024-05-15 21:20:45 +00:00
|
|
|
coinIdentifier: map["coin"] as String,
|
2023-09-18 21:28:31 +00:00
|
|
|
walletId: map["id"] as String,
|
|
|
|
name: map["name"] as String,
|
|
|
|
);
|
|
|
|
}).toList();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Get current ordered list of favourite wallet Ids
|
|
|
|
//
|
|
|
|
final List<String> favourites =
|
2024-06-10 22:50:26 +00:00
|
|
|
(await DB.instance.hive.openBox<String>(DB.boxNameFavoriteWallets))
|
|
|
|
.values
|
|
|
|
.toList();
|
2023-09-18 21:28:31 +00:00
|
|
|
|
2024-01-09 20:44:16 +00:00
|
|
|
final List<(WalletInfo, WalletInfoMeta)> newInfo = [];
|
2024-01-10 23:15:56 +00:00
|
|
|
final List<TokenWalletInfo> tokenInfo = [];
|
2023-11-09 15:33:51 +00:00
|
|
|
final List<TransactionNote> migratedNotes = [];
|
2023-09-18 21:28:31 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Convert each old info into the new Isar WalletInfo
|
|
|
|
//
|
|
|
|
for (final old in oldInfo) {
|
2024-06-10 22:50:26 +00:00
|
|
|
final walletBox = await DB.instance.hive.openBox<dynamic>(old.walletId);
|
2023-09-18 21:28:31 +00:00
|
|
|
|
2023-11-09 15:33:51 +00:00
|
|
|
//
|
|
|
|
// First handle transaction notes
|
|
|
|
//
|
|
|
|
final newNoteCount = await MainDB.instance.isar.transactionNotes
|
|
|
|
.where()
|
|
|
|
.walletIdEqualTo(old.walletId)
|
|
|
|
.count();
|
|
|
|
if (newNoteCount == 0) {
|
|
|
|
final map = walletBox.get('notes') as Map?;
|
|
|
|
|
|
|
|
if (map != null) {
|
|
|
|
final notes = Map<String, String>.from(map);
|
|
|
|
|
|
|
|
for (final txid in notes.keys) {
|
|
|
|
final note = notes[txid];
|
|
|
|
if (note != null && note.isNotEmpty) {
|
|
|
|
final newNote = TransactionNote(
|
|
|
|
walletId: old.walletId,
|
|
|
|
txid: txid,
|
|
|
|
value: note,
|
|
|
|
);
|
|
|
|
migratedNotes.add(newNote);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:26:21 +00:00
|
|
|
// reset stellar + tezos address type
|
2024-05-15 21:20:45 +00:00
|
|
|
if (old.coinIdentifier == Stellar(CryptoCurrencyNetwork.main).identifier ||
|
|
|
|
old.coinIdentifier == Stellar(CryptoCurrencyNetwork.test).identifier ||
|
|
|
|
old.coinIdentifier == Tezos(CryptoCurrencyNetwork.main).identifier) {
|
2024-01-11 23:18:58 +00:00
|
|
|
await MainDB.instance.deleteWalletBlockchainData(old.walletId);
|
|
|
|
}
|
|
|
|
|
2023-09-18 21:28:31 +00:00
|
|
|
//
|
|
|
|
// Set other data values
|
|
|
|
//
|
2024-05-15 21:20:45 +00:00
|
|
|
final Map<String, dynamic> otherData = {};
|
2023-09-18 21:28:31 +00:00
|
|
|
|
2024-01-10 23:15:56 +00:00
|
|
|
final List<String>? tokenContractAddresses = walletBox.get(
|
|
|
|
"ethTokenContracts",
|
2023-09-18 21:28:31 +00:00
|
|
|
) as List<String>?;
|
|
|
|
|
2024-01-10 23:15:56 +00:00
|
|
|
if (tokenContractAddresses?.isNotEmpty == true) {
|
|
|
|
otherData[WalletInfoKeys.tokenContractAddresses] = tokenContractAddresses;
|
|
|
|
|
|
|
|
for (final address in tokenContractAddresses!) {
|
|
|
|
final contract = await MainDB.instance.isar.ethContracts
|
|
|
|
.where()
|
|
|
|
.addressEqualTo(address)
|
|
|
|
.findFirst();
|
|
|
|
if (contract != null) {
|
|
|
|
tokenInfo.add(
|
|
|
|
TokenWalletInfo(
|
|
|
|
walletId: old.walletId,
|
|
|
|
tokenAddress: address,
|
|
|
|
tokenFractionDigits: contract.decimals,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-18 21:28:31 +00:00
|
|
|
// epiccash specifics
|
2024-05-15 21:20:45 +00:00
|
|
|
if (old.coinIdentifier == Epiccash(CryptoCurrencyNetwork.main)) {
|
2023-09-18 21:28:31 +00:00
|
|
|
final epicWalletInfo = ExtraEpiccashWalletInfo.fromMap({
|
|
|
|
"receivingIndex": walletBox.get("receivingIndex") as int? ?? 0,
|
|
|
|
"changeIndex": walletBox.get("changeIndex") as int? ?? 0,
|
2023-11-06 17:23:51 +00:00
|
|
|
"slatesToAddresses": walletBox.get("slate_to_address") as Map? ?? {},
|
2023-09-18 21:28:31 +00:00
|
|
|
"slatesToCommits": walletBox.get("slatesToCommits") as Map? ?? {},
|
|
|
|
"lastScannedBlock": walletBox.get("lastScannedBlock") as int? ?? 0,
|
|
|
|
"restoreHeight": walletBox.get("restoreHeight") as int? ?? 0,
|
|
|
|
"creationHeight": walletBox.get("creationHeight") as int? ?? 0,
|
|
|
|
});
|
|
|
|
otherData[WalletInfoKeys.epiccashData] = jsonEncode(
|
|
|
|
epicWalletInfo.toMap(),
|
|
|
|
);
|
2024-05-15 21:20:45 +00:00
|
|
|
} else if (old.coinIdentifier ==
|
|
|
|
Firo(CryptoCurrencyNetwork.main).identifier ||
|
|
|
|
old.coinIdentifier == Firo(CryptoCurrencyNetwork.test).identifier) {
|
2024-01-15 15:42:49 +00:00
|
|
|
otherData[WalletInfoKeys.lelantusCoinIsarRescanRequired] = walletBox
|
|
|
|
.get(WalletInfoKeys.lelantusCoinIsarRescanRequired) as bool? ??
|
|
|
|
true;
|
2023-09-18 21:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Clear out any keys with null values as they are not needed
|
|
|
|
//
|
|
|
|
otherData.removeWhere((key, value) => value == null);
|
|
|
|
|
2024-01-09 20:44:16 +00:00
|
|
|
final infoMeta = WalletInfoMeta(
|
|
|
|
walletId: old.walletId,
|
|
|
|
isMnemonicVerified: allWalletsBox
|
|
|
|
.get("${old.walletId}_mnemonicHasBeenVerified") as bool? ??
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
|
2023-09-18 21:28:31 +00:00
|
|
|
final info = WalletInfo(
|
2024-05-15 21:20:45 +00:00
|
|
|
coinName: old.coinIdentifier,
|
2023-09-18 21:28:31 +00:00
|
|
|
walletId: old.walletId,
|
|
|
|
name: old.name,
|
2024-05-23 17:05:30 +00:00
|
|
|
mainAddressType: AppConfig.getCryptoCurrencyFor(old.coinIdentifier)!
|
2024-06-20 16:16:12 +00:00
|
|
|
.defaultAddressType,
|
2023-09-18 21:28:31 +00:00
|
|
|
favouriteOrderIndex: favourites.indexOf(old.walletId),
|
|
|
|
cachedChainHeight: walletBox.get(
|
|
|
|
DBKeys.storedChainHeight,
|
|
|
|
) as int? ??
|
|
|
|
0,
|
|
|
|
cachedBalanceString: walletBox.get(
|
|
|
|
DBKeys.cachedBalance,
|
|
|
|
) as String?,
|
2023-11-16 23:32:47 +00:00
|
|
|
cachedBalanceSecondaryString: walletBox.get(
|
|
|
|
DBKeys.cachedBalanceSecondary,
|
|
|
|
) as String?,
|
2023-09-18 21:28:31 +00:00
|
|
|
otherDataJsonString: jsonEncode(otherData),
|
|
|
|
);
|
|
|
|
|
2024-01-09 20:44:16 +00:00
|
|
|
newInfo.add((info, infoMeta));
|
2023-09-18 21:28:31 +00:00
|
|
|
}
|
2023-11-06 17:01:52 +00:00
|
|
|
|
2023-11-09 15:33:51 +00:00
|
|
|
if (migratedNotes.isNotEmpty) {
|
|
|
|
await MainDB.instance.isar.writeTxn(() async {
|
|
|
|
await MainDB.instance.isar.transactionNotes.putAll(migratedNotes);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-01-10 23:15:56 +00:00
|
|
|
if (newInfo.isNotEmpty) {
|
|
|
|
await MainDB.instance.isar.writeTxn(() async {
|
|
|
|
await MainDB.instance.isar.walletInfo
|
|
|
|
.putAll(newInfo.map((e) => e.$1).toList());
|
|
|
|
await MainDB.instance.isar.walletInfoMeta
|
|
|
|
.putAll(newInfo.map((e) => e.$2).toList());
|
|
|
|
|
|
|
|
if (tokenInfo.isNotEmpty) {
|
|
|
|
await MainDB.instance.isar.tokenWalletInfo.putAll(tokenInfo);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2023-11-06 17:37:23 +00:00
|
|
|
|
2024-01-09 20:44:16 +00:00
|
|
|
await _cleanupOnSuccess(
|
2024-05-27 23:56:22 +00:00
|
|
|
walletIds: newInfo.map((e) => e.$1.walletId).toList(),
|
|
|
|
);
|
2023-09-18 21:28:31 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:37:23 +00:00
|
|
|
Future<void> _cleanupOnSuccess({required List<String> walletIds}) async {
|
2024-06-10 22:50:26 +00:00
|
|
|
await DB.instance.hive.deleteBoxFromDisk(DB.boxNameFavoriteWallets);
|
|
|
|
await DB.instance.hive.deleteBoxFromDisk(DB.boxNameAllWalletsData);
|
2023-09-18 21:28:31 +00:00
|
|
|
for (final walletId in walletIds) {
|
2024-06-10 22:50:26 +00:00
|
|
|
await DB.instance.hive.deleteBoxFromDisk(walletId);
|
2023-09-18 21:28:31 +00:00
|
|
|
}
|
|
|
|
}
|