Updated on 2026-08-14

This commit is contained in:
Tangem 2025-01-27 12:51:42 +03:00
commit 6b7a309a37
17 changed files with 389 additions and 5 deletions

View file

@ -26,6 +26,7 @@ dependencies {
implementation(projects.domain.onramp)
implementation(projects.domain.legacy)
implementation(projects.domain.appTheme.models)
implementation(projects.domain.models)
// region DI

View file

@ -0,0 +1,41 @@
package com.tangem.data.onramp
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.data.onramp.converters.HotCryptoCurrencyConverter
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.onramp.repositories.HotCryptoRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
/**
* Default implementation of [HotCryptoRepository]
*
* @property excludedBlockchains excluded blockchains
* @property hotCryptoResponseStore store of `HotCryptoResponse`
* @property userWalletsStore store of `UserWallet`
*
[REDACTED_AUTHOR]
*/
internal class DefaultHotCryptoRepository(
private val excludedBlockchains: ExcludedBlockchains,
private val hotCryptoResponseStore: HotCryptoResponseStore,
private val userWalletsStore: UserWalletsStore,
) : HotCryptoRepository {
override fun getCurrencies(userWalletId: UserWalletId): Flow<List<HotCryptoCurrency>> {
return hotCryptoResponseStore.get()
.map {
val userWallet = userWalletsStore.getSyncOrNull(userWalletId)
?: error("UserWalletId [$userWalletId] not found")
HotCryptoCurrencyConverter(
scanResponse = userWallet.scanResponse,
imageHost = it.imageHost,
excludedBlockchains = excludedBlockchains,
).convertList(input = it.tokens)
}
}
}

View file

@ -0,0 +1,78 @@
package com.tangem.data.onramp.converters
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.data.common.currency.getNetwork
import com.tangem.datasource.api.tangemTech.models.HotCryptoResponse
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
import com.tangem.utils.converter.Converter
/**
* Converter from [HotCryptoResponse.Token] to [HotCryptoCurrency]
*
* @property scanResponse scan response
* @property imageHost image host
* @property excludedBlockchains excluded blockchains
*
[REDACTED_AUTHOR]
*/
internal class HotCryptoCurrencyConverter(
private val scanResponse: ScanResponse,
private val imageHost: String?,
private val excludedBlockchains: ExcludedBlockchains,
) : Converter<HotCryptoResponse.Token, HotCryptoCurrency> {
private val cryptoCurrencyFactory by lazy { CryptoCurrencyFactory(excludedBlockchains) }
override fun convert(value: HotCryptoResponse.Token): HotCryptoCurrency {
val network = createNetwork(value.networkId)
val contractAddress = value.contractAddress
val decimals = value.decimalCount
val currency = if (contractAddress != null && decimals != null) {
cryptoCurrencyFactory.createToken(
network = network,
rawId = value.id,
name = value.name,
symbol = value.symbol,
decimals = decimals,
contractAddress = contractAddress,
)
} else {
cryptoCurrencyFactory.createCoin(network = network)
}
return HotCryptoCurrency(
cryptoCurrency = currency.setupIconUrl(id = value.id),
fiatRate = value.currentPrice,
priceChange = value.priceChangePercentage,
)
}
private fun createNetwork(networkId: String): Network {
return requireNotNull(
getNetwork(
blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)),
extraDerivationPath = null,
scanResponse = scanResponse,
excludedBlockchains = excludedBlockchains,
),
)
}
private fun CryptoCurrency.setupIconUrl(id: String): CryptoCurrency {
imageHost ?: return this
val iconUrl = "${imageHost}large/$id.png"
return when (this) {
is CryptoCurrency.Coin -> copy(iconUrl = iconUrl)
is CryptoCurrency.Token -> copy(iconUrl = iconUrl)
}
}
}

View file

@ -1,6 +1,8 @@
package com.tangem.data.onramp.di
import com.squareup.moshi.Moshi
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.data.onramp.DefaultHotCryptoRepository
import com.tangem.data.onramp.DefaultOnrampErrorResolver
import com.tangem.data.onramp.DefaultOnrampRepository
import com.tangem.data.onramp.DefaultOnrampTransactionRepository
@ -10,12 +12,15 @@ import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
import com.tangem.datasource.api.onramp.OnrampApi
import com.tangem.datasource.crypto.DataSignatureVerifier
import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoResponseStore
import com.tangem.datasource.local.onramp.countries.OnrampCountriesStore
import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.onramp.repositories.HotCryptoRepository
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
import com.tangem.domain.onramp.repositories.OnrampRepository
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
@ -83,4 +88,18 @@ internal object OnrampDataModule {
OnrampErrorConverter(jsonAdapter),
)
}
@Provides
@Singleton
fun provideHotCryptoRepository(
excludedBlockchains: ExcludedBlockchains,
hotCryptoResponseStore: HotCryptoResponseStore,
userWalletsStore: UserWalletsStore,
): HotCryptoRepository {
return DefaultHotCryptoRepository(
excludedBlockchains = excludedBlockchains,
hotCryptoResponseStore = hotCryptoResponseStore,
userWalletsStore = userWalletsStore,
)
}
}

View file

@ -4,6 +4,7 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.data.common.cache.CacheRegistry
import com.tangem.data.tokens.repository.*
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoLoader
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.network.NetworksStatusesStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
@ -32,6 +33,7 @@ internal object TokensDataModule {
cacheRegistry: CacheRegistry,
dispatchers: CoroutineDispatcherProvider,
expressServiceLoader: ExpressServiceLoader,
hotCryptoLoader: HotCryptoLoader,
excludedBlockchains: ExcludedBlockchains,
): CurrenciesRepository {
return DefaultCurrenciesRepository(
@ -42,6 +44,7 @@ internal object TokensDataModule {
appPreferencesStore = appPreferencesStore,
dispatchers = dispatchers,
expressServiceLoader = expressServiceLoader,
hotCryptoLoader = hotCryptoLoader,
excludedBlockchains = excludedBlockchains,
)
}

View file

@ -15,6 +15,7 @@ import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRA
import com.tangem.datasource.api.express.models.request.LeastTokenInfo
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoLoader
import com.tangem.datasource.exchangeservice.swap.ExpressServiceLoader
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
@ -33,10 +34,8 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
import timber.log.Timber
import com.tangem.blockchain.common.FeePaidCurrency as FeePaidSdkCurrency
@ -48,6 +47,7 @@ internal class DefaultCurrenciesRepository(
private val cacheRegistry: CacheRegistry,
private val appPreferencesStore: AppPreferencesStore,
private val expressServiceLoader: ExpressServiceLoader,
private val hotCryptoLoader: HotCryptoLoader,
private val dispatchers: CoroutineDispatcherProvider,
excludedBlockchains: ExcludedBlockchains,
) : CurrenciesRepository {
@ -601,7 +601,11 @@ internal class DefaultCurrenciesRepository(
network = token.networkId,
)
}
expressServiceLoader.update(userWalletId, tokens)
coroutineScope {
launch { expressServiceLoader.update(userWalletId, tokens) }
launch { hotCryptoLoader.fetch(tokens = userTokens.tokens) }
}
}
private suspend fun fetchExpressAssetsByNetworkIds(
@ -619,7 +623,12 @@ internal class DefaultCurrenciesRepository(
cacheRegistry.invokeOnExpire(
key = getAssetsCacheKey(userWalletId),
skipCache = refresh,
block = { expressServiceLoader.update(userWalletId, tokens) },
block = {
coroutineScope {
launch { expressServiceLoader.update(userWalletId, tokens) }
launch { hotCryptoLoader.update(cryptoCurrencies) }
}
},
)
}