Updated on 2026-08-14
This commit is contained in:
parent
73832d3e8e
commit
867d9fd735
9 changed files with 66 additions and 79 deletions
|
|
@ -18,6 +18,7 @@ import com.tangem.domain.tokens.GetNetworkCoinStatusUseCase
|
|||
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.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -55,7 +56,7 @@ internal class DefaultRampManager(
|
|||
}
|
||||
|
||||
override suspend fun availableForSell(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
status: CryptoCurrencyStatus,
|
||||
): Either<ScenarioUnavailabilityReason, Unit> {
|
||||
return either {
|
||||
|
|
@ -68,7 +69,7 @@ internal class DefaultRampManager(
|
|||
catch = { raise(ScenarioUnavailabilityReason.NotSupportedBySellService(status.currency.name)) },
|
||||
)
|
||||
|
||||
val reason = getSendUnavailabilityReason(userWalletId, status)
|
||||
val reason = getSendUnavailabilityReason(userWallet = userWallet, cryptoCurrencyStatus = status)
|
||||
|
||||
ensure(condition = reason is ScenarioUnavailabilityReason.None) {
|
||||
when (reason) {
|
||||
|
|
@ -205,14 +206,13 @@ internal class DefaultRampManager(
|
|||
}
|
||||
|
||||
private suspend fun getSendUnavailabilityReason(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): ScenarioUnavailabilityReason {
|
||||
val coinStatus = getNetworkCoinStatusUseCase.invokeSync(
|
||||
userWalletId = userWalletId,
|
||||
userWallet = userWallet,
|
||||
networkId = cryptoCurrencyStatus.currency.network.id,
|
||||
derivationPath = cryptoCurrencyStatus.currency.network.derivationPath,
|
||||
isSingleWalletWithTokens = false,
|
||||
).getOrNull()
|
||||
|
||||
return when {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Common implementation of network status fetcher
|
||||
|
|
@ -24,6 +25,7 @@ import javax.inject.Inject
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Singleton
|
||||
internal class CommonNetworkStatusFetcher @Inject constructor(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val networksStatusesStore: NetworksStatusesStore,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.scan.ScanResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -23,11 +24,11 @@ interface RampStateManager {
|
|||
/**
|
||||
* Check if [CryptoCurrency] is available for sell
|
||||
*
|
||||
* @param userWalletId id of multi-currency wallet
|
||||
* @param userWallet user wallet
|
||||
* @param status crypto currency status
|
||||
*/
|
||||
suspend fun availableForSell(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
status: CryptoCurrencyStatus,
|
||||
): Either<ScenarioUnavailabilityReason, Unit>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.Either
|
|||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
|
|
@ -51,17 +52,18 @@ class FetchCurrencyStatusUseCase(
|
|||
return either {
|
||||
val currency = getCurrency(userWalletId, id)
|
||||
|
||||
coroutineScope {
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId, currency.network)
|
||||
}
|
||||
val fetchQuote = async {
|
||||
fetchQuote(currency.id)
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
val fetchStakingBalance = async {
|
||||
fetchStakingBalance(userWalletId, currency, refresh)
|
||||
fetchStakingBalance(userWalletId = userWalletId, cryptoCurrency = currency, refresh = refresh)
|
||||
}
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance)
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -80,14 +82,14 @@ class FetchCurrencyStatusUseCase(
|
|||
return either {
|
||||
val currency = getPrimaryCurrency(userWalletId, refresh)
|
||||
|
||||
coroutineScope {
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId, currency.network)
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
val fetchQuote = async {
|
||||
fetchQuote(currency.id)
|
||||
}
|
||||
awaitAll(fetchStatus, fetchQuote)
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,9 +99,7 @@ class FetchCurrencyStatusUseCase(
|
|||
id: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return catch(
|
||||
block = {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, id)
|
||||
},
|
||||
block = { currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = id) },
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
|
|
@ -114,31 +114,27 @@ class FetchCurrencyStatusUseCase(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchNetworkStatus(userWalletId: UserWalletId, network: Network) {
|
||||
singleNetworkStatusFetcher(
|
||||
private suspend fun fetchNetworkStatus(userWalletId: UserWalletId, network: Network): Either<Throwable, Unit> {
|
||||
return singleNetworkStatusFetcher(
|
||||
params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.mapLeft { CurrencyStatusError.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchQuote(currencyId: CryptoCurrency.ID) {
|
||||
multiQuoteFetcher(
|
||||
private suspend fun fetchQuote(currencyId: CryptoCurrency.ID): Either<Throwable, Unit> {
|
||||
return multiQuoteFetcher(
|
||||
params = MultiQuoteFetcher.Params(
|
||||
currenciesIds = setOfNotNull(currencyId.rawCurrencyId),
|
||||
appCurrencyId = null,
|
||||
),
|
||||
)
|
||||
.mapLeft { CurrencyStatusError.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.fetchStakingBalance(
|
||||
private suspend fun fetchStakingBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
refresh: Boolean,
|
||||
) {
|
||||
if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
): Either<Throwable, Unit> {
|
||||
return if (tokensFeatureToggles.isStakingLoadingRefactoringEnabled) {
|
||||
singleYieldBalanceFetcher(
|
||||
params = SingleYieldBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -147,11 +143,11 @@ class FetchCurrencyStatusUseCase(
|
|||
),
|
||||
)
|
||||
} else {
|
||||
catch(
|
||||
block = { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) },
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
Either.catch { stakingRepository.fetchSingleYieldBalance(userWalletId, cryptoCurrency, refresh) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<Either<Throwable, Unit>>.summarizeResult(): Either<Throwable, Unit> {
|
||||
return firstOrNull { it.isLeft() } ?: Unit.right()
|
||||
}
|
||||
}
|
||||
|
|
@ -194,10 +194,7 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
}
|
||||
|
||||
// region sell
|
||||
rampManager.availableForSell(
|
||||
userWalletId = userWallet.walletId,
|
||||
status = cryptoCurrencyStatus,
|
||||
)
|
||||
rampManager.availableForSell(userWallet = userWallet, status = cryptoCurrencyStatus)
|
||||
.onRight {
|
||||
activeList.add(TokenActionsState.ActionState.Sell(ScenarioUnavailabilityReason.None))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.models.requireColdWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
|
|
@ -36,16 +39,21 @@ class GetNetworkCoinStatusUseCase(
|
|||
}
|
||||
|
||||
suspend fun invokeSync(
|
||||
userWalletId: UserWalletId,
|
||||
userWallet: UserWallet,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
val maybeCurrency = if (isSingleWalletWithTokens) {
|
||||
val userWalletId = userWallet.walletId
|
||||
val cardTypesResolver = userWallet.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
|
||||
|
||||
val maybeCurrency = if (userWallet.isMultiCurrency) {
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
|
||||
} else if (cardTypesResolver.isSingleWalletWithToken()) {
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenSync(userWalletId, networkId)
|
||||
} else {
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
|
||||
currencyStatusOperations.getPrimaryCurrencyStatusSync(userWalletId)
|
||||
}
|
||||
|
||||
return maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,11 +54,6 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>>
|
||||
|
||||
protected abstract fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>>
|
||||
|
||||
protected abstract suspend fun fetchComponents(
|
||||
userWalletId: UserWalletId,
|
||||
networks: Set<Network>,
|
||||
|
|
@ -106,13 +101,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
val statusFlow = getNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
|
||||
val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
|
||||
|
|
@ -349,6 +338,15 @@ abstract class BaseCurrencyStatusOperations(
|
|||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getNetworkStatus(userWalletId: UserWalletId, network: Network): EitherFlow<Error, NetworkStatus> {
|
||||
return singleNetworkStatusSupplier(
|
||||
params = SingleNetworkStatusProducer.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.map<NetworkStatus, Either<Error, NetworkStatus>>(NetworkStatus::right)
|
||||
.distinctUntilChanged()
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoin(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
|
|
|
|||
|
|
@ -303,18 +303,6 @@ class CachedCurrenciesStatusesOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return singleNetworkStatusSupplier(
|
||||
params = SingleNetworkStatusProducer.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
.map<NetworkStatus, Either<Error, Set<NetworkStatus>>> { setOf(it).right() }
|
||||
.distinctUntilChanged()
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
val state: StateFlow<TokenListUM> = tokenListUMController.state
|
||||
|
||||
private val params: OnrampTokenListComponent.Params = paramsContainer.require()
|
||||
private val scanResponse by lazy {
|
||||
private val userWallet by lazy {
|
||||
getWalletsUseCase.invokeSync().first { it.walletId == params.userWalletId }
|
||||
.requireColdWallet().scanResponse // TODO [REDACTED_TASK_KEY]
|
||||
.requireColdWallet() // TODO [REDACTED_TASK_KEY]
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
@ -229,16 +229,13 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
return when (params.filterOperation) {
|
||||
OnrampOperation.BUY -> {
|
||||
rampStateManager.availableForBuy(
|
||||
scanResponse = scanResponse,
|
||||
scanResponse = userWallet.scanResponse,
|
||||
userWalletId = params.userWalletId,
|
||||
cryptoCurrency = status.currency,
|
||||
).isAvailable()
|
||||
}
|
||||
OnrampOperation.SELL -> {
|
||||
rampStateManager.availableForSell(
|
||||
userWalletId = params.userWalletId,
|
||||
status = status,
|
||||
).isRight()
|
||||
rampStateManager.availableForSell(userWallet = userWallet, status = status).isRight()
|
||||
}
|
||||
OnrampOperation.SWAP -> {
|
||||
val isAvailable = rampStateManager.availableForSwap(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue