diff --git a/android/app/build.gradle b/android/app/build.gradle
index 5b67a6f4e4..650b99789a 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -48,7 +48,7 @@ if (flutterVersionName == null) {
android {
namespace 'com.komodoplatform.atomicdex'
- compileSdk 35
+ compileSdk 36
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
@@ -63,7 +63,7 @@ android {
defaultConfig {
applicationId "com.komodoplatform.atomicdex"
minSdkVersion 28
- targetSdkVersion 35
+ targetSdkVersion 36
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/app_theme/pubspec.lock b/app_theme/pubspec.lock
deleted file mode 100644
index c4cb968fff..0000000000
--- a/app_theme/pubspec.lock
+++ /dev/null
@@ -1,64 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
- characters:
- dependency: transitive
- description:
- name: characters
- sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
- url: "https://pub.dev"
- source: hosted
- version: "1.4.0"
- collection:
- dependency: transitive
- description:
- name: collection
- sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
- url: "https://pub.dev"
- source: hosted
- version: "1.19.1"
- flutter:
- dependency: "direct main"
- description: flutter
- source: sdk
- version: "0.0.0"
- material_color_utilities:
- dependency: transitive
- description:
- name: material_color_utilities
- sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
- url: "https://pub.dev"
- source: hosted
- version: "0.11.1"
- meta:
- dependency: transitive
- description:
- name: meta
- sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
- url: "https://pub.dev"
- source: hosted
- version: "1.16.0"
- plugin_platform_interface:
- dependency: "direct main"
- description:
- name: plugin_platform_interface
- sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
- url: "https://pub.dev"
- source: hosted
- version: "2.1.8"
- sky_engine:
- dependency: transitive
- description: flutter
- source: sdk
- version: "0.0.0"
- vector_math:
- dependency: transitive
- description:
- name: vector_math
- sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
- url: "https://pub.dev"
- source: hosted
- version: "2.2.0"
-sdks:
- dart: ">=3.8.1 <4.0.0"
- flutter: ">=3.35.1"
diff --git a/app_theme/pubspec.yaml b/app_theme/pubspec.yaml
index 4d11719378..27e1c6afc1 100644
--- a/app_theme/pubspec.yaml
+++ b/app_theme/pubspec.yaml
@@ -3,6 +3,8 @@ description: App theme.
version: 0.0.1
# homepage:
+resolution: workspace
+
environment:
sdk: ">=3.8.1 <4.0.0"
flutter: ">=3.35.2 <4.0.0"
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 8c6e56146e..d57061dd6b 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 12.0
+ 13.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 391a080413..d367030ef2 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -33,48 +33,48 @@ PODS:
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- - Firebase/Analytics (11.10.0):
+ - Firebase/Analytics (11.15.0):
- Firebase/Core
- - Firebase/Core (11.10.0):
+ - Firebase/Core (11.15.0):
- Firebase/CoreOnly
- - FirebaseAnalytics (~> 11.10.0)
- - Firebase/CoreOnly (11.10.0):
- - FirebaseCore (~> 11.10.0)
- - firebase_analytics (11.4.5):
- - Firebase/Analytics (= 11.10.0)
+ - FirebaseAnalytics (~> 11.15.0)
+ - Firebase/CoreOnly (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - firebase_analytics (11.6.0):
+ - Firebase/Analytics (= 11.15.0)
- firebase_core
- Flutter
- - firebase_core (3.13.0):
- - Firebase/CoreOnly (= 11.10.0)
+ - firebase_core (3.15.2):
+ - Firebase/CoreOnly (= 11.15.0)
- Flutter
- - FirebaseAnalytics (11.10.0):
- - FirebaseAnalytics/AdIdSupport (= 11.10.0)
- - FirebaseCore (~> 11.10.0)
+ - FirebaseAnalytics (11.15.0):
+ - FirebaseAnalytics/Default (= 11.15.0)
+ - FirebaseCore (~> 11.15.0)
- FirebaseInstallations (~> 11.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/MethodSwizzler (~> 8.0)
- - GoogleUtilities/Network (~> 8.0)
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- - FirebaseAnalytics/AdIdSupport (11.10.0):
- - FirebaseCore (~> 11.10.0)
+ - FirebaseAnalytics/Default (11.15.0):
+ - FirebaseCore (~> 11.15.0)
- FirebaseInstallations (~> 11.0)
- - GoogleAppMeasurement (= 11.10.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/MethodSwizzler (~> 8.0)
- - GoogleUtilities/Network (~> 8.0)
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - GoogleAppMeasurement/Default (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- - FirebaseCore (11.10.0):
- - FirebaseCoreInternal (~> 11.10.0)
- - GoogleUtilities/Environment (~> 8.0)
- - GoogleUtilities/Logger (~> 8.0)
- - FirebaseCoreInternal (11.10.0):
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
- - FirebaseInstallations (11.10.0):
- - FirebaseCore (~> 11.10.0)
- - GoogleUtilities/Environment (~> 8.0)
- - GoogleUtilities/UserDefaults (~> 8.0)
+ - FirebaseCore (11.15.0):
+ - FirebaseCoreInternal (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/Logger (~> 8.1)
+ - FirebaseCoreInternal (11.15.0):
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - FirebaseInstallations (11.15.0):
+ - FirebaseCore (~> 11.15.0)
+ - GoogleUtilities/Environment (~> 8.1)
+ - GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4)
- Flutter (1.0.0)
- flutter_inappwebview_ios (0.0.1):
@@ -87,51 +87,57 @@ PODS:
- flutter_secure_storage_darwin (10.0.0):
- Flutter
- FlutterMacOS
- - GoogleAppMeasurement (11.10.0):
- - GoogleAppMeasurement/AdIdSupport (= 11.10.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/MethodSwizzler (~> 8.0)
- - GoogleUtilities/Network (~> 8.0)
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - GoogleAdsOnDeviceConversion (2.1.0):
+ - GoogleUtilities/Logger (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
- nanopb (~> 3.30910.0)
- - GoogleAppMeasurement/AdIdSupport (11.10.0):
- - GoogleAppMeasurement/WithoutAdIdSupport (= 11.10.0)
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/MethodSwizzler (~> 8.0)
- - GoogleUtilities/Network (~> 8.0)
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - GoogleAppMeasurement/Core (11.15.0):
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- - GoogleAppMeasurement/WithoutAdIdSupport (11.10.0):
- - GoogleUtilities/AppDelegateSwizzler (~> 8.0)
- - GoogleUtilities/MethodSwizzler (~> 8.0)
- - GoogleUtilities/Network (~> 8.0)
- - "GoogleUtilities/NSData+zlib (~> 8.0)"
+ - GoogleAppMeasurement/Default (11.15.0):
+ - GoogleAdsOnDeviceConversion (= 2.1.0)
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleAppMeasurement/IdentitySupport (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
- nanopb (~> 3.30910.0)
- - GoogleUtilities/AppDelegateSwizzler (8.0.2):
+ - GoogleAppMeasurement/IdentitySupport (11.15.0):
+ - GoogleAppMeasurement/Core (= 11.15.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
+ - GoogleUtilities/MethodSwizzler (~> 8.1)
+ - GoogleUtilities/Network (~> 8.1)
+ - "GoogleUtilities/NSData+zlib (~> 8.1)"
+ - nanopb (~> 3.30910.0)
+ - GoogleUtilities/AppDelegateSwizzler (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- - GoogleUtilities/Environment (8.0.2):
+ - GoogleUtilities/Environment (8.1.0):
- GoogleUtilities/Privacy
- - GoogleUtilities/Logger (8.0.2):
+ - GoogleUtilities/Logger (8.1.0):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- - GoogleUtilities/MethodSwizzler (8.0.2):
+ - GoogleUtilities/MethodSwizzler (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- - GoogleUtilities/Network (8.0.2):
+ - GoogleUtilities/Network (8.1.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (8.0.2)":
+ - "GoogleUtilities/NSData+zlib (8.1.0)":
- GoogleUtilities/Privacy
- - GoogleUtilities/Privacy (8.0.2)
- - GoogleUtilities/Reachability (8.0.2):
+ - GoogleUtilities/Privacy (8.1.0)
+ - GoogleUtilities/Reachability (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- - GoogleUtilities/UserDefaults (8.0.2):
+ - GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- integration_test (0.0.1):
@@ -198,6 +204,7 @@ SPEC REPOS:
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
+ - GoogleAdsOnDeviceConversion
- GoogleAppMeasurement
- GoogleUtilities
- nanopb
@@ -244,18 +251,19 @@ SPEC CHECKSUMS:
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
- Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
- firebase_analytics: 1998960b8fa16fd0cd9e77a6f9fd35a2009ad65e
- firebase_core: 2d4534e7b489907dcede540c835b48981d890943
- FirebaseAnalytics: 4e42333f02cf78ed93703a5c36f36dd518aebdef
- FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
- FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
- FirebaseInstallations: 9980995bdd06ec8081dfb6ab364162bdd64245c3
- Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
+ firebase_analytics: 0e25ca1d4001ccedd40b4e5b74c0ec34e18f6425
+ firebase_core: 995454a784ff288be5689b796deb9e9fa3601818
+ FirebaseAnalytics: 6433dfd311ba78084fc93bdfc145e8cb75740eae
+ FirebaseCore: efb3893e5b94f32b86e331e3bd6dadf18b66568e
+ FirebaseCoreInternal: 9afa45b1159304c963da48addb78275ef701c6b4
+ FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
+ Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_secure_storage_darwin: ce237a8775b39723566dc72571190a3769d70468
- GoogleAppMeasurement: 36684bfb3ee034e2b42b4321eb19da3a1b81e65d
- GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
+ GoogleAdsOnDeviceConversion: 2be6297a4f048459e0ae17fad9bfd2844e10cf64
+ GoogleAppMeasurement: 700dce7541804bec33db590a5c496b663fbe2539
+ GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
komodo_defi_framework: b6929645df13ccb8d2c1c177ccf8b7bbb81f6859
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 4557b6e61f..f84a4524e3 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -371,7 +371,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -462,7 +462,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -512,7 +512,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/lib/bloc/app_bloc_root.dart b/lib/bloc/app_bloc_root.dart
index 923f77a49b..4cee603b84 100644
--- a/lib/bloc/app_bloc_root.dart
+++ b/lib/bloc/app_bloc_root.dart
@@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
-import 'package:komodo_cex_market_data/komodo_cex_market_data.dart';
import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
import 'package:komodo_ui/komodo_ui.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -51,6 +50,7 @@ import 'package:web_dex/bloc/trading_status/trading_status_bloc.dart';
import 'package:web_dex/bloc/trading_status/trading_status_repository.dart';
import 'package:web_dex/bloc/transaction_history/transaction_history_bloc.dart';
import 'package:web_dex/bloc/transaction_history/transaction_history_repo.dart';
+import 'package:web_dex/bloc/version_info/version_info_bloc.dart';
import 'package:web_dex/blocs/kmd_rewards_bloc.dart';
import 'package:web_dex/blocs/maker_form_bloc.dart';
import 'package:web_dex/blocs/orderbook_bloc.dart';
@@ -121,13 +121,12 @@ class AppBlocRoot extends StatelessWidget {
final transactionsRepo = performanceMode != null
? MockTransactionHistoryRepo(
performanceMode: performanceMode,
- demoDataGenerator: DemoDataCache.withDefaults(),
+ demoDataGenerator: DemoDataCache.withDefaults(komodoDefiSdk),
)
: SdkTransactionHistoryRepository(sdk: komodoDefiSdk);
final profitLossRepo = ProfitLossRepository.withDefaults(
transactionHistoryRepo: transactionsRepo,
- cexRepository: binanceRepository,
// Returns real data if performanceMode is null. Consider changing the
// other repositories to use this pattern.
demoMode: performanceMode,
@@ -136,7 +135,6 @@ class AppBlocRoot extends StatelessWidget {
final portfolioGrowthRepo = PortfolioGrowthRepository.withDefaults(
transactionHistoryRepo: transactionsRepo,
- cexRepository: binanceRepository,
demoMode: performanceMode,
coinsRepository: coinsRepository,
sdk: komodoDefiSdk,
@@ -187,13 +185,13 @@ class AppBlocRoot extends StatelessWidget {
CoinsBloc(komodoDefiSdk, coinsRepository)..add(CoinsStarted()),
),
BlocProvider(
- create: (context) =>
- PriceChartBloc(binanceRepository, komodoDefiSdk)..add(
- const PriceChartStarted(
- symbols: ['BTC'],
- period: Duration(days: 30),
- ),
+ create: (context) => PriceChartBloc(komodoDefiSdk)
+ ..add(
+ const PriceChartStarted(
+ symbols: ['BTC'],
+ period: Duration(days: 30),
),
+ ),
),
BlocProvider(
create: (context) => AssetOverviewBloc(
@@ -291,6 +289,13 @@ class AppBlocRoot extends StatelessWidget {
create: (context) =>
FaucetBloc(kdfSdk: context.read()),
),
+ BlocProvider(
+ lazy: false,
+ create: (context) =>
+ VersionInfoBloc(mm2Api: mm2Api, komodoDefiSdk: komodoDefiSdk)
+ ..add(const LoadVersionInfo())
+ ..add(const StartPeriodicPolling()),
+ ),
BlocProvider(
lazy: false,
create: (context) =>
diff --git a/lib/bloc/assets_overview/bloc/asset_overview_bloc.dart b/lib/bloc/assets_overview/bloc/asset_overview_bloc.dart
index 231e16316e..5182b22023 100644
--- a/lib/bloc/assets_overview/bloc/asset_overview_bloc.dart
+++ b/lib/bloc/assets_overview/bloc/asset_overview_bloc.dart
@@ -48,11 +48,8 @@ class AssetOverviewBloc extends Bloc {
event.walletId,
);
- final totalInvestment =
- await _investmentRepository.calculateTotalInvestment(
- event.walletId,
- [event.coin],
- );
+ final totalInvestment = await _investmentRepository
+ .calculateTotalInvestment(event.walletId, [event.coin]);
final profitAmount = profitLosses.lastOrNull?.profitLoss ?? 0.0;
// The percent which the user has gained or lost on their investment
@@ -108,18 +105,16 @@ class AssetOverviewBloc extends Bloc {
'USDT',
event.walletId,
);
- } catch (e) {
+ } catch (e, s) {
+ _log.shout('Failed to fetch profit/loss for ${coin.id.id}', e, s);
return Future.value([]);
}
});
final profitLosses = await Future.wait(profitLossesFutures);
- final totalInvestment =
- await _investmentRepository.calculateTotalInvestment(
- event.walletId,
- event.coins,
- );
+ final totalInvestment = await _investmentRepository
+ .calculateTotalInvestment(event.walletId, event.coins);
final profitAmount = profitLosses.fold(0.0, (sum, item) {
return sum + (item.lastOrNull?.profitLoss ?? 0.0);
@@ -128,8 +123,10 @@ class AssetOverviewBloc extends Bloc {
final double portfolioInvestmentReturnPercentage =
_calculateInvestmentReturnPercentage(profitAmount, totalInvestment);
// Total profit / total purchase amount
- final assetPortionPercentages =
- _calculateAssetPortionPercentages(profitLosses, profitAmount);
+ final assetPortionPercentages = _calculateAssetPortionPercentages(
+ profitLosses,
+ profitAmount,
+ );
emit(
PortfolioAssetsOverviewLoadSuccess(
@@ -164,20 +161,12 @@ class AssetOverviewBloc extends Bloc {
AssetOverviewSubscriptionRequested event,
Emitter emit,
) async {
- add(
- AssetOverviewLoadRequested(
- coin: event.coin,
- walletId: event.walletId,
- ),
- );
+ add(AssetOverviewLoadRequested(coin: event.coin, walletId: event.walletId));
_updateTimer?.cancel();
_updateTimer = Timer.periodic(event.updateFrequency, (_) {
add(
- AssetOverviewLoadRequested(
- coin: event.coin,
- walletId: event.walletId,
- ),
+ AssetOverviewLoadRequested(coin: event.coin, walletId: event.walletId),
);
});
}
diff --git a/lib/bloc/assets_overview/investment_repository.dart b/lib/bloc/assets_overview/investment_repository.dart
index 94ddd014a7..dacfefc48c 100644
--- a/lib/bloc/assets_overview/investment_repository.dart
+++ b/lib/bloc/assets_overview/investment_repository.dart
@@ -1,14 +1,14 @@
+import 'package:logging/logging.dart';
import 'package:web_dex/bloc/cex_market_data/profit_loss/models/fiat_value.dart';
import 'package:web_dex/bloc/cex_market_data/profit_loss/profit_loss_repository.dart';
import 'package:web_dex/model/coin.dart';
-import 'package:web_dex/shared/utils/utils.dart' as logger;
class InvestmentRepository {
- InvestmentRepository({
- required ProfitLossRepository profitLossRepository,
- }) : _profitLossRepository = profitLossRepository;
+ InvestmentRepository({required ProfitLossRepository profitLossRepository})
+ : _profitLossRepository = profitLossRepository;
final ProfitLossRepository _profitLossRepository;
+ final Logger _log = Logger('InvestmentRepository');
// TODO: Create a balance repository to fetch the current balance for a coin
// and also calculate its fiat value
@@ -46,8 +46,8 @@ class InvestmentRepository {
);
return totalPurchased;
- } catch (e) {
- logger.log('Failed to calculate total investment: $e', isError: true);
+ } catch (e, s) {
+ _log.shout('Failed to calculate total investment', e, s);
return FiatValue.usd(0);
}
});
diff --git a/lib/bloc/bridge_form/bridge_bloc.dart b/lib/bloc/bridge_form/bridge_bloc.dart
index 500d246f44..099e0327a7 100644
--- a/lib/bloc/bridge_form/bridge_bloc.dart
+++ b/lib/bloc/bridge_form/bridge_bloc.dart
@@ -1,10 +1,14 @@
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
-import 'package:komodo_defi_types/komodo_defi_types.dart';
+import 'package:komodo_defi_sdk/komodo_defi_sdk.dart' show KomodoDefiSdk;
+import 'package:komodo_defi_types/komodo_defi_type_utils.dart'
+ show LinearBackoff, retry;
+import 'package:komodo_defi_types/komodo_defi_types.dart' show KdfUser;
import 'package:rational/rational.dart';
+import 'package:web_dex/analytics/events/cross_chain_events.dart';
import 'package:web_dex/app_config/app_config.dart';
+import 'package:web_dex/bloc/analytics/analytics_bloc.dart';
import 'package:web_dex/bloc/bridge_form/bridge_event.dart';
import 'package:web_dex/bloc/bridge_form/bridge_repository.dart';
import 'package:web_dex/bloc/bridge_form/bridge_state.dart';
@@ -27,9 +31,6 @@ import 'package:web_dex/model/typedef.dart';
import 'package:web_dex/model/wallet.dart';
import 'package:web_dex/shared/utils/utils.dart';
import 'package:web_dex/views/dex/dex_helpers.dart';
-import 'package:komodo_defi_types/komodo_defi_type_utils.dart';
-import 'package:web_dex/bloc/analytics/analytics_bloc.dart';
-import 'package:web_dex/analytics/events/cross_chain_events.dart';
class BridgeBloc extends Bloc {
BridgeBloc({
@@ -38,12 +39,12 @@ class BridgeBloc extends Bloc {
required CoinsRepo coinsRepository,
required KomodoDefiSdk kdfSdk,
required AnalyticsBloc analyticsBloc,
- }) : _bridgeRepository = bridgeRepository,
- _dexRepository = dexRepository,
- _coinsRepository = coinsRepository,
- _kdfSdk = kdfSdk,
- _analyticsBloc = analyticsBloc,
- super(BridgeState.initial()) {
+ }) : _bridgeRepository = bridgeRepository,
+ _dexRepository = dexRepository,
+ _coinsRepository = coinsRepository,
+ _kdfSdk = kdfSdk,
+ _analyticsBloc = analyticsBloc,
+ super(BridgeState.initial()) {
on(_onInit);
on(_onReInit);
on(_onLogout);
@@ -80,8 +81,9 @@ class BridgeBloc extends Bloc {
sdk: _kdfSdk,
);
- _authorizationSubscription =
- _kdfSdk.auth.watchCurrentUser().listen((event) {
+ _authorizationSubscription = _kdfSdk.auth.watchCurrentUser().listen((
+ event,
+ ) {
_isLoggedIn = event != null;
if (!_isLoggedIn) add(const BridgeLogout());
});
@@ -101,30 +103,19 @@ class BridgeBloc extends Bloc {
Timer? _maxSellAmountTimer;
Timer? _preimageTimer;
- void _onInit(
- BridgeInit event,
- Emitter emit,
- ) {
+ void _onInit(BridgeInit event, Emitter emit) {
if (state.selectedTicker != null) return;
final Coin? defaultTickerCoin = _coinsRepository.getCoin(event.ticker);
- emit(state.copyWith(
- selectedTicker: () => defaultTickerCoin?.abbr,
- ));
+ emit(state.copyWith(selectedTicker: () => defaultTickerCoin?.abbr));
add(const BridgeUpdateTickers());
}
- Future _onReInit(
- BridgeReInit event,
- Emitter emit,
- ) async {
+ Future _onReInit(BridgeReInit event, Emitter emit) async {
_isLoggedIn = true;
- emit(state.copyWith(
- error: () => null,
- autovalidate: () => false,
- ));
+ emit(state.copyWith(error: () => null, autovalidate: () => false));
add(const BridgeUpdateMaxSellAmount(true));
@@ -135,37 +126,35 @@ class BridgeBloc extends Bloc {
_subscribeFees();
}
- void _onLogout(
- BridgeLogout event,
- Emitter emit,
- ) {
+ void _onLogout(BridgeLogout event, Emitter emit) {
_isLoggedIn = false;
- emit(state.copyWith(
- availableBalanceState: () => AvailableBalanceState.unavailable,
- maxSellAmount: () => null,
- preimageData: () => null,
- step: () => BridgeStep.form,
- ));
+ emit(
+ state.copyWith(
+ availableBalanceState: () => AvailableBalanceState.unavailable,
+ maxSellAmount: () => null,
+ preimageData: () => null,
+ step: () => BridgeStep.form,
+ ),
+ );
}
- void _onTickerChanged(
- BridgeTickerChanged event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- selectedTicker: () => event.ticker,
- showTickerDropdown: () => false,
- sellCoin: () => null,
- sellAmount: () => null,
- bestOrders: () => null,
- bestOrder: () => null,
- buyAmount: () => null,
- maxSellAmount: () => null,
- availableBalanceState: () => AvailableBalanceState.unavailable,
- preimageData: () => null,
- error: () => null,
- ));
+ void _onTickerChanged(BridgeTickerChanged event, Emitter emit) {
+ emit(
+ state.copyWith(
+ selectedTicker: () => event.ticker,
+ showTickerDropdown: () => false,
+ sellCoin: () => null,
+ sellAmount: () => null,
+ bestOrders: () => null,
+ bestOrder: () => null,
+ buyAmount: () => null,
+ maxSellAmount: () => null,
+ availableBalanceState: () => AvailableBalanceState.unavailable,
+ preimageData: () => null,
+ error: () => null,
+ ),
+ );
}
Future _onUpdateTickers(
@@ -174,9 +163,7 @@ class BridgeBloc extends Bloc {
) async {
final CoinsByTicker tickers = await _bridgeRepository.getAvailableTickers();
- emit(state.copyWith(
- tickers: () => tickers,
- ));
+ emit(state.copyWith(tickers: () => tickers));
add(const BridgeUpdateSellCoins());
}
@@ -185,64 +172,71 @@ class BridgeBloc extends Bloc {
BridgeShowTickerDropdown event,
Emitter emit,
) {
- emit(state.copyWith(
- showTickerDropdown: () => event.show,
- showSourceDropdown: () => false,
- showTargetDropdown: () => false,
- ));
+ emit(
+ state.copyWith(
+ showTickerDropdown: () => event.show,
+ showSourceDropdown: () => false,
+ showTargetDropdown: () => false,
+ ),
+ );
}
void _onShowSourceDropdown(
BridgeShowSourceDropdown event,
Emitter emit,
) {
- emit(state.copyWith(
- showSourceDropdown: () => event.show,
- showTickerDropdown: () => false,
- showTargetDropdown: () => false,
- ));
+ emit(
+ state.copyWith(
+ showSourceDropdown: () => event.show,
+ showTickerDropdown: () => false,
+ showTargetDropdown: () => false,
+ ),
+ );
}
void _onShowTargetDropdown(
BridgeShowTargetDropdown event,
Emitter emit,
) {
- emit(state.copyWith(
- showTargetDropdown: () => event.show,
- showTickerDropdown: () => false,
- showSourceDropdown: () => false,
- ));
+ emit(
+ state.copyWith(
+ showTargetDropdown: () => event.show,
+ showTickerDropdown: () => false,
+ showSourceDropdown: () => false,
+ ),
+ );
}
Future _onUpdateSellCoins(
BridgeUpdateSellCoins event,
Emitter emit,
) async {
- final CoinsByTicker? sellCoins =
- await _bridgeRepository.getSellCoins(state.tickers);
+ final CoinsByTicker? sellCoins = await _bridgeRepository.getSellCoins(
+ state.tickers,
+ );
- emit(state.copyWith(
- sellCoins: () => sellCoins,
- ));
+ emit(state.copyWith(sellCoins: () => sellCoins));
}
Future _onSetSellCoin(
BridgeSetSellCoin event,
Emitter emit,
) async {
- emit(state.copyWith(
- sellCoin: () => event.coin,
- sellAmount: () => null,
- showSourceDropdown: () => false,
- bestOrders: () => null,
- bestOrder: () => null,
- buyAmount: () => null,
- maxSellAmount: () => null,
- availableBalanceState: () => AvailableBalanceState.initial,
- preimageData: () => null,
- error: () => null,
- autovalidate: () => false,
- ));
+ emit(
+ state.copyWith(
+ sellCoin: () => event.coin,
+ sellAmount: () => null,
+ showSourceDropdown: () => false,
+ bestOrders: () => null,
+ bestOrder: () => null,
+ buyAmount: () => null,
+ maxSellAmount: () => null,
+ availableBalanceState: () => AvailableBalanceState.initial,
+ preimageData: () => null,
+ error: () => null,
+ autovalidate: () => false,
+ ),
+ );
_autoActivateCoin(event.coin.abbr);
_subscribeMaxSellAmount();
@@ -262,39 +256,45 @@ class BridgeBloc extends Bloc {
final sellCoin = state.sellCoin;
if (sellCoin == null) return;
- final bestOrders = await _dexRepository.getBestOrders(BestOrdersRequest(
- coin: sellCoin.abbr,
- action: 'sell',
- type: BestOrdersRequestType.number,
- number: 1,
- ));
+ final bestOrders = await _dexRepository.getBestOrders(
+ BestOrdersRequest(
+ coin: sellCoin.abbr,
+ action: 'sell',
+ type: BestOrdersRequestType.number,
+ number: 1,
+ ),
+ );
/// Unsupported coins like ARRR cause downstream errors, so we need to
/// remove them from the list here
- bestOrders.result
- ?.removeWhere((coinId, _) => excludedAssetList.contains(coinId));
+ bestOrders.result?.removeWhere(
+ (coinId, _) => excludedAssetList.contains(coinId),
+ );
- emit(state.copyWith(
- bestOrders: () => bestOrders,
- ));
+ emit(state.copyWith(bestOrders: () => bestOrders));
}
void _onSelectBestOrder(
BridgeSelectBestOrder event,
Emitter emit,
) async {
- final bool switchingCoin = state.bestOrder != null &&
+ final bool switchingCoin =
+ state.bestOrder != null &&
event.order != null &&
state.bestOrder!.coin != event.order!.coin;
- emit(state.copyWith(
- bestOrder: () => event.order,
- showTargetDropdown: () => false,
- buyAmount: () => calculateBuyAmount(
- sellAmount: state.sellAmount, selectedOrder: event.order),
- error: () => null,
- autovalidate: switchingCoin ? () => false : null,
- ));
+ emit(
+ state.copyWith(
+ bestOrder: () => event.order,
+ showTargetDropdown: () => false,
+ buyAmount: () => calculateBuyAmount(
+ sellAmount: state.sellAmount,
+ selectedOrder: event.order,
+ ),
+ error: () => null,
+ autovalidate: switchingCoin ? () => false : null,
+ ),
+ );
if (!state.autovalidate) add(const BridgeVerifyOrderVolume());
@@ -303,22 +303,12 @@ class BridgeBloc extends Bloc {
_subscribeFees();
}
- void _onSetError(
- BridgeSetError event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- error: () => event.error,
- ));
+ void _onSetError(BridgeSetError event, Emitter emit) {
+ emit(state.copyWith(error: () => event.error));
}
- void _onClearErrors(
- BridgeClearErrors event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- error: () => null,
- ));
+ void _onClearErrors(BridgeClearErrors event, Emitter emit) {
+ emit(state.copyWith(error: () => null));
}
void _subscribeFees() {
@@ -346,8 +336,10 @@ class BridgeBloc extends Bloc {
) {
final Rational? maxSellAmount = state.maxSellAmount;
if (maxSellAmount == null) return;
- final Rational sellAmount =
- getFractionOfAmount(maxSellAmount, event.fraction);
+ final Rational sellAmount = getFractionOfAmount(
+ maxSellAmount,
+ event.fraction,
+ );
add(BridgeSetSellAmount(sellAmount));
}
@@ -355,8 +347,9 @@ class BridgeBloc extends Bloc {
BridgeSellAmountChange event,
Emitter emit,
) {
- final Rational? amount =
- event.value.isNotEmpty ? Rational.parse(event.value) : null;
+ final Rational? amount = event.value.isNotEmpty
+ ? Rational.tryParse(event.value)
+ : null;
if (amount == state.sellAmount) return;
@@ -367,13 +360,15 @@ class BridgeBloc extends Bloc {
BridgeSetSellAmount event,
Emitter emit,
) async {
- emit(state.copyWith(
- sellAmount: () => event.amount,
- buyAmount: () => calculateBuyAmount(
- selectedOrder: state.bestOrder,
- sellAmount: event.amount,
+ emit(
+ state.copyWith(
+ sellAmount: () => event.amount,
+ buyAmount: () => calculateBuyAmount(
+ selectedOrder: state.bestOrder,
+ sellAmount: event.amount,
+ ),
),
- ));
+ );
if (state.autovalidate) {
await _validator.validateForm();
@@ -389,50 +384,56 @@ class BridgeBloc extends Bloc {
) async {
if (state.sellCoin == null) {
_maxSellAmountTimer?.cancel();
- emit(state.copyWith(
- availableBalanceState: () => AvailableBalanceState.unavailable,
- ));
+ emit(
+ state.copyWith(
+ availableBalanceState: () => AvailableBalanceState.unavailable,
+ ),
+ );
return;
}
if (state.availableBalanceState == AvailableBalanceState.initial ||
event.setLoadingStatus) {
- emit(state.copyWith(
- availableBalanceState: () => AvailableBalanceState.loading,
- ));
+ emit(
+ state.copyWith(
+ availableBalanceState: () => AvailableBalanceState.loading,
+ ),
+ );
}
if (!_isLoggedIn) {
- emit(state.copyWith(
- availableBalanceState: () => AvailableBalanceState.unavailable,
- ));
+ emit(
+ state.copyWith(
+ availableBalanceState: () => AvailableBalanceState.unavailable,
+ ),
+ );
} else {
- Rational? maxSellAmount =
- await _dexRepository.getMaxTakerVolume(state.sellCoin!.abbr);
+ Rational? maxSellAmount = await _dexRepository.getMaxTakerVolume(
+ state.sellCoin!.abbr,
+ );
if (maxSellAmount != null) {
- emit(state.copyWith(
- maxSellAmount: () => maxSellAmount,
- availableBalanceState: () => AvailableBalanceState.success,
- ));
+ emit(
+ state.copyWith(
+ maxSellAmount: () => maxSellAmount,
+ availableBalanceState: () => AvailableBalanceState.success,
+ ),
+ );
} else {
maxSellAmount = await _frequentlyGetMaxTakerVolume();
- emit(state.copyWith(
- maxSellAmount: () => maxSellAmount,
- availableBalanceState: maxSellAmount == null
- ? () => AvailableBalanceState.failure
- : () => AvailableBalanceState.success,
- ));
+ emit(
+ state.copyWith(
+ maxSellAmount: () => maxSellAmount,
+ availableBalanceState: maxSellAmount == null
+ ? () => AvailableBalanceState.failure
+ : () => AvailableBalanceState.success,
+ ),
+ );
}
}
}
- void _onUpdateFees(
- BridgeUpdateFees event,
- Emitter emit,
- ) async {
- emit(state.copyWith(
- preimageData: () => null,
- ));
+ void _onUpdateFees(BridgeUpdateFees event, Emitter emit) async {
+ emit(state.copyWith(preimageData: () => null));
if (!_validator.canRequestPreimage) {
_preimageTimer?.cancel();
@@ -449,65 +450,45 @@ class BridgeBloc extends Bloc {
) async {
if (state.sellCoin == null) return;
if (!_isLoggedIn) {
- emit(state.copyWith(
- minSellAmount: () => null,
- ));
+ emit(state.copyWith(minSellAmount: () => null));
return;
}
- final Rational? minSellAmount =
- await _dexRepository.getMinTradingVolume(state.sellCoin!.abbr);
+ final Rational? minSellAmount = await _dexRepository.getMinTradingVolume(
+ state.sellCoin!.abbr,
+ );
- emit(state.copyWith(
- minSellAmount: () => minSellAmount,
- ));
+ emit(state.copyWith(minSellAmount: () => minSellAmount));
}
- void _onSetPreimage(
- BridgeSetPreimage event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- preimageData: () => event.preimageData,
- ));
+ void _onSetPreimage(BridgeSetPreimage event, Emitter emit) {
+ emit(state.copyWith(preimageData: () => event.preimageData));
}
- void _onSetInProgress(
- BridgeSetInProgress event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- inProgress: () => event.inProgress,
- ));
+ void _onSetInProgress(BridgeSetInProgress event, Emitter emit) {
+ emit(state.copyWith(inProgress: () => event.inProgress));
}
void _onSubmitClick(
BridgeSubmitClick event,
Emitter emit,
) async {
- emit(state.copyWith(
- inProgress: () => true,
- autovalidate: () => true,
- ));
+ emit(state.copyWith(inProgress: () => true, autovalidate: () => true));
await pauseWhile(() => _waitingForWallet || _activatingAssets);
final bool isValid = await _validator.validate();
- emit(state.copyWith(
- inProgress: () => false,
- step: () => isValid ? BridgeStep.confirm : BridgeStep.form,
- ));
+ emit(
+ state.copyWith(
+ inProgress: () => false,
+ step: () => isValid ? BridgeStep.confirm : BridgeStep.form,
+ ),
+ );
}
- void _onBackClick(
- BridgeBackClick event,
- Emitter emit,
- ) {
- emit(state.copyWith(
- step: () => BridgeStep.form,
- error: () => null,
- ));
+ void _onBackClick(BridgeBackClick event, Emitter emit) {
+ emit(state.copyWith(step: () => BridgeStep.form, error: () => null));
}
void _onSetWalletIsReady(
@@ -517,10 +498,7 @@ class BridgeBloc extends Bloc {
_waitingForWallet = !event.isReady;
}
- void _onStartSwap(
- BridgeStartSwap event,
- Emitter emit,
- ) async {
+ void _onStartSwap(BridgeStartSwap event, Emitter emit) async {
final sellCoin = state.sellCoin;
final bestOrder = state.bestOrder;
if (sellCoin != null && bestOrder != null) {
@@ -536,16 +514,16 @@ class BridgeBloc extends Bloc {
),
);
}
- emit(state.copyWith(
- inProgress: () => true,
- ));
- final SellResponse response = await _dexRepository.sell(SellRequest(
- base: state.sellCoin!.abbr,
- rel: state.bestOrder!.coin,
- volume: state.sellAmount!,
- price: state.bestOrder!.price,
- orderType: SellBuyOrderType.fillOrKill,
- ));
+ emit(state.copyWith(inProgress: () => true));
+ final SellResponse response = await _dexRepository.sell(
+ SellRequest(
+ base: state.sellCoin!.abbr,
+ rel: state.bestOrder!.coin,
+ volume: state.sellAmount!,
+ price: state.bestOrder!.price,
+ orderType: SellBuyOrderType.fillOrKill,
+ ),
+ );
final String? uuid = response.result?.uuid;
@@ -578,10 +556,12 @@ class BridgeBloc extends Bloc {
add(BridgeSetError(DexFormError(error: error)));
}
- emit(state.copyWith(
- inProgress: uuid == null ? () => false : null,
- swapUuid: () => uuid,
- ));
+ emit(
+ state.copyWith(
+ inProgress: uuid == null ? () => false : null,
+ swapUuid: () => uuid,
+ ),
+ );
}
void _verifyOrderVolume(
@@ -591,10 +571,7 @@ class BridgeBloc extends Bloc {
_validator.verifyOrderVolume();
}
- void _onClear(
- BridgeClear event,
- Emitter emit,
- ) {
+ void _onClear(BridgeClear event, Emitter emit) {
emit(BridgeState.initial());
}
@@ -621,8 +598,10 @@ class BridgeBloc extends Bloc {
if (abbr == null) return;
_activatingAssets = true;
- final List activationErrors =
- await activateCoinIfNeeded(abbr, _coinsRepository);
+ final List activationErrors = await activateCoinIfNeeded(
+ abbr,
+ _coinsRepository,
+ );
_activatingAssets = false;
if (activationErrors.isNotEmpty) {
@@ -638,20 +617,18 @@ class BridgeBloc extends Bloc {
bestOrders.forEach((key, value) => list.addAll(value));
- list.removeWhere(
- (order) {
- final Coin? item = _coinsRepository.getCoin(order.coin);
- if (item == null) return true;
+ list.removeWhere((order) {
+ final Coin? item = _coinsRepository.getCoin(order.coin);
+ if (item == null) return true;
- final sameTicker = abbr2Ticker(item.abbr) == abbr2Ticker(sellCoin.abbr);
- if (!sameTicker) return true;
+ final sameTicker = abbr2Ticker(item.abbr) == abbr2Ticker(sellCoin.abbr);
+ if (!sameTicker) return true;
- if (item.isSuspended) return true;
- if (item.walletOnly) return true;
+ if (item.isSuspended) return true;
+ if (item.walletOnly) return true;
- return false;
- },
- );
+ return false;
+ });
list.sort((a, b) => a.coin.compareTo(b.coin));
@@ -668,8 +645,12 @@ class BridgeBloc extends Bloc {
state.sellAmount,
);
} catch (e, s) {
- log(e.toString(),
- trace: s, path: 'bridge_bloc::_getFeesData', isError: true);
+ log(
+ e.toString(),
+ trace: s,
+ path: 'bridge_bloc::_getFeesData',
+ isError: true,
+ );
return DataFromService(error: TextError(error: 'Failed to request fees'));
}
}
diff --git a/lib/bloc/cex_market_data/mockup/generate_demo_data.dart b/lib/bloc/cex_market_data/mockup/generate_demo_data.dart
index c6d07d1a24..d6e466f803 100644
--- a/lib/bloc/cex_market_data/mockup/generate_demo_data.dart
+++ b/lib/bloc/cex_market_data/mockup/generate_demo_data.dart
@@ -1,22 +1,22 @@
import 'dart:math';
import 'package:decimal/decimal.dart';
-import 'package:komodo_cex_market_data/komodo_cex_market_data.dart';
+import 'package:komodo_defi_sdk/komodo_defi_sdk.dart';
import 'package:komodo_defi_types/komodo_defi_types.dart';
import 'package:uuid/uuid.dart';
import 'package:web_dex/bloc/cex_market_data/mockup/performance_mode.dart';
-// similar to generator implementation to allow for const constructor
-final _ohlcvCache = >{};
+// Cache for demo price history data
+final _priceHistoryCache = >{};
/// Generates semi-random transaction data for demo purposes. The transactions
-/// are generated based on the historical OHLCV data for the given coin. The
+/// are generated based on simulated historical price data for the given coin. The
/// transactions are generated in a way that the overall balance of the user
/// will increase or decrease based on the given performance mode.
class DemoDataGenerator {
- final CexRepository _ohlcRepo;
+ final KomodoDefiSdk _sdk;
final int randomSeed;
- final List coinPairs;
+ final List assetIds;
final Map transactionsPerMode;
final Map overallReturn;
final Map> buyProbabilities;
@@ -24,16 +24,9 @@ class DemoDataGenerator {
final double initialBalance;
const DemoDataGenerator(
- this._ohlcRepo, {
+ this._sdk, {
this.initialBalance = 1000.0,
- this.coinPairs = const [
- CexCoinPair.usdtPrice('KMD'),
- CexCoinPair.usdtPrice('LTC'),
- CexCoinPair.usdtPrice('MATIC'),
- CexCoinPair.usdtPrice('AVAX'),
- CexCoinPair.usdtPrice('FTM'),
- CexCoinPair.usdtPrice('ATOM'),
- ],
+ this.assetIds = const [], // Will be initialized with default list
this.transactionsPerMode = const {
PerformanceMode.good: 28,
PerformanceMode.mediocre: 52,
@@ -57,47 +50,118 @@ class DemoDataGenerator {
this.randomSeed = 42,
});
+ /// Default asset IDs for demo purposes
+ static final List defaultAssetIds = [
+ AssetId(
+ chainId: AssetChainId(chainId: 1),
+ derivationPath: '',
+ id: 'KMD',
+ name: 'Komodo',
+ subClass: CoinSubClass.smartChain,
+ symbol: AssetSymbol(assetConfigId: 'KMD'),
+ ),
+ AssetId(
+ chainId: AssetChainId(chainId: 2),
+ derivationPath: '',
+ id: 'LTC',
+ name: 'Litecoin',
+ subClass: CoinSubClass.smartChain,
+ symbol: AssetSymbol(assetConfigId: 'LTC'),
+ ),
+ AssetId(
+ chainId: AssetChainId(chainId: 137),
+ derivationPath: '',
+ id: 'MATIC',
+ name: 'Polygon',
+ subClass: CoinSubClass.matic,
+ symbol: AssetSymbol(assetConfigId: 'MATIC'),
+ ),
+ AssetId(
+ chainId: AssetChainId(chainId: 43114),
+ derivationPath: '',
+ id: 'AVAX',
+ name: 'Avalanche',
+ subClass: CoinSubClass.avx20,
+ symbol: AssetSymbol(assetConfigId: 'AVAX'),
+ ),
+ AssetId(
+ chainId: AssetChainId(chainId: 250),
+ derivationPath: '',
+ id: 'FTM',
+ name: 'Fantom',
+ subClass: CoinSubClass.ftm20,
+ symbol: AssetSymbol(assetConfigId: 'FTM'),
+ ),
+ AssetId(
+ chainId: AssetChainId(chainId: 118),
+ derivationPath: '',
+ id: 'ATOM',
+ name: 'Cosmos',
+ subClass: CoinSubClass.tendermint,
+ symbol: AssetSymbol(assetConfigId: 'ATOM'),
+ ),
+ ];
+
Future> generateTransactions(
String coinId,
PerformanceMode mode,
) async {
- if (_ohlcvCache.isEmpty) {
- _ohlcvCache.addAll(await fetchOhlcData());
+ if (_priceHistoryCache.isEmpty) {
+ await fetchPriceHistoryData();
}
- // Remove segwit suffix for cache key, as the ohlc data from cex providers
- // does not include the segwit suffix
- final cacheKey = coinId.replaceAll('-segwit', '');
- if (!_ohlcvCache.containsKey(CexCoinPair.usdtPrice(cacheKey))) {
+ // Try to match the coinId to one of our asset IDs
+ final actualAssetIds = assetIds.isEmpty ? defaultAssetIds : assetIds;
+ final assetId = actualAssetIds.cast().firstWhere(
+ (asset) =>
+ asset!.id.toLowerCase() == coinId.toLowerCase() ||
+ asset.symbol.assetConfigId.toLowerCase() == coinId.toLowerCase(),
+ orElse: () => null,
+ );
+
+ if (assetId == null || !_priceHistoryCache.containsKey(assetId)) {
return [];
}
- final ohlcvData = _ohlcvCache[CexCoinPair.usdtPrice(cacheKey)]!;
+
+ final priceHistory = _priceHistoryCache[assetId]!;
+ final priceEntries = priceHistory.entries.toList()
+ ..sort((a, b) => a.key.compareTo(b.key));
final numTransactions = transactionsPerMode[mode]!;
final random = Random(randomSeed);
- final buyProbalities = buyProbabilities[mode]!;
+ final buyProbabilities = this.buyProbabilities[mode]!;
final tradeAmounts = tradeAmountFactors[mode]!;
- double totalBalance = initialBalance / ohlcvData.last.close;
+
+ // Get the initial price for calculations
+ final initialPrice = priceEntries.first.value;
+ final finalPrice = priceEntries.last.value;
+ double totalBalance = initialBalance / initialPrice;
double targetFinalBalance =
- (initialBalance * overallReturn[mode]!) / ohlcvData.first.close;
+ (initialBalance * overallReturn[mode]!) / finalPrice;
List transactions = [];
for (int i = 0; i < numTransactions; i++) {
- final int index = (i * ohlcvData.length ~/ numTransactions)
- .clamp(0, ohlcvData.length - 1);
- final Ohlc ohlcv = ohlcvData[index];
+ final int index = (i * priceEntries.length ~/ numTransactions).clamp(
+ 0,
+ priceEntries.length - 1,
+ );
+ final priceEntry = priceEntries[index];
final int quarter = (i * 4 ~/ numTransactions).clamp(0, 3);
- final bool isBuy = random.nextDouble() < buyProbalities[quarter];
+ final bool isBuy = random.nextDouble() < buyProbabilities[quarter];
final bool isSameDay = random.nextDouble() < tradeAmounts[quarter];
final double tradeAmountFactor = tradeAmounts[quarter];
final double tradeAmount =
random.nextDouble() * tradeAmountFactor * totalBalance;
- final transaction =
- fromTradeAmount(coinId, tradeAmount, isBuy, ohlcv.closeTime);
+ final transaction = fromTradeAmount(
+ coinId,
+ tradeAmount,
+ isBuy,
+ priceEntry.key.millisecondsSinceEpoch,
+ );
transactions.add(transaction);
if (isSameDay) {
@@ -105,7 +169,7 @@ class DemoDataGenerator {
coinId,
-tradeAmount,
!isBuy,
- ohlcv.closeTime + 100,
+ priceEntry.key.millisecondsSinceEpoch + 100,
);
transactions.add(transaction);
}
@@ -131,8 +195,9 @@ class DemoDataGenerator {
double totalBalance,
List transactions,
) {
- final Decimal adjustmentFactor =
- Decimal.parse((targetFinalBalance / totalBalance).toString());
+ final Decimal adjustmentFactor = Decimal.parse(
+ (targetFinalBalance / totalBalance).toString(),
+ );
final adjustedTransactions = [];
for (var transaction in transactions) {
final netChange = transaction.balanceChanges.netChange;
@@ -154,33 +219,101 @@ class DemoDataGenerator {
return adjustedTransactions;
}
- Future