Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-13 16:51:37 +04:00
parent 4bac2a189e
commit cbd9ad505d
4 changed files with 55 additions and 13 deletions

View file

@ -120,7 +120,7 @@ internal class DefaultStakingRepository(
when (val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)) {
is ApiResponse.Success -> stakingYieldsStore.store(
stakingTokensWithYields.data.data.filter {
it.isAvailable ?: false
it.isAvailable == true
},
)
else -> {
@ -651,15 +651,16 @@ internal class DefaultStakingRepository(
}
override suspend fun isAnyTokenStaked(userWalletId: UserWalletId): Boolean {
return withContext(dispatchers.io) {
stakingBalanceStore.getSyncOrNull(userWalletId)
?.let {
it.isNotEmpty() &&
it.any { yieldBalance ->
(yieldBalance as? YieldBalance.Data)?.balance?.items?.isNotEmpty() == true
}
return withContext(dispatchers.default) {
val balances = stakingBalanceStoreV2.getAllSyncOrNull(userWalletId) ?: return@withContext false
val hasDataYieldBalance by lazy {
balances.any { yieldBalance ->
(yieldBalance as? YieldBalance.Data)?.balance?.items?.isNotEmpty() == true
}
?: false
}
balances.isNotEmpty() && hasDataYieldBalance
}
}

View file

@ -1,5 +1,7 @@
package com.tangem.data.staking.single
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
import com.tangem.data.staking.utils.StakingIdFactory
import com.tangem.domain.staking.model.StakingID
import com.tangem.domain.staking.model.stakekit.YieldBalance
@ -7,6 +9,7 @@ import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
import com.tangem.domain.staking.multi.MultiYieldBalanceSupplier
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.indexOfFirstOrNull
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -14,6 +17,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.mapNotNull
import timber.log.Timber
/**
* Default implementation of [SingleYieldBalanceProducer]
@ -29,6 +33,7 @@ internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
@Assisted private val params: SingleYieldBalanceProducer.Params,
private val multiYieldBalanceSupplier: MultiYieldBalanceSupplier,
private val stakingIdFactory: StakingIdFactory,
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
private val dispatchers: CoroutineDispatcherProvider,
) : SingleYieldBalanceProducer {
@ -48,8 +53,34 @@ internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
.mapNotNull { balances ->
val currentStakingId = getStakingId() ?: return@mapNotNull YieldBalance.Unsupported
balances.firstOrNull { it.getStakingId() == currentStakingId }
?: YieldBalance.Unsupported
val currentBalances = balances.filter { it.getStakingId() == currentStakingId }
if (currentBalances.size > 1) {
analyticsExceptionHandler.sendException(
event = ExceptionAnalyticsEvent(
exception = IllegalStateException("Multiple balances found for staking ID"),
params = mapOf(
"stakingId" to currentStakingId.toString(),
"balances" to currentBalances.joinToString(",") { it.toString() },
),
),
)
Timber.w(
"Multiple balances found for staking ID $currentStakingId:\n%s",
currentBalances.joinToString("\n"),
)
val dataIndex = currentBalances.indexOfFirstOrNull { it is YieldBalance.Data }
if (dataIndex != null) {
currentBalances[dataIndex]
} else {
currentBalances.first()
}
} else {
currentBalances.firstOrNull() ?: YieldBalance.Unsupported
}
}
.distinctUntilChanged()
.flowOn(dispatchers.default)

View file

@ -109,8 +109,15 @@ internal class DefaultYieldsBalancesStore(
private suspend fun storeInPersistence(userWalletId: UserWalletId, values: Set<YieldBalanceWrapperDTO>) {
persistenceStore.updateData { current ->
current.toMutableMap().apply {
this[userWalletId.stringValue] = current[userWalletId.stringValue]
?.addOrReplace(items = values) { old, new -> old.getStakingId() == new.getStakingId() }
this[userWalletId.stringValue] = this[userWalletId.stringValue]
?.addOrReplace(items = values) { old, new ->
val oldId = old.getStakingId()
val newId = new.getStakingId()
if (oldId == null || newId == null) return@addOrReplace false
oldId == newId
}
?: values
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
import com.tangem.common.test.utils.getEmittedValues
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
import com.tangem.data.staking.toDomain
import com.tangem.data.staking.utils.StakingIdFactory
import com.tangem.domain.staking.model.StakingID
@ -32,12 +33,14 @@ internal class DefaultSingleYieldBalanceProducerTest {
private val multiNetworkStatusSupplier = mockk<MultiYieldBalanceSupplier>()
private val stakingIdFactory = mockk<StakingIdFactory>()
private val analyticsExceptionHandler = mockk<AnalyticsExceptionHandler>(relaxUnitFun = true)
private val dispatchers = TestingCoroutineDispatcherProvider()
private val producer = DefaultSingleYieldBalanceProducer(
params = params,
stakingIdFactory = stakingIdFactory,
multiYieldBalanceSupplier = multiNetworkStatusSupplier,
analyticsExceptionHandler = analyticsExceptionHandler,
dispatchers = dispatchers,
)