Updated on 2026-08-14

This commit is contained in:
Tangem 2025-04-11 15:57:54 +04:00
parent 4efcc839ed
commit 13a474b281
10 changed files with 130 additions and 34 deletions

View file

@ -5,6 +5,7 @@ import com.tangem.domain.managetokens.*
import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
import com.tangem.domain.tokens.repository.CurrenciesRepository
@ -73,6 +74,7 @@ internal object ManageTokensDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): SaveManagedTokensUseCase {
return SaveManagedTokensUseCase(
@ -84,6 +86,7 @@ internal object ManageTokensDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}

View file

@ -5,6 +5,7 @@ import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.markets.*
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.quotes.single.SingleQuoteSupplier
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
@ -72,6 +73,7 @@ object MarketsDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): SaveMarketTokensUseCase {
return SaveMarketTokensUseCase(
@ -82,6 +84,7 @@ object MarketsDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}

View file

@ -37,6 +37,7 @@ internal object TokensDomainModule {
stakingRepository: StakingRepository,
quotesRepository: QuotesRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): AddCryptoCurrenciesUseCase {
return AddCryptoCurrenciesUseCase(
@ -45,6 +46,7 @@ internal object TokensDomainModule {
stakingRepository = stakingRepository,
quotesRepository = quotesRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}
@ -366,10 +368,14 @@ internal object TokensDomainModule {
fun provideRefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository: CurrenciesRepository,
quotesRepository: QuotesRepository,
multiQuoteFetcher: MultiQuoteFetcher,
tokensFeatureToggles: TokensFeatureToggles,
): RefreshMultiCurrencyWalletQuotesUseCase {
return RefreshMultiCurrencyWalletQuotesUseCase(
currenciesRepository = currenciesRepository,
quotesRepository = quotesRepository,
multiQuoteFetcher = multiQuoteFetcher,
tokensFeatureToggles = tokensFeatureToggles,
)
}

View file

@ -14,6 +14,7 @@ dependencies {
api(projects.domain.core)
api(projects.domain.manageTokens.models)
api(projects.domain.networks)
api(projects.domain.quotes)
implementation(projects.domain.wallets.models)
implementation(projects.domain.tokens.models)
implementation(projects.domain.staking)

View file

@ -6,6 +6,7 @@ import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.repository.CustomTokensRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
import com.tangem.domain.tokens.model.CryptoCurrency
@ -26,6 +27,7 @@ class SaveManagedTokensUseCase(
private val stakingRepository: StakingRepository,
private val quotesRepository: QuotesRepository,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
private val multiQuoteFetcher: MultiQuoteFetcher,
private val tokensFeatureToggles: TokensFeatureToggles,
) {
@ -124,10 +126,19 @@ class SaveManagedTokensUseCase(
}
private suspend fun refreshUpdatedQuotes(addedCurrencies: List<CryptoCurrency>) {
quotesRepository.fetchQuotes(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
refresh = true,
)
if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
multiQuoteFetcher(
params = MultiQuoteFetcher.Params(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
appCurrencyId = null,
),
)
} else {
quotesRepository.fetchQuotes(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
refresh = true,
)
}
}
/**

View file

@ -4,6 +4,7 @@ import arrow.core.Either
import com.tangem.domain.card.repository.DerivationsRepository
import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.TokensFeatureToggles
import com.tangem.domain.tokens.model.CryptoCurrency
@ -31,6 +32,7 @@ class SaveMarketTokensUseCase(
private val stakingRepository: StakingRepository,
private val quotesRepository: QuotesRepository,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
private val multiQuoteFetcher: MultiQuoteFetcher,
private val tokensFeatureToggles: TokensFeatureToggles,
) {
@ -106,9 +108,18 @@ class SaveMarketTokensUseCase(
}
private suspend fun refreshUpdatedQuotes(addedCurrencies: List<CryptoCurrency>) {
quotesRepository.fetchQuotes(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
refresh = true,
)
if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
multiQuoteFetcher(
params = MultiQuoteFetcher.Params(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
appCurrencyId = null,
),
)
} else {
quotesRepository.fetchQuotes(
currenciesIds = addedCurrencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
refresh = true,
)
}
}
}

View file

@ -5,6 +5,7 @@ import arrow.core.raise.Raise
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.Network
@ -12,6 +13,9 @@ import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
/**
* A use case for adding multiple cryptocurrencies to a user's wallet.
@ -20,12 +24,14 @@ import com.tangem.domain.wallets.models.UserWalletId
* network statuses, particularly after the addition of new tokens.
*/
// TODO: Add tests
@Suppress("LongParameterList")
class AddCryptoCurrenciesUseCase(
private val currenciesRepository: CurrenciesRepository,
private val networksRepository: NetworksRepository,
private val stakingRepository: StakingRepository,
private val quotesRepository: QuotesRepository,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
private val multiQuoteFetcher: MultiQuoteFetcher,
private val tokensFeatureToggles: TokensFeatureToggles,
) {
@ -68,9 +74,14 @@ class AddCryptoCurrenciesUseCase(
val currencyToAdd = currency.takeUnless(existingCurrencies::contains) ?: return@either
addCurrencies(userWalletId, currencyToAdd)
refreshUpdatedNetworks(userWalletId, currencyToAdd, existingCurrencies)
refreshUpdatedYieldBalances(userWalletId, currencyToAdd)
refreshUpdatedQuotes(currencyToAdd)
coroutineScope {
awaitAll(
async { refreshUpdatedNetworks(userWalletId, currencyToAdd, existingCurrencies) },
async { refreshUpdatedYieldBalances(userWalletId, currencyToAdd) },
async { refreshUpdatedQuotes(currencyToAdd) },
)
}
}
suspend operator fun invoke(
@ -94,9 +105,15 @@ class AddCryptoCurrenciesUseCase(
}
val tokenToAdd = createTokenCurrency(userWalletId, contractAddress, networkId)
addCurrencies(userWalletId, tokenToAdd)
refreshUpdatedNetworks(userWalletId, tokenToAdd, existingCurrencies)
refreshUpdatedYieldBalances(userWalletId, tokenToAdd)
refreshUpdatedQuotes(tokenToAdd)
coroutineScope {
awaitAll(
async { refreshUpdatedNetworks(userWalletId, tokenToAdd, existingCurrencies) },
async { refreshUpdatedYieldBalances(userWalletId, tokenToAdd) },
async { refreshUpdatedQuotes(tokenToAdd) },
)
}
tokenToAdd
}
@ -150,10 +167,19 @@ class AddCryptoCurrenciesUseCase(
}
private suspend fun refreshUpdatedQuotes(currencyToAdd: CryptoCurrency) {
quotesRepository.fetchQuotes(
currenciesIds = setOfNotNull(currencyToAdd.id.rawCurrencyId),
refresh = true,
)
if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
multiQuoteFetcher(
params = MultiQuoteFetcher.Params(
currenciesIds = setOfNotNull(currencyToAdd.id.rawCurrencyId),
appCurrencyId = null,
),
)
} else {
quotesRepository.fetchQuotes(
currenciesIds = setOfNotNull(currencyToAdd.id.rawCurrencyId),
refresh = true,
)
}
}
private suspend fun Raise<Throwable>.createTokenCurrency(

View file

@ -4,6 +4,7 @@ import arrow.core.Either
import arrow.core.getOrElse
import arrow.core.raise.catch
import arrow.core.raise.either
import com.tangem.domain.quotes.multi.MultiQuoteFetcher
import com.tangem.domain.tokens.error.QuotesError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.repository.CurrenciesRepository
@ -16,6 +17,8 @@ import kotlinx.coroutines.coroutineScope
class RefreshMultiCurrencyWalletQuotesUseCase(
private val quotesRepository: QuotesRepository,
private val currenciesRepository: CurrenciesRepository,
private val multiQuoteFetcher: MultiQuoteFetcher,
private val tokensFeatureToggles: TokensFeatureToggles,
) {
suspend operator fun invoke(userWalletId: UserWalletId): Either<QuotesError, Unit> {
@ -45,14 +48,23 @@ class RefreshMultiCurrencyWalletQuotesUseCase(
}
private suspend fun fetchQuotes(currenciesIds: Set<CryptoCurrency.ID>) {
catch(
block = {
quotesRepository.fetchQuotes(
if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
multiQuoteFetcher(
params = MultiQuoteFetcher.Params(
currenciesIds = currenciesIds.mapNotNullTo(hashSetOf(), CryptoCurrency.ID::rawCurrencyId),
refresh = true,
)
},
catch = { /* Ignore error */ },
)
appCurrencyId = null,
),
)
} else {
catch(
block = {
quotesRepository.fetchQuotes(
currenciesIds = currenciesIds.mapNotNullTo(hashSetOf(), CryptoCurrency.ID::rawCurrencyId),
refresh = true,
)
},
catch = { /* Ignore error */ },
)
}
}
}

View file

@ -10,6 +10,8 @@ import com.tangem.domain.networks.multi.MultiNetworkStatusProducer
import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
import com.tangem.domain.networks.single.SingleNetworkStatusProducer
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
import com.tangem.domain.quotes.single.SingleQuoteProducer
import com.tangem.domain.quotes.single.SingleQuoteSupplier
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
import com.tangem.domain.staking.repositories.StakingRepository
@ -41,6 +43,7 @@ abstract class BaseCurrencyStatusOperations(
private val stakingRepository: StakingRepository,
private val multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
private val singleNetworkStatusSupplier: SingleNetworkStatusSupplier,
private val singleQuoteSupplier: SingleQuoteSupplier,
private val tokensFeatureToggles: TokensFeatureToggles,
) {
@ -171,7 +174,16 @@ abstract class BaseCurrencyStatusOperations(
} else {
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, cryptoCurrencyId)
}
val quote = cryptoCurrencyId.rawCurrencyId?.let { quotesRepository.getQuoteSync(it) }?.right()
val quote = cryptoCurrencyId.rawCurrencyId?.let { rawId ->
if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
singleQuoteSupplier(params = SingleQuoteProducer.Params(rawCurrencyId = rawId))
.firstOrNull()
} else {
quotesRepository.getQuoteSync(rawId)
}
}
?.right()
?: Error.EmptyQuotes.left()
val networkStatuses = if (tokensFeatureToggles.isNetworksLoadingRefactoringEnabled) {
@ -268,13 +280,23 @@ abstract class BaseCurrencyStatusOperations(
block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) },
catch = { raise(Error.DataError(it)) },
)
val quotes = catch(
block = {
currency.id.rawCurrencyId?.let { quotesRepository.getQuoteSync(it) }
?.right() ?: Error.EmptyQuotes.left()
},
catch = { Error.DataError(it).left() },
)
val quotes = if (tokensFeatureToggles.isQuotesLoadingRefactoringEnabled) {
currency.id.rawCurrencyId?.let {
singleQuoteSupplier(params = SingleQuoteProducer.Params(rawCurrencyId = it))
.firstOrNull()
}
?.right()
?: Error.EmptyQuotes.left()
} else {
catch(
block = {
currency.id.rawCurrencyId?.let { quotesRepository.getQuoteSync(it) }
?.right() ?: Error.EmptyQuotes.left()
},
catch = { Error.DataError(it).left() },
)
}
val networkStatus = if (tokensFeatureToggles.isNetworksLoadingRefactoringEnabled) {
singleNetworkStatusSupplier(

View file

@ -53,6 +53,7 @@ class CachedCurrenciesStatusesOperations(
stakingRepository = stakingRepository,
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
singleNetworkStatusSupplier = singleNetworkStatusSupplier,
singleQuoteSupplier = singleQuoteSupplier,
tokensFeatureToggles = tokensFeatureToggles,
) {