2023-05-26 21:21:16 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2023-02-05 20:32:39 +00:00
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:isar/isar.dart';
|
2024-05-23 00:37:06 +00:00
|
|
|
import '../../db/hive/db.dart';
|
|
|
|
import '../../models/exchange/active_pair.dart';
|
|
|
|
import '../../models/exchange/aggregate_currency.dart';
|
|
|
|
import '../../models/isar/exchange_cache/currency.dart';
|
|
|
|
import '../../models/isar/exchange_cache/pair.dart';
|
|
|
|
import 'change_now/change_now_exchange.dart';
|
|
|
|
import 'majestic_bank/majestic_bank_exchange.dart';
|
|
|
|
import 'trocador/trocador_exchange.dart';
|
|
|
|
import '../../utilities/enums/exchange_rate_type_enum.dart';
|
|
|
|
import '../../utilities/logger.dart';
|
|
|
|
import '../../utilities/prefs.dart';
|
|
|
|
import '../../utilities/stack_file_system.dart';
|
2023-02-10 14:04:12 +00:00
|
|
|
import 'package:tuple/tuple.dart';
|
2022-09-09 14:03:36 +00:00
|
|
|
|
2022-10-04 17:06:14 +00:00
|
|
|
class ExchangeDataLoadingService {
|
2023-02-05 20:32:39 +00:00
|
|
|
ExchangeDataLoadingService._();
|
|
|
|
static final ExchangeDataLoadingService _instance =
|
|
|
|
ExchangeDataLoadingService._();
|
|
|
|
static ExchangeDataLoadingService get instance => _instance;
|
|
|
|
|
|
|
|
Isar? _isar;
|
|
|
|
Isar get isar => _isar!;
|
|
|
|
|
2023-02-08 14:43:42 +00:00
|
|
|
VoidCallback? onLoadingError;
|
|
|
|
VoidCallback? onLoadingComplete;
|
|
|
|
|
|
|
|
static const int cacheVersion = 1;
|
|
|
|
|
|
|
|
static int get currentCacheVersion =>
|
|
|
|
DB.instance.get<dynamic>(
|
|
|
|
boxName: DB.boxNameDBInfo,
|
|
|
|
key: "exchange_data_cache_version") as int? ??
|
|
|
|
0;
|
|
|
|
|
|
|
|
Future<void> _updateCurrentCacheVersion(int version) async {
|
|
|
|
await DB.instance.put<dynamic>(
|
|
|
|
boxName: DB.boxNameDBInfo,
|
|
|
|
key: "exchange_data_cache_version",
|
|
|
|
value: version,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-04-18 13:56:14 +00:00
|
|
|
Future<void> initDB() async {
|
|
|
|
if (_isar != null) return;
|
|
|
|
await _isar?.close();
|
2023-02-05 20:32:39 +00:00
|
|
|
_isar = await Isar.open(
|
|
|
|
[
|
|
|
|
CurrencySchema,
|
2023-02-13 15:05:22 +00:00
|
|
|
// PairSchema,
|
2023-02-05 20:32:39 +00:00
|
|
|
],
|
|
|
|
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
2023-02-10 23:59:05 +00:00
|
|
|
// inspector: kDebugMode,
|
|
|
|
inspector: false,
|
2023-02-05 20:32:39 +00:00
|
|
|
name: "exchange_cache",
|
2023-02-13 15:05:22 +00:00
|
|
|
maxSizeMiB: 64,
|
2023-02-05 20:32:39 +00:00
|
|
|
);
|
2022-09-09 14:03:36 +00:00
|
|
|
}
|
|
|
|
|
2023-05-03 20:03:31 +00:00
|
|
|
Future<void> setCurrenciesIfEmpty(
|
|
|
|
ActivePair? pair,
|
|
|
|
ExchangeRateType rateType,
|
|
|
|
) async {
|
|
|
|
if (pair?.send == null && pair?.receive == null) {
|
2023-02-10 14:04:12 +00:00
|
|
|
if (await isar.currencies.count() > 0) {
|
2023-05-03 20:03:31 +00:00
|
|
|
pair?.setSend(
|
|
|
|
await getAggregateCurrency(
|
|
|
|
"BTC",
|
|
|
|
rateType,
|
|
|
|
null,
|
|
|
|
),
|
|
|
|
notifyListeners: false,
|
2023-02-10 14:04:12 +00:00
|
|
|
);
|
2023-05-03 20:03:31 +00:00
|
|
|
|
|
|
|
pair?.setReceive(
|
|
|
|
await getAggregateCurrency(
|
|
|
|
"XMR",
|
|
|
|
rateType,
|
|
|
|
null,
|
|
|
|
),
|
|
|
|
notifyListeners: false,
|
2023-02-10 14:04:12 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<AggregateCurrency?> getAggregateCurrency(
|
2023-04-10 20:14:03 +00:00
|
|
|
String ticker,
|
|
|
|
ExchangeRateType rateType,
|
|
|
|
String? contract,
|
|
|
|
) async {
|
2023-02-10 14:04:12 +00:00
|
|
|
final currencies = await ExchangeDataLoadingService.instance.isar.currencies
|
|
|
|
.filter()
|
|
|
|
.group((q) => rateType == ExchangeRateType.fixed
|
|
|
|
? q
|
|
|
|
.rateTypeEqualTo(SupportedRateType.both)
|
|
|
|
.or()
|
|
|
|
.rateTypeEqualTo(SupportedRateType.fixed)
|
|
|
|
: q
|
|
|
|
.rateTypeEqualTo(SupportedRateType.both)
|
|
|
|
.or()
|
|
|
|
.rateTypeEqualTo(SupportedRateType.estimated))
|
|
|
|
.and()
|
|
|
|
.tickerEqualTo(
|
|
|
|
ticker,
|
|
|
|
caseSensitive: false,
|
|
|
|
)
|
2023-04-10 20:14:03 +00:00
|
|
|
.and()
|
|
|
|
.tokenContractEqualTo(contract)
|
2023-02-10 14:04:12 +00:00
|
|
|
.findAll();
|
|
|
|
|
|
|
|
final items = currencies
|
|
|
|
.map((e) => Tuple2(e.exchangeName, e))
|
|
|
|
.toList(growable: false);
|
|
|
|
|
|
|
|
return items.isNotEmpty
|
|
|
|
? AggregateCurrency(exchangeCurrencyPairs: items)
|
|
|
|
: null;
|
|
|
|
}
|
|
|
|
|
2023-02-08 14:43:42 +00:00
|
|
|
bool get isLoading => _locked;
|
|
|
|
|
2023-02-05 20:32:39 +00:00
|
|
|
bool _locked = false;
|
|
|
|
|
|
|
|
Future<void> loadAll() async {
|
|
|
|
if (!_locked) {
|
|
|
|
_locked = true;
|
2023-07-17 16:36:33 +00:00
|
|
|
if (_isar == null) {
|
|
|
|
await initDB();
|
|
|
|
}
|
2023-02-08 14:43:42 +00:00
|
|
|
Logging.instance.log(
|
|
|
|
"ExchangeDataLoadingService.loadAll starting...",
|
|
|
|
level: LogLevel.Info,
|
|
|
|
);
|
|
|
|
final start = DateTime.now();
|
2023-02-05 20:32:39 +00:00
|
|
|
try {
|
2023-09-11 21:31:48 +00:00
|
|
|
/*
|
2023-09-11 23:07:59 +00:00
|
|
|
// Old exchange data loading code.
|
2023-02-05 20:32:39 +00:00
|
|
|
await Future.wait([
|
2023-02-05 23:50:40 +00:00
|
|
|
_loadChangeNowCurrencies(),
|
2023-02-11 00:38:39 +00:00
|
|
|
// _loadChangeNowFixedRatePairs(),
|
|
|
|
// _loadChangeNowEstimatedRatePairs(),
|
2023-02-05 20:32:39 +00:00
|
|
|
// loadSimpleswapFixedRateCurrencies(ref),
|
|
|
|
// loadSimpleswapFloatingRateCurrencies(ref),
|
|
|
|
loadMajesticBankCurrencies(),
|
2023-04-28 20:32:44 +00:00
|
|
|
loadTrocadorCurrencies(),
|
2023-02-05 20:32:39 +00:00
|
|
|
]);
|
2023-02-11 00:38:39 +00:00
|
|
|
|
2023-02-13 15:05:22 +00:00
|
|
|
// quicker to load available currencies on the fly for a specific base currency
|
|
|
|
// await _loadChangeNowFixedRatePairs();
|
|
|
|
// await _loadChangeNowEstimatedRatePairs();
|
2023-09-11 21:31:48 +00:00
|
|
|
*/
|
2023-09-11 23:07:59 +00:00
|
|
|
|
2023-09-20 15:10:29 +00:00
|
|
|
// Exchanges which support Tor just get treated normally.
|
|
|
|
final futures = [
|
|
|
|
loadMajesticBankCurrencies(),
|
|
|
|
loadTrocadorCurrencies(),
|
|
|
|
];
|
|
|
|
|
2023-09-11 23:07:59 +00:00
|
|
|
// If using Tor, don't load data for exchanges which don't support Tor.
|
|
|
|
//
|
|
|
|
// Add to this list when adding an exchange which doesn't supports Tor.
|
|
|
|
if (!Prefs.instance.useTor) {
|
2023-09-20 15:10:29 +00:00
|
|
|
futures.add(_loadChangeNowCurrencies());
|
2023-09-11 21:31:48 +00:00
|
|
|
}
|
2023-09-11 23:07:59 +00:00
|
|
|
|
2023-09-20 15:10:29 +00:00
|
|
|
// wait for all loading futures to complete
|
|
|
|
await Future.wait(futures);
|
2023-02-11 00:38:39 +00:00
|
|
|
|
2023-02-08 14:43:42 +00:00
|
|
|
Logging.instance.log(
|
|
|
|
"ExchangeDataLoadingService.loadAll finished in ${DateTime.now().difference(start).inSeconds} seconds",
|
|
|
|
level: LogLevel.Info,
|
|
|
|
);
|
|
|
|
onLoadingComplete?.call();
|
|
|
|
await _updateCurrentCacheVersion(cacheVersion);
|
2023-02-05 20:32:39 +00:00
|
|
|
} catch (e, s) {
|
|
|
|
Logging.instance.log(
|
2023-02-08 14:43:42 +00:00
|
|
|
"ExchangeDataLoadingService.loadAll failed after ${DateTime.now().difference(start).inSeconds} seconds: $e\n$s",
|
|
|
|
level: LogLevel.Error,
|
|
|
|
);
|
|
|
|
onLoadingError?.call();
|
2022-09-09 14:03:36 +00:00
|
|
|
}
|
2023-02-05 20:32:39 +00:00
|
|
|
_locked = false;
|
2022-09-09 14:03:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 23:50:40 +00:00
|
|
|
Future<void> _loadChangeNowCurrencies() async {
|
2023-12-10 18:58:50 +00:00
|
|
|
if (_isar == null) {
|
|
|
|
await initDB();
|
|
|
|
}
|
2023-02-05 20:32:39 +00:00
|
|
|
final exchange = ChangeNowExchange.instance;
|
2023-02-05 23:50:40 +00:00
|
|
|
final responseCurrencies = await exchange.getAllCurrencies(false);
|
2023-02-05 20:32:39 +00:00
|
|
|
if (responseCurrencies.value != null) {
|
2023-02-05 23:50:40 +00:00
|
|
|
await isar.writeTxn(() async {
|
|
|
|
final idsToDelete = await isar.currencies
|
|
|
|
.where()
|
|
|
|
.exchangeNameEqualTo(ChangeNowExchange.exchangeName)
|
|
|
|
.idProperty()
|
|
|
|
.findAll();
|
|
|
|
await isar.currencies.deleteAll(idsToDelete);
|
|
|
|
await isar.currencies.putAll(responseCurrencies.value!);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Logging.instance.log(
|
|
|
|
"Failed to load changeNOW currencies: ${responseCurrencies.exception?.message}",
|
|
|
|
level: LogLevel.Error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-09-09 14:03:36 +00:00
|
|
|
|
2023-02-13 15:05:22 +00:00
|
|
|
// Future<void> _loadChangeNowFixedRatePairs() async {
|
|
|
|
// final exchange = ChangeNowExchange.instance;
|
|
|
|
//
|
|
|
|
// final responsePairs = await compute(exchange.getAllPairs, true);
|
|
|
|
//
|
|
|
|
// if (responsePairs.value != null) {
|
|
|
|
// await isar.writeTxn(() async {
|
|
|
|
// final idsToDelete2 = await isar.pairs
|
|
|
|
// .where()
|
|
|
|
// .exchangeNameEqualTo(ChangeNowExchange.exchangeName)
|
|
|
|
// .filter()
|
|
|
|
// .rateTypeEqualTo(SupportedRateType.fixed)
|
|
|
|
// .idProperty()
|
|
|
|
// .findAll();
|
|
|
|
// await isar.pairs.deleteAll(idsToDelete2);
|
|
|
|
// await isar.pairs.putAll(responsePairs.value!);
|
|
|
|
// });
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "Failed to load changeNOW available fixed rate pairs: ${responsePairs.exception?.message}",
|
|
|
|
// level: LogLevel.Error);
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
2023-02-05 20:32:39 +00:00
|
|
|
|
2023-02-13 15:05:22 +00:00
|
|
|
// Future<void> _loadChangeNowEstimatedRatePairs() async {
|
|
|
|
// final exchange = ChangeNowExchange.instance;
|
|
|
|
//
|
|
|
|
// final responsePairs = await compute(exchange.getAllPairs, false);
|
|
|
|
//
|
|
|
|
// if (responsePairs.value != null) {
|
|
|
|
// await isar.writeTxn(() async {
|
|
|
|
// final idsToDelete = await isar.pairs
|
|
|
|
// .where()
|
|
|
|
// .exchangeNameEqualTo(ChangeNowExchange.exchangeName)
|
|
|
|
// .filter()
|
|
|
|
// .rateTypeEqualTo(SupportedRateType.estimated)
|
|
|
|
// .idProperty()
|
|
|
|
// .findAll();
|
|
|
|
// await isar.pairs.deleteAll(idsToDelete);
|
|
|
|
// await isar.pairs.putAll(responsePairs.value!);
|
|
|
|
// });
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "Failed to load changeNOW available floating rate pairs: ${responsePairs.exception?.message}",
|
|
|
|
// level: LogLevel.Error);
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
2023-02-05 20:32:39 +00:00
|
|
|
//
|
|
|
|
// Future<void> loadSimpleswapFloatingRateCurrencies(WidgetRef ref) async {
|
|
|
|
// final exchange = SimpleSwapExchange();
|
|
|
|
// final responseCurrencies = await exchange.getAllCurrencies(false);
|
|
|
|
//
|
|
|
|
// if (responseCurrencies.value != null) {
|
|
|
|
// ref
|
|
|
|
// .read(availableSimpleswapCurrenciesProvider)
|
|
|
|
// .updateFloatingCurrencies(responseCurrencies.value!);
|
|
|
|
//
|
|
|
|
// final responsePairs = await exchange.getAllPairs(false);
|
|
|
|
//
|
|
|
|
// if (responsePairs.value != null) {
|
|
|
|
// ref
|
|
|
|
// .read(availableSimpleswapCurrenciesProvider)
|
|
|
|
// .updateFloatingPairs(responsePairs.value!);
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "loadSimpleswapFloatingRateCurrencies: $responsePairs",
|
|
|
|
// level: LogLevel.Warning,
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "loadSimpleswapFloatingRateCurrencies: $responseCurrencies",
|
|
|
|
// level: LogLevel.Warning,
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// Future<void> loadSimpleswapFixedRateCurrencies(WidgetRef ref) async {
|
|
|
|
// final exchange = SimpleSwapExchange();
|
|
|
|
// final responseCurrencies = await exchange.getAllCurrencies(true);
|
|
|
|
//
|
|
|
|
// if (responseCurrencies.value != null) {
|
|
|
|
// ref
|
|
|
|
// .read(availableSimpleswapCurrenciesProvider)
|
|
|
|
// .updateFixedCurrencies(responseCurrencies.value!);
|
|
|
|
//
|
|
|
|
// final responsePairs = await exchange.getAllPairs(true);
|
|
|
|
//
|
|
|
|
// if (responsePairs.value != null) {
|
|
|
|
// ref
|
|
|
|
// .read(availableSimpleswapCurrenciesProvider)
|
|
|
|
// .updateFixedPairs(responsePairs.value!);
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "loadSimpleswapFixedRateCurrencies: $responsePairs",
|
|
|
|
// level: LogLevel.Warning,
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "loadSimpleswapFixedRateCurrencies: $responseCurrencies",
|
|
|
|
// level: LogLevel.Warning,
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
Future<void> loadMajesticBankCurrencies() async {
|
2023-12-10 18:58:50 +00:00
|
|
|
if (_isar == null) {
|
|
|
|
await initDB();
|
|
|
|
}
|
2023-04-01 15:04:34 +00:00
|
|
|
final exchange = MajesticBankExchange.instance;
|
|
|
|
final responseCurrencies = await exchange.getAllCurrencies(false);
|
|
|
|
|
|
|
|
if (responseCurrencies.value != null) {
|
|
|
|
await isar.writeTxn(() async {
|
|
|
|
final idsToDelete = await isar.currencies
|
|
|
|
.where()
|
|
|
|
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
|
|
|
.idProperty()
|
|
|
|
.findAll();
|
|
|
|
await isar.currencies.deleteAll(idsToDelete);
|
|
|
|
await isar.currencies.putAll(responseCurrencies.value!);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Logging.instance.log(
|
|
|
|
"loadMajesticBankCurrencies: $responseCurrencies",
|
|
|
|
level: LogLevel.Warning,
|
|
|
|
);
|
|
|
|
}
|
2022-10-04 17:06:14 +00:00
|
|
|
}
|
2023-02-13 15:05:22 +00:00
|
|
|
|
2023-04-28 20:32:44 +00:00
|
|
|
Future<void> loadTrocadorCurrencies() async {
|
2023-12-10 18:58:50 +00:00
|
|
|
if (_isar == null) {
|
|
|
|
await initDB();
|
|
|
|
}
|
2023-04-28 20:32:44 +00:00
|
|
|
final exchange = TrocadorExchange.instance;
|
|
|
|
final responseCurrencies = await exchange.getAllCurrencies(false);
|
|
|
|
|
|
|
|
if (responseCurrencies.value != null) {
|
|
|
|
await isar.writeTxn(() async {
|
|
|
|
final idsToDelete = await isar.currencies
|
|
|
|
.where()
|
|
|
|
.exchangeNameEqualTo(TrocadorExchange.exchangeName)
|
|
|
|
.idProperty()
|
|
|
|
.findAll();
|
|
|
|
await isar.currencies.deleteAll(idsToDelete);
|
|
|
|
await isar.currencies.putAll(responseCurrencies.value!);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
Logging.instance.log(
|
|
|
|
"loadTrocadorCurrencies: $responseCurrencies",
|
|
|
|
level: LogLevel.Warning,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-13 15:05:22 +00:00
|
|
|
// Future<void> loadMajesticBankPairs() async {
|
|
|
|
// final exchange = MajesticBankExchange.instance;
|
|
|
|
//
|
|
|
|
// final responsePairs = await exchange.getAllPairs(false);
|
|
|
|
// if (responsePairs.value != null) {
|
|
|
|
// await isar.writeTxn(() async {
|
|
|
|
// final idsToDelete2 = await isar.pairs
|
|
|
|
// .where()
|
|
|
|
// .exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
|
|
|
// .idProperty()
|
|
|
|
// .findAll();
|
|
|
|
// await isar.pairs.deleteAll(idsToDelete2);
|
|
|
|
// await isar.pairs.putAll(responsePairs.value!);
|
|
|
|
// });
|
|
|
|
// } else {
|
|
|
|
// Logging.instance.log(
|
|
|
|
// "loadMajesticBankCurrencies: $responsePairs",
|
|
|
|
// level: LogLevel.Warning,
|
|
|
|
// );
|
|
|
|
// }
|
|
|
|
// }
|
2022-09-09 14:03:36 +00:00
|
|
|
}
|