diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index f6252946fb..e61ff4a8d6 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -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, ) } diff --git a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt index 045c5f948e..8617e45745 100644 --- a/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt +++ b/app/src/main/java/com/tangem/tap/network/exchangeServices/DefaultRampManager.kt @@ -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, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/Asset.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/Asset.kt index 87f83ea98f..a4de3fcb40 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/Asset.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/Asset.kt @@ -11,4 +11,7 @@ data class Asset( @Json(name = "exchangeAvailable") val exchangeAvailable: Boolean, + + @Json(name = "onrampAvailable") + val onrampAvailable: Boolean?, ) \ No newline at end of file diff --git a/core/datasource/src/test/kotlin/com/tangem/datasource/asset/loader/AssetLoaderTest.kt b/core/datasource/src/test/kotlin/com/tangem/datasource/asset/loader/AssetLoaderTest.kt index 529f1271a9..49924b9fe8 100644 --- a/core/datasource/src/test/kotlin/com/tangem/datasource/asset/loader/AssetLoaderTest.kt +++ b/core/datasource/src/test/kotlin/com/tangem/datasource/asset/loader/AssetLoaderTest.kt @@ -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() diff --git a/domain/legacy/src/main/java/com/tangem/domain/exchange/RampStateManager.kt b/domain/legacy/src/main/java/com/tangem/domain/exchange/RampStateManager.kt index 9aacb2358c..8e4928a02d 100644 --- a/domain/legacy/src/main/java/com/tangem/domain/exchange/RampStateManager.kt +++ b/domain/legacy/src/main/java/com/tangem/domain/exchange/RampStateManager.kt @@ -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 diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt index 6d668d1e97..5b6491d0de 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetCryptoCurrencyActionsUseCase.kt @@ -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( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt index 4df19b9727..6586f193f7 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt @@ -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)