Updated on 2026-08-14
This commit is contained in:
parent
732452b611
commit
d92b32d25d
7 changed files with 71 additions and 92 deletions
|
|
@ -1,74 +0,0 @@
|
|||
package com.tangem.tap.domain
|
||||
|
||||
import com.tangem.common.services.Result
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.domain.common.ThrottlerWithValues
|
||||
import com.tangem.tap.features.wallet.models.Currency
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
|
||||
class RatesRepository(
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
private val throttler = ThrottlerWithValues<Currency, Result<BigDecimal>?>(60000)
|
||||
|
||||
suspend fun loadFiatRate(currencyId: String, coinsList: List<Currency>): Result<RatesResult> =
|
||||
withContext(dispatchers.io) {
|
||||
// get and submit previous result of equivalents.
|
||||
val throttledResult = coinsList.filter { throttler.isStillThrottled(it) }.map {
|
||||
Pair(it, throttler.geValue(it))
|
||||
}
|
||||
|
||||
val currenciesToUpdate = coinsList.filter { !throttler.isStillThrottled(it) }
|
||||
val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct()
|
||||
if (coinIds.isEmpty()) return@withContext handleFiatRatesResult(throttledResult.toMap())
|
||||
|
||||
runCatching { tangemTechApi.getRates(currencyId.lowercase(), coinIds.joinToString(",")) }
|
||||
.onSuccess { response ->
|
||||
val ratesResultList: Map<String, Result<BigDecimal>> = response.rates.mapValues {
|
||||
Result.Success(it.value.toBigDecimal())
|
||||
}
|
||||
val updatedCurrencies = throttledResult.toMap().toMutableMap()
|
||||
coinsList.forEach { currency ->
|
||||
ratesResultList[currency.coinId]?.let {
|
||||
updatedCurrencies[currency] = it
|
||||
throttler.updateThrottlingTo(currency)
|
||||
throttler.setValue(currency, it)
|
||||
}
|
||||
}
|
||||
return@withContext handleFiatRatesResult(updatedCurrencies)
|
||||
}
|
||||
.onFailure { Result.Failure(it) }
|
||||
|
||||
error("Unreachable code because runCatching must return result")
|
||||
}
|
||||
|
||||
private fun handleFiatRatesResult(rates: Map<Currency, Result<BigDecimal>?>): Result.Success<RatesResult> {
|
||||
val success = mutableMapOf<Currency, BigDecimal>()
|
||||
val failures = mutableMapOf<Currency, Throwable>()
|
||||
|
||||
rates.mapNotNull { (currency, priceResult) ->
|
||||
when (priceResult) {
|
||||
is Result.Success -> success[currency] = priceResult.data
|
||||
is Result.Failure -> failures[currency] = priceResult.error
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success(success to failures)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
throttler.clear()
|
||||
}
|
||||
}
|
||||
|
||||
typealias RatesResult = Pair<MutableMap<Currency, BigDecimal>, MutableMap<Currency, Throwable>>
|
||||
|
||||
val RatesResult.loadedRates
|
||||
get() = this.first
|
||||
|
||||
val RatesResult.failedRates
|
||||
get() = this.second
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
},
|
||||
{
|
||||
"name": "REDESIGNED_WALLET_SCREEN_ENABLED",
|
||||
"version": "undefined"
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "1INCH_LEARN_2_EARN_ENABLED",
|
||||
|
|
@ -21,10 +21,10 @@
|
|||
},
|
||||
{
|
||||
"name": "REDESIGNED_APP_CURRENCY_SELECTOR_ENABLED",
|
||||
"version": "undefined"
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "DARK_THEME_ENABLED",
|
||||
"version": "undefined"
|
||||
"version": "1.0.0"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -51,19 +51,14 @@ fun getActiveIconRes(blockchainId: String): Int {
|
|||
|
||||
@Suppress("ComplexMethod")
|
||||
@DrawableRes
|
||||
fun getActiveIconResByCoinId(coinId: String, networkId: String): Int {
|
||||
fun getActiveIconResByCoinId(coinId: String): Int {
|
||||
return when (coinId) {
|
||||
"binancecoin" -> R.drawable.img_bsc_22
|
||||
"bitcoin" -> R.drawable.img_btc_22
|
||||
"bitcoin-cash" -> R.drawable.img_btc_cash_22
|
||||
"ethereum" -> {
|
||||
when (networkId) {
|
||||
"ethereum" -> R.drawable.img_eth_22
|
||||
"arbitrum-one" -> R.drawable.img_arbitrum_22
|
||||
"optimistic-ethereum" -> R.drawable.img_optimism_22
|
||||
else -> R.drawable.ic_alert_24
|
||||
}
|
||||
}
|
||||
"ethereum" -> R.drawable.img_eth_22
|
||||
"arbitrum-one" -> R.drawable.img_arbitrum_22
|
||||
"optimistic-ethereum" -> R.drawable.img_optimism_22
|
||||
"ethereum-classic" -> R.drawable.img_eth_classic_22
|
||||
"stellar" -> R.drawable.img_stellar_22
|
||||
"cardano" -> R.drawable.img_cardano_22
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.tokens.repository
|
|||
import com.tangem.data.common.api.safeApiCall
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.tokens.utils.QuotesConverter
|
||||
import com.tangem.data.tokens.utils.QuotesUnsupportedCurrenciesIdAdapter
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.appcurrency.SelectedAppCurrencyStore
|
||||
import com.tangem.datasource.local.quote.QuotesStore
|
||||
|
|
@ -23,6 +24,7 @@ internal class DefaultQuotesRepository(
|
|||
) : QuotesRepository {
|
||||
|
||||
private val quotesConverter = QuotesConverter()
|
||||
private val quotesUnsupportedCurrenciesAdapter = QuotesUnsupportedCurrenciesIdAdapter()
|
||||
|
||||
@Volatile
|
||||
private var quotesFetchedForAppCurrency: String? = null
|
||||
|
|
@ -71,9 +73,10 @@ internal class DefaultQuotesRepository(
|
|||
}
|
||||
|
||||
private suspend fun fetchQuotes(rawCurrenciesIds: Set<String>, appCurrencyId: String) {
|
||||
val replacementIdsResult = quotesUnsupportedCurrenciesAdapter.replaceUnsupportedCurrencies(rawCurrenciesIds)
|
||||
val response = safeApiCall(
|
||||
call = {
|
||||
val coinIds = rawCurrenciesIds.joinToString(separator = ",")
|
||||
val coinIds = replacementIdsResult.idsForRequest.joinToString(separator = ",")
|
||||
tangemTechApi.getQuotes(appCurrencyId, coinIds).bind()
|
||||
},
|
||||
onError = {
|
||||
|
|
@ -83,7 +86,11 @@ internal class DefaultQuotesRepository(
|
|||
)
|
||||
|
||||
if (response != null) {
|
||||
quotesStore.store(response)
|
||||
val updatedResponse = quotesUnsupportedCurrenciesAdapter.getResponseWithUnsupportedCurrencies(
|
||||
response,
|
||||
replacementIdsResult.idsFiltered,
|
||||
)
|
||||
quotesStore.store(updatedResponse)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.tangem.data.tokens.utils
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.QuotesResponse
|
||||
|
||||
/**
|
||||
* Adapter to replace unsupported currencies for quotes request if it necessary
|
||||
*/
|
||||
class QuotesUnsupportedCurrenciesIdAdapter {
|
||||
|
||||
/**
|
||||
* Replaces unsupported currencies id to it replacements for request
|
||||
*/
|
||||
fun replaceUnsupportedCurrencies(currenciesIds: Set<String>): ReplacementResult {
|
||||
val idsForRequest = mutableSetOf<String>()
|
||||
val idsFiltered = mutableSetOf<String>()
|
||||
currenciesIds.forEach { currencyId ->
|
||||
unsupportedMapWithReplacement[currencyId]?.let {
|
||||
idsFiltered.add(currencyId)
|
||||
idsForRequest.add(it)
|
||||
} ?: idsForRequest.add(currencyId)
|
||||
}
|
||||
return ReplacementResult(idsForRequest = idsForRequest, idsFiltered = idsFiltered)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover previously replaced currencies to response that uses in application
|
||||
*/
|
||||
fun getResponseWithUnsupportedCurrencies(response: QuotesResponse, filteredIds: Set<String>): QuotesResponse {
|
||||
val updatedQuotes = mutableMapOf<String, QuotesResponse.Quote>()
|
||||
filteredIds.forEach { filteredId ->
|
||||
unsupportedMapWithReplacement[filteredId]?.let { baseId ->
|
||||
response.quotes[baseId]?.let { quote ->
|
||||
updatedQuotes[filteredId] = quote
|
||||
}
|
||||
}
|
||||
}
|
||||
return response.copy(quotes = updatedQuotes + response.quotes)
|
||||
}
|
||||
|
||||
data class ReplacementResult(val idsForRequest: Set<String>, val idsFiltered: Set<String>)
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Map that contains unsupported currencies and their replacement for request
|
||||
*/
|
||||
private val unsupportedMapWithReplacement = mapOf(
|
||||
"optimistic-ethereum" to "ethereum",
|
||||
"arbitrum-one" to "ethereum",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ fun Blockchain.toCoinId(): String {
|
|||
Blockchain.Stellar, Blockchain.StellarTestnet -> "stellar"
|
||||
Blockchain.Cardano -> "cardano"
|
||||
Blockchain.Polygon, Blockchain.PolygonTestnet -> "matic-network"
|
||||
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> "ethereum"
|
||||
Blockchain.Arbitrum, Blockchain.ArbitrumTestnet -> "arbitrum-one"
|
||||
Blockchain.Avalanche, Blockchain.AvalancheTestnet -> "avalanche-2"
|
||||
Blockchain.Solana, Blockchain.SolanaTestnet -> "solana"
|
||||
Blockchain.Fantom, Blockchain.FantomTestnet -> "fantom"
|
||||
|
|
@ -175,7 +175,7 @@ fun Blockchain.toCoinId(): String {
|
|||
Blockchain.EthereumPow, Blockchain.EthereumPowTestnet -> "ethereum-pow-iou"
|
||||
Blockchain.EthereumFair -> "ethereumfair"
|
||||
Blockchain.Kusama -> "kusama"
|
||||
Blockchain.Optimism, Blockchain.OptimismTestnet -> "ethereum"
|
||||
Blockchain.Optimism, Blockchain.OptimismTestnet -> "optimistic-ethereum"
|
||||
Blockchain.Dash -> "dash"
|
||||
Blockchain.Kaspa -> "kaspa"
|
||||
Blockchain.TON, Blockchain.TONTestnet -> "the-open-network"
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ private fun MainInfo(state: SwapStateHolder) {
|
|||
priceImpact = priceImpactWarning,
|
||||
networkIconRes = if (state.sendCardData.isNotNativeToken) networkIconRes else null,
|
||||
iconPlaceholder = state.sendCardData.coinId?.let {
|
||||
getActiveIconResByCoinId(it, state.networkId)
|
||||
getActiveIconResByCoinId(it)
|
||||
},
|
||||
onChangeTokenClick = if (state.sendCardData.canSelectAnotherToken) state.onSelectTokenClick else null,
|
||||
modifier = Modifier.constrainAs(topCard) {
|
||||
|
|
@ -174,7 +174,7 @@ private fun MainInfo(state: SwapStateHolder) {
|
|||
priceImpact = priceImpactWarning,
|
||||
networkIconRes = if (state.receiveCardData.isNotNativeToken) networkIconRes else null,
|
||||
iconPlaceholder = state.receiveCardData.coinId?.let {
|
||||
getActiveIconResByCoinId(it, state.networkId)
|
||||
getActiveIconResByCoinId(it)
|
||||
},
|
||||
onChangeTokenClick = if (state.receiveCardData.canSelectAnotherToken) {
|
||||
state.onSelectTokenClick
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue