diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index ac813e234c..b3ab55fbeb 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -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 } } diff --git a/data/staking/src/main/java/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducer.kt b/data/staking/src/main/java/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducer.kt index 887db9af5f..82a820ebae 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducer.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducer.kt @@ -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) diff --git a/data/staking/src/main/java/com/tangem/data/staking/store/DefaultYieldsBalancesStore.kt b/data/staking/src/main/java/com/tangem/data/staking/store/DefaultYieldsBalancesStore.kt index 2f28162955..808ba7a7ae 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/store/DefaultYieldsBalancesStore.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/store/DefaultYieldsBalancesStore.kt @@ -109,8 +109,15 @@ internal class DefaultYieldsBalancesStore( private suspend fun storeInPersistence(userWalletId: UserWalletId, values: Set) { 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 } } diff --git a/data/staking/src/test/kotlin/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducerTest.kt b/data/staking/src/test/kotlin/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducerTest.kt index b05ad2e885..c594ea3515 100644 --- a/data/staking/src/test/kotlin/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducerTest.kt +++ b/data/staking/src/test/kotlin/com/tangem/data/staking/single/DefaultSingleYieldBalanceProducerTest.kt @@ -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() private val stakingIdFactory = mockk() + private val analyticsExceptionHandler = mockk(relaxUnitFun = true) private val dispatchers = TestingCoroutineDispatcherProvider() private val producer = DefaultSingleYieldBalanceProducer( params = params, stakingIdFactory = stakingIdFactory, multiYieldBalanceSupplier = multiNetworkStatusSupplier, + analyticsExceptionHandler = analyticsExceptionHandler, dispatchers = dispatchers, )