Updated on 2026-08-14

This commit is contained in:
Tangem 2026-01-19 13:32:27 +02:00
parent 27e199afdd
commit d839a616ef
16 changed files with 172 additions and 115 deletions

View file

@ -3,7 +3,7 @@ package com.tangem.data.staking
import arrow.core.getOrElse import arrow.core.getOrElse
import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.domain.card.common.TapWorkarounds.isWallet2 import com.tangem.domain.card.common.TapWorkarounds.isWallet2
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.staking.StakingBalance import com.tangem.domain.models.staking.StakingBalance
@ -30,7 +30,7 @@ import kotlinx.coroutines.withContext
internal class DefaultStakingRepository( internal class DefaultStakingRepository(
private val stakeKitRepository: StakeKitRepository, private val stakeKitRepository: StakeKitRepository,
private val p2pEthPoolRepository: P2PEthPoolRepository, private val p2pEthPoolRepository: P2PEthPoolRepository,
private val stakingBalanceStoreV2: StakingBalancesStore, private val stakingBalanceStoreV2: StakeKitBalancesStore,
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
private val getUserWalletUseCase: GetUserWalletUseCase, private val getUserWalletUseCase: GetUserWalletUseCase,
private val stakingFeatureToggles: StakingFeatureToggles, private val stakingFeatureToggles: StakingFeatureToggles,

View file

@ -2,9 +2,9 @@ package com.tangem.data.staking.di
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import com.tangem.data.staking.store.DefaultP2PEthPoolBalancesStore import com.tangem.data.staking.store.DefaultP2PEthPoolBalancesStore
import com.tangem.data.staking.store.DefaultStakingBalancesStore import com.tangem.data.staking.store.DefaultStakeKitBalancesStore
import com.tangem.data.staking.store.P2PEthPoolBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
import com.tangem.datasource.local.datastore.RuntimeSharedStore import com.tangem.datasource.local.datastore.RuntimeSharedStore
@ -28,8 +28,8 @@ internal object StakingBalanceSupplierModule {
fun provideStakingBalancesStore( fun provideStakingBalancesStore(
persistenceStore: DataStore<Map<String, Set<YieldBalanceWrapperDTO>>>, persistenceStore: DataStore<Map<String, Set<YieldBalanceWrapperDTO>>>,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
): StakingBalancesStore { ): StakeKitBalancesStore {
return DefaultStakingBalancesStore( return DefaultStakeKitBalancesStore(
runtimeStore = RuntimeSharedStore(), runtimeStore = RuntimeSharedStore(),
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = dispatchers, dispatchers = dispatchers,

View file

@ -5,7 +5,8 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.configtoggle.feature.FeatureTogglesManager import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.data.staking.* import com.tangem.data.staking.*
import com.tangem.data.staking.converters.error.StakeKitErrorConverter import com.tangem.data.staking.converters.error.StakeKitErrorConverter
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles
import com.tangem.data.staking.utils.DefaultStakingCleaner import com.tangem.data.staking.utils.DefaultStakingCleaner
import com.tangem.datasource.api.ethpool.P2PEthPoolApi import com.tangem.datasource.api.ethpool.P2PEthPoolApi
@ -56,7 +57,7 @@ internal object StakingDataModule {
fun provideStakingRepository( fun provideStakingRepository(
stakeKitRepository: StakeKitRepository, stakeKitRepository: StakeKitRepository,
p2pEthPoolRepository: P2PEthPoolRepository, p2pEthPoolRepository: P2PEthPoolRepository,
stakingBalancesStore: StakingBalancesStore, stakeKitBalancesStore: StakeKitBalancesStore,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
getUserWalletUseCase: GetUserWalletUseCase, getUserWalletUseCase: GetUserWalletUseCase,
stakingFeatureToggles: StakingFeatureToggles, stakingFeatureToggles: StakingFeatureToggles,
@ -65,7 +66,7 @@ internal object StakingDataModule {
return DefaultStakingRepository( return DefaultStakingRepository(
stakeKitRepository = stakeKitRepository, stakeKitRepository = stakeKitRepository,
p2pEthPoolRepository = p2pEthPoolRepository, p2pEthPoolRepository = p2pEthPoolRepository,
stakingBalanceStoreV2 = stakingBalancesStore, stakingBalanceStoreV2 = stakeKitBalancesStore,
dispatchers = dispatchers, dispatchers = dispatchers,
getUserWalletUseCase = getUserWalletUseCase, getUserWalletUseCase = getUserWalletUseCase,
walletManagersFacade = walletManagersFacade, walletManagersFacade = walletManagersFacade,
@ -138,12 +139,14 @@ internal object StakingDataModule {
@Singleton @Singleton
fun provideStakingCleaner( fun provideStakingCleaner(
stakingIdFactory: StakingIdFactory, stakingIdFactory: StakingIdFactory,
stakingBalancesStore: StakingBalancesStore, stakeKitBalancesStore: StakeKitBalancesStore,
p2pEthPoolBalancesStore: P2PEthPoolBalancesStore,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
): StakingCleaner { ): StakingCleaner {
return DefaultStakingCleaner( return DefaultStakingCleaner(
stakingIdFactory = stakingIdFactory, stakingIdFactory = stakingIdFactory,
stakingBalancesStore = stakingBalancesStore, stakeKitBalancesStore = stakeKitBalancesStore,
p2pEthPoolBalancesStore = p2pEthPoolBalancesStore,
dispatchers = dispatchers, dispatchers = dispatchers,
) )
} }

View file

@ -6,7 +6,7 @@ import arrow.core.right
import arrow.core.toOption import arrow.core.toOption
import com.tangem.data.common.api.safeApiCall import com.tangem.data.common.api.safeApiCall
import com.tangem.data.staking.store.P2PEthPoolBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.ethpool.P2PEthPoolApi import com.tangem.datasource.api.ethpool.P2PEthPoolApi
@ -43,7 +43,7 @@ import javax.inject.Inject
* *
* @property userWalletsStore user wallets store * @property userWalletsStore user wallets store
* @property stakingYieldsStore staking yields store * @property stakingYieldsStore staking yields store
* @property stakingBalancesStore staking balances store (StakeKit) * @property stakeKitBalancesStore staking balances store (StakeKit)
* @property p2PEthPoolBalancesStore P2PEthPool balances store * @property p2PEthPoolBalancesStore P2PEthPool balances store
* @property stakeKitApi stake kit API * @property stakeKitApi stake kit API
* @property p2pEthPoolApi P2PEthPool API * @property p2pEthPoolApi P2PEthPool API
@ -56,7 +56,7 @@ import javax.inject.Inject
internal class DefaultMultiStakingBalanceFetcher @Inject constructor( internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
private val userWalletsStore: UserWalletsStore, private val userWalletsStore: UserWalletsStore,
private val stakingYieldsStore: StakingYieldsStore, private val stakingYieldsStore: StakingYieldsStore,
private val stakingBalancesStore: StakingBalancesStore, private val stakeKitBalancesStore: StakeKitBalancesStore,
private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore, private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore,
private val stakeKitApi: StakeKitApi, private val stakeKitApi: StakeKitApi,
private val p2pEthPoolApi: P2PEthPoolApi, private val p2pEthPoolApi: P2PEthPoolApi,
@ -106,7 +106,7 @@ internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
Timber.e(throwable, "Unable to fetch staking balances $params") Timber.e(throwable, "Unable to fetch staking balances $params")
if (stakeKitIds.isNotEmpty()) { if (stakeKitIds.isNotEmpty()) {
stakingBalancesStore.storeError( stakeKitBalancesStore.storeError(
userWalletId = params.userWalletId, userWalletId = params.userWalletId,
stakingIds = stakeKitIds.toSet(), stakingIds = stakeKitIds.toSet(),
) )
@ -121,7 +121,7 @@ internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
} }
private suspend fun fetchStakeKitBalances(userWalletId: UserWalletId, stakingIds: Set<StakingID>) { private suspend fun fetchStakeKitBalances(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
stakingBalancesStore.refresh(userWalletId = userWalletId, stakingIds = stakingIds) stakeKitBalancesStore.refresh(userWalletId = userWalletId, stakingIds = stakingIds)
val availableStakingIds = getAvailableStakingIds( val availableStakingIds = getAvailableStakingIds(
userWalletId = userWalletId, userWalletId = userWalletId,
@ -270,7 +270,7 @@ internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
) )
if (unavailableStakingIds.isNotEmpty()) { if (unavailableStakingIds.isNotEmpty()) {
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = unavailableStakingIds.toSet()) stakeKitBalancesStore.storeError(userWalletId = userWalletId, stakingIds = unavailableStakingIds.toSet())
} }
return availableStakingIds.toSet().ifEmpty { return availableStakingIds.toSet().ifEmpty {
@ -322,7 +322,7 @@ internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
Timber.i( Timber.i(
"Successfully fetched staking balances for $userWalletId:\n${yieldBalances.joinToString("\n")}", "Successfully fetched staking balances for $userWalletId:\n${yieldBalances.joinToString("\n")}",
) )
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = yieldBalances) stakeKitBalancesStore.storeActual(userWalletId = userWalletId, values = yieldBalances)
if (!allResponsesReceived(requests, yieldBalances)) { if (!allResponsesReceived(requests, yieldBalances)) {
val values = stakingIds.filter { stakingId -> val values = stakingIds.filter { stakingId ->
@ -332,13 +332,13 @@ internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
} }
} }
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = values.toSet()) stakeKitBalancesStore.storeError(userWalletId = userWalletId, stakingIds = values.toSet())
} }
}, },
onError = { throwable -> onError = { throwable ->
Timber.e(throwable, "Unable to fetch staking balances $userWalletId") Timber.e(throwable, "Unable to fetch staking balances $userWalletId")
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds) stakeKitBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds)
throw throwable throw throwable
}, },

View file

@ -3,7 +3,7 @@ package com.tangem.data.staking.multi
import arrow.core.Option import arrow.core.Option
import arrow.core.some import arrow.core.some
import com.tangem.data.staking.store.P2PEthPoolBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.domain.models.staking.StakingBalance import com.tangem.domain.models.staking.StakingBalance
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.onEmpty
* Combines staking balances from both StakeKit and P2PEthPool providers. * Combines staking balances from both StakeKit and P2PEthPool providers.
* *
* @property params params * @property params params
* @property stakingBalancesStore StakeKit staking balances store * @property stakeKitBalancesStore StakeKit staking balances store
* @property p2PEthPoolBalancesStore P2PEthPool balances store * @property p2PEthPoolBalancesStore P2PEthPool balances store
* @property dispatchers dispatchers * @property dispatchers dispatchers
* *
@ -30,7 +30,7 @@ import kotlinx.coroutines.flow.onEmpty
*/ */
internal class DefaultMultiStakingBalanceProducer @AssistedInject constructor( internal class DefaultMultiStakingBalanceProducer @AssistedInject constructor(
@Assisted val params: MultiStakingBalanceProducer.Params, @Assisted val params: MultiStakingBalanceProducer.Params,
private val stakingBalancesStore: StakingBalancesStore, private val stakeKitBalancesStore: StakeKitBalancesStore,
private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore, private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore,
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
) : MultiStakingBalanceProducer { ) : MultiStakingBalanceProducer {
@ -38,7 +38,7 @@ internal class DefaultMultiStakingBalanceProducer @AssistedInject constructor(
override val fallback: Option<Set<StakingBalance>> = emptySet<StakingBalance>().some() override val fallback: Option<Set<StakingBalance>> = emptySet<StakingBalance>().some()
override fun produce(): Flow<Set<StakingBalance>> { override fun produce(): Flow<Set<StakingBalance>> {
val stakeKitFlow = stakingBalancesStore.get(userWalletId = params.userWalletId) val stakeKitFlow = stakeKitBalancesStore.get(userWalletId = params.userWalletId)
val p2pEthPoolFlow = p2PEthPoolBalancesStore.get(userWalletId = params.userWalletId) val p2pEthPoolFlow = p2PEthPoolBalancesStore.get(userWalletId = params.userWalletId)
return combine(stakeKitFlow, p2pEthPoolFlow) { stakeKitBalances, p2pEthPoolBalances -> return combine(stakeKitFlow, p2pEthPoolFlow) { stakeKitBalances, p2pEthPoolBalances ->

View file

@ -8,7 +8,6 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.staking.StakingBalance import com.tangem.domain.models.staking.StakingBalance
import com.tangem.domain.models.staking.StakingID import com.tangem.domain.models.staking.StakingID
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.model.StakingIntegrationID
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.addOrReplace import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -151,13 +150,13 @@ internal class DefaultP2PEthPoolBalancesStore(
} }
private suspend fun clearInPersistence(userWalletId: UserWalletId, stakingIds: Set<StakingID>) { private suspend fun clearInPersistence(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
val integrationIds = stakingIds.map { it.integrationId }.toSet() val addressesToClear = stakingIds.map { it.address }.toSet()
persistenceStore.updateData { current -> persistenceStore.updateData { current ->
current.toMutableMap().apply { current.toMutableMap().apply {
this[userWalletId.stringValue] = this[userWalletId.stringValue].orEmpty() this[userWalletId.stringValue] = this[userWalletId.stringValue].orEmpty()
.filterNot { response -> .filterNot { response ->
StakingIntegrationID.P2PEthPool.value in integrationIds response.delegatorAddress in addressesToClear
} }
.toSet() .toSet()
} }

View file

@ -22,7 +22,7 @@ internal typealias WalletIdWithWrappers = Map<String, Set<YieldBalanceWrapperDTO
internal typealias WalletIdWithStakingBalances = Map<UserWalletId, Set<StakingBalance>> internal typealias WalletIdWithStakingBalances = Map<UserWalletId, Set<StakingBalance>>
/** /**
* Default implementation of [StakingBalancesStore] * Default implementation of [StakeKitBalancesStore]
* *
* @property runtimeStore runtime store * @property runtimeStore runtime store
* @property persistenceStore persistence store * @property persistenceStore persistence store
@ -30,11 +30,11 @@ internal typealias WalletIdWithStakingBalances = Map<UserWalletId, Set<StakingBa
* *
[REDACTED_AUTHOR] [REDACTED_AUTHOR]
*/ */
internal class DefaultStakingBalancesStore( internal class DefaultStakeKitBalancesStore(
private val runtimeStore: RuntimeSharedStore<WalletIdWithStakingBalances>, private val runtimeStore: RuntimeSharedStore<WalletIdWithStakingBalances>,
private val persistenceStore: DataStore<WalletIdWithWrappers>, private val persistenceStore: DataStore<WalletIdWithWrappers>,
dispatchers: CoroutineDispatcherProvider, dispatchers: CoroutineDispatcherProvider,
) : StakingBalancesStore { ) : StakeKitBalancesStore {
private val scope = CoroutineScope(context = SupervisorJob() + dispatchers.io) private val scope = CoroutineScope(context = SupervisorJob() + dispatchers.io)
@ -97,6 +97,23 @@ internal class DefaultStakingBalancesStore(
} }
override suspend fun clear(userWalletId: UserWalletId, stakingIds: Set<StakingID>) { override suspend fun clear(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
coroutineScope {
launch { clearInRuntime(userWalletId = userWalletId, stakingIds = stakingIds) }
launch { clearInPersistence(userWalletId = userWalletId, stakingIds = stakingIds) }
}
}
private suspend fun clearInRuntime(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
runtimeStore.update(default = emptyMap()) { stored ->
stored.toMutableMap().apply {
this[userWalletId] = this[userWalletId].orEmpty()
.filterNot { it.stakingId in stakingIds }
.toSet()
}
}
}
private suspend fun clearInPersistence(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
persistenceStore.updateData { current -> persistenceStore.updateData { current ->
current.toMutableMap().apply { current.toMutableMap().apply {
this[userWalletId.stringValue] = this[userWalletId.stringValue].orEmpty() this[userWalletId.stringValue] = this[userWalletId.stringValue].orEmpty()

View file

@ -8,7 +8,7 @@ import com.tangem.domain.models.wallet.UserWalletId
* *
* Extends [BaseStakingBalancesStore] with StakeKit-specific storage operations. * Extends [BaseStakingBalancesStore] with StakeKit-specific storage operations.
*/ */
interface StakingBalancesStore : BaseStakingBalancesStore { interface StakeKitBalancesStore : BaseStakingBalancesStore {
/** Store actual StakeKit yield balances */ /** Store actual StakeKit yield balances */
suspend fun storeActual(userWalletId: UserWalletId, values: Set<YieldBalanceWrapperDTO>) suspend fun storeActual(userWalletId: UserWalletId, values: Set<YieldBalanceWrapperDTO>)

View file

@ -1,7 +1,8 @@
package com.tangem.data.staking.utils package com.tangem.data.staking.utils
import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.data.staking.store.StakingBalancesStore
import com.tangem.domain.models.staking.StakingID import com.tangem.domain.models.staking.StakingID
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.StakingIdFactory import com.tangem.domain.staking.StakingIdFactory
@ -16,14 +17,16 @@ import timber.log.Timber
/** /**
* Default implementation of [StakingCleaner]. * Default implementation of [StakingCleaner].
* *
* @property stakingBalancesStore Store to manage staking balances. * @property stakeKitBalancesStore Store to manage StakeKit staking balances.
* @property p2pEthPoolBalancesStore Store to manage P2PEthPool staking balances.
* @property dispatchers Coroutine dispatchers provider. * @property dispatchers Coroutine dispatchers provider.
* *
[REDACTED_AUTHOR] [REDACTED_AUTHOR]
*/ */
internal class DefaultStakingCleaner( internal class DefaultStakingCleaner(
private val stakingIdFactory: StakingIdFactory, private val stakingIdFactory: StakingIdFactory,
private val stakingBalancesStore: StakingBalancesStore, private val stakeKitBalancesStore: StakeKitBalancesStore,
private val p2pEthPoolBalancesStore: P2PEthPoolBalancesStore,
private val dispatchers: CoroutineDispatcherProvider, private val dispatchers: CoroutineDispatcherProvider,
) : StakingCleaner { ) : StakingCleaner {
@ -53,15 +56,23 @@ internal class DefaultStakingCleaner(
withContext(dispatchers.default) { withContext(dispatchers.default) {
awaitAll( awaitAll(
async { clearStatusesStore(userWalletId = userWalletId, stakingIds = stakingIds) }, async { clearStakeKitBalancesStore(userWalletId = userWalletId, stakingIds = stakingIds) },
async { clearP2PEthPoolBalancesStore(userWalletId = userWalletId, stakingIds = stakingIds) },
) )
} }
} }
private suspend fun clearStatusesStore(userWalletId: UserWalletId, stakingIds: Set<StakingID>) { private suspend fun clearStakeKitBalancesStore(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
runSuspendCatching { runSuspendCatching {
stakingBalancesStore.clear(userWalletId, stakingIds) stakeKitBalancesStore.clear(userWalletId, stakingIds)
} }
.onFailure { Timber.e(it, "Failed to clear yield balance statuses for wallet: $userWalletId") } .onFailure { Timber.e(it, "Failed to clear StakeKit balance statuses for wallet: $userWalletId") }
}
private suspend fun clearP2PEthPoolBalancesStore(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
runSuspendCatching {
p2pEthPoolBalancesStore.clear(userWalletId, stakingIds)
}
.onFailure { Timber.e(it, "Failed to clear P2PEthPool balance statuses for wallet: $userWalletId") }
} }
} }

View file

@ -5,7 +5,7 @@ import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
import com.tangem.common.test.data.staking.MockYieldDTOFactory import com.tangem.common.test.data.staking.MockYieldDTOFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.data.staking.store.P2PEthPoolBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
import com.tangem.datasource.api.common.response.ApiResponse import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError import com.tangem.datasource.api.common.response.ApiResponseError
@ -35,7 +35,7 @@ internal class DefaultMultiStakingBalanceFetcherTest {
private val userWalletsStore: UserWalletsStore = mockk() private val userWalletsStore: UserWalletsStore = mockk()
private val stakingYieldsStore: StakingYieldsStore = mockk() private val stakingYieldsStore: StakingYieldsStore = mockk()
private val stakingBalancesStore: StakingBalancesStore = mockk(relaxUnitFun = true) private val stakeKitBalancesStore: StakeKitBalancesStore = mockk(relaxUnitFun = true)
private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore = mockk(relaxUnitFun = true) private val p2PEthPoolBalancesStore: P2PEthPoolBalancesStore = mockk(relaxUnitFun = true)
private val stakeKitApi: StakeKitApi = mockk() private val stakeKitApi: StakeKitApi = mockk()
private val p2pEthPoolApi: P2PEthPoolApi = mockk() private val p2pEthPoolApi: P2PEthPoolApi = mockk()
@ -44,7 +44,7 @@ internal class DefaultMultiStakingBalanceFetcherTest {
private val fetcher = DefaultMultiStakingBalanceFetcher( private val fetcher = DefaultMultiStakingBalanceFetcher(
userWalletsStore = userWalletsStore, userWalletsStore = userWalletsStore,
stakingYieldsStore = stakingYieldsStore, stakingYieldsStore = stakingYieldsStore,
stakingBalancesStore = stakingBalancesStore, stakeKitBalancesStore = stakeKitBalancesStore,
p2PEthPoolBalancesStore = p2PEthPoolBalancesStore, p2PEthPoolBalancesStore = p2PEthPoolBalancesStore,
stakeKitApi = stakeKitApi, stakeKitApi = stakeKitApi,
p2pEthPoolApi = p2pEthPoolApi, p2pEthPoolApi = p2pEthPoolApi,
@ -54,7 +54,7 @@ internal class DefaultMultiStakingBalanceFetcherTest {
@BeforeEach @BeforeEach
fun resetMocks() { fun resetMocks() {
clearMocks(userWalletsStore, stakingYieldsStore, stakingBalancesStore, stakeKitApi) clearMocks(userWalletsStore, stakingYieldsStore, stakeKitBalancesStore, stakeKitApi)
} }
@Test @Test
@ -81,13 +81,13 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakeKitApi.getMultipleYieldBalances(requests) stakeKitApi.getMultipleYieldBalances(requests)
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = result) stakeKitBalancesStore.storeActual(userWalletId = userWalletId, values = result)
} }
coVerify(inverse = true) { stakingBalancesStore.storeError(any(), any()) } coVerify(inverse = true) { stakeKitBalancesStore.storeError(any(), any()) }
assertEitherRight(actual) assertEitherRight(actual)
} }
@ -113,11 +113,11 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = setOf(solanaId)) stakeKitBalancesStore.storeError(userWalletId = userWalletId, stakingIds = setOf(solanaId))
stakeKitApi.getMultipleYieldBalances(requests) stakeKitApi.getMultipleYieldBalances(requests)
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = result) stakeKitBalancesStore.storeActual(userWalletId = userWalletId, values = result)
} }
assertEitherRight(actual) assertEitherRight(actual)
@ -138,11 +138,11 @@ internal class DefaultMultiStakingBalanceFetcherTest {
coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) } coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) }
coVerify(inverse = true) { coVerify(inverse = true) {
stakingBalancesStore.refresh(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.refresh(userWalletId = any(), stakingIds = any())
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any()) stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
stakingBalancesStore.storeError(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.storeError(userWalletId = any(), stakingIds = any())
} }
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${userWallet.toOption()}") val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${userWallet.toOption()}")
@ -164,11 +164,11 @@ internal class DefaultMultiStakingBalanceFetcherTest {
coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) } coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) }
coVerify(inverse = true) { coVerify(inverse = true) {
stakingBalancesStore.refresh(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.refresh(userWalletId = any(), stakingIds = any())
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any()) stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
stakingBalancesStore.storeError(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.storeError(userWalletId = any(), stakingIds = any())
} }
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${null.toOption()}") val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${null.toOption()}")
@ -190,14 +190,14 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) stakeKitBalancesStore.refresh(params.userWalletId, tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds) stakeKitBalancesStore.storeError(userWalletId, tonAndSolanaIds)
} }
coVerify(inverse = true) { coVerify(inverse = true) {
stakeKitApi.getMultipleYieldBalances(any()) stakeKitApi.getMultipleYieldBalances(any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
} }
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}") val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
@ -219,14 +219,14 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds) stakeKitBalancesStore.storeError(userWalletId, tonAndSolanaIds)
} }
coVerify(inverse = true) { coVerify(inverse = true) {
stakeKitApi.getMultipleYieldBalances(any()) stakeKitApi.getMultipleYieldBalances(any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
} }
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}") val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
@ -253,14 +253,14 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds) stakeKitBalancesStore.storeError(userWalletId, tonAndSolanaIds)
} }
coVerify(inverse = true) { coVerify(inverse = true) {
stakeKitApi.getMultipleYieldBalances(any()) stakeKitApi.getMultipleYieldBalances(any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
} }
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}") val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
@ -284,14 +284,14 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds) stakeKitBalancesStore.storeError(userWalletId, tonAndSolanaIds)
} }
coVerify(inverse = true) { coVerify(inverse = true) {
stakeKitApi.getMultipleYieldBalances(any()) stakeKitApi.getMultipleYieldBalances(any())
stakingBalancesStore.storeActual(userWalletId = any(), values = any()) stakeKitBalancesStore.storeActual(userWalletId = any(), values = any())
} }
val expected = IllegalStateException( val expected = IllegalStateException(
@ -329,13 +329,13 @@ internal class DefaultMultiStakingBalanceFetcherTest {
// Assert // Assert
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncOrNull(params.userWalletId) userWalletsStore.getSyncOrNull(params.userWalletId)
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
stakingYieldsStore.getSyncWithTimeout() stakingYieldsStore.getSyncWithTimeout()
stakeKitApi.getMultipleYieldBalances(requests) stakeKitApi.getMultipleYieldBalances(requests)
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = tonAndSolanaIds) stakeKitBalancesStore.storeError(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
} }
coVerify(inverse = true) { stakingBalancesStore.storeActual(userWalletId = any(), values = any()) } coVerify(inverse = true) { stakeKitBalancesStore.storeActual(userWalletId = any(), values = any()) }
val expected = ApiResponseError.NetworkException() val expected = ApiResponseError.NetworkException()

View file

@ -4,7 +4,7 @@ import com.google.common.truth.Truth
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
import com.tangem.common.test.data.staking.MockP2PEthPoolAccountResponseFactory import com.tangem.common.test.data.staking.MockP2PEthPoolAccountResponseFactory
import com.tangem.data.staking.store.P2PEthPoolBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.data.staking.toDomain import com.tangem.data.staking.toDomain
import com.tangem.domain.models.StatusSource import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.staking.* import com.tangem.domain.models.staking.*
@ -27,13 +27,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
private val params = MultiStakingBalanceProducer.Params(userWalletId = UserWalletId("011")) private val params = MultiStakingBalanceProducer.Params(userWalletId = UserWalletId("011"))
private val stakingBalancesStore = mockk<StakingBalancesStore>() private val stakeKitBalancesStore = mockk<StakeKitBalancesStore>()
private val p2PEthPoolBalancesStore = mockk<P2PEthPoolBalancesStore>() private val p2PEthPoolBalancesStore = mockk<P2PEthPoolBalancesStore>()
private val dispatchers = TestingCoroutineDispatcherProvider() private val dispatchers = TestingCoroutineDispatcherProvider()
private val producer = DefaultMultiStakingBalanceProducer( private val producer = DefaultMultiStakingBalanceProducer(
params = params, params = params,
stakingBalancesStore = stakingBalancesStore, stakeKitBalancesStore = stakeKitBalancesStore,
p2PEthPoolBalancesStore = p2PEthPoolBalancesStore, p2PEthPoolBalancesStore = p2PEthPoolBalancesStore,
dispatchers = dispatchers, dispatchers = dispatchers,
) )
@ -47,13 +47,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
val networksStatusesFlow = flowOf(balances) val networksStatusesFlow = flowOf(balances)
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet()) every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
val values = getEmittedValues(flow = actual) val values = getEmittedValues(flow = actual)
@ -66,13 +66,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
fun `test that flow is updated if balances are updated`() = runTest { fun `test that flow is updated if balances are updated`() = runTest {
val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2) val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet()) every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
// first emit // first emit
@ -107,13 +107,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
fun `test that flow is filtered the same balance`() = runTest { fun `test that flow is filtered the same balance`() = runTest {
val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2) val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet()) every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
// first emit // first emit
@ -156,13 +156,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
} }
.buffer(capacity = 5) .buffer(capacity = 5)
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow every { stakeKitBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet()) every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
val actual = producer.produceWithFallback() val actual = producer.produceWithFallback()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
val values1 = getEmittedValues(flow = actual) val values1 = getEmittedValues(flow = actual)
@ -180,13 +180,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
@Test @Test
fun `test that flow is empty`() = runTest { fun `test that flow is empty`() = runTest {
every { stakingBalancesStore.get(params.userWalletId) } returns emptyFlow() every { stakeKitBalancesStore.get(params.userWalletId) } returns emptyFlow()
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns emptyFlow() every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns emptyFlow()
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
val values = getEmittedValues(flow = actual) val values = getEmittedValues(flow = actual)
@ -200,13 +200,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
val stakeKitBalances = createStakeKitBalances() val stakeKitBalances = createStakeKitBalances()
val p2pEthPoolBalances = createP2PEthPoolBalances() val p2pEthPoolBalances = createP2PEthPoolBalances()
every { stakingBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances) every { stakeKitBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(p2pEthPoolBalances) every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns flowOf(p2pEthPoolBalances)
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
val values = getEmittedValues(flow = actual) val values = getEmittedValues(flow = actual)
@ -220,13 +220,13 @@ internal class DefaultMultiStakingBalanceProducerTest {
val stakeKitBalances = createStakeKitBalancesWithTonOnly() val stakeKitBalances = createStakeKitBalancesWithTonOnly()
val p2pEthPoolFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2) val p2pEthPoolFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
every { stakingBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances) every { stakeKitBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns p2pEthPoolFlow every { p2PEthPoolBalancesStore.get(params.userWalletId) } returns p2pEthPoolFlow
val actual = producer.produce() val actual = producer.produce()
// check after producer.produce() // check after producer.produce()
verify { stakingBalancesStore.get(params.userWalletId) } verify { stakeKitBalancesStore.get(params.userWalletId) }
verify { p2PEthPoolBalancesStore.get(params.userWalletId) } verify { p2PEthPoolBalancesStore.get(params.userWalletId) }
// first emit - empty P2PEthPool // first emit - empty P2PEthPool

View file

@ -20,7 +20,7 @@ internal class StakingBalancesStoreGetMethodTest {
private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>() private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap()) private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
private val store = DefaultStakingBalancesStore( private val store = DefaultStakeKitBalancesStore(
runtimeStore = runtimeStore, runtimeStore = runtimeStore,
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),

View file

@ -27,7 +27,7 @@ internal class StakingBalancesStoreInitializationTest {
every { persistenceStore.data } returns emptyFlow() every { persistenceStore.data } returns emptyFlow()
DefaultStakingBalancesStore( DefaultStakeKitBalancesStore(
runtimeStore = runtimeStore, runtimeStore = runtimeStore,
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),
@ -41,7 +41,7 @@ internal class StakingBalancesStoreInitializationTest {
val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>() val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap()) val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
DefaultStakingBalancesStore( DefaultStakeKitBalancesStore(
runtimeStore = runtimeStore, runtimeStore = runtimeStore,
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),
@ -63,7 +63,7 @@ internal class StakingBalancesStoreInitializationTest {
} }
} }
DefaultStakingBalancesStore( DefaultStakeKitBalancesStore(
runtimeStore = runtimeStore, runtimeStore = runtimeStore,
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),

View file

@ -23,7 +23,7 @@ internal class StakingBalancesStoreUpdateMethodsTest {
private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>() private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap()) private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
private val store = DefaultStakingBalancesStore( private val store = DefaultStakeKitBalancesStore(
runtimeStore = runtimeStore, runtimeStore = runtimeStore,
persistenceStore = persistenceStore, persistenceStore = persistenceStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),

View file

@ -2,7 +2,8 @@ package com.tangem.data.staking.utils
import arrow.core.right import arrow.core.right
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
import com.tangem.data.staking.store.StakingBalancesStore import com.tangem.data.staking.store.P2PEthPoolBalancesStore
import com.tangem.data.staking.store.StakeKitBalancesStore
import com.tangem.domain.models.staking.StakingID import com.tangem.domain.models.staking.StakingID
import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.staking.StakingIdFactory import com.tangem.domain.staking.StakingIdFactory
@ -10,7 +11,7 @@ import com.tangem.domain.staking.model.StakingIntegrationID
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.clearMocks import io.mockk.clearMocks
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerifyOrder import io.mockk.coVerify
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -22,10 +23,12 @@ import org.junit.jupiter.api.TestInstance
class DefaultStakingCleanerTest { class DefaultStakingCleanerTest {
private val stakingIdFactory = mockk<StakingIdFactory>(relaxed = true) private val stakingIdFactory = mockk<StakingIdFactory>(relaxed = true)
private val stakingBalancesStore = mockk<StakingBalancesStore>(relaxed = true) private val stakeKitBalancesStore = mockk<StakeKitBalancesStore>(relaxed = true)
private val p2pEthPoolBalancesStore = mockk<P2PEthPoolBalancesStore>(relaxed = true)
private val cleaner = DefaultStakingCleaner( private val cleaner = DefaultStakingCleaner(
stakingIdFactory = stakingIdFactory, stakingIdFactory = stakingIdFactory,
stakingBalancesStore = stakingBalancesStore, stakeKitBalancesStore = stakeKitBalancesStore,
p2pEthPoolBalancesStore = p2pEthPoolBalancesStore,
dispatchers = TestingCoroutineDispatcherProvider(), dispatchers = TestingCoroutineDispatcherProvider(),
) )
@ -33,7 +36,7 @@ class DefaultStakingCleanerTest {
@BeforeEach @BeforeEach
fun setUp() { fun setUp() {
clearMocks(stakingIdFactory, stakingBalancesStore) clearMocks(stakingIdFactory, stakeKitBalancesStore, p2pEthPoolBalancesStore)
} }
@Nested @Nested
@ -50,8 +53,9 @@ class DefaultStakingCleanerTest {
cleaner(userWalletId = userWalletId, stakingIds = stakingIds) cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
// Assert // Assert
coVerifyOrder { coVerify {
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds) stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
p2pEthPoolBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
} }
} }
@ -61,22 +65,39 @@ class DefaultStakingCleanerTest {
cleaner(userWalletId = userWalletId, stakingIds = emptySet()) cleaner(userWalletId = userWalletId, stakingIds = emptySet())
// Assert // Assert
coVerifyOrder(inverse = true) { coVerify(inverse = true) {
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.clear(userWalletId = any(), stakingIds = any())
p2pEthPoolBalancesStore.clear(userWalletId = any(), stakingIds = any())
} }
} }
@Test @Test
fun `should catch exception from stakingBalancesStore and not throw`() = runTest { fun `should catch exception from stakingBalancesStore and not throw`() = runTest {
// Arrange // Arrange
coEvery { stakingBalancesStore.clear(userWalletId, stakingIds) } throws Exception() coEvery { stakeKitBalancesStore.clear(userWalletId, stakingIds) } throws Exception()
// Act // Act
cleaner(userWalletId = userWalletId, stakingIds = stakingIds) cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
// Assert // Assert
coVerifyOrder { coVerify {
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds) stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
p2pEthPoolBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
}
}
@Test
fun `should catch exception from p2pEthPoolBalancesStore and not throw`() = runTest {
// Arrange
coEvery { p2pEthPoolBalancesStore.clear(userWalletId, stakingIds) } throws Exception()
// Act
cleaner(userWalletId = userWalletId, stakingIds = stakingIds)
// Assert
coVerify {
stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
p2pEthPoolBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
} }
} }
} }
@ -102,9 +123,10 @@ class DefaultStakingCleanerTest {
cleaner(userWalletId = userWalletId, currency = coin) cleaner(userWalletId = userWalletId, currency = coin)
// Assert // Assert
coVerifyOrder { coVerify {
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin) stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin)
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId)) stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
p2pEthPoolBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
} }
} }
@ -114,9 +136,10 @@ class DefaultStakingCleanerTest {
cleaner(userWalletId = userWalletId, currencies = emptyList()) cleaner(userWalletId = userWalletId, currencies = emptyList())
// Assert // Assert
coVerifyOrder(inverse = true) { coVerify(inverse = true) {
stakingIdFactory.create(userWalletId = any(), cryptoCurrency = any()) stakingIdFactory.create(userWalletId = any(), cryptoCurrency = any())
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any()) stakeKitBalancesStore.clear(userWalletId = any(), stakingIds = any())
p2pEthPoolBalancesStore.clear(userWalletId = any(), stakingIds = any())
} }
} }
@ -130,16 +153,17 @@ class DefaultStakingCleanerTest {
coEvery { stakingIdFactory.create(userWalletId, coin) } returns stakingId.right() coEvery { stakingIdFactory.create(userWalletId, coin) } returns stakingId.right()
coEvery { coEvery {
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId)) stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
} throws Exception() } throws Exception()
// Act // Act
cleaner(userWalletId = userWalletId, currency = coin) cleaner(userWalletId = userWalletId, currency = coin)
// Assert // Assert
coVerifyOrder { coVerify {
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin) stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = coin)
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId)) stakeKitBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
p2pEthPoolBalancesStore.clear(userWalletId = userWalletId, stakingIds = setOf(stakingId))
} }
} }
} }

View file

@ -267,11 +267,12 @@ internal class StakingModel @Inject constructor(
private val transactionsInProgress: CopyOnWriteArrayList<StakingTransaction> = CopyOnWriteArrayList() private val transactionsInProgress: CopyOnWriteArrayList<StakingTransaction> = CopyOnWriteArrayList()
private var actionsJobHolder: JobHolder = JobHolder() private val actionsJobHolder: JobHolder = JobHolder()
private var approvalJobHolder: JobHolder = JobHolder() private val approvalJobHolder: JobHolder = JobHolder()
private var feeJobHolder: JobHolder = JobHolder() private val feeJobHolder: JobHolder = JobHolder()
private var sendTransactionJobHolder = JobHolder() private val sendTransactionJobHolder = JobHolder()
private var stepChangesJobHolder = JobHolder() private val stepChangesJobHolder = JobHolder()
private val balanceHidingJobHolder = JobHolder()
init { init {
subscribeOnSelectedAppCurrency() subscribeOnSelectedAppCurrency()
@ -286,6 +287,7 @@ internal class StakingModel @Inject constructor(
feeJobHolder.cancel() feeJobHolder.cancel()
sendTransactionJobHolder.cancel() sendTransactionJobHolder.cancel()
stepChangesJobHolder.cancel() stepChangesJobHolder.cancel()
balanceHidingJobHolder.cancel()
} }
override fun onBackClick() { override fun onBackClick() {
@ -1284,6 +1286,7 @@ internal class StakingModel @Inject constructor(
} }
.flowOn(dispatchers.main) .flowOn(dispatchers.main)
.launchIn(modelScope) .launchIn(modelScope)
.saveIn(balanceHidingJobHolder)
} }
private fun subscribeOnSelectedAppCurrency() { private fun subscribeOnSelectedAppCurrency() {