Updated on 2026-08-14
This commit is contained in:
parent
daf2a6b636
commit
81a7b760ae
104 changed files with 1197 additions and 941 deletions
|
|
@ -3,11 +3,11 @@ package com.tangem.data.staking
|
|||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.card.common.TapWorkarounds.isWallet2
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
|
|
@ -30,7 +30,7 @@ import kotlinx.coroutines.withContext
|
|||
internal class DefaultStakingRepository(
|
||||
private val stakeKitRepository: StakeKitRepository,
|
||||
private val p2pEthPoolRepository: P2PEthPoolRepository,
|
||||
private val stakingBalanceStoreV2: YieldsBalancesStore,
|
||||
private val stakingBalanceStoreV2: StakingBalancesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getUserWalletUseCase: GetUserWalletUseCase,
|
||||
private val stakingFeatureToggles: StakingFeatureToggles,
|
||||
|
|
@ -106,13 +106,13 @@ internal class DefaultStakingRepository(
|
|||
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
|
||||
val hasDataStakingBalance by lazy {
|
||||
balances.any { stakingBalance ->
|
||||
stakingBalance is StakingBalance.Data
|
||||
}
|
||||
}
|
||||
|
||||
balances.isNotEmpty() && hasDataYieldBalance
|
||||
balances.isNotEmpty() && hasDataStakingBalance
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ internal class DefaultStakingRepository(
|
|||
address = address,
|
||||
),
|
||||
)
|
||||
if (balance != null && balance is YieldBalance.Data && balance.balance.items.isNotEmpty()) {
|
||||
if ((balance as? StakingBalance.Data.StakeKit)?.balance?.items?.isNotEmpty() == true) {
|
||||
return true
|
||||
} else {
|
||||
stakingFeatureToggles.isCardanoStakingEnabled
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
package com.tangem.data.staking.converters.ethpool
|
||||
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolExitQueueDTO
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolExitRequestDTO
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolStakeDTO
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.*
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
/** Converts P2P ETH Pool API response to [StakingBalance.Data.P2P] */
|
||||
internal object P2PStakingBalanceConverter {
|
||||
|
||||
fun convert(response: P2PEthPoolAccountResponse, source: StatusSource): StakingBalance.Data.P2P {
|
||||
val stakingId = StakingID(
|
||||
integrationId = StakingIntegrationID.P2P.EthereumPooled.value,
|
||||
address = response.delegatorAddress,
|
||||
)
|
||||
|
||||
val account = P2PStakingAccount(
|
||||
delegatorAddress = response.delegatorAddress,
|
||||
vaultAddress = response.vaultAddress,
|
||||
stake = convertStake(response.stake),
|
||||
availableToUnstake = response.availableToUnstake,
|
||||
availableToWithdraw = response.availableToWithdraw,
|
||||
exitQueue = convertExitQueue(response.exitQueue),
|
||||
)
|
||||
|
||||
return StakingBalance.Data.P2P(
|
||||
stakingId = stakingId,
|
||||
source = source,
|
||||
account = account,
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertStake(dto: P2PEthPoolStakeDTO): P2PStake {
|
||||
return P2PStake(
|
||||
assets = dto.assets,
|
||||
totalEarnedAssets = dto.totalEarnedAssets,
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertExitQueue(dto: P2PEthPoolExitQueueDTO): P2PExitQueue {
|
||||
return P2PExitQueue(
|
||||
total = dto.total.toBigDecimal(),
|
||||
requests = dto.requests.map(::convertExitRequest),
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertExitRequest(dto: P2PEthPoolExitRequestDTO): P2PExitRequest {
|
||||
return P2PExitRequest(
|
||||
ticket = dto.ticket,
|
||||
totalAssets = dto.totalAssets.toBigDecimal(),
|
||||
timestamp = Instant.fromEpochSeconds(dto.timestamp),
|
||||
withdrawalTimestamp = Instant.fromEpochSeconds(dto.withdrawalTimestamp),
|
||||
isClaimable = dto.isClaimable,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.data.staking.di
|
||||
|
||||
import com.tangem.data.staking.multi.DefaultMultiStakingBalanceFetcher
|
||||
import com.tangem.data.staking.single.DefaultSingleStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface StakingBalanceFetcherModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSingleStakingBalanceFetcher(impl: DefaultSingleStakingBalanceFetcher): SingleStakingBalanceFetcher
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMultiStakingBalanceFetcher(impl: DefaultMultiStakingBalanceFetcher): MultiStakingBalanceFetcher
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.data.staking.di
|
||||
|
||||
import com.tangem.data.staking.multi.DefaultMultiStakingBalanceProducer
|
||||
import com.tangem.data.staking.single.DefaultSingleStakingBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceProducer
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface StakingBalanceProducerFactoryModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSingleStakingBalanceProducerFactory(
|
||||
impl: DefaultSingleStakingBalanceProducer.Factory,
|
||||
): SingleStakingBalanceProducer.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMultiStakingBalanceProducerFactory(
|
||||
impl: DefaultMultiStakingBalanceProducer.Factory,
|
||||
): MultiStakingBalanceProducer.Factory
|
||||
}
|
||||
|
|
@ -2,19 +2,17 @@ package com.tangem.data.staking.di
|
|||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.data.staking.store.DefaultP2PBalancesStore
|
||||
import com.tangem.data.staking.store.DefaultYieldsBalancesStore
|
||||
import com.tangem.data.staking.store.DefaultStakingBalancesStore
|
||||
import com.tangem.data.staking.store.P2PBalancesStore
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.token.P2PEthPoolVaultsStore
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceProducer
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceSupplier
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -23,15 +21,15 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object YieldBalanceSupplierModule {
|
||||
internal object StakingBalanceSupplierModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideYieldsBalancesStore(
|
||||
fun provideStakingBalancesStore(
|
||||
persistenceStore: DataStore<Map<String, Set<YieldBalanceWrapperDTO>>>,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): YieldsBalancesStore {
|
||||
return DefaultYieldsBalancesStore(
|
||||
): StakingBalancesStore {
|
||||
return DefaultStakingBalancesStore(
|
||||
runtimeStore = RuntimeSharedStore(),
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = dispatchers,
|
||||
|
|
@ -42,25 +40,25 @@ internal object YieldBalanceSupplierModule {
|
|||
@Singleton
|
||||
fun provideP2PBalancesStore(
|
||||
persistenceStore: DataStore<Map<String, Set<P2PEthPoolAccountResponse>>>,
|
||||
p2pVaultsStore: P2PEthPoolVaultsStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): P2PBalancesStore {
|
||||
return DefaultP2PBalancesStore(
|
||||
runtimeStore = RuntimeSharedStore(),
|
||||
persistenceStore = persistenceStore,
|
||||
vaultsProvider = { runSuspendCatching { p2pVaultsStore.getSync() }.getOrNull().orEmpty() },
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSingleYieldBalanceSupplier(factory: SingleYieldBalanceProducer.Factory): SingleYieldBalanceSupplier {
|
||||
return object : SingleYieldBalanceSupplier(
|
||||
fun provideSingleStakingBalanceSupplier(
|
||||
factory: SingleStakingBalanceProducer.Factory,
|
||||
): SingleStakingBalanceSupplier {
|
||||
return object : SingleStakingBalanceSupplier(
|
||||
factory = factory,
|
||||
keyCreator = { params ->
|
||||
listOf(
|
||||
"single_yield_balance",
|
||||
"single_staking_balance",
|
||||
params.userWalletId.stringValue,
|
||||
params.stakingId.integrationId,
|
||||
params.stakingId.address,
|
||||
|
|
@ -72,10 +70,10 @@ internal object YieldBalanceSupplierModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideMultiYieldBalanceSupplier(factory: MultiYieldBalanceProducer.Factory): MultiYieldBalanceSupplier {
|
||||
return object : MultiYieldBalanceSupplier(
|
||||
fun provideMultiStakingBalanceSupplier(factory: MultiStakingBalanceProducer.Factory): MultiStakingBalanceSupplier {
|
||||
return object : MultiStakingBalanceSupplier(
|
||||
factory = factory,
|
||||
keyCreator = { "multi_yields_balances_${it.userWalletId.stringValue}" },
|
||||
keyCreator = { "multi_staking_balances_${it.userWalletId.stringValue}" },
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
|
||||
import com.tangem.data.staking.*
|
||||
import com.tangem.data.staking.converters.error.StakeKitErrorConverter
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.data.staking.toggles.DefaultStakingFeatureToggles
|
||||
import com.tangem.data.staking.utils.DefaultStakingCleaner
|
||||
import com.tangem.datasource.api.ethpool.P2PEthPoolApi
|
||||
|
|
@ -55,7 +55,7 @@ internal object StakingDataModule {
|
|||
fun provideStakingRepository(
|
||||
stakeKitRepository: StakeKitRepository,
|
||||
p2pEthPoolRepository: P2PEthPoolRepository,
|
||||
yieldsBalancesStore: YieldsBalancesStore,
|
||||
stakingBalancesStore: StakingBalancesStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
getUserWalletUseCase: GetUserWalletUseCase,
|
||||
stakingFeatureToggles: StakingFeatureToggles,
|
||||
|
|
@ -64,7 +64,7 @@ internal object StakingDataModule {
|
|||
return DefaultStakingRepository(
|
||||
stakeKitRepository = stakeKitRepository,
|
||||
p2pEthPoolRepository = p2pEthPoolRepository,
|
||||
stakingBalanceStoreV2 = yieldsBalancesStore,
|
||||
stakingBalanceStoreV2 = stakingBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
getUserWalletUseCase = getUserWalletUseCase,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
|
|
@ -134,11 +134,11 @@ internal object StakingDataModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideStakingCleaner(
|
||||
yieldsBalancesStore: YieldsBalancesStore,
|
||||
stakingBalancesStore: StakingBalancesStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): StakingCleaner {
|
||||
return DefaultStakingCleaner(
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.data.staking.di
|
||||
|
||||
import com.tangem.data.staking.multi.DefaultMultiYieldBalanceFetcher
|
||||
import com.tangem.data.staking.single.DefaultSingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface YieldBalanceFetcherModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSingleYieldBalanceFetcher(impl: DefaultSingleYieldBalanceFetcher): SingleYieldBalanceFetcher
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMultiYieldBalanceFetcher(impl: DefaultMultiYieldBalanceFetcher): MultiYieldBalanceFetcher
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.data.staking.di
|
||||
|
||||
import com.tangem.data.staking.multi.DefaultMultiYieldBalanceProducer
|
||||
import com.tangem.data.staking.single.DefaultSingleYieldBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface YieldBalanceProducerFactoryModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindSingleYieldBalanceProducerFactory(
|
||||
impl: DefaultSingleYieldBalanceProducer.Factory,
|
||||
): SingleYieldBalanceProducer.Factory
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindMultiYieldBalanceProducerFactory(
|
||||
impl: DefaultMultiYieldBalanceProducer.Factory,
|
||||
): MultiYieldBalanceProducer.Factory
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import arrow.core.right
|
|||
import arrow.core.toOption
|
||||
import com.tangem.data.common.api.safeApiCall
|
||||
import com.tangem.data.staking.store.P2PBalancesStore
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.ethpool.P2PEthPoolApi
|
||||
|
|
@ -25,7 +25,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolNetwork
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
import kotlinx.coroutines.async
|
||||
|
|
@ -36,13 +36,13 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [MultiYieldBalanceFetcher]
|
||||
* Default implementation of [MultiStakingBalanceFetcher]
|
||||
*
|
||||
* Supports both StakeKit and P2P staking providers.
|
||||
*
|
||||
* @property userWalletsStore user wallets store
|
||||
* @property stakingYieldsStore staking yields store
|
||||
* @property yieldsBalancesStore yields balances store (StakeKit)
|
||||
* @property stakingBalancesStore staking balances store (StakeKit)
|
||||
* @property p2pBalancesStore P2P balances store
|
||||
* @property stakeKitApi stake kit API
|
||||
* @property p2pApi P2P ETH Pool API
|
||||
|
|
@ -52,19 +52,19 @@ import javax.inject.Inject
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
||||
internal class DefaultMultiStakingBalanceFetcher @Inject constructor(
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val stakingYieldsStore: StakingYieldsStore,
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
private val stakingBalancesStore: StakingBalancesStore,
|
||||
private val p2pBalancesStore: P2PBalancesStore,
|
||||
private val stakeKitApi: StakeKitApi,
|
||||
private val p2pApi: P2PEthPoolApi,
|
||||
private val p2pVaultsStore: P2PEthPoolVaultsStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : MultiYieldBalanceFetcher {
|
||||
) : MultiStakingBalanceFetcher {
|
||||
|
||||
override suspend fun invoke(params: MultiYieldBalanceFetcher.Params): Either<Throwable, Unit> {
|
||||
Timber.i("Start fetching yield balances for params:\n$params")
|
||||
override suspend fun invoke(params: MultiStakingBalanceFetcher.Params): Either<Throwable, Unit> {
|
||||
Timber.i("Start fetching staking balances for params:\n$params")
|
||||
|
||||
val stakingIds = params.stakingIds.ifEmpty {
|
||||
Timber.i("Nothing to fetch, empty stakingIds for ${params.userWalletId}")
|
||||
|
|
@ -102,10 +102,13 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
}
|
||||
}
|
||||
.onLeft { throwable ->
|
||||
Timber.e(throwable, "Unable to fetch yield balances $params")
|
||||
Timber.e(throwable, "Unable to fetch staking balances $params")
|
||||
|
||||
if (stakeKitIds.isNotEmpty()) {
|
||||
yieldsBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = stakeKitIds.toSet())
|
||||
stakingBalancesStore.storeError(
|
||||
userWalletId = params.userWalletId,
|
||||
stakingIds = stakeKitIds.toSet(),
|
||||
)
|
||||
}
|
||||
if (p2pIds.isNotEmpty()) {
|
||||
p2pBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = p2pIds.toSet())
|
||||
|
|
@ -114,7 +117,7 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
}
|
||||
|
||||
private suspend fun fetchStakeKitBalances(userWalletId: UserWalletId, stakingIds: Set<StakingID>) {
|
||||
yieldsBalancesStore.refresh(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
stakingBalancesStore.refresh(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
|
||||
val availableStakingIds = getAvailableStakingIds(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -252,7 +255,7 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
)
|
||||
|
||||
if (unavailableStakingIds.isNotEmpty()) {
|
||||
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = unavailableStakingIds.toSet())
|
||||
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = unavailableStakingIds.toSet())
|
||||
}
|
||||
|
||||
return availableStakingIds.toSet().ifEmpty {
|
||||
|
|
@ -301,8 +304,10 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
.toSet()
|
||||
}
|
||||
|
||||
Timber.i("Successfully fetched yield balances for $userWalletId:\n${yieldBalances.joinToString("\n")}")
|
||||
yieldsBalancesStore.storeActual(userWalletId = userWalletId, values = yieldBalances)
|
||||
Timber.i(
|
||||
"Successfully fetched staking balances for $userWalletId:\n${yieldBalances.joinToString("\n")}",
|
||||
)
|
||||
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = yieldBalances)
|
||||
|
||||
if (!allResponsesReceived(requests, yieldBalances)) {
|
||||
val values = stakingIds.filter { stakingId ->
|
||||
|
|
@ -312,13 +317,13 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = values.toSet())
|
||||
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = values.toSet())
|
||||
}
|
||||
},
|
||||
onError = { throwable ->
|
||||
Timber.e(throwable, "Unable to fetch yield balances $userWalletId")
|
||||
Timber.e(throwable, "Unable to fetch staking balances $userWalletId")
|
||||
|
||||
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
|
||||
throw throwable
|
||||
},
|
||||
|
|
@ -3,9 +3,9 @@ package com.tangem.data.staking.multi
|
|||
import arrow.core.Option
|
||||
import arrow.core.some
|
||||
import com.tangem.data.staking.store.P2PBalancesStore
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
|
|
@ -17,28 +17,28 @@ import kotlinx.coroutines.flow.flowOn
|
|||
import kotlinx.coroutines.flow.onEmpty
|
||||
|
||||
/**
|
||||
* Default implementation of [MultiYieldBalanceProducer]
|
||||
* Default implementation of [MultiStakingBalanceProducer]
|
||||
*
|
||||
* Combines yield balances from both StakeKit and P2P providers.
|
||||
* Combines staking balances from both StakeKit and P2P providers.
|
||||
*
|
||||
* @property params params
|
||||
* @property yieldsBalancesStore StakeKit yields balances store
|
||||
* @property stakingBalancesStore StakeKit staking balances store
|
||||
* @property p2pBalancesStore P2P balances store
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultMultiYieldBalanceProducer @AssistedInject constructor(
|
||||
@Assisted val params: MultiYieldBalanceProducer.Params,
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
internal class DefaultMultiStakingBalanceProducer @AssistedInject constructor(
|
||||
@Assisted val params: MultiStakingBalanceProducer.Params,
|
||||
private val stakingBalancesStore: StakingBalancesStore,
|
||||
private val p2pBalancesStore: P2PBalancesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : MultiYieldBalanceProducer {
|
||||
) : MultiStakingBalanceProducer {
|
||||
|
||||
override val fallback: Option<Set<YieldBalance>> = emptySet<YieldBalance>().some()
|
||||
override val fallback: Option<Set<StakingBalance>> = emptySet<StakingBalance>().some()
|
||||
|
||||
override fun produce(): Flow<Set<YieldBalance>> {
|
||||
val stakeKitFlow = yieldsBalancesStore.get(userWalletId = params.userWalletId)
|
||||
override fun produce(): Flow<Set<StakingBalance>> {
|
||||
val stakeKitFlow = stakingBalancesStore.get(userWalletId = params.userWalletId)
|
||||
val p2pFlow = p2pBalancesStore.get(userWalletId = params.userWalletId)
|
||||
|
||||
return combine(stakeKitFlow, p2pFlow) { stakeKitBalances, p2pBalances ->
|
||||
|
|
@ -50,7 +50,7 @@ internal class DefaultMultiYieldBalanceProducer @AssistedInject constructor(
|
|||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : MultiYieldBalanceProducer.Factory {
|
||||
override fun create(params: MultiYieldBalanceProducer.Params): DefaultMultiYieldBalanceProducer
|
||||
interface Factory : MultiStakingBalanceProducer.Factory {
|
||||
override fun create(params: MultiStakingBalanceProducer.Params): DefaultMultiStakingBalanceProducer
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.tangem.data.staking.single
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [SingleStakingBalanceFetcher]
|
||||
*
|
||||
* @property multiStakingBalanceFetcher multi staking balance fetcher
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleStakingBalanceFetcher @Inject constructor(
|
||||
private val multiStakingBalanceFetcher: MultiStakingBalanceFetcher,
|
||||
) : SingleStakingBalanceFetcher {
|
||||
|
||||
override suspend fun invoke(params: SingleStakingBalanceFetcher.Params): Either<Throwable, Unit> {
|
||||
return multiStakingBalanceFetcher(
|
||||
params = MultiStakingBalanceFetcher.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
stakingIds = setOf(params.stakingId),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,10 +4,10 @@ import arrow.core.Option
|
|||
import arrow.core.some
|
||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||
import com.tangem.core.analytics.models.ExceptionAnalyticsEvent
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceProducer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.indexOfFirstOrNull
|
||||
import dagger.assisted.Assisted
|
||||
|
|
@ -20,29 +20,29 @@ import kotlinx.coroutines.flow.mapNotNull
|
|||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* Default implementation of [SingleYieldBalanceProducer]
|
||||
* Default implementation of [SingleStakingBalanceProducer]
|
||||
*
|
||||
* @property params params
|
||||
* @property multiYieldBalanceSupplier multi yield balance supplier
|
||||
* @property analyticsExceptionHandler analytics exception handler
|
||||
* @property dispatchers dispatchers
|
||||
* @property params params
|
||||
* @property multiStakingBalanceSupplier multi staking balance supplier
|
||||
* @property analyticsExceptionHandler analytics exception handler
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
|
||||
@Assisted private val params: SingleYieldBalanceProducer.Params,
|
||||
private val multiYieldBalanceSupplier: MultiYieldBalanceSupplier,
|
||||
internal class DefaultSingleStakingBalanceProducer @AssistedInject constructor(
|
||||
@Assisted private val params: SingleStakingBalanceProducer.Params,
|
||||
private val multiStakingBalanceSupplier: MultiStakingBalanceSupplier,
|
||||
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : SingleYieldBalanceProducer {
|
||||
) : SingleStakingBalanceProducer {
|
||||
|
||||
override val fallback: Option<YieldBalance> = YieldBalance.Error(stakingId = params.stakingId).some()
|
||||
override val fallback: Option<StakingBalance> = StakingBalance.Error(stakingId = params.stakingId).some()
|
||||
|
||||
override fun produce(): Flow<YieldBalance> {
|
||||
Timber.i("Producing yield balance for params:\n$params")
|
||||
override fun produce(): Flow<StakingBalance> {
|
||||
Timber.i("Producing staking balance for params:\n$params")
|
||||
|
||||
return multiYieldBalanceSupplier(
|
||||
params = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId),
|
||||
return multiStakingBalanceSupplier(
|
||||
params = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId),
|
||||
)
|
||||
.mapNotNull { balances ->
|
||||
val currentStakingId = params.stakingId
|
||||
|
|
@ -65,7 +65,7 @@ internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
|
|||
currentBalances.joinToString("\n"),
|
||||
)
|
||||
|
||||
val dataIndex = currentBalances.indexOfFirstOrNull { it is YieldBalance.Data }
|
||||
val dataIndex = currentBalances.indexOfFirstOrNull { it is StakingBalance.Data }
|
||||
|
||||
if (dataIndex != null) {
|
||||
currentBalances[dataIndex]
|
||||
|
|
@ -75,7 +75,7 @@ internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
|
|||
} else {
|
||||
val balance = currentBalances.firstOrNull() ?: return@mapNotNull null
|
||||
|
||||
Timber.i("Yield balance found for $currentStakingId:\n$balance")
|
||||
Timber.i("Staking balance found for $currentStakingId:\n$balance")
|
||||
balance
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ internal class DefaultSingleYieldBalanceProducer @AssistedInject constructor(
|
|||
}
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory : SingleYieldBalanceProducer.Factory {
|
||||
override fun create(params: SingleYieldBalanceProducer.Params): DefaultSingleYieldBalanceProducer
|
||||
interface Factory : SingleStakingBalanceProducer.Factory {
|
||||
override fun create(params: SingleStakingBalanceProducer.Params): DefaultSingleStakingBalanceProducer
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
package com.tangem.data.staking.single
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [MultiYieldBalanceFetcher]
|
||||
*
|
||||
* @property multiYieldBalanceFetcher multi yield balance fetcher
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleYieldBalanceFetcher @Inject constructor(
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
||||
) : SingleYieldBalanceFetcher {
|
||||
|
||||
override suspend fun invoke(params: SingleYieldBalanceFetcher.Params): Either<Throwable, Unit> {
|
||||
return multiYieldBalanceFetcher(
|
||||
params = MultiYieldBalanceFetcher.Params(
|
||||
userWalletId = params.userWalletId,
|
||||
stakingIds = setOf(params.stakingId),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
package com.tangem.data.staking.store
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.data.staking.converters.ethpool.P2PEthPoolAccountConverter
|
||||
import com.tangem.data.staking.converters.ethpool.P2PYieldBalanceConverter
|
||||
import com.tangem.data.staking.converters.ethpool.P2PStakingBalanceConverter
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -19,25 +18,22 @@ import kotlinx.coroutines.flow.Flow
|
|||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal typealias WalletIdWithP2PBalances = Map<UserWalletId, Set<YieldBalance>>
|
||||
internal typealias WalletIdWithP2PStakingBalances = Map<UserWalletId, Set<StakingBalance>>
|
||||
internal typealias WalletIdWithP2PResponses = Map<String, Set<P2PEthPoolAccountResponse>>
|
||||
|
||||
/**
|
||||
* Default implementation of [P2PBalancesStore]
|
||||
*
|
||||
* Stores P2P ETH Pool staking balances with persistence support.
|
||||
* Stores P2P ETH Pool staking balances.
|
||||
*
|
||||
* @property runtimeStore runtime store
|
||||
* @property persistenceStore persistence store
|
||||
* @property vaultsProvider provider for vaults
|
||||
* @param dispatchers coroutine dispatchers
|
||||
*/
|
||||
internal class DefaultP2PBalancesStore(
|
||||
private val runtimeStore: RuntimeSharedStore<WalletIdWithP2PBalances>,
|
||||
private val runtimeStore: RuntimeSharedStore<WalletIdWithP2PStakingBalances>,
|
||||
private val persistenceStore: DataStore<WalletIdWithP2PResponses>,
|
||||
private val vaultsProvider: suspend () -> List<P2PEthPoolVault>,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : P2PBalancesStore {
|
||||
|
||||
|
|
@ -46,19 +42,13 @@ internal class DefaultP2PBalancesStore(
|
|||
init {
|
||||
scope.launch {
|
||||
val cachedData = persistenceStore.data.firstOrNull() ?: return@launch
|
||||
val vaults = vaultsProvider()
|
||||
|
||||
runtimeStore.store(
|
||||
value = cachedData.map { (stringWalletId, responses) ->
|
||||
val key = UserWalletId(stringWalletId)
|
||||
val value = responses.mapNotNull { response ->
|
||||
val vault = vaults.firstOrNull { it.vaultAddress == response.vaultAddress }
|
||||
?: return@mapNotNull null
|
||||
val account = P2PEthPoolAccountConverter.convert(response)
|
||||
P2PYieldBalanceConverter.convert(
|
||||
account = account,
|
||||
vault = vault,
|
||||
address = account.delegatorAddress,
|
||||
val value = responses.map { response ->
|
||||
P2PStakingBalanceConverter.convert(
|
||||
response = response,
|
||||
source = StatusSource.CACHE,
|
||||
)
|
||||
}.toSet()
|
||||
|
|
@ -69,17 +59,17 @@ internal class DefaultP2PBalancesStore(
|
|||
}
|
||||
}
|
||||
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>> {
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<StakingBalance>> {
|
||||
return runtimeStore.get().map { it[userWalletId].orEmpty() }
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): YieldBalance? {
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): StakingBalance? {
|
||||
return runtimeStore.getSyncOrNull()
|
||||
?.get(userWalletId)
|
||||
?.firstOrNull { it.stakingId == stakingId }
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>? {
|
||||
override suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<StakingBalance>? {
|
||||
return runtimeStore.getSyncOrNull()?.get(userWalletId)
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +94,7 @@ internal class DefaultP2PBalancesStore(
|
|||
updateInRuntime(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = stakingIds,
|
||||
ifNotFound = ::createErrorYieldBalance,
|
||||
ifNotFound = ::createErrorStakingBalance,
|
||||
update = { it.copySealed(source = StatusSource.ONLY_CACHE) },
|
||||
)
|
||||
}
|
||||
|
|
@ -117,20 +107,9 @@ internal class DefaultP2PBalancesStore(
|
|||
}
|
||||
|
||||
private suspend fun storeInRuntime(userWalletId: UserWalletId, values: Set<P2PEthPoolAccountResponse>) {
|
||||
val vaults = vaultsProvider()
|
||||
|
||||
val newBalances = values.mapNotNull { response ->
|
||||
val vault = vaults.firstOrNull { it.vaultAddress == response.vaultAddress }
|
||||
if (vault == null) {
|
||||
Timber.w("Vault not found for ${response.vaultAddress}")
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
val account = P2PEthPoolAccountConverter.convert(response)
|
||||
P2PYieldBalanceConverter.convert(
|
||||
account = account,
|
||||
vault = vault,
|
||||
address = account.delegatorAddress,
|
||||
val newBalances = values.map { response ->
|
||||
P2PStakingBalanceConverter.convert(
|
||||
response = response,
|
||||
source = StatusSource.ACTUAL,
|
||||
)
|
||||
}.toSet()
|
||||
|
|
@ -173,8 +152,7 @@ internal class DefaultP2PBalancesStore(
|
|||
current.toMutableMap().apply {
|
||||
this[userWalletId.stringValue] = this[userWalletId.stringValue].orEmpty()
|
||||
.filterNot { response ->
|
||||
val responseIntegrationId = "p2p-ethereum-pooled:${response.vaultAddress}"
|
||||
responseIntegrationId in integrationIds
|
||||
StakingIntegrationID.P2P.EthereumPooled.value in integrationIds
|
||||
}
|
||||
.toSet()
|
||||
}
|
||||
|
|
@ -184,8 +162,8 @@ internal class DefaultP2PBalancesStore(
|
|||
private suspend fun updateInRuntime(
|
||||
userWalletId: UserWalletId,
|
||||
stakingIds: Set<StakingID>,
|
||||
ifNotFound: (StakingID) -> YieldBalance? = { null },
|
||||
update: (YieldBalance) -> YieldBalance,
|
||||
ifNotFound: (StakingID) -> StakingBalance? = { null },
|
||||
update: (StakingBalance) -> StakingBalance,
|
||||
) {
|
||||
runtimeStore.update(default = emptyMap()) { stored ->
|
||||
stored.toMutableMap().apply {
|
||||
|
|
@ -209,5 +187,5 @@ internal class DefaultP2PBalancesStore(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createErrorYieldBalance(id: StakingID): YieldBalance = YieldBalance.Error(stakingId = id)
|
||||
private fun createErrorStakingBalance(id: StakingID): StakingBalance = StakingBalance.Error(stakingId = id)
|
||||
}
|
||||
|
|
@ -3,10 +3,10 @@ package com.tangem.data.staking.store
|
|||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.datasource.local.token.converter.YieldBalanceConverter
|
||||
import com.tangem.datasource.local.token.converter.StakingBalanceConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.addOrReplace
|
||||
|
|
@ -19,10 +19,10 @@ import kotlinx.coroutines.flow.map
|
|||
import kotlinx.coroutines.launch
|
||||
|
||||
internal typealias WalletIdWithWrappers = Map<String, Set<YieldBalanceWrapperDTO>>
|
||||
internal typealias WalletIdWithBalances = Map<UserWalletId, Set<YieldBalance>>
|
||||
internal typealias WalletIdWithStakingBalances = Map<UserWalletId, Set<StakingBalance>>
|
||||
|
||||
/**
|
||||
* Default implementation of [YieldsBalancesStore]
|
||||
* Default implementation of [StakingBalancesStore]
|
||||
*
|
||||
* @property runtimeStore runtime store
|
||||
* @property persistenceStore persistence store
|
||||
|
|
@ -30,11 +30,11 @@ internal typealias WalletIdWithBalances = Map<UserWalletId, Set<YieldBalance>>
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultYieldsBalancesStore(
|
||||
private val runtimeStore: RuntimeSharedStore<WalletIdWithBalances>,
|
||||
internal class DefaultStakingBalancesStore(
|
||||
private val runtimeStore: RuntimeSharedStore<WalletIdWithStakingBalances>,
|
||||
private val persistenceStore: DataStore<WalletIdWithWrappers>,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
) : YieldsBalancesStore {
|
||||
) : StakingBalancesStore {
|
||||
|
||||
private val scope = CoroutineScope(context = SupervisorJob() + dispatchers.io)
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ internal class DefaultYieldsBalancesStore(
|
|||
runtimeStore.store(
|
||||
value = cachedStatuses.map { (stringWalletId, wrappers) ->
|
||||
val key = UserWalletId(stringWalletId)
|
||||
val value = YieldBalanceConverter(isCached = true).convertSet(input = wrappers)
|
||||
val value = StakingBalanceConverter(isCached = true).convertSet(input = wrappers)
|
||||
.filterNotNull()
|
||||
.toSet()
|
||||
|
||||
|
|
@ -56,17 +56,17 @@ internal class DefaultYieldsBalancesStore(
|
|||
}
|
||||
}
|
||||
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>> {
|
||||
override fun get(userWalletId: UserWalletId): Flow<Set<StakingBalance>> {
|
||||
return runtimeStore.get().map { it[userWalletId].orEmpty() }
|
||||
}
|
||||
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): YieldBalance? {
|
||||
override suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): StakingBalance? {
|
||||
return runtimeStore.getSyncOrNull()
|
||||
?.get(userWalletId)
|
||||
?.firstOrNull { it.stakingId == stakingId }
|
||||
}
|
||||
|
||||
override suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>? {
|
||||
override suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<StakingBalance>? {
|
||||
return runtimeStore.getSyncOrNull()?.get(userWalletId)
|
||||
}
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ internal class DefaultYieldsBalancesStore(
|
|||
updateInRuntime(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = stakingIds,
|
||||
ifNotFound = ::createErrorYieldBalance,
|
||||
ifNotFound = ::createErrorStakingBalance,
|
||||
update = { it.copySealed(source = StatusSource.ONLY_CACHE) },
|
||||
)
|
||||
}
|
||||
|
|
@ -107,7 +107,7 @@ internal class DefaultYieldsBalancesStore(
|
|||
}
|
||||
|
||||
private suspend fun storeInRuntime(userWalletId: UserWalletId, values: Set<YieldBalanceWrapperDTO>) {
|
||||
val newBalances = YieldBalanceConverter(isCached = false).convertSet(input = values)
|
||||
val newBalances = StakingBalanceConverter(isCached = false).convertSet(input = values)
|
||||
.filterNotNull()
|
||||
.toSet()
|
||||
|
||||
|
|
@ -140,8 +140,8 @@ internal class DefaultYieldsBalancesStore(
|
|||
private suspend fun updateInRuntime(
|
||||
userWalletId: UserWalletId,
|
||||
stakingIds: Set<StakingID>,
|
||||
ifNotFound: (StakingID) -> YieldBalance? = { null },
|
||||
update: (YieldBalance) -> YieldBalance,
|
||||
ifNotFound: (StakingID) -> StakingBalance? = { null },
|
||||
update: (StakingBalance) -> StakingBalance,
|
||||
) {
|
||||
runtimeStore.update(default = emptyMap()) { stored ->
|
||||
stored.toMutableMap().apply {
|
||||
|
|
@ -165,7 +165,7 @@ internal class DefaultYieldsBalancesStore(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createErrorYieldBalance(id: StakingID): YieldBalance = YieldBalance.Error(stakingId = id)
|
||||
private fun createErrorStakingBalance(id: StakingID): StakingBalance = StakingBalance.Error(stakingId = id)
|
||||
|
||||
private fun YieldBalanceWrapperDTO.getStakingId(): StakingID? {
|
||||
val integrationId = integrationId
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.data.staking.store
|
||||
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -11,11 +11,11 @@ import kotlinx.coroutines.flow.Flow
|
|||
*/
|
||||
interface P2PBalancesStore {
|
||||
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>>
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<StakingBalance>>
|
||||
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): YieldBalance?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): StakingBalance?
|
||||
|
||||
suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>?
|
||||
suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<StakingBalance>?
|
||||
|
||||
suspend fun refresh(userWalletId: UserWalletId, stakingId: StakingID)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,39 +1,27 @@
|
|||
package com.tangem.data.staking.store
|
||||
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
/**
|
||||
* Store of [YieldBalance]'s set
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface YieldsBalancesStore {
|
||||
/** Store of StakeKit [StakingBalance] */
|
||||
interface StakingBalancesStore {
|
||||
|
||||
/** Get flow of [YieldBalance]'s set by [userWalletId] */
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<YieldBalance>>
|
||||
fun get(userWalletId: UserWalletId): Flow<Set<StakingBalance>>
|
||||
|
||||
/** Get [YieldBalance] by [userWalletId] and [stakingId] synchronously or null */
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): YieldBalance?
|
||||
suspend fun getSyncOrNull(userWalletId: UserWalletId, stakingId: StakingID): StakingBalance?
|
||||
|
||||
/** Get all [YieldBalance] by [userWalletId] synchronously or null */
|
||||
suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<YieldBalance>?
|
||||
suspend fun getAllSyncOrNull(userWalletId: UserWalletId): Set<StakingBalance>?
|
||||
|
||||
/** Refresh balance of [stakingId] by [userWalletId] */
|
||||
suspend fun refresh(userWalletId: UserWalletId, stakingId: StakingID)
|
||||
|
||||
/** Refresh balances of [stakingIds] by [userWalletId] */
|
||||
suspend fun refresh(userWalletId: UserWalletId, stakingIds: Set<StakingID>)
|
||||
|
||||
/** Store actual [values] by [userWalletId] */
|
||||
suspend fun storeActual(userWalletId: UserWalletId, values: Set<YieldBalanceWrapperDTO>)
|
||||
|
||||
/** Store error by [userWalletId] and [stakingIds] */
|
||||
suspend fun storeError(userWalletId: UserWalletId, stakingIds: Set<StakingID>)
|
||||
|
||||
/** Clear balances of [stakingIds] by [userWalletId] */
|
||||
suspend fun clear(userWalletId: UserWalletId, stakingIds: Set<StakingID>)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.utils.StakingCleaner
|
||||
|
|
@ -9,13 +9,13 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
|||
/**
|
||||
* Default implementation of [StakingCleaner].
|
||||
*
|
||||
* @property yieldsBalancesStore Store to manage yields balances.
|
||||
* @property stakingBalancesStore Store to manage staking balances.
|
||||
* @property dispatchers Coroutine dispatchers provider.
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultStakingCleaner(
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
private val stakingBalancesStore: StakingBalancesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : StakingCleaner {
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ internal class DefaultStakingCleaner(
|
|||
if (stakingIds.isEmpty()) return
|
||||
|
||||
with(dispatchers.default) {
|
||||
yieldsBalancesStore.clear(userWalletId, stakingIds)
|
||||
stakingBalancesStore.clear(userWalletId, stakingIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,19 @@
|
|||
package com.tangem.data.staking
|
||||
|
||||
import com.tangem.common.test.data.staking.MockP2PEthPoolAccountResponseFactory
|
||||
import com.tangem.data.staking.converters.ethpool.P2PEthPoolAccountConverter
|
||||
import com.tangem.data.staking.converters.ethpool.P2PYieldBalanceConverter
|
||||
import com.tangem.data.staking.converters.ethpool.P2PStakingBalanceConverter
|
||||
import com.tangem.datasource.api.ethpool.models.response.P2PEthPoolAccountResponse
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.token.converter.YieldBalanceConverter
|
||||
import com.tangem.datasource.local.token.converter.StakingBalanceConverter
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.staking.model.ethpool.P2PEthPoolVault
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
|
||||
internal fun YieldBalanceWrapperDTO.toDomain(source: StatusSource = StatusSource.CACHE): YieldBalance {
|
||||
return YieldBalanceConverter(source = source).convert(this)!!
|
||||
internal fun YieldBalanceWrapperDTO.toDomain(source: StatusSource = StatusSource.CACHE): StakingBalance {
|
||||
return StakingBalanceConverter(isCached = source == StatusSource.CACHE).convert(this)!!
|
||||
}
|
||||
|
||||
internal fun P2PEthPoolAccountResponse.toDomain(
|
||||
vault: P2PEthPoolVault = MockP2PEthPoolAccountResponseFactory.createMockVault(vaultAddress = vaultAddress),
|
||||
source: StatusSource = StatusSource.CACHE,
|
||||
): YieldBalance {
|
||||
val account = P2PEthPoolAccountConverter.convert(this)
|
||||
return P2PYieldBalanceConverter.convert(
|
||||
account = account,
|
||||
vault = vault,
|
||||
address = account.delegatorAddress,
|
||||
internal fun P2PEthPoolAccountResponse.toDomain(source: StatusSource = StatusSource.CACHE): StakingBalance.Data.P2P {
|
||||
return P2PStakingBalanceConverter.convert(
|
||||
response = this,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
|
|
@ -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.domain.wallet.MockUserWalletFactory
|
||||
import com.tangem.data.staking.store.P2PBalancesStore
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
|
||||
import com.tangem.datasource.api.common.response.ApiResponse
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
|
|
@ -17,7 +17,7 @@ import com.tangem.datasource.local.token.StakingYieldsStore
|
|||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.test.core.assertEitherLeft
|
||||
import com.tangem.test.core.assertEitherRight
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
|
|
@ -31,20 +31,20 @@ import org.junit.jupiter.api.TestInstance
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultMultiYieldBalanceFetcherTest {
|
||||
internal class DefaultMultiStakingBalanceFetcherTest {
|
||||
|
||||
private val userWalletsStore: UserWalletsStore = mockk()
|
||||
private val stakingYieldsStore: StakingYieldsStore = mockk()
|
||||
private val yieldsBalancesStore: YieldsBalancesStore = mockk(relaxUnitFun = true)
|
||||
private val stakingBalancesStore: StakingBalancesStore = mockk(relaxUnitFun = true)
|
||||
private val p2pBalancesStore: P2PBalancesStore = mockk(relaxUnitFun = true)
|
||||
private val stakeKitApi: StakeKitApi = mockk()
|
||||
private val p2pApi: P2PEthPoolApi = mockk()
|
||||
private val p2pVaultsStore: P2PEthPoolVaultsStore = mockk()
|
||||
|
||||
private val fetcher = DefaultMultiYieldBalanceFetcher(
|
||||
private val fetcher = DefaultMultiStakingBalanceFetcher(
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
p2pBalancesStore = p2pBalancesStore,
|
||||
stakeKitApi = stakeKitApi,
|
||||
p2pApi = p2pApi,
|
||||
|
|
@ -54,13 +54,13 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(userWalletsStore, stakingYieldsStore, yieldsBalancesStore, stakeKitApi)
|
||||
clearMocks(userWalletsStore, stakingYieldsStore, stakingBalancesStore, stakeKitApi)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances successfully`() = runTest {
|
||||
fun `fetch staking balances successfully`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
|
|
@ -81,21 +81,21 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
stakeKitApi.getMultipleYieldBalances(requests)
|
||||
yieldsBalancesStore.storeActual(userWalletId = userWalletId, values = result)
|
||||
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = result)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) { yieldsBalancesStore.storeError(any(), any()) }
|
||||
coVerify(inverse = true) { stakingBalancesStore.storeError(any(), any()) }
|
||||
|
||||
assertEitherRight(actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances successfully if one of stakingIds is unavailable`() = runTest {
|
||||
fun `fetch staking balances successfully if one of stakingIds is unavailable`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
|
|
@ -113,20 +113,20 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = setOf(solanaId))
|
||||
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = setOf(solanaId))
|
||||
stakeKitApi.getMultipleYieldBalances(requests)
|
||||
yieldsBalancesStore.storeActual(userWalletId = userWalletId, values = result)
|
||||
stakingBalancesStore.storeActual(userWalletId = userWalletId, values = result)
|
||||
}
|
||||
|
||||
assertEitherRight(actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if user wallet is not supported`() = runTest {
|
||||
fun `fetch staking balances failure if user wallet is not supported`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
val userWallet = MockUserWalletFactory.create().copy(isMultiCurrency = false)
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
|
@ -138,11 +138,11 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
yieldsBalancesStore.refresh(userWalletId = any(), stakingIds = any())
|
||||
stakingBalancesStore.refresh(userWalletId = any(), stakingIds = any())
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
yieldsBalancesStore.storeError(userWalletId = any(), stakingIds = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeError(userWalletId = any(), stakingIds = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${userWallet.toOption()}")
|
||||
|
|
@ -151,9 +151,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if userWalletsStore returns null`() = runTest {
|
||||
fun `fetch staking balances failure if userWalletsStore returns null`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns null
|
||||
|
||||
|
|
@ -164,11 +164,11 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
coVerifyOrder { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
yieldsBalancesStore.refresh(userWalletId = any(), stakingIds = any())
|
||||
stakingBalancesStore.refresh(userWalletId = any(), stakingIds = any())
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
stakeKitApi.getSingleYieldBalance(integrationId = any(), body = any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
yieldsBalancesStore.storeError(userWalletId = any(), stakingIds = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeError(userWalletId = any(), stakingIds = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${null.toOption()}")
|
||||
|
|
@ -177,9 +177,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if stakingYieldsStore getSyncWithTimeout returns null`() = runTest {
|
||||
fun `fetch staking balances failure if stakingYieldsStore getSyncWithTimeout returns null`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingYieldsStore.getSyncWithTimeout() } returns null
|
||||
|
|
@ -190,14 +190,14 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(params.userWalletId, tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
yieldsBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakeKitApi.getMultipleYieldBalances(any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
|
||||
|
|
@ -206,9 +206,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if stakingYieldsStore getSyncWithTimeout returns empty list`() = runTest {
|
||||
fun `fetch staking balances failure if stakingYieldsStore getSyncWithTimeout returns empty list`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingYieldsStore.getSyncWithTimeout() } returns emptyList()
|
||||
|
|
@ -219,14 +219,14 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
yieldsBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakeKitApi.getMultipleYieldBalances(any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
|
||||
|
|
@ -235,9 +235,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if yields converting is failed`() = runTest {
|
||||
fun `fetch staking balances failure if yields converting is failed`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
|
|
@ -253,14 +253,14 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
yieldsBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakeKitApi.getMultipleYieldBalances(any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("No enabled yields for ${params.userWalletId}")
|
||||
|
|
@ -269,9 +269,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if available yields does not contain ids from params`() = runTest {
|
||||
fun `fetch staking balances failure if available yields does not contain ids from params`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
|
|
@ -284,14 +284,14 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
yieldsBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
stakingBalancesStore.storeError(userWalletId, tonAndSolanaIds)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakeKitApi.getMultipleYieldBalances(any())
|
||||
yieldsBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
stakingBalancesStore.storeActual(userWalletId = any(), values = any())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException(
|
||||
|
|
@ -306,9 +306,9 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if stakeKitApi getMultipleYieldBalances is failed`() = runTest {
|
||||
fun `fetch staking balances failure if stakeKitApi getMultipleYieldBalances is failed`() = runTest {
|
||||
// Arrange
|
||||
val params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
val params = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
|
|
@ -329,13 +329,13 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
coVerifyOrder {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
stakeKitApi.getMultipleYieldBalances(requests)
|
||||
yieldsBalancesStore.storeError(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
stakingBalancesStore.storeError(userWalletId = userWalletId, stakingIds = tonAndSolanaIds)
|
||||
}
|
||||
|
||||
coVerify(inverse = true) { yieldsBalancesStore.storeActual(userWalletId = any(), values = any()) }
|
||||
coVerify(inverse = true) { stakingBalancesStore.storeActual(userWalletId = any(), values = any()) }
|
||||
|
||||
val expected = ApiResponseError.NetworkException()
|
||||
|
||||
|
|
@ -4,12 +4,13 @@ import com.google.common.truth.Truth
|
|||
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
||||
import com.tangem.common.test.data.staking.MockP2PEthPoolAccountResponseFactory
|
||||
import com.tangem.data.staking.store.P2PBalancesStore
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.data.staking.toDomain
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.*
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
|
|
@ -22,17 +23,17 @@ import org.junit.Test
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultMultiYieldBalanceProducerTest {
|
||||
internal class DefaultMultiStakingBalanceProducerTest {
|
||||
|
||||
private val params = MultiYieldBalanceProducer.Params(userWalletId = UserWalletId("011"))
|
||||
private val params = MultiStakingBalanceProducer.Params(userWalletId = UserWalletId("011"))
|
||||
|
||||
private val yieldsBalancesStore = mockk<YieldsBalancesStore>()
|
||||
private val stakingBalancesStore = mockk<StakingBalancesStore>()
|
||||
private val p2pBalancesStore = mockk<P2PBalancesStore>()
|
||||
private val dispatchers = TestingCoroutineDispatcherProvider()
|
||||
|
||||
private val producer = DefaultMultiYieldBalanceProducer(
|
||||
private val producer = DefaultMultiStakingBalanceProducer(
|
||||
params = params,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
p2pBalancesStore = p2pBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
|
@ -46,13 +47,13 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
|
||||
val networksStatusesFlow = flowOf(balances)
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
|
@ -63,15 +64,15 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is updated if balances are updated`() = runTest {
|
||||
val networksStatusesFlow = MutableSharedFlow<Set<YieldBalance>>(replay = 2)
|
||||
val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
// first emit
|
||||
|
|
@ -104,15 +105,15 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is filtered the same balance`() = runTest {
|
||||
val networksStatusesFlow = MutableSharedFlow<Set<YieldBalance>>(replay = 2)
|
||||
val networksStatusesFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
// first emit
|
||||
|
|
@ -155,19 +156,19 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
}
|
||||
.buffer(capacity = 5)
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns networksStatusesFlow
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns flowOf(emptySet())
|
||||
|
||||
val actual = producer.produceWithFallback()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
val values1 = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values1.size).isEqualTo(1)
|
||||
Truth.assertThat(values1).isEqualTo(listOf(emptySet<YieldBalance>()))
|
||||
Truth.assertThat(values1).isEqualTo(listOf(emptySet<StakingBalance>()))
|
||||
|
||||
innerFlow.emit(value = true)
|
||||
|
||||
|
|
@ -179,19 +180,19 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
|
||||
@Test
|
||||
fun `test that flow is empty`() = runTest {
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns emptyFlow()
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns emptyFlow()
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns emptyFlow()
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values.size).isEqualTo(1)
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<YieldBalance>()))
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<StakingBalance>()))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -199,13 +200,13 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
val stakeKitBalances = createStakeKitBalances()
|
||||
val p2pBalances = createP2PBalances()
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns flowOf(p2pBalances)
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
|
@ -217,15 +218,15 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
@Test
|
||||
fun `test that P2P balances are updated independently from StakeKit`() = runTest {
|
||||
val stakeKitBalances = createStakeKitBalancesWithTonOnly()
|
||||
val p2pFlow = MutableSharedFlow<Set<YieldBalance>>(replay = 2)
|
||||
val p2pFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2)
|
||||
|
||||
every { yieldsBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
|
||||
every { stakingBalancesStore.get(params.userWalletId) } returns flowOf(stakeKitBalances)
|
||||
every { p2pBalancesStore.get(params.userWalletId) } returns p2pFlow
|
||||
|
||||
val actual = producer.produce()
|
||||
|
||||
// check after producer.produce()
|
||||
verify { yieldsBalancesStore.get(params.userWalletId) }
|
||||
verify { stakingBalancesStore.get(params.userWalletId) }
|
||||
verify { p2pBalancesStore.get(params.userWalletId) }
|
||||
|
||||
// first emit - empty P2P
|
||||
|
|
@ -254,24 +255,24 @@ internal class DefaultMultiYieldBalanceProducerTest {
|
|||
address = "0x1",
|
||||
)
|
||||
val p2pEthereumId = StakingID(
|
||||
integrationId = "p2p-ethereum-pooled",
|
||||
integrationId = StakingIntegrationID.P2P.EthereumPooled.value,
|
||||
address = "0x5aa711F440Eb6d4361148bBD89d03464628ace84",
|
||||
)
|
||||
|
||||
fun createStakeKitBalances(): Set<YieldBalance> {
|
||||
fun createStakeKitBalances(): Set<StakingBalance> {
|
||||
return setOf(
|
||||
MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain(),
|
||||
MockYieldBalanceWrapperDTOFactory.createWithBalance(solanaId).toDomain(),
|
||||
)
|
||||
}
|
||||
|
||||
fun createStakeKitBalancesWithTonOnly(): Set<YieldBalance> {
|
||||
fun createStakeKitBalancesWithTonOnly(): Set<StakingBalance> {
|
||||
return setOf(
|
||||
MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain(),
|
||||
)
|
||||
}
|
||||
|
||||
fun createP2PBalances(): Set<YieldBalance> {
|
||||
fun createP2PBalances(): Set<StakingBalance> {
|
||||
return setOf(
|
||||
MockP2PEthPoolAccountResponseFactory.createWithBalance(stakingId = p2pEthereumId).toDomain(
|
||||
source = StatusSource.ACTUAL,
|
||||
|
|
@ -5,8 +5,8 @@ import arrow.core.right
|
|||
import com.google.common.truth.Truth
|
||||
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceFetcher
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
|
|
@ -20,32 +20,32 @@ import org.junit.jupiter.api.TestInstance
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultSingleYieldBalanceFetcherTest {
|
||||
internal class DefaultSingleStakingBalanceFetcherTest {
|
||||
|
||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher = mockk()
|
||||
private val multiStakingBalanceFetcher: MultiStakingBalanceFetcher = mockk()
|
||||
|
||||
private val fetcher = DefaultSingleYieldBalanceFetcher(
|
||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
||||
private val fetcher = DefaultSingleStakingBalanceFetcher(
|
||||
multiStakingBalanceFetcher = multiStakingBalanceFetcher,
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun resetMocks() {
|
||||
clearMocks(multiYieldBalanceFetcher)
|
||||
clearMocks(multiStakingBalanceFetcher)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yield balance successfully`() = runTest {
|
||||
fun `fetch staking balance successfully`() = runTest {
|
||||
// Arrange
|
||||
val params = SingleYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingId = tonId)
|
||||
val params = SingleStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingId = tonId)
|
||||
|
||||
val multiParams = MultiYieldBalanceFetcher.Params(
|
||||
val multiParams = MultiStakingBalanceFetcher.Params(
|
||||
userWalletId = userWalletId,
|
||||
stakingIds = setOf(tonId),
|
||||
)
|
||||
|
||||
val multiResult = Unit.right()
|
||||
|
||||
coEvery { multiYieldBalanceFetcher(params = multiParams) } returns multiResult
|
||||
coEvery { multiStakingBalanceFetcher(params = multiParams) } returns multiResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher.invoke(params).isRight()
|
||||
|
|
@ -53,26 +53,26 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
// Assert
|
||||
Truth.assertThat(actual).isTrue()
|
||||
|
||||
coVerify { multiYieldBalanceFetcher(params = multiParams) }
|
||||
coVerify { multiStakingBalanceFetcher(params = multiParams) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yield balance failure`() = runTest {
|
||||
fun `fetch staking balance failure`() = runTest {
|
||||
// Arrange
|
||||
val params = SingleYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingId = tonId)
|
||||
val params = SingleStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingId = tonId)
|
||||
|
||||
val multiParams = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = setOf(tonId))
|
||||
val multiParams = MultiStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = setOf(tonId))
|
||||
|
||||
val multiResult = IllegalStateException().left()
|
||||
|
||||
coEvery { multiYieldBalanceFetcher(params = multiParams) } returns multiResult
|
||||
coEvery { multiStakingBalanceFetcher(params = multiParams) } returns multiResult
|
||||
|
||||
// Act
|
||||
val actual = fetcher.invoke(params)
|
||||
|
||||
// Assert
|
||||
Truth.assertThat(actual).isEqualTo(multiResult)
|
||||
coVerify { multiYieldBalanceFetcher(params = multiParams) }
|
||||
coVerify { multiStakingBalanceFetcher(params = multiParams) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
@ -4,12 +4,12 @@ import com.google.common.truth.Truth
|
|||
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
||||
import com.tangem.core.analytics.api.AnalyticsExceptionHandler
|
||||
import com.tangem.data.staking.toDomain
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleYieldBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceProducer
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceSupplier
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceProducer
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.clearMocks
|
||||
|
|
@ -26,20 +26,20 @@ import org.junit.jupiter.api.TestInstance
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class DefaultSingleYieldBalanceProducerTest {
|
||||
internal class DefaultSingleStakingBalanceProducerTest {
|
||||
|
||||
private val params = SingleYieldBalanceProducer.Params(
|
||||
private val params = SingleStakingBalanceProducer.Params(
|
||||
userWalletId = UserWalletId(stringValue = "011"),
|
||||
stakingId = tonId,
|
||||
)
|
||||
|
||||
private val multiNetworkStatusSupplier = mockk<MultiYieldBalanceSupplier>()
|
||||
private val multiNetworkStatusSupplier = mockk<MultiStakingBalanceSupplier>()
|
||||
private val analyticsExceptionHandler = mockk<AnalyticsExceptionHandler>(relaxUnitFun = true)
|
||||
private val dispatchers = TestingCoroutineDispatcherProvider()
|
||||
|
||||
private val producer = DefaultSingleYieldBalanceProducer(
|
||||
private val producer = DefaultSingleStakingBalanceProducer(
|
||||
params = params,
|
||||
multiYieldBalanceSupplier = multiNetworkStatusSupplier,
|
||||
multiStakingBalanceSupplier = multiNetworkStatusSupplier,
|
||||
analyticsExceptionHandler = analyticsExceptionHandler,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
|
@ -61,7 +61,7 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
),
|
||||
)
|
||||
|
||||
val multiParams = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
// Act
|
||||
|
|
@ -74,17 +74,17 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `flow is updated if yield balance is updated`() = runTest {
|
||||
fun `flow is updated if staking balance is updated`() = runTest {
|
||||
// Arrange
|
||||
val multiFlow = MutableSharedFlow<Set<YieldBalance>>(replay = 2, extraBufferCapacity = 1)
|
||||
val multiFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
val multiParams = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
|
||||
val balance = MockYieldBalanceWrapperDTOFactory.createWithBalance(tonId).toDomain()
|
||||
val updatedBalance = YieldBalance.Error(stakingId = tonId)
|
||||
val updatedBalance = StakingBalance.Error(stakingId = tonId)
|
||||
|
||||
// Act (first emit)
|
||||
multiFlow.emit(value = setOf(balance))
|
||||
|
|
@ -108,9 +108,9 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
@Test
|
||||
fun `flow is filtered the same status`() = runTest {
|
||||
// Arrange
|
||||
val multiFlow = MutableSharedFlow<Set<YieldBalance>>(replay = 2, extraBufferCapacity = 1)
|
||||
val multiFlow = MutableSharedFlow<Set<StakingBalance>>(replay = 2, extraBufferCapacity = 1)
|
||||
|
||||
val multiParams = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
|
|
@ -153,7 +153,7 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
}
|
||||
.buffer(capacity = 5)
|
||||
|
||||
val multiParams = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produceWithFallback()
|
||||
|
|
@ -162,7 +162,7 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
val actual1 = getEmittedValues(flow = producerFlow)
|
||||
|
||||
// Assert (first emit)
|
||||
val fallbackStatus = YieldBalance.Error(stakingId = tonId.copy(address = "0x1"))
|
||||
val fallbackStatus = StakingBalance.Error(stakingId = tonId.copy(address = "0x1"))
|
||||
|
||||
Truth.assertThat(actual1).hasSize(1)
|
||||
Truth.assertThat(actual1).containsExactly(fallbackStatus)
|
||||
|
|
@ -184,7 +184,7 @@ internal class DefaultSingleYieldBalanceProducerTest {
|
|||
|
||||
val multiFlow = flowOf(setOf(balance))
|
||||
|
||||
val multiParams = MultiYieldBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
val multiParams = MultiStakingBalanceProducer.Params(userWalletId = params.userWalletId)
|
||||
every { multiNetworkStatusSupplier(multiParams) } returns multiFlow
|
||||
|
||||
val producerFlow = producer.produce()
|
||||
|
|
@ -5,7 +5,7 @@ import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
|||
import com.tangem.common.test.datastore.MockStateDataStore
|
||||
import com.tangem.data.staking.toDomain
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.test.core.getEmittedValues
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
|
|
@ -15,12 +15,12 @@ import org.junit.Test
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class YieldsBalancesStoreGetMethodTest {
|
||||
internal class StakingBalancesStoreGetMethodTest {
|
||||
|
||||
private val runtimeStore = RuntimeSharedStore<WalletIdWithBalances>()
|
||||
private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
|
||||
private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
|
||||
|
||||
private val store = DefaultYieldsBalancesStore(
|
||||
private val store = DefaultStakingBalancesStore(
|
||||
runtimeStore = runtimeStore,
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
|
|
@ -32,7 +32,7 @@ internal class YieldsBalancesStoreGetMethodTest {
|
|||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
val expected = listOf(emptySet<YieldBalance>())
|
||||
val expected = listOf(emptySet<StakingBalance>())
|
||||
Truth.assertThat(values).isEqualTo(expected)
|
||||
}
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ internal class YieldsBalancesStoreGetMethodTest {
|
|||
|
||||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
val expected = listOf(emptySet<YieldBalance>())
|
||||
val expected = listOf(emptySet<StakingBalance>())
|
||||
Truth.assertThat(values).isEqualTo(expected)
|
||||
}
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ internal class YieldsBalancesStoreGetMethodTest {
|
|||
val values = getEmittedValues(flow = actual)
|
||||
|
||||
Truth.assertThat(values.size).isEqualTo(1)
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<YieldBalance>()))
|
||||
Truth.assertThat(values).isEqualTo(listOf(emptySet<StakingBalance>()))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -6,7 +6,7 @@ import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
|||
import com.tangem.common.test.datastore.MockStateDataStore
|
||||
import com.tangem.data.staking.toDomain
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.every
|
||||
|
|
@ -18,16 +18,16 @@ import org.junit.Test
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class YieldsBalancesStoreInitializationTest {
|
||||
internal class StakingBalancesStoreInitializationTest {
|
||||
|
||||
@Test
|
||||
fun `test initialization if cache store is empty`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithBalances>()
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
|
||||
val persistenceStore: DataStore<WalletIdWithWrappers> = mockk()
|
||||
|
||||
every { persistenceStore.data } returns emptyFlow()
|
||||
|
||||
DefaultYieldsBalancesStore(
|
||||
DefaultStakingBalancesStore(
|
||||
runtimeStore = runtimeStore,
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
|
|
@ -38,21 +38,21 @@ internal class YieldsBalancesStoreInitializationTest {
|
|||
|
||||
@Test
|
||||
fun `test initialization if cache store contains empty map`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithBalances>()
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
|
||||
val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
|
||||
|
||||
DefaultYieldsBalancesStore(
|
||||
DefaultStakingBalancesStore(
|
||||
runtimeStore = runtimeStore,
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(emptyMap<String, Set<YieldBalance>>())
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(emptyMap<String, Set<StakingBalance>>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test initialization if cache store is not empty`() = runTest {
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithBalances>()
|
||||
val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
|
||||
val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
|
||||
|
||||
val wrapper = MockYieldBalanceWrapperDTOFactory.createWithBalance()
|
||||
|
|
@ -63,7 +63,7 @@ internal class YieldsBalancesStoreInitializationTest {
|
|||
}
|
||||
}
|
||||
|
||||
DefaultYieldsBalancesStore(
|
||||
DefaultStakingBalancesStore(
|
||||
runtimeStore = runtimeStore,
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
|
|
@ -7,8 +7,8 @@ import com.tangem.data.staking.toDomain
|
|||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.datastore.RuntimeSharedStore
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.staking.YieldBalance
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
|
@ -18,12 +18,12 @@ import org.junit.Test
|
|||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class YieldsBalancesStoreUpdateMethodsTest {
|
||||
internal class StakingBalancesStoreUpdateMethodsTest {
|
||||
|
||||
private val runtimeStore = RuntimeSharedStore<WalletIdWithBalances>()
|
||||
private val runtimeStore = RuntimeSharedStore<WalletIdWithStakingBalances>()
|
||||
private val persistenceStore = MockStateDataStore<WalletIdWithWrappers>(default = emptyMap())
|
||||
|
||||
private val store = DefaultYieldsBalancesStore(
|
||||
private val store = DefaultStakingBalancesStore(
|
||||
runtimeStore = runtimeStore,
|
||||
persistenceStore = persistenceStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
|
|
@ -33,7 +33,7 @@ internal class YieldsBalancesStoreUpdateMethodsTest {
|
|||
fun `refresh the single id if runtime store is empty`() = runTest {
|
||||
store.refresh(userWalletId = userWalletId, stakingId = stakingId)
|
||||
|
||||
val runtimeExpected = mapOf(userWalletId to emptySet<YieldBalance>())
|
||||
val runtimeExpected = mapOf(userWalletId to emptySet<StakingBalance>())
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<YieldBalanceWrapperDTO>>())
|
||||
|
|
@ -63,7 +63,7 @@ internal class YieldsBalancesStoreUpdateMethodsTest {
|
|||
fun `refresh the multi ids if runtime store is empty`() = runTest {
|
||||
store.refresh(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
|
||||
val runtimeExpected = mapOf(userWalletId to emptySet<YieldBalance>())
|
||||
val runtimeExpected = mapOf(userWalletId to emptySet<StakingBalance>())
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
Truth.assertThat(persistenceStore.data.firstOrNull()).isEqualTo(emptyMap<String, Set<YieldBalanceWrapperDTO>>())
|
||||
|
|
@ -129,7 +129,7 @@ internal class YieldsBalancesStoreUpdateMethodsTest {
|
|||
store.storeError(userWalletId = userWalletId, stakingIds = setOf(stakingId))
|
||||
|
||||
val runtimeExpected = mapOf(
|
||||
userWalletId to setOf(YieldBalance.Error(stakingId)),
|
||||
userWalletId to setOf(StakingBalance.Error(stakingId)),
|
||||
)
|
||||
|
||||
Truth.assertThat(runtimeStore.getSyncOrNull()).isEqualTo(runtimeExpected)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.data.staking.utils
|
||||
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.store.StakingBalancesStore
|
||||
import com.tangem.domain.models.staking.StakingID
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
|
|
@ -16,9 +16,9 @@ import org.junit.jupiter.api.TestInstance
|
|||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class DefaultStakingCleanerTest {
|
||||
|
||||
private val yieldsBalancesStore = mockk<YieldsBalancesStore>(relaxed = true)
|
||||
private val stakingBalancesStore = mockk<StakingBalancesStore>(relaxed = true)
|
||||
private val cleaner = DefaultStakingCleaner(
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingBalancesStore = stakingBalancesStore,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
private val userWalletId = UserWalletId("011")
|
||||
|
|
@ -28,7 +28,7 @@ class DefaultStakingCleanerTest {
|
|||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
clearMocks(yieldsBalancesStore)
|
||||
clearMocks(stakingBalancesStore)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -38,7 +38,7 @@ class DefaultStakingCleanerTest {
|
|||
|
||||
// Assert
|
||||
coVerifyOrder {
|
||||
yieldsBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
stakingBalancesStore.clear(userWalletId = userWalletId, stakingIds = stakingIds)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ class DefaultStakingCleanerTest {
|
|||
|
||||
// Assert
|
||||
coVerifyOrder(inverse = true) {
|
||||
yieldsBalancesStore.clear(userWalletId = any(), stakingIds = any())
|
||||
stakingBalancesStore.clear(userWalletId = any(), stakingIds = any())
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue