From ff2d8f3f02132679dc5de509f0ecc099686a0620 Mon Sep 17 00:00:00 2001 From: Francois Date: Thu, 17 Jul 2025 12:47:26 +0200 Subject: [PATCH 1/3] fix(market-data-manager): default to KomodoPriceRepository Binance CexRepository supports a limited number of symbols and no longer lists KMD price history after the delisting --- .../src/market_data/market_data_manager.dart | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart index 2bb6fdb6..d359db86 100644 --- a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart +++ b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart @@ -143,7 +143,16 @@ class CexMarketDataManager implements MarketDataManager { fiatCurrency: fiatCurrency, ); - return _priceCache[cacheKey]; + // Check cache first + final cachedPrice = _priceCache[cacheKey]; + if (cachedPrice != null) { + return cachedPrice; + } + + // For synchronous method, we can only check if we have cached data + // from KomodoPriceRepository (which would have been populated by previous calls) + // The actual fetching from KomodoPriceRepository happens asynchronously in other methods + return null; } @override @@ -170,6 +179,29 @@ class CexMarketDataManager implements MarketDataManager { } try { + // First try to get price from KomodoPriceRepository if no specific date is requested + // and the currency is USDT (which is essentially USD for Komodo prices) + if (priceDate == null && + (fiatCurrency.toLowerCase() == 'usdt' || + fiatCurrency.toLowerCase() == 'usd')) { + try { + final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); + final priceData = komodoPrices[_getTradingSymbol(assetId)]; + + if (priceData != null && priceData.price > 0) { + final price = Decimal.parse(priceData.price.toString()); + + // Cache the result + _priceCache[cacheKey] = price; + + return price; + } + } catch (_) { + // If KomodoPriceRepository fails, continue to fallback + } + } + + // Fallback to the original repository final priceDouble = await _priceRepository.getCoinFiatPrice( _getTradingSymbol(assetId), priceDate: priceDate, @@ -208,6 +240,29 @@ class CexMarketDataManager implements MarketDataManager { return cachedPrice; } + // First try to get price from KomodoPriceRepository if no specific date is requested + // and the currency is USDT (which is essentially USD for Komodo prices) + if (priceDate == null && + (fiatCurrency.toLowerCase() == 'usdt' || + fiatCurrency.toLowerCase() == 'usd')) { + try { + final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); + final priceData = komodoPrices[_getTradingSymbol(assetId)]; + + if (priceData != null && priceData.price > 0) { + final price = Decimal.parse(priceData.price.toString()); + + // Cache the result + _priceCache[cacheKey] = price; + + return price; + } + } catch (_) { + // If KomodoPriceRepository fails, continue to fallback + } + } + + // Fallback to the original CEX repository logic final tradingSymbol = _getTradingSymbol(assetId); final isKnownTicker = _knownTickers?.contains(tradingSymbol) ?? false; From db2a5fc2a7765efc433982c7a65f650149e70eef Mon Sep 17 00:00:00 2001 From: Francois Date: Fri, 1 Aug 2025 17:03:05 +0200 Subject: [PATCH 2/3] refactor(market-data-manager): deduplicate and clarify intent --- .../src/market_data/market_data_manager.dart | 158 ++++++++++-------- 1 file changed, 88 insertions(+), 70 deletions(-) diff --git a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart index d359db86..db3879a7 100644 --- a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart +++ b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart @@ -127,6 +127,65 @@ class CexMarketDataManager implements MarketDataManager { return assetId.symbol.configSymbol; } + /// Determines if the request can be handled by Komodo price repository + /// NOTE: currently only supports USDT and USD fiat currencies + /// and does not support specific price dates (always uses current price) + bool _canUseKomodoRepository({ + DateTime? priceDate, + String fiatCurrency = 'usdt', + }) { + return priceDate == null && + (fiatCurrency.toLowerCase() == 'usdt' || + fiatCurrency.toLowerCase() == 'usd'); + } + + /// Attempts to get price from Komodo repository + Future _tryKomodoPrice(String symbol) async { + try { + final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); + final priceData = komodoPrices[symbol]; + + if (priceData != null && priceData.price > 0) { + return Decimal.parse(priceData.price.toString()); + } + } catch (_) { + // Ignore errors and fall back + } + return null; + } + + /// Gets price with automatic fallback logic + Future _getPriceWithFallback( + AssetId assetId, { + DateTime? priceDate, + String fiatCurrency = 'usdt', + }) async { + final symbol = _getTradingSymbol(assetId); + + // Try Komodo repository first if applicable + if (_canUseKomodoRepository( + priceDate: priceDate, + fiatCurrency: fiatCurrency, + )) { + final komodoPrice = await _tryKomodoPrice(symbol); + if (komodoPrice != null) { + return komodoPrice; + } + } + + // Fallback to CEX repository + try { + final priceDouble = await _priceRepository.getCoinFiatPrice( + symbol, + priceDate: priceDate, + fiatCoinId: fiatCurrency, + ); + return Decimal.parse(priceDouble.toString()); + } catch (_) { + return null; + } + } + @override Decimal? priceIfKnown( AssetId assetId, { @@ -178,46 +237,20 @@ class CexMarketDataManager implements MarketDataManager { return cachedPrice; } - try { - // First try to get price from KomodoPriceRepository if no specific date is requested - // and the currency is USDT (which is essentially USD for Komodo prices) - if (priceDate == null && - (fiatCurrency.toLowerCase() == 'usdt' || - fiatCurrency.toLowerCase() == 'usd')) { - try { - final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); - final priceData = komodoPrices[_getTradingSymbol(assetId)]; - - if (priceData != null && priceData.price > 0) { - final price = Decimal.parse(priceData.price.toString()); - - // Cache the result - _priceCache[cacheKey] = price; - - return price; - } - } catch (_) { - // If KomodoPriceRepository fails, continue to fallback - } - } - - // Fallback to the original repository - final priceDouble = await _priceRepository.getCoinFiatPrice( - _getTradingSymbol(assetId), - priceDate: priceDate, - fiatCoinId: fiatCurrency, - ); + final price = await _getPriceWithFallback( + assetId, + priceDate: priceDate, + fiatCurrency: fiatCurrency, + ); - // Convert double to Decimal via string - final price = Decimal.parse(priceDouble.toString()); + if (price == null) { + throw StateError('Failed to get price for ${assetId.name}'); + } - // Cache the result - _priceCache[cacheKey] = price; + // Cache the result + _priceCache[cacheKey] = price; - return price; - } catch (e) { - throw StateError('Failed to get price for ${assetId.name}: $e'); - } + return price; } @override @@ -240,46 +273,31 @@ class CexMarketDataManager implements MarketDataManager { return cachedPrice; } - // First try to get price from KomodoPriceRepository if no specific date is requested - // and the currency is USDT (which is essentially USD for Komodo prices) - if (priceDate == null && - (fiatCurrency.toLowerCase() == 'usdt' || - fiatCurrency.toLowerCase() == 'usd')) { - try { - final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); - final priceData = komodoPrices[_getTradingSymbol(assetId)]; - - if (priceData != null && priceData.price > 0) { - final price = Decimal.parse(priceData.price.toString()); - - // Cache the result - _priceCache[cacheKey] = price; - - return price; - } - } catch (_) { - // If KomodoPriceRepository fails, continue to fallback - } - } - - // Fallback to the original CEX repository logic + // Check if ticker is known in CEX repository for fallback scenarios final tradingSymbol = _getTradingSymbol(assetId); final isKnownTicker = _knownTickers?.contains(tradingSymbol) ?? false; - if (!isKnownTicker) { + // If not using Komodo repository and ticker is not known in CEX, return null + if (!_canUseKomodoRepository( + priceDate: priceDate, + fiatCurrency: fiatCurrency, + ) && + !isKnownTicker) { return null; } - try { - final price = await fiatPrice( - assetId, - priceDate: priceDate, - fiatCurrency: fiatCurrency, - ); - return price; - } catch (_) { - return null; + final price = await _getPriceWithFallback( + assetId, + priceDate: priceDate, + fiatCurrency: fiatCurrency, + ); + + if (price != null) { + // Cache the result + _priceCache[cacheKey] = price; } + + return price; } @override From 7d5b9480462f0029ce0355ca27e6b81920f2985d Mon Sep 17 00:00:00 2001 From: Francois Date: Fri, 1 Aug 2025 17:33:24 +0200 Subject: [PATCH 3/3] refactor(review): remove zero check and add log statements also simplify the priceIfKnown function --- .../src/market_data/market_data_manager.dart | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart index db3879a7..9c43d5bf 100644 --- a/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart +++ b/packages/komodo_defi_sdk/lib/src/market_data/market_data_manager.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:collection'; +import 'dart:developer'; import 'package:decimal/decimal.dart'; import 'package:komodo_cex_market_data/komodo_cex_market_data.dart'; @@ -145,10 +146,14 @@ class CexMarketDataManager implements MarketDataManager { final komodoPrices = await _komodoPriceRepository.getKomodoPrices(); final priceData = komodoPrices[symbol]; - if (priceData != null && priceData.price > 0) { + if (priceData != null) { return Decimal.parse(priceData.price.toString()); } - } catch (_) { + } catch (e) { + log( + 'Failed to get price from Komodo repository for symbol: $symbol', + error: e, + ); // Ignore errors and fall back } return null; @@ -181,7 +186,11 @@ class CexMarketDataManager implements MarketDataManager { fiatCoinId: fiatCurrency, ); return Decimal.parse(priceDouble.toString()); - } catch (_) { + } catch (e) { + log( + 'Failed to get price from Cex Repository for symbol $symbol', + error: e, + ); return null; } } @@ -203,15 +212,7 @@ class CexMarketDataManager implements MarketDataManager { ); // Check cache first - final cachedPrice = _priceCache[cacheKey]; - if (cachedPrice != null) { - return cachedPrice; - } - - // For synchronous method, we can only check if we have cached data - // from KomodoPriceRepository (which would have been populated by previous calls) - // The actual fetching from KomodoPriceRepository happens asynchronously in other methods - return null; + return _priceCache[cacheKey]; } @override