Updated on 2026-08-14
This commit is contained in:
parent
d9bef76e89
commit
2227762050
12 changed files with 57 additions and 278 deletions
|
|
@ -20,11 +20,7 @@ import com.tangem.domain.staking.single.SingleYieldBalanceSupplier
|
||||||
import com.tangem.domain.tokens.*
|
import com.tangem.domain.tokens.*
|
||||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||||
import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
import com.tangem.domain.tokens.operations.CachedCurrenciesStatusesOperations
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
import com.tangem.domain.tokens.repository.*
|
||||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
|
||||||
import com.tangem.domain.tokens.repository.PolkadotAccountHealthCheckRepository
|
|
||||||
import com.tangem.domain.tokens.repository.TokenReceiveWarningsViewedRepository
|
|
||||||
import com.tangem.domain.tokens.repository.YieldSupplyWarningsViewedRepository
|
|
||||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||||
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
import com.tangem.tap.domain.tokens.DefaultTokensFeatureToggles
|
||||||
|
|
@ -60,24 +56,6 @@ internal object TokensDomainModule {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideFetchTokenListUseCase(
|
|
||||||
currenciesRepository: CurrenciesRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
|
||||||
stakingIdFactory: StakingIdFactory,
|
|
||||||
): FetchTokenListUseCase {
|
|
||||||
return FetchTokenListUseCase(
|
|
||||||
currenciesRepository = currenciesRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
|
||||||
stakingIdFactory = stakingIdFactory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideFetchPendingTransactionsUseCase(
|
fun provideFetchPendingTransactionsUseCase(
|
||||||
|
|
@ -184,24 +162,6 @@ internal object TokensDomainModule {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideFetchCardTokenListUseCase(
|
|
||||||
currenciesRepository: CurrenciesRepository,
|
|
||||||
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
|
||||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
|
||||||
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
|
||||||
stakingIdFactory: StakingIdFactory,
|
|
||||||
): FetchCardTokenListUseCase {
|
|
||||||
return FetchCardTokenListUseCase(
|
|
||||||
currenciesRepository = currenciesRepository,
|
|
||||||
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
|
|
||||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
|
||||||
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
|
|
||||||
stakingIdFactory = stakingIdFactory,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideGetCryptoCurrencyUseCase(
|
fun provideGetCryptoCurrencyUseCase(
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ dependencies {
|
||||||
api(projects.domain.common)
|
api(projects.domain.common)
|
||||||
api(projects.domain.models)
|
api(projects.domain.models)
|
||||||
api(projects.domain.tokens)
|
api(projects.domain.tokens)
|
||||||
|
api(projects.domain.wallets)
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Project - Data
|
// region Project - Data
|
||||||
|
|
|
||||||
|
|
@ -51,18 +51,25 @@ internal class DefaultWalletAccountsFetcher @Inject constructor(
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : WalletAccountsFetcher, WalletAccountsSaver {
|
) : WalletAccountsFetcher, WalletAccountsSaver {
|
||||||
|
|
||||||
override suspend fun fetch(userWalletId: UserWalletId) {
|
override suspend fun fetch(userWalletId: UserWalletId): GetWalletAccountsResponse {
|
||||||
val savedAccountsResponse = getAccountsResponseStore(userWalletId = userWalletId).getSyncOrNull()
|
val savedAccountsResponse = getAccountsResponseStore(userWalletId = userWalletId).getSyncOrNull()
|
||||||
val accountsResponse = fetchWalletAccounts(userWalletId, savedAccountsResponse)
|
val accountsResponse = fetchWalletAccounts(userWalletId, savedAccountsResponse)
|
||||||
?: return
|
|
||||||
|
|
||||||
if (accountsResponse.accounts.isEmpty()) {
|
return when {
|
||||||
initializeAccounts(userWalletId, accountsResponse)
|
accountsResponse.accounts.isEmpty() -> {
|
||||||
} else if (accountsResponse.unassignedTokens.isNotEmpty()) {
|
initializeAccounts(userWalletId, accountsResponse)
|
||||||
assignTokens(userWalletId, accountsResponse)
|
}
|
||||||
|
accountsResponse.unassignedTokens.isNotEmpty() -> {
|
||||||
|
assignTokens(userWalletId, accountsResponse)
|
||||||
|
}
|
||||||
|
else -> accountsResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getSaved(userWalletId: UserWalletId): GetWalletAccountsResponse? {
|
||||||
|
return getAccountsResponseStore(userWalletId = userWalletId).getSyncOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun store(userWalletId: UserWalletId, response: GetWalletAccountsResponse) {
|
override suspend fun store(userWalletId: UserWalletId, response: GetWalletAccountsResponse) {
|
||||||
val store = getAccountsResponseStore(userWalletId = userWalletId)
|
val store = getAccountsResponseStore(userWalletId = userWalletId)
|
||||||
|
|
||||||
|
|
@ -115,7 +122,7 @@ internal class DefaultWalletAccountsFetcher @Inject constructor(
|
||||||
private suspend fun fetchWalletAccounts(
|
private suspend fun fetchWalletAccounts(
|
||||||
userWalletId: UserWalletId,
|
userWalletId: UserWalletId,
|
||||||
savedAccountsResponse: GetWalletAccountsResponse?,
|
savedAccountsResponse: GetWalletAccountsResponse?,
|
||||||
): GetWalletAccountsResponse? {
|
): GetWalletAccountsResponse {
|
||||||
return safeApiCall(
|
return safeApiCall(
|
||||||
call = {
|
call = {
|
||||||
val apiResponse = withContext(dispatchers.io) {
|
val apiResponse = withContext(dispatchers.io) {
|
||||||
|
|
@ -145,7 +152,10 @@ internal class DefaultWalletAccountsFetcher @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun initializeAccounts(userWalletId: UserWalletId, accountsResponse: GetWalletAccountsResponse) {
|
private suspend fun initializeAccounts(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
accountsResponse: GetWalletAccountsResponse,
|
||||||
|
): GetWalletAccountsResponse {
|
||||||
val response = defaultWalletAccountsResponseFactory.create(
|
val response = defaultWalletAccountsResponseFactory.create(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
userTokensResponse = UserTokensResponse(
|
userTokensResponse = UserTokensResponse(
|
||||||
|
|
@ -156,14 +166,17 @@ internal class DefaultWalletAccountsFetcher @Inject constructor(
|
||||||
)
|
)
|
||||||
|
|
||||||
userTokensSaver.push(userWalletId = userWalletId, response = response.toUserTokensResponse())
|
userTokensSaver.push(userWalletId = userWalletId, response = response.toUserTokensResponse())
|
||||||
val syncedResponse = push(userWalletId = userWalletId, accounts = response.accounts)
|
val syncedResponse = push(userWalletId = userWalletId, accounts = response.accounts) ?: response
|
||||||
|
|
||||||
if (syncedResponse != null) {
|
store(userWalletId = userWalletId, response = syncedResponse)
|
||||||
store(userWalletId = userWalletId, response = syncedResponse)
|
|
||||||
}
|
return syncedResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun assignTokens(userWalletId: UserWalletId, accountsResponse: GetWalletAccountsResponse) {
|
private suspend fun assignTokens(
|
||||||
|
userWalletId: UserWalletId,
|
||||||
|
accountsResponse: GetWalletAccountsResponse,
|
||||||
|
): GetWalletAccountsResponse {
|
||||||
val accountsResponseWithTokens = accountsResponse.assignTokens(userWalletId)
|
val accountsResponseWithTokens = accountsResponse.assignTokens(userWalletId)
|
||||||
|
|
||||||
store(userWalletId = userWalletId, response = accountsResponseWithTokens)
|
store(userWalletId = userWalletId, response = accountsResponseWithTokens)
|
||||||
|
|
@ -172,6 +185,8 @@ internal class DefaultWalletAccountsFetcher @Inject constructor(
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
response = accountsResponseWithTokens.toUserTokensResponse(),
|
response = accountsResponseWithTokens.toUserTokensResponse(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return accountsResponseWithTokens
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getETag(userWalletId: UserWalletId): String? {
|
private suspend fun getETag(userWalletId: UserWalletId): String? {
|
||||||
|
|
|
||||||
|
|
@ -49,11 +49,13 @@ internal class FetchWalletAccountsErrorHandler @Inject constructor(
|
||||||
savedAccountsResponse: GetWalletAccountsResponse?,
|
savedAccountsResponse: GetWalletAccountsResponse?,
|
||||||
pushWalletAccounts: suspend (UserWalletId, List<WalletAccountDTO>) -> GetWalletAccountsResponse?,
|
pushWalletAccounts: suspend (UserWalletId, List<WalletAccountDTO>) -> GetWalletAccountsResponse?,
|
||||||
storeWalletAccounts: suspend (UserWalletId, GetWalletAccountsResponse) -> Unit,
|
storeWalletAccounts: suspend (UserWalletId, GetWalletAccountsResponse) -> Unit,
|
||||||
): GetWalletAccountsResponse? {
|
): GetWalletAccountsResponse {
|
||||||
val isResponseUpToDate = error.isNetworkError(code = Code.NOT_MODIFIED)
|
val isResponseUpToDate = error.isNetworkError(code = Code.NOT_MODIFIED)
|
||||||
if (isResponseUpToDate) {
|
if (isResponseUpToDate) {
|
||||||
Timber.e("ETag is up to date, no need to update accounts for wallet: $userWalletId")
|
Timber.e("ETag is up to date, no need to update accounts for wallet: $userWalletId")
|
||||||
return savedAccountsResponse
|
return requireNotNull(savedAccountsResponse) {
|
||||||
|
"Saved accounts response is null for wallet: $userWalletId"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var response = savedAccountsResponse ?: createDefaultResponse(userWalletId)
|
var response = savedAccountsResponse ?: createDefaultResponse(userWalletId)
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ class DefaultSingleAccountListFetcherTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val params = SingleAccountListFetcher.Params(userWalletId = userWalletId)
|
val params = SingleAccountListFetcher.Params(userWalletId = userWalletId)
|
||||||
|
|
||||||
|
coEvery { walletAccountsFetcher.fetch(userWalletId) } returns mockk()
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
val actual = fetcher.invoke(params)
|
val actual = fetcher.invoke(params)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ class DefaultWalletAccountsFetcherTest {
|
||||||
@Test
|
@Test
|
||||||
fun `fetch should call error handler when getWalletAccounts returns error`() = runTest {
|
fun `fetch should call error handler when getWalletAccounts returns error`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
val savedAccountsResponse = null
|
val savedAccountsResponse = createGetWalletAccountsResponse(userWalletId)
|
||||||
val apiError = ApiResponse.Error(ApiResponseError.NetworkException())
|
val apiError = ApiResponse.Error(ApiResponseError.NetworkException())
|
||||||
|
|
||||||
accountsResponseStoreFlow.value = savedAccountsResponse
|
accountsResponseStoreFlow.value = savedAccountsResponse
|
||||||
|
|
@ -212,7 +212,7 @@ class DefaultWalletAccountsFetcherTest {
|
||||||
fetchWalletAccountsErrorHandler.handle(
|
fetchWalletAccountsErrorHandler.handle(
|
||||||
error = apiError.cause,
|
error = apiError.cause,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
savedAccountsResponse = null,
|
savedAccountsResponse = savedAccountsResponse,
|
||||||
pushWalletAccounts = any(),
|
pushWalletAccounts = any(),
|
||||||
storeWalletAccounts = any(),
|
storeWalletAccounts = any(),
|
||||||
)
|
)
|
||||||
|
|
@ -231,7 +231,7 @@ class DefaultWalletAccountsFetcherTest {
|
||||||
fetchWalletAccountsErrorHandler.handle(
|
fetchWalletAccountsErrorHandler.handle(
|
||||||
error = apiError.cause,
|
error = apiError.cause,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
savedAccountsResponse = null,
|
savedAccountsResponse = savedAccountsResponse,
|
||||||
pushWalletAccounts = any(),
|
pushWalletAccounts = any(),
|
||||||
storeWalletAccounts = any(),
|
storeWalletAccounts = any(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,8 @@ class FetchWalletAccountsErrorHandlerTest {
|
||||||
@Test
|
@Test
|
||||||
fun `does not update accounts when response is up to date`() = runTest {
|
fun `does not update accounts when response is up to date`() = runTest {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
val response = createGetWalletAccountsResponse(userWalletId)
|
||||||
|
|
||||||
val error = ApiResponseError.HttpException(
|
val error = ApiResponseError.HttpException(
|
||||||
code = Code.NOT_MODIFIED,
|
code = Code.NOT_MODIFIED,
|
||||||
message = "Not Modified",
|
message = "Not Modified",
|
||||||
|
|
@ -63,7 +65,7 @@ class FetchWalletAccountsErrorHandlerTest {
|
||||||
handler.handle(
|
handler.handle(
|
||||||
error = error,
|
error = error,
|
||||||
userWalletId = userWalletId,
|
userWalletId = userWalletId,
|
||||||
savedAccountsResponse = null,
|
savedAccountsResponse = response,
|
||||||
pushWalletAccounts = pushWalletAccounts,
|
pushWalletAccounts = pushWalletAccounts,
|
||||||
storeWalletAccounts = storeWalletAccounts,
|
storeWalletAccounts = storeWalletAccounts,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.data.common.account
|
package com.tangem.data.common.account
|
||||||
|
|
||||||
|
import com.tangem.datasource.api.tangemTech.models.account.GetWalletAccountsResponse
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -11,5 +12,8 @@ interface WalletAccountsFetcher {
|
||||||
|
|
||||||
/** Fetch wallet accounts by [userWalletId] */
|
/** Fetch wallet accounts by [userWalletId] */
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun fetch(userWalletId: UserWalletId)
|
suspend fun fetch(userWalletId: UserWalletId): GetWalletAccountsResponse
|
||||||
|
|
||||||
|
/** Get saved wallet accounts by [userWalletId] */
|
||||||
|
suspend fun getSaved(userWalletId: UserWalletId): GetWalletAccountsResponse?
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.tangem.data.tokens
|
package com.tangem.data.tokens
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
|
import arrow.core.right
|
||||||
import com.tangem.data.common.account.WalletAccountsFetcher
|
import com.tangem.data.common.account.WalletAccountsFetcher
|
||||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||||
import com.tangem.domain.core.utils.catchOn
|
import com.tangem.domain.core.utils.catchOn
|
||||||
|
|
@ -25,11 +26,15 @@ internal class AccountListCryptoCurrenciesFetcher(
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : MultiWalletCryptoCurrenciesFetcher {
|
) : MultiWalletCryptoCurrenciesFetcher {
|
||||||
|
|
||||||
override suspend fun invoke(params: Params) = Either.catchOn(dispatchers.default) {
|
override suspend fun invoke(params: Params): Either<Throwable, Unit> {
|
||||||
val userWallet = userWalletsStore.getSyncStrict(key = params.userWalletId)
|
return Either.catchOn(dispatchers.default) {
|
||||||
|
val userWallet = userWalletsStore.getSyncStrict(key = params.userWalletId)
|
||||||
|
|
||||||
if (!userWallet.isMultiCurrency) error("${this::class.simpleName} supports only multi-currency wallet")
|
if (!userWallet.isMultiCurrency) error("${this::class.simpleName} supports only multi-currency wallet")
|
||||||
|
|
||||||
walletAccountsFetcher.fetch(userWalletId = params.userWalletId)
|
walletAccountsFetcher.fetch(userWalletId = params.userWalletId)
|
||||||
|
|
||||||
|
Unit.right()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -61,6 +61,7 @@ internal class AccountListCryptoCurrenciesFetcherTest {
|
||||||
val mockUserWallet = mockk<UserWallet> { every { isMultiCurrency } returns true }
|
val mockUserWallet = mockk<UserWallet> { every { isMultiCurrency } returns true }
|
||||||
|
|
||||||
every { userWalletsStore.getSyncStrict(key = params.userWalletId) } returns mockUserWallet
|
every { userWalletsStore.getSyncStrict(key = params.userWalletId) } returns mockUserWallet
|
||||||
|
coEvery { walletAccountsFetcher.fetch(userWalletId = params.userWalletId) } returns mockk()
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
val actual = fetcher(params)
|
val actual = fetcher(params)
|
||||||
|
|
|
||||||
|
|
@ -1,96 +0,0 @@
|
||||||
package com.tangem.domain.tokens
|
|
||||||
|
|
||||||
import arrow.core.Either
|
|
||||||
import arrow.core.raise.Raise
|
|
||||||
import arrow.core.raise.catch
|
|
||||||
import arrow.core.raise.either
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.domain.models.network.Network
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
|
||||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
|
||||||
import com.tangem.domain.staking.StakingIdFactory
|
|
||||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
|
||||||
|
|
||||||
class FetchCardTokenListUseCase(
|
|
||||||
private val currenciesRepository: CurrenciesRepository,
|
|
||||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
|
||||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
|
||||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
|
||||||
private val stakingIdFactory: StakingIdFactory,
|
|
||||||
) {
|
|
||||||
|
|
||||||
suspend operator fun invoke(userWalletId: UserWalletId, refresh: Boolean = false): Either<TokenListError, Unit> {
|
|
||||||
return either {
|
|
||||||
val currencies = fetchCurrencies(userWalletId = userWalletId, refresh = refresh)
|
|
||||||
|
|
||||||
coroutineScope {
|
|
||||||
val fetchStatuses = async {
|
|
||||||
fetchNetworksStatuses(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
networks = currencies.mapTo(destination = hashSetOf(), transform = CryptoCurrency::network),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val fetchQuotes = async {
|
|
||||||
fetchQuotes(
|
|
||||||
currenciesIds = currencies.mapNotNullTo(destination = hashSetOf()) { it.id.rawCurrencyId },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val yieldBalances = async {
|
|
||||||
fetchYieldBalances(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
currencies = currencies,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
awaitAll(fetchStatuses, fetchQuotes, yieldBalances)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun Raise<TokenListError>.fetchCurrencies(
|
|
||||||
userWalletId: UserWalletId,
|
|
||||||
refresh: Boolean = false,
|
|
||||||
): List<CryptoCurrency> {
|
|
||||||
return catch(
|
|
||||||
block = {
|
|
||||||
currenciesRepository.getSingleCurrencyWalletWithCardCurrencies(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
refresh = refresh,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
catch = { raise(TokenListError.DataError(it)) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun Raise<TokenListError>.fetchNetworksStatuses(
|
|
||||||
userWalletId: UserWalletId,
|
|
||||||
networks: Set<Network>,
|
|
||||||
) {
|
|
||||||
multiNetworkStatusFetcher(
|
|
||||||
MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks),
|
|
||||||
)
|
|
||||||
.mapLeft(TokenListError::DataError)
|
|
||||||
.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.RawID>) {
|
|
||||||
multiQuoteStatusFetcher(
|
|
||||||
params = MultiQuoteStatusFetcher.Params(currenciesIds = currenciesIds, appCurrencyId = null),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun fetchYieldBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
|
||||||
val stakingIds = currencies.mapNotNullTo(hashSetOf()) {
|
|
||||||
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it).getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
multiYieldBalanceFetcher(
|
|
||||||
params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = stakingIds),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
package com.tangem.domain.tokens
|
|
||||||
|
|
||||||
import arrow.core.Either
|
|
||||||
import arrow.core.raise.Raise
|
|
||||||
import arrow.core.raise.catch
|
|
||||||
import arrow.core.raise.either
|
|
||||||
import arrow.core.raise.ensureNotNull
|
|
||||||
import arrow.core.toNonEmptyListOrNull
|
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
|
||||||
import com.tangem.domain.models.network.Network
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
|
|
||||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
|
||||||
import com.tangem.domain.staking.StakingIdFactory
|
|
||||||
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
|
|
||||||
import com.tangem.domain.tokens.error.TokenListError
|
|
||||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.awaitAll
|
|
||||||
import kotlinx.coroutines.coroutineScope
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use case responsible for fetching token list information, including currency data,
|
|
||||||
* network statuses, and quotes for tokens associated with a user's wallet.
|
|
||||||
*
|
|
||||||
* @param currenciesRepository The repository for retrieving currency-related data.
|
|
||||||
*/
|
|
||||||
class FetchTokenListUseCase(
|
|
||||||
private val currenciesRepository: CurrenciesRepository,
|
|
||||||
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
|
|
||||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
|
||||||
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
|
|
||||||
private val stakingIdFactory: StakingIdFactory,
|
|
||||||
) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the token list information for a user's wallet, including currency data,
|
|
||||||
* network statuses, and quotes for associated tokens.
|
|
||||||
*
|
|
||||||
* @param userWalletId The ID of the user's wallet.
|
|
||||||
* @return An [Either] representing success (Right) or an error (Left) in fetching the token list.
|
|
||||||
*/
|
|
||||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<TokenListError, Unit> = either {
|
|
||||||
val currencies = fetchCurrencies(userWalletId)
|
|
||||||
|
|
||||||
invoke(userWalletId = userWalletId, currencies = currencies)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend operator fun invoke(
|
|
||||||
userWalletId: UserWalletId,
|
|
||||||
currencies: List<CryptoCurrency>,
|
|
||||||
): Either<TokenListError, Unit> = either {
|
|
||||||
coroutineScope {
|
|
||||||
val fetchStatuses = async {
|
|
||||||
fetchNetworksStatuses(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
networks = currencies.mapTo(hashSetOf()) { it.network },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val fetchQuotes = async {
|
|
||||||
fetchQuotes(
|
|
||||||
currenciesIds = currencies.mapTo(hashSetOf()) { it.id },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val yieldBalances = async {
|
|
||||||
fetchYieldBalances(userWalletId = userWalletId, currencies = currencies)
|
|
||||||
}
|
|
||||||
|
|
||||||
awaitAll(fetchStatuses, fetchQuotes, yieldBalances)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun Raise<TokenListError>.fetchCurrencies(userWalletId: UserWalletId): List<CryptoCurrency> {
|
|
||||||
val currencies = catch(
|
|
||||||
block = { currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId, true) },
|
|
||||||
) {
|
|
||||||
raise(TokenListError.DataError(it))
|
|
||||||
}
|
|
||||||
|
|
||||||
return ensureNotNull(currencies.toNonEmptyListOrNull()) {
|
|
||||||
TokenListError.EmptyTokens
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun Raise<TokenListError>.fetchNetworksStatuses(
|
|
||||||
userWalletId: UserWalletId,
|
|
||||||
networks: Set<Network>,
|
|
||||||
) {
|
|
||||||
multiNetworkStatusFetcher(
|
|
||||||
params = MultiNetworkStatusFetcher.Params(userWalletId = userWalletId, networks = networks),
|
|
||||||
)
|
|
||||||
.mapLeft(TokenListError::DataError)
|
|
||||||
.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun Raise<TokenListError>.fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>) {
|
|
||||||
multiQuoteStatusFetcher(
|
|
||||||
params = MultiQuoteStatusFetcher.Params(
|
|
||||||
currenciesIds = currenciesIds.mapNotNull { it.rawCurrencyId }.toSet(),
|
|
||||||
appCurrencyId = null,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.mapLeft(TokenListError::DataError)
|
|
||||||
.bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun fetchYieldBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
|
||||||
val stakingIds = currencies.mapNotNullTo(hashSetOf()) {
|
|
||||||
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it).getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
multiYieldBalanceFetcher(
|
|
||||||
params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = stakingIds),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue