Updated on 2026-08-14
This commit is contained in:
parent
dc097a7815
commit
6901522cf7
6 changed files with 66 additions and 29 deletions
|
|
@ -3,4 +3,11 @@ package com.tangem.datasource.api.common.response
|
|||
fun <T : Any> ApiResponse<T>.getOrThrow(): T = when (this) {
|
||||
is ApiResponse.Error -> throw cause
|
||||
is ApiResponse.Success -> data
|
||||
}
|
||||
|
||||
fun <T : Any, R : Any> ApiResponse<T>.fold(onSuccess: (T) -> R, onError: (ApiResponseError) -> R): R {
|
||||
return when (this) {
|
||||
is ApiResponse.Error -> onError(cause)
|
||||
is ApiResponse.Success -> onSuccess(data)
|
||||
}
|
||||
}
|
||||
|
|
@ -179,7 +179,15 @@ internal class DefaultStakingBalanceStore(
|
|||
cachedBalances: Set<YieldBalance>,
|
||||
runtimeBalances: Set<YieldBalance>,
|
||||
): Set<YieldBalance> {
|
||||
if (runtimeBalances.isEmpty()) return cachedBalances
|
||||
if (runtimeBalances.isEmpty()) {
|
||||
return cachedBalances.mapNotNullTo(hashSetOf()) {
|
||||
when (it) {
|
||||
is YieldBalance.Data -> it.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Empty -> it.copy(source = StatusSource.ONLY_CACHE)
|
||||
is YieldBalance.Error -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return runtimeBalances
|
||||
.map { runtime ->
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.tangem.data.staking.converters.transaction.GasEstimateConverter
|
|||
import com.tangem.data.staking.converters.transaction.StakingTransactionConverter
|
||||
import com.tangem.data.staking.converters.transaction.StakingTransactionStatusConverter
|
||||
import com.tangem.data.staking.converters.transaction.StakingTransactionTypeConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.stakekit.models.request.*
|
||||
|
|
@ -59,8 +60,11 @@ import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
|||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import timber.log.Timber
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
|
|
@ -108,10 +112,17 @@ internal class DefaultStakingRepository(
|
|||
key = YIELDS_STORE_KEY,
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)
|
||||
.getOrThrow()
|
||||
|
||||
stakingYieldsStore.store(stakingTokensWithYields.data.filter { it.isAvailable ?: false })
|
||||
when (val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)) {
|
||||
is ApiResponse.Success -> stakingYieldsStore.store(
|
||||
stakingTokensWithYields.data.data.filter {
|
||||
it.isAvailable ?: false
|
||||
},
|
||||
)
|
||||
else -> {
|
||||
stakingYieldsStore.store(emptyList())
|
||||
throw (stakingTokensWithYields as ApiResponse.Error).cause
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -209,6 +220,11 @@ internal class DefaultStakingRepository(
|
|||
getEnabledYields()
|
||||
.distinctUntilChanged()
|
||||
.onEach { yields ->
|
||||
if (yields.isEmpty()) {
|
||||
send(StakingAvailability.TemporaryUnavailable)
|
||||
return@onEach
|
||||
}
|
||||
|
||||
val prefetchedYield = findPrefetchedYield(
|
||||
yields = yields,
|
||||
currencyId = rawCurrencyId,
|
||||
|
|
@ -446,21 +462,21 @@ internal class DefaultStakingRepository(
|
|||
)
|
||||
}
|
||||
|
||||
val yieldDTOs = withTimeoutOrNull(YIELDS_WATITING_TIMEOUT) {
|
||||
runCatching { stakingYieldsStore.get().firstOrNull() }.getOrNull()
|
||||
}
|
||||
|
||||
if (yieldDTOs == null) {
|
||||
Timber.i("No enabled yields for $userWalletId")
|
||||
stakingBalanceStore.store(userWalletId, emptySet())
|
||||
|
||||
return@withContext
|
||||
}
|
||||
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getYieldBalancesKey(userWalletId),
|
||||
skipCache = refresh,
|
||||
block = {
|
||||
val yieldDTOs = withTimeoutOrNull(YIELDS_WATITING_TIMEOUT) {
|
||||
runCatching { stakingYieldsStore.get().firstOrNull() }.getOrNull()
|
||||
}
|
||||
|
||||
if (yieldDTOs == null) {
|
||||
Timber.i("No enabled yields for $userWalletId")
|
||||
stakingBalanceStore.store(userWalletId, emptySet())
|
||||
|
||||
return@invokeOnExpire
|
||||
}
|
||||
|
||||
val yields = YieldConverter.convertListIgnoreErrors(
|
||||
input = yieldDTOs,
|
||||
onError = { Timber.e("Error converting one of the items in enabled yields: $it") },
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import com.tangem.utils.isNullOrZero
|
|||
import java.math.BigDecimal
|
||||
|
||||
internal class TokenDetailsStakingInfoConverter(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus?>,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
private val currentState: TokenDetailsState,
|
||||
|
|
@ -35,7 +35,6 @@ internal class TokenDetailsStakingInfoConverter(
|
|||
) : Converter<StakingAvailability, TokenDetailsState> {
|
||||
|
||||
override fun convert(value: StakingAvailability): TokenDetailsState {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider.invoke() ?: return currentState
|
||||
return currentState.copy(
|
||||
stakingBlocksState = getYieldBalance(cryptoCurrencyStatus, currentState, value),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -129,10 +129,11 @@ internal class TokenDetailsStateFactory(
|
|||
state: TokenDetailsState,
|
||||
stakingEntryInfo: StakingEntryInfo?,
|
||||
stakingAvailability: StakingAvailability,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): TokenDetailsState {
|
||||
return TokenDetailsStakingInfoConverter(
|
||||
currentState = state,
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
clickIntents = clickIntents,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
stakingEntryInfo = stakingEntryInfo,
|
||||
|
|
|
|||
|
|
@ -321,9 +321,9 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
cryptoCurrencyStatus = status
|
||||
updateButtons(currencyStatus = status)
|
||||
updateWarnings(status)
|
||||
subscribeOnUpdateStakingInfo(status)
|
||||
}
|
||||
currencyStatusAnalyticsSender.send(maybeCurrencyStatus)
|
||||
subscribeOnUpdateStakingInfo()
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
|
|
@ -409,7 +409,7 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun subscribeOnUpdateStakingInfo() {
|
||||
private fun subscribeOnUpdateStakingInfo(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
getStakingAvailabilityUseCase(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
|
|
@ -417,16 +417,22 @@ internal class TokenDetailsViewModel @Inject constructor(
|
|||
.map { it.getOrElse { StakingAvailability.Unavailable } }
|
||||
.distinctUntilChanged()
|
||||
.onEach {
|
||||
if (it is StakingAvailability.Available) {
|
||||
val stakingInfo = getStakingEntryInfoUseCase(
|
||||
val stakingEntryInfo = if (it is StakingAvailability.Available) {
|
||||
getStakingEntryInfoUseCase(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
)
|
||||
).getOrNull()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val stakingEntryInfo = stakingInfo.getOrNull()
|
||||
internalUiState.update { state ->
|
||||
stateFactory.getStakingInfoState(state, stakingEntryInfo, it)
|
||||
}
|
||||
internalUiState.update { state ->
|
||||
stateFactory.getStakingInfoState(
|
||||
state = state,
|
||||
stakingEntryInfo = stakingEntryInfo,
|
||||
stakingAvailability = it,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
)
|
||||
}
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue