Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-02 17:55:23 +05:00
parent f7842bdaf3
commit 9315fd5b15
7 changed files with 58 additions and 18 deletions

View file

@ -2,6 +2,7 @@ package com.tangem.tap.di
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.datasource.exchangeservice.swap.SwapServiceLoader
import com.tangem.datasource.local.token.ExpressAssetsStore
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.exchange.RampStateManager
@ -10,6 +11,7 @@ import com.tangem.domain.tokens.GetPolkadotCheckHasImmortalUseCase
import com.tangem.domain.tokens.GetPolkadotCheckHasResetUseCase
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
import com.tangem.features.onramp.OnrampFeatureToggles
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
import com.tangem.tap.network.exchangeServices.DefaultRampManager
@ -52,6 +54,8 @@ internal object ActivityModule {
getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
excludedBlockchains: ExcludedBlockchains,
dispatchers: CoroutineDispatcherProvider,
onrampFeatureToggles: OnrampFeatureToggles,
expressAssetsStore: ExpressAssetsStore,
): RampStateManager {
return DefaultRampManager(
exchangeService = appStateHolder.exchangeService,
@ -62,6 +66,8 @@ internal object ActivityModule {
getNetworkCoinStatusUseCase = getNetworkCoinStatusUseCase,
excludedBlockchains = excludedBlockchains,
dispatchers = dispatchers,
onrampFeatureToggles = onrampFeatureToggles,
expressAssetsStore = expressAssetsStore,
)
}

View file

@ -2,7 +2,9 @@ package com.tangem.tap.network.exchangeServices
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.datasource.api.express.models.TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
import com.tangem.datasource.api.express.models.response.Asset
import com.tangem.datasource.exchangeservice.swap.SwapServiceLoader
import com.tangem.datasource.local.token.ExpressAssetsStore
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
@ -11,6 +13,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.features.onramp.OnrampFeatureToggles
import com.tangem.utils.Provider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.isNullOrZero
@ -26,6 +29,8 @@ internal class DefaultRampManager(
private val currenciesRepository: CurrenciesRepository,
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
private val dispatchers: CoroutineDispatcherProvider,
private val onrampFeatureToggles: OnrampFeatureToggles,
private val expressAssetsStore: ExpressAssetsStore,
excludedBlockchains: ExcludedBlockchains,
) : RampStateManager {
@ -37,11 +42,19 @@ internal class DefaultRampManager(
) ?: false
}
override fun availableForBuy(scanResponse: ScanResponse, cryptoCurrency: CryptoCurrency): Boolean {
return exchangeService?.availableForBuy(
scanResponse = scanResponse,
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
) ?: false
override suspend fun availableForBuy(
scanResponse: ScanResponse,
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): Boolean {
return when {
onrampFeatureToggles.isFeatureEnabled -> getOnrampAvailable(userWalletId, cryptoCurrency)
exchangeService != null -> exchangeService.availableForBuy(
scanResponse = scanResponse,
currency = cryptoCurrencyConverter.convertBack(cryptoCurrency),
)
else -> false
}
}
override suspend fun availableForSell(userWalletId: UserWalletId, status: CryptoCurrencyStatus): Boolean {
@ -84,18 +97,26 @@ internal class DefaultRampManager(
private suspend fun getExchangeableFlag(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean {
return withContext(dispatchers.io) {
val contractAddress = (cryptoCurrency as? CryptoCurrency.Token)?.contractAddress
?: EMPTY_CONTRACT_ADDRESS_VALUE
val asset = swapServiceLoader.getInitializationStatus(userWalletId).value.getOrNull()?.find {
it.network == cryptoCurrency.network.backendId &&
it.contractAddress.equals(contractAddress, ignoreCase = true)
}
val asset = swapServiceLoader.getInitializationStatus(userWalletId)
.value
.getOrNull()
?.find { cryptoCurrency.findAssetPredicate(it) }
asset?.exchangeAvailable ?: false
}
}
private suspend fun getOnrampAvailable(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): Boolean {
val asset = expressAssetsStore.getSyncOrNull(userWalletId)?.find { cryptoCurrency.findAssetPredicate(it) }
return asset?.onrampAvailable ?: false
}
private fun CryptoCurrency.findAssetPredicate(asset: Asset): Boolean {
val contractAddress = (this as? CryptoCurrency.Token)?.contractAddress ?: EMPTY_CONTRACT_ADDRESS_VALUE
return asset.network == network.backendId && asset.contractAddress.equals(contractAddress, ignoreCase = true)
}
private suspend fun getSendUnavailabilityReason(
userWalletId: UserWalletId,
cryptoCurrencyStatus: CryptoCurrencyStatus,

View file

@ -11,4 +11,7 @@ data class Asset(
@Json(name = "exchangeAvailable")
val exchangeAvailable: Boolean,
@Json(name = "onrampAvailable")
val onrampAvailable: Boolean?,
)

View file

@ -90,6 +90,7 @@ class AssetLoaderTest {
contractAddress = "0x0000000000000000000000000000000000000000",
network = "Network",
exchangeAvailable = true,
onrampAvailable = true,
)
val assetList = listOf(assetObject, assetObject)
@ -100,7 +101,8 @@ class AssetLoaderTest {
{
"contractAddress": "${assetObject.contractAddress}",
"network": "${assetObject.network}",
"exchangeAvailable": ${assetObject.exchangeAvailable}
"exchangeAvailable": ${assetObject.exchangeAvailable},
"onrampAvailable": ${assetObject.onrampAvailable}
}
""".trimIndent()

View file

@ -15,7 +15,11 @@ interface RampStateManager {
/** Check if sell service is supported for given [CryptoCurrency] */
fun isSellSupportedByService(cryptoCurrency: CryptoCurrency): Boolean
fun availableForBuy(scanResponse: ScanResponse, cryptoCurrency: CryptoCurrency): Boolean
suspend fun availableForBuy(
scanResponse: ScanResponse,
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): Boolean
/**
* Check if [CryptoCurrency] is available for sell

View file

@ -180,7 +180,7 @@ class GetCryptoCurrencyActionsUseCase(
}
// buy
if (rampManager.availableForBuy(userWallet.scanResponse, cryptoCurrency)) {
if (rampManager.availableForBuy(userWallet.scanResponse, userWallet.walletId, cryptoCurrency)) {
activeList.add(TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None))
} else {
disabledList.add(
@ -233,7 +233,7 @@ class GetCryptoCurrencyActionsUseCase(
return activeList + disabledList
}
private fun getActionsForUnreachableCurrency(
private suspend fun getActionsForUnreachableCurrency(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
needAssociateAsset: Boolean,
@ -243,7 +243,7 @@ class GetCryptoCurrencyActionsUseCase(
if (isAddressAvailable(cryptoCurrencyStatus.value.networkAddress)) {
actionsList.add(TokenActionsState.ActionState.CopyAddress(ScenarioUnavailabilityReason.None))
}
if (rampManager.availableForBuy(userWallet.scanResponse, cryptoCurrencyStatus.currency)) {
if (rampManager.availableForBuy(userWallet.scanResponse, userWallet.walletId, cryptoCurrencyStatus.currency)) {
actionsList.add(TokenActionsState.ActionState.Buy(ScenarioUnavailabilityReason.None))
} else {
actionsList.add(

View file

@ -148,7 +148,11 @@ internal class OnrampTokenListModel @Inject constructor(
private suspend fun checkAvailabilityByOperation(status: CryptoCurrencyStatus): Boolean {
return when (params.filterOperation) {
OnrampOperation.BUY -> {
rampStateManager.availableForBuy(scanResponse = scanResponse, cryptoCurrency = status.currency)
rampStateManager.availableForBuy(
scanResponse = scanResponse,
userWalletId = params.userWalletId,
cryptoCurrency = status.currency,
)
}
OnrampOperation.SELL -> {
rampStateManager.availableForSell(userWalletId = params.userWalletId, status = status)