Updated on 2026-08-14
This commit is contained in:
parent
4aa74c4b70
commit
3d16de3f4f
6 changed files with 221 additions and 10 deletions
|
|
@ -6,27 +6,32 @@ import arrow.core.left
|
|||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.ensure
|
||||
import arrow.core.toOption
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
|
||||
import com.tangem.datasource.api.stakekit.models.request.YieldBalanceRequestBody
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldDTO
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.core.flow.FlowFetcher
|
||||
import com.tangem.domain.core.utils.catchOn
|
||||
import com.tangem.domain.staking.fetcher.YieldBalanceFetcherParams
|
||||
import com.tangem.domain.staking.model.StakingID
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import timber.log.Timber
|
||||
|
||||
internal fun <Params : YieldBalanceFetcherParams> commonFetcher(
|
||||
implementor: YieldBalanceFetcherImplementor<Params>,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
stakingYieldsStore: StakingYieldsStore,
|
||||
yieldsBalancesStore: YieldsBalancesStore,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): FlowFetcher<Params> {
|
||||
return CommonYieldBalanceFetcher(
|
||||
implementor = implementor,
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
|
|
@ -36,19 +41,25 @@ internal fun <Params : YieldBalanceFetcherParams> commonFetcher(
|
|||
/**
|
||||
* Common implementation of YieldBalanceFetcher
|
||||
*
|
||||
* @param implementor fetcher implementor
|
||||
* @property implementor fetcher implementor
|
||||
* @property userWalletsStore user wallets store
|
||||
* @property stakingYieldsStore staking yields store
|
||||
* @property yieldsBalancesStore yields balances store
|
||||
* @property dispatchers dispatchers
|
||||
*/
|
||||
private class CommonYieldBalanceFetcher<Params : YieldBalanceFetcherParams>(
|
||||
private val implementor: YieldBalanceFetcherImplementor<Params>,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val stakingYieldsStore: StakingYieldsStore,
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : FlowFetcher<Params> {
|
||||
|
||||
override suspend fun invoke(params: Params): Either<Throwable, Unit> {
|
||||
checkIsSupportedByWalletOrElse(userWalletId = params.userWalletId) {
|
||||
return it.left()
|
||||
}
|
||||
|
||||
val stakingIds = getStakingIds(params).getOrElse {
|
||||
return it.left()
|
||||
}
|
||||
|
|
@ -58,7 +69,23 @@ private class CommonYieldBalanceFetcher<Params : YieldBalanceFetcherParams>(
|
|||
|
||||
implementor.fetch(params = params, stakingIds = stakingIds, requests)
|
||||
}
|
||||
.onLeft { yieldsBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = stakingIds) }
|
||||
.onLeft {
|
||||
Timber.e(it, "Unable to fetch yield balances $params")
|
||||
yieldsBalancesStore.storeError(userWalletId = params.userWalletId, stakingIds = stakingIds)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun checkIsSupportedByWalletOrElse(userWalletId: UserWalletId, ifNotSupported: (Throwable) -> Unit) {
|
||||
val maybeUserWallet = userWalletsStore.getSyncOrNull(key = userWalletId).toOption()
|
||||
|
||||
val isSupportedByWallet = maybeUserWallet.isSome(UserWallet::isMultiCurrency)
|
||||
|
||||
if (!isSupportedByWallet) {
|
||||
val exception = IllegalStateException("Wallet $userWalletId is not supported: $maybeUserWallet")
|
||||
Timber.e(exception)
|
||||
|
||||
ifNotSupported(exception)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getStakingIds(params: Params): Either<Throwable, Set<StakingID>> = either {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.data.staking.store.YieldsBalancesStore
|
|||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.core.flow.FlowFetcher
|
||||
import com.tangem.domain.staking.fetcher.YieldBalanceFetcherParams
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
|
|
@ -15,6 +16,7 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Default implementation of [MultiYieldBalanceFetcher]
|
||||
*
|
||||
* @property userWalletsStore user wallets store
|
||||
* @property stakingYieldsStore staking yields store
|
||||
* @property yieldsBalancesStore yields balances store
|
||||
* @property stakingIdFactory factory for creating StakingID
|
||||
|
|
@ -24,6 +26,7 @@ import javax.inject.Inject
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val stakingYieldsStore: StakingYieldsStore,
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
|
|
@ -32,6 +35,7 @@ internal class DefaultMultiYieldBalanceFetcher @Inject constructor(
|
|||
) : MultiYieldBalanceFetcher,
|
||||
FlowFetcher<YieldBalanceFetcherParams.Multi> by commonFetcher(
|
||||
implementor = createMultiFetcherImplementor(yieldsBalancesStore, stakingIdFactory, stakeKitApi, dispatchers),
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import com.tangem.data.staking.store.YieldsBalancesStore
|
|||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.core.flow.FlowFetcher
|
||||
import com.tangem.domain.staking.fetcher.YieldBalanceFetcherParams
|
||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
||||
|
|
@ -16,6 +17,7 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Default implementation of [MultiYieldBalanceFetcher]
|
||||
*
|
||||
* @property userWalletsStore user wallets store
|
||||
* @property stakingYieldsStore staking yields store
|
||||
* @property yieldsBalancesStore yields balances store
|
||||
* @property stakingIdFactory factory for creating StakingID
|
||||
|
|
@ -25,6 +27,7 @@ import javax.inject.Inject
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultSingleYieldBalanceFetcher @Inject constructor(
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val stakingYieldsStore: StakingYieldsStore,
|
||||
private val yieldsBalancesStore: YieldsBalancesStore,
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
|
|
@ -33,6 +36,7 @@ internal class DefaultSingleYieldBalanceFetcher @Inject constructor(
|
|||
) : SingleYieldBalanceFetcher,
|
||||
FlowFetcher<YieldBalanceFetcherParams.Single> by commonFetcher(
|
||||
implementor = createSingleFetcherImplementor(yieldsBalancesStore, stakingIdFactory, stakeKitApi, dispatchers),
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
dispatchers = dispatchers,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.data.staking.multi
|
||||
|
||||
import arrow.core.toOption
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
||||
import com.tangem.common.test.data.staking.MockYieldDTOFactory
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
|
||||
|
|
@ -13,6 +15,7 @@ import com.tangem.datasource.api.common.response.ApiResponseError
|
|||
import com.tangem.datasource.api.stakekit.StakeKitApi
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.staking.fetcher.YieldBalanceFetcherParams
|
||||
import com.tangem.domain.staking.model.StakingID
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -26,12 +29,14 @@ import org.junit.Test
|
|||
*/
|
||||
internal class DefaultMultiYieldBalanceFetcherTest {
|
||||
|
||||
private val userWalletsStore: UserWalletsStore = mockk()
|
||||
private val stakingYieldsStore: StakingYieldsStore = mockk()
|
||||
private val yieldsBalancesStore: YieldsBalancesStore = mockk()
|
||||
private val stakingIdFactory: StakingIdFactory = mockk()
|
||||
private val stakeKitApi: StakeKitApi = mockk()
|
||||
|
||||
private val fetcher = DefaultMultiYieldBalanceFetcher(
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
|
|
@ -45,6 +50,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -63,6 +69,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
|
@ -76,18 +83,77 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
Truth.assertThat(actual.isRight()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if user wallet is not supported`() = runTest {
|
||||
val currencyIdWithNetworkMap = mapOf(ton.id to ton.network, solana.id to solana.network)
|
||||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
val userWallet = MockUserWalletFactory.create().copy(isMultiCurrency = false)
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.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())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${userWallet.toOption()}")
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if userWalletsStore returns null`() = runTest {
|
||||
val currencyIdWithNetworkMap = mapOf(ton.id to ton.network, solana.id to solana.network)
|
||||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns null
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.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())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${null.toOption()}")
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if stakingIdFactory returns empty list`() = runTest {
|
||||
val currencyIdWithNetworkMap = mapOf(ton.id to ton.network, solana.id to solana.network)
|
||||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns emptySet()
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns emptySet()
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
}
|
||||
|
|
@ -113,6 +179,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -122,6 +189,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds)
|
||||
|
|
@ -147,6 +215,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -156,6 +225,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
|
@ -181,6 +251,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -195,6 +266,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
|
@ -226,6 +298,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -237,6 +310,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
|
@ -268,6 +342,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
val params = YieldBalanceFetcherParams.Multi(userWalletId, currencyIdWithNetworkMap)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, ton.id, ton.network) } returns setOf(tonId)
|
||||
coEvery { stakingIdFactory.create(params.userWalletId, solana.id, solana.network) } returns setOf(solanaId)
|
||||
coEvery { yieldsBalancesStore.refresh(params.userWalletId, tonAndSolanaIds) } just Runs
|
||||
|
|
@ -287,6 +362,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.create(params.userWalletId, ton.id, ton.network)
|
||||
stakingIdFactory.create(params.userWalletId, solana.id, solana.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = tonAndSolanaIds)
|
||||
|
|
@ -306,6 +382,7 @@ internal class DefaultMultiYieldBalanceFetcherTest {
|
|||
|
||||
private companion object {
|
||||
val userWalletId = UserWalletId("011")
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
|
||||
val mocks = MockCryptoCurrencyFactory()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.data.staking.single
|
||||
|
||||
import arrow.core.toOption
|
||||
import com.google.common.truth.Truth
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.test.data.staking.MockYieldBalanceWrapperDTOFactory
|
||||
import com.tangem.common.test.data.staking.MockYieldDTOFactory
|
||||
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
|
||||
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
|
||||
import com.tangem.data.staking.store.YieldsBalancesStore
|
||||
import com.tangem.data.staking.utils.StakingIdFactory
|
||||
import com.tangem.data.staking.utils.YieldBalanceRequestBodyFactory
|
||||
|
|
@ -17,6 +19,7 @@ import com.tangem.datasource.api.stakekit.models.response.model.NetworkTypeDTO
|
|||
import com.tangem.datasource.api.stakekit.models.response.model.TokenDTO
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.staking.fetcher.YieldBalanceFetcherParams
|
||||
import com.tangem.domain.staking.model.StakingID
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -31,12 +34,14 @@ import java.math.BigDecimal
|
|||
*/
|
||||
internal class DefaultSingleYieldBalanceFetcherTest {
|
||||
|
||||
private val userWalletsStore: UserWalletsStore = mockk()
|
||||
private val stakingYieldsStore: StakingYieldsStore = mockk()
|
||||
private val yieldsBalancesStore: YieldsBalancesStore = mockk()
|
||||
private val stakingIdFactory: StakingIdFactory = mockk()
|
||||
private val stakeKitApi: StakeKitApi = mockk()
|
||||
|
||||
private val fetcher = DefaultSingleYieldBalanceFetcher(
|
||||
userWalletsStore = userWalletsStore,
|
||||
stakingYieldsStore = stakingYieldsStore,
|
||||
yieldsBalancesStore = yieldsBalancesStore,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
|
|
@ -52,6 +57,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -70,6 +76,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -82,6 +89,67 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
Truth.assertThat(actual.isRight()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if user wallet is not supported`() = runTest {
|
||||
val params = YieldBalanceFetcherParams.Single(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = ton.id,
|
||||
network = ton.network,
|
||||
)
|
||||
|
||||
val userWallet = MockUserWalletFactory.create().copy(isMultiCurrency = false)
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.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())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${userWallet.toOption()}")
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if userWalletsStore returns null`() = runTest {
|
||||
val params = YieldBalanceFetcherParams.Single(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = ton.id,
|
||||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns null
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify { userWalletsStore.getSyncOrNull(params.userWalletId) }
|
||||
|
||||
coVerify(inverse = true) {
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.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())
|
||||
}
|
||||
|
||||
val expected = IllegalStateException("Wallet ${params.userWalletId} is not supported: ${null.toOption()}")
|
||||
|
||||
Truth.assertThat(actual.isLeft()).isTrue()
|
||||
Truth.assertThat(actual.leftOrNull()).isInstanceOf(expected::class.java)
|
||||
Truth.assertThat(actual.leftOrNull()).hasMessageThat().isEqualTo(expected.message)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fetch yields balances failure if stakingIdFactory createForDefault returns null`() = runTest {
|
||||
val params = YieldBalanceFetcherParams.Single(
|
||||
|
|
@ -90,11 +158,13 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns null
|
||||
|
||||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(userWalletId = userWalletId, currencyId = ton.id, network = ton.network)
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +191,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -132,6 +203,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -158,6 +230,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -169,6 +242,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -195,6 +269,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -207,6 +282,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -239,6 +315,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -251,6 +328,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -283,6 +361,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
network = ton.network,
|
||||
)
|
||||
|
||||
coEvery { userWalletsStore.getSyncOrNull(params.userWalletId) } returns userWallet
|
||||
coEvery { stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network) } returns tonId
|
||||
coEvery {
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
|
|
@ -302,6 +381,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
val actual = fetcher(params)
|
||||
|
||||
coVerify {
|
||||
userWalletsStore.getSyncOrNull(params.userWalletId)
|
||||
stakingIdFactory.createForDefault(params.userWalletId, ton.id, ton.network)
|
||||
yieldsBalancesStore.refresh(userWalletId = params.userWalletId, stakingIds = setOf(tonId))
|
||||
stakingYieldsStore.getSyncWithTimeout()
|
||||
|
|
@ -353,6 +433,7 @@ internal class DefaultSingleYieldBalanceFetcherTest {
|
|||
|
||||
private companion object {
|
||||
val userWalletId = UserWalletId("011")
|
||||
val userWallet = MockUserWalletFactory.create()
|
||||
|
||||
val mocks = MockCryptoCurrencyFactory()
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ abstract class BaseCurrencyStatusOperations(
|
|||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
includeQuotes: Boolean = true,
|
||||
subscribeOnYieldBalance: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val rawCurrencyId = currency.id.rawCurrencyId
|
||||
|
||||
|
|
@ -117,13 +118,24 @@ abstract class BaseCurrencyStatusOperations(
|
|||
|
||||
val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
|
||||
return combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = maybeQuote,
|
||||
maybeNetworkStatus = maybeNetworkStatus,
|
||||
maybeYieldBalance = maybeYieldBalance,
|
||||
)
|
||||
return if (subscribeOnYieldBalance) {
|
||||
combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = maybeQuote,
|
||||
maybeNetworkStatus = maybeNetworkStatus,
|
||||
maybeYieldBalance = maybeYieldBalance,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
combine(quoteFlow, statusFlow) { maybeQuote, maybeNetworkStatus ->
|
||||
currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = maybeQuote,
|
||||
maybeNetworkStatus = maybeNetworkStatus,
|
||||
maybeYieldBalance = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +254,13 @@ abstract class BaseCurrencyStatusOperations(
|
|||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency, includeQuotes)
|
||||
return getCurrencyStatusFlow(
|
||||
userWalletId = userWalletId,
|
||||
currency = currency,
|
||||
includeQuotes = includeQuotes,
|
||||
// If toggle is off, then subscribe on yield balance. If toggle is on, then don't
|
||||
subscribeOnYieldBalance = !tokensFeatureToggles.isStakingLoadingRefactoringEnabled,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getCurrenciesStatusesSync(userWalletId: UserWalletId): Either<Error, List<CryptoCurrencyStatus>> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue