Updated on 2026-08-14
This commit is contained in:
parent
a0ef13e0cf
commit
2286db21d0
22 changed files with 733 additions and 1005 deletions
|
|
@ -5,6 +5,7 @@ import com.tangem.domain.exchange.RampStateManager
|
|||
import com.tangem.domain.promo.PromoRepository
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.operations.*
|
||||
import com.tangem.domain.tokens.repository.*
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.features.swap.SwapFeatureToggles
|
||||
|
|
@ -62,17 +63,11 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideGetTokenListUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
baseCurrenciesStatusesOperations: BaseCurrenciesStatusesOperations,
|
||||
): GetTokenListUseCase {
|
||||
return GetTokenListUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
currenciesStatusesOperations = baseCurrenciesStatusesOperations,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -88,20 +83,12 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCurrencyUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
baseCurrencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
): GetCurrencyStatusUpdatesUseCase {
|
||||
return GetCurrencyStatusUpdatesUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
currencyStatusOperations = baseCurrencyStatusOperations,
|
||||
dispatchers = dispatchers,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -109,16 +96,12 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideGetAllWalletsCryptoCurrencyStatusesUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetAllWalletsCryptoCurrencyStatusesUseCase {
|
||||
return GetAllWalletsCryptoCurrencyStatusesUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
currencyStatusOperations = currencyStatusOperations,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -128,40 +111,30 @@ internal object TokensDomainModule {
|
|||
fun provideGetCurrencyWarningsUseCase(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
currencyChecksRepository: CurrencyChecksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
baseCurrencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
): GetCurrencyWarningsUseCase {
|
||||
return GetCurrencyWarningsUseCase(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
currencyChecksRepository = currencyChecksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatchers,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
currencyStatusOperations = baseCurrencyStatusOperations,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetPrimaryCurrencyUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetPrimaryCurrencyStatusUpdatesUseCase {
|
||||
return GetPrimaryCurrencyStatusUpdatesUseCase(
|
||||
currenciesRepository,
|
||||
quotesRepository,
|
||||
networksRepository,
|
||||
stakingRepository,
|
||||
dispatchers,
|
||||
currencyStatusOperations = currencyStatusOperations,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -190,19 +163,9 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun providesGetCryptoCurrencyStatusSyncUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
dispatcherProvider: CoroutineDispatcherProvider,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
): GetCryptoCurrencyStatusSyncUseCase {
|
||||
return GetCryptoCurrencyStatusSyncUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatcherProvider,
|
||||
)
|
||||
return GetCryptoCurrencyStatusSyncUseCase(currencyStatusOperations)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -240,40 +203,32 @@ internal object TokensDomainModule {
|
|||
rampStateManager: RampStateManager,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
promoRepository: PromoRepository,
|
||||
swapFeatureToggles: SwapFeatureToggles,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
): GetCryptoCurrencyActionsUseCase {
|
||||
return GetCryptoCurrencyActionsUseCase(
|
||||
rampManager = rampStateManager,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
promoRepository = promoRepository,
|
||||
swapFeatureToggles = swapFeatureToggles,
|
||||
dispatchers = dispatchers,
|
||||
currencyStatusOperations = currencyStatusOperations,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCurrencyStatusByNetworkUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): GetNetworkCoinStatusUseCase {
|
||||
return GetNetworkCoinStatusUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
currencyStatusOperations = currencyStatusOperations,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -282,17 +237,11 @@ internal object TokensDomainModule {
|
|||
@Singleton
|
||||
fun provideGetFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
): GetFeePaidCryptoCurrencyStatusSyncUseCase {
|
||||
return GetFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatchers,
|
||||
currencyStatusOperations = currencyStatusOperations,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -363,19 +312,9 @@ internal object TokensDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideGetWalletTotalBalanceUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
baseCurrenciesStatusesOperations: BaseCurrenciesStatusesOperations,
|
||||
): GetWalletTotalBalanceUseCase {
|
||||
return GetWalletTotalBalanceUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
tokensFeatureToggles = tokensFeatureToggles,
|
||||
)
|
||||
return GetWalletTotalBalanceUseCase(baseCurrenciesStatusesOperations)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -398,4 +337,56 @@ internal object TokensDomainModule {
|
|||
): GetCurrencyCheckUseCase {
|
||||
return GetCurrencyCheckUseCase(currencyChecksRepository, dispatchers)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBaseCurrenciesStatusesOperations(
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
): BaseCurrenciesStatusesOperations {
|
||||
return if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CachedCurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
} else {
|
||||
LceCurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBaseCurrencyStatusOperations(
|
||||
tokensFeatureToggles: TokensFeatureToggles,
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
): BaseCurrencyStatusOperations {
|
||||
return if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CachedCurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
} else {
|
||||
CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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.UserWallet
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
|
@ -19,19 +17,14 @@ import kotlinx.coroutines.flow.*
|
|||
* Get crypto currency statuses by raw ID for all wallets
|
||||
*
|
||||
* @property currenciesRepository currencies repository
|
||||
* @property quotesRepository quotes repository
|
||||
* @property networksRepository networks repository
|
||||
* @property stakingRepository staking repository
|
||||
* @property dispatchers dispatchers
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class GetAllWalletsCryptoCurrencyStatusesUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -47,16 +40,8 @@ class GetAllWalletsCryptoCurrencyStatusesUseCase(
|
|||
return currenciesRepository.getAllWalletsCryptoCurrencies(currencyRawId, needFilterByAvailable)
|
||||
.flatMapLatest { userWalletsWithCurrencies: Map<UserWallet, List<CryptoCurrency>> ->
|
||||
val walletStatusFlows = userWalletsWithCurrencies.map { (userWallet, cryptoCurrencies) ->
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWallet.walletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
val currencyStatusFlows = cryptoCurrencies.map { cryptoCurrency ->
|
||||
operations.getCurrencyStatusFlow(cryptoCurrency)
|
||||
currencyStatusOperations.getCurrencyStatusFlow(userWallet.walletId, cryptoCurrency)
|
||||
.map { it.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,8 @@ import com.tangem.domain.promo.models.StoryContentIds
|
|||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
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.transaction.models.AssetRequirementsCondition
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
|
|
@ -30,36 +28,29 @@ class GetCryptoCurrencyActionsUseCase(
|
|||
private val rampManager: RampStateManager,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val promoRepository: PromoRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val swapFeatureToggles: SwapFeatureToggles,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWallet: UserWallet,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): Flow<TokenActionsState> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWallet.walletId,
|
||||
)
|
||||
val networkId = cryptoCurrencyStatus.currency.network.id
|
||||
val requirements = withTimeoutOrNull(REQUEST_EXCHANGE_DATA_TIMEOUT) {
|
||||
walletManagersFacade.getAssetRequirements(userWallet.walletId, cryptoCurrencyStatus.currency)
|
||||
}
|
||||
return flow {
|
||||
val networkFlow = if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
|
||||
operations.getNetworkCoinForSingleWalletWithTokenFlow(networkId)
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenFlow(userWallet.walletId, networkId)
|
||||
} else if (!userWallet.isMultiCurrency) {
|
||||
operations.getPrimaryCurrencyStatusFlow(includeQuotes = false)
|
||||
currencyStatusOperations.getPrimaryCurrencyStatusFlow(userWallet.walletId, includeQuotes = false)
|
||||
} else {
|
||||
operations.getNetworkCoinFlow(
|
||||
currencyStatusOperations.getNetworkCoinFlow(
|
||||
userWallet.walletId,
|
||||
networkId = networkId,
|
||||
derivationPath = cryptoCurrencyStatus.currency.network.derivationPath,
|
||||
includeQuotes = false,
|
||||
|
|
|
|||
|
|
@ -1,24 +1,15 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
||||
class GetCryptoCurrencyStatusSyncUseCase(
|
||||
internal val currenciesRepository: CurrenciesRepository,
|
||||
internal val quotesRepository: QuotesRepository,
|
||||
internal val networksRepository: NetworksRepository,
|
||||
internal val stakingRepository: StakingRepository,
|
||||
internal val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
// multi-currency
|
||||
|
|
@ -27,29 +18,13 @@ class GetCryptoCurrencyStatusSyncUseCase(
|
|||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean = false,
|
||||
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getCurrencyStatusSync(cryptoCurrencyId, isSingleWalletWithTokens)
|
||||
return currencyStatusOperations.getCurrencyStatusSync(userWalletId, cryptoCurrencyId, isSingleWalletWithTokens)
|
||||
.mapLeft { error -> error.mapToCurrencyError() }
|
||||
}
|
||||
|
||||
// single-currency
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getPrimaryCurrencyStatusSync()
|
||||
return currencyStatusOperations.getPrimaryCurrencyStatusSync(userWalletId)
|
||||
.mapLeft { error -> error.mapToCurrencyError() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,18 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToTokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
||||
class GetCryptoCurrencyStatusesSyncUseCase(
|
||||
internal val currenciesRepository: CurrenciesRepository,
|
||||
internal val quotesRepository: QuotesRepository,
|
||||
internal val networksRepository: NetworksRepository,
|
||||
internal val stakingRepository: StakingRepository,
|
||||
internal val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return operations.getCurrenciesStatusesSync()
|
||||
return currencyStatusOperations.getCurrenciesStatusesSync(userWalletId)
|
||||
.mapLeft { error -> error.mapToTokenListError() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,12 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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 com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -18,17 +14,10 @@ import kotlinx.coroutines.flow.*
|
|||
/**
|
||||
* Use case for fetching the status of a cryptocurrency associated with a user wallet.
|
||||
*
|
||||
* @property currenciesRepository Repository for managing and fetching cryptocurrencies.
|
||||
* @property quotesRepository Repository for managing and fetching cryptocurrency quotes.
|
||||
* @property networksRepository Repository for managing and fetching information related to blockchain networks.
|
||||
*/
|
||||
class GetCurrencyStatusUpdatesUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -60,28 +49,12 @@ class GetCurrencyStatusUpdatesUseCase(
|
|||
currencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrencyStatusFlow(userWalletId, currencyId)
|
||||
} else {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
val currencyFlow = currencyStatusOperations.getCurrencyStatusFlow(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = currencyId,
|
||||
isSingleWalletWithTokens = isSingleWalletWithTokens,
|
||||
)
|
||||
|
||||
if (isSingleWalletWithTokens) {
|
||||
operations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
} else {
|
||||
operations.getCurrencyStatusFlow(currencyId)
|
||||
}
|
||||
}
|
||||
return currencyFlow.map { maybeCurrency ->
|
||||
maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,14 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
import com.tangem.domain.tokens.model.warnings.HederaWarnings
|
||||
import com.tangem.domain.tokens.model.warnings.KaspaWarnings
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
import com.tangem.domain.tokens.repository.QuotesRepository
|
||||
import com.tangem.domain.transaction.models.AssetRequirementsCondition
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
|
@ -24,12 +21,10 @@ import java.math.BigDecimal
|
|||
class GetCurrencyWarningsUseCase(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyChecksRepository: CurrencyChecksRepository,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
|
@ -75,43 +70,16 @@ class GetCurrencyWarningsUseCase(
|
|||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<List<CryptoCurrencyWarning>> {
|
||||
val cachedOperations by lazy {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
}
|
||||
val currencyFlow = currencyStatusOperations.getCurrencyStatusFlow(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = currencyId,
|
||||
isSingleWalletWithTokens = isSingleWalletWithTokens,
|
||||
)
|
||||
|
||||
val lceOperations by lazy {
|
||||
CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
}
|
||||
|
||||
val currencyFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
cachedOperations.getCurrencyStatusFlow(userWalletId, currencyId)
|
||||
val networkFlow = if (isSingleWalletWithTokens) {
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenFlow(userWalletId, networkId)
|
||||
} else {
|
||||
if (isSingleWalletWithTokens) {
|
||||
lceOperations.getCurrencyStatusSingleWalletWithTokensFlow(currencyId)
|
||||
} else {
|
||||
lceOperations.getCurrencyStatusFlow(currencyId)
|
||||
}
|
||||
}
|
||||
|
||||
val networkFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
cachedOperations.getNetworkCoinFlow(userWalletId, networkId, derivationPath)
|
||||
} else {
|
||||
if (isSingleWalletWithTokens) {
|
||||
lceOperations.getNetworkCoinForSingleWalletWithTokenFlow(networkId)
|
||||
} else {
|
||||
lceOperations.getNetworkCoinFlow(networkId, derivationPath)
|
||||
}
|
||||
currencyStatusOperations.getNetworkCoinFlow(userWalletId, networkId, derivationPath)
|
||||
}
|
||||
|
||||
return combine(
|
||||
|
|
|
|||
|
|
@ -2,23 +2,16 @@ package com.tangem.domain.tokens
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
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 com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
||||
class GetFeePaidCryptoCurrencyStatusSyncUseCase(
|
||||
internal val currenciesRepository: CurrenciesRepository,
|
||||
internal val quotesRepository: QuotesRepository,
|
||||
internal val networksRepository: NetworksRepository,
|
||||
internal val stakingRepository: StakingRepository,
|
||||
internal val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
|
|
@ -28,24 +21,20 @@ class GetFeePaidCryptoCurrencyStatusSyncUseCase(
|
|||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
val network = cryptoCurrency.network
|
||||
val feePaidCurrency = currenciesRepository.getFeePaidCurrency(userWalletId, network)
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
userWalletId = userWalletId,
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
)
|
||||
|
||||
return either {
|
||||
when (feePaidCurrency) {
|
||||
FeePaidCurrency.Coin ->
|
||||
operations
|
||||
.getNetworkCoinSync(network.id, network.derivationPath)
|
||||
is FeePaidCurrency.Coin -> {
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, network.id, network.derivationPath)
|
||||
.getOrNull()
|
||||
FeePaidCurrency.SameCurrency,
|
||||
}
|
||||
is FeePaidCurrency.Token -> {
|
||||
currencyStatusOperations.getCurrencyStatusSync(userWalletId, feePaidCurrency.tokenId)
|
||||
.getOrNull()
|
||||
}
|
||||
is FeePaidCurrency.SameCurrency,
|
||||
is FeePaidCurrency.FeeResource,
|
||||
-> cryptoCurrencyStatus
|
||||
is FeePaidCurrency.Token -> operations.getCurrencyStatusSync(feePaidCurrency.tokenId).getOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,18 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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 com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
class GetNetworkCoinStatusUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
|
|
@ -47,17 +41,10 @@ class GetNetworkCoinStatusUseCase(
|
|||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Either<CurrencyStatusError, CryptoCurrencyStatus> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
val maybeCurrency = if (isSingleWalletWithTokens) {
|
||||
operations.getNetworkCoinForSingleWalletWithTokenSync(networkId)
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenSync(userWalletId, networkId)
|
||||
} else {
|
||||
operations.getNetworkCoinSync(networkId, derivationPath)
|
||||
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
|
||||
}
|
||||
return maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
|
|
@ -68,17 +55,10 @@ class GetNetworkCoinStatusUseCase(
|
|||
derivationPath: Network.DerivationPath,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
val networkFlow = if (isSingleWalletWithTokens) {
|
||||
operations.getNetworkCoinForSingleWalletWithTokenFlow(networkId)
|
||||
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenFlow(userWalletId, networkId)
|
||||
} else {
|
||||
operations.getNetworkCoinFlow(networkId, derivationPath)
|
||||
currencyStatusOperations.getNetworkCoinFlow(userWalletId, networkId, derivationPath)
|
||||
}
|
||||
return networkFlow.map { maybeCurrency ->
|
||||
maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToCurrencyError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
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 com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -16,17 +13,11 @@ import kotlinx.coroutines.flow.*
|
|||
/**
|
||||
* Use case for fetching the status of the primary cryptocurrency associated with a user wallet.
|
||||
*
|
||||
* @property currenciesRepository Repository for managing and fetching cryptocurrencies.
|
||||
* @property quotesRepository Repository for managing and fetching cryptocurrency quotes.
|
||||
* @property networksRepository Repository for managing and fetching information related to blockchain networks.
|
||||
* @property dispatchers Provides coroutine dispatchers.
|
||||
*/
|
||||
class GetPrimaryCurrencyStatusUpdatesUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
) {
|
||||
|
||||
/**
|
||||
|
|
@ -44,15 +35,7 @@ class GetPrimaryCurrencyStatusUpdatesUseCase(
|
|||
private suspend fun getPrimaryCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
return operations.getPrimaryCurrencyStatusFlow().map { maybeCurrency ->
|
||||
return currencyStatusOperations.getPrimaryCurrencyStatusFlow(userWalletId).map { maybeCurrency ->
|
||||
maybeCurrency.mapLeft(CurrenciesStatusesOperations.Error::mapToCurrencyError)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,13 @@ import com.tangem.domain.core.lce.LceFlow
|
|||
import com.tangem.domain.core.utils.lceError
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.core.utils.toLce
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.error.mapper.mapToTokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TokenList
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListOperations
|
||||
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.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.emitAll
|
||||
|
|
@ -23,45 +19,27 @@ import kotlinx.coroutines.flow.transformLatest
|
|||
|
||||
class GetTokenListUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
private val currenciesStatusesOperations: BaseCurrenciesStatusesOperations,
|
||||
) {
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
fun launch(userWalletId: UserWalletId): LceFlow<TokenListError, TokenList> {
|
||||
val statusesFlow = if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
} else {
|
||||
CurrenciesStatusesLceOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
}
|
||||
|
||||
return statusesFlow.transformLatest { maybeCurrencies ->
|
||||
maybeCurrencies.fold(
|
||||
ifLoading = { maybeContent ->
|
||||
if (maybeContent != null) {
|
||||
emitAll(createTokenListLce(userWalletId, maybeContent, isCurrenciesLoading = true))
|
||||
} else {
|
||||
emit(lceLoading())
|
||||
}
|
||||
},
|
||||
ifContent = { content ->
|
||||
emitAll(createTokenListLce(userWalletId, content, isCurrenciesLoading = false))
|
||||
},
|
||||
ifError = { error -> emit(error.lceError()) },
|
||||
)
|
||||
}
|
||||
return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId)
|
||||
.transformLatest { maybeCurrencies ->
|
||||
maybeCurrencies.fold(
|
||||
ifLoading = { maybeContent ->
|
||||
if (maybeContent != null) {
|
||||
emitAll(createTokenListLce(userWalletId, maybeContent, isCurrenciesLoading = true))
|
||||
} else {
|
||||
emit(lceLoading())
|
||||
}
|
||||
},
|
||||
ifContent = { content ->
|
||||
emitAll(createTokenListLce(userWalletId, content, isCurrenciesLoading = false))
|
||||
},
|
||||
ifError = { error -> emit(error.lceError()) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTokenListLce(
|
||||
|
|
|
|||
|
|
@ -7,16 +7,11 @@ import com.tangem.domain.core.lce.Lce
|
|||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.core.lce.lce
|
||||
import com.tangem.domain.core.utils.lceLoading
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesCachedOperations
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesLceOperations
|
||||
import com.tangem.domain.tokens.operations.BaseCurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.operations.TokenListFiatBalanceOperations
|
||||
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.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -25,11 +20,7 @@ import kotlinx.coroutines.flow.transformLatest
|
|||
import timber.log.Timber
|
||||
|
||||
class GetWalletTotalBalanceUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val tokensFeatureToggles: TokensFeatureToggles,
|
||||
private val currenciesStatusesOperations: BaseCurrenciesStatusesOperations,
|
||||
) {
|
||||
|
||||
operator fun invoke(
|
||||
|
|
@ -65,13 +56,12 @@ class GetWalletTotalBalanceUseCase(
|
|||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
operator fun invoke(userWalletId: UserWalletId): LceFlow<TokenListError, TotalFiatBalance> {
|
||||
val currenciesStatuses = getStatuses(userWalletId)
|
||||
return currenciesStatusesOperations.getCurrenciesStatuses(userWalletId)
|
||||
.transformLatest { maybeStatuses ->
|
||||
val balance = createBalance(maybeStatuses)
|
||||
|
||||
return currenciesStatuses.transformLatest { maybeStatuses ->
|
||||
val balance = createBalance(maybeStatuses)
|
||||
|
||||
emit(balance)
|
||||
}
|
||||
emit(balance)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createBalance(
|
||||
|
|
@ -86,22 +76,4 @@ class GetWalletTotalBalanceUseCase(
|
|||
|
||||
operations.calculateFiatBalance()
|
||||
}
|
||||
|
||||
private fun getStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
return if (tokensFeatureToggles.isBalancesCachingEnabled) {
|
||||
CurrenciesStatusesCachedOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
} else {
|
||||
CurrenciesStatusesLceOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
).getCurrenciesStatuses(userWalletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.tokens.error.TokenListError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Base operations for working with currencies statuses
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface BaseCurrenciesStatusesOperations {
|
||||
|
||||
/** Get [LceFlow] of currencies statuses by [userWalletId] */
|
||||
fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>>
|
||||
}
|
||||
|
|
@ -0,0 +1,366 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import arrow.core.*
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.raise.recover
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
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.tokens.utils.CurrencyStatusProxyCreator
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
/**
|
||||
* Base operations for working with currency status
|
||||
*
|
||||
* @property currenciesRepository repository for currencies
|
||||
* @property quotesRepository repository for quotes
|
||||
* @property networksRepository repository for networks
|
||||
* @property stakingRepository repository for staking
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
abstract class BaseCurrencyStatusOperations(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
|
||||
protected val currencyStatusProxyCreator = CurrencyStatusProxyCreator(stakingRepository)
|
||||
|
||||
protected abstract fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>>
|
||||
|
||||
protected abstract fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>>
|
||||
|
||||
suspend fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = {
|
||||
if (isSingleWalletWithTokens) {
|
||||
getSingleCurrencyWalletWithCardTokensCurrency(userWalletId, currencyId)
|
||||
} else {
|
||||
getMultiCurrencyWalletCurrency(userWalletId, currencyId)
|
||||
}
|
||||
},
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId = userWalletId, currency = currency)
|
||||
}
|
||||
|
||||
fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val rawCurrencyId = currency.id.rawCurrencyId
|
||||
|
||||
val quoteFlow = if (includeQuotes && rawCurrencyId != null) {
|
||||
getQuotes(rawCurrencyId)
|
||||
.map { maybeQuotes ->
|
||||
maybeQuotes.flatMap { quotes ->
|
||||
quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// don't use emptyFlow()
|
||||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinFlow(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoin(userWalletId, networkId, derivationPath) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency, includeQuotes)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinForSingleWalletWithTokenFlow(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoinForSingleWalletWithToken(userWalletId, networkId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinSync(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): Either<Error, CryptoCurrencyStatus> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoin(userWalletId, networkId, derivationPath) },
|
||||
recover = { return it.left() },
|
||||
)
|
||||
|
||||
return getCurrencyStatusSync(userWalletId, currency.id)
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean = false,
|
||||
): Either<Error, CryptoCurrencyStatus> {
|
||||
return either {
|
||||
catch(
|
||||
block = {
|
||||
val currency = if (isSingleWalletWithTokens) {
|
||||
currenciesRepository.getSingleCurrencyWalletWithCardCurrency(userWalletId, cryptoCurrencyId)
|
||||
} else {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, cryptoCurrencyId)
|
||||
}
|
||||
val quote = cryptoCurrencyId.rawCurrencyId?.let { quotesRepository.getQuoteSync(it) }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
val networkStatuses =
|
||||
networksRepository.getNetworkStatusesSync(
|
||||
userWalletId = userWalletId,
|
||||
networks = setOf(currency.network),
|
||||
refresh = false,
|
||||
).firstOrNull { it.network == currency.network }.right()
|
||||
|
||||
val yieldBalances = getYieldBalanceSync(userWalletId, currency)
|
||||
|
||||
return currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = quote,
|
||||
maybeNetworkStatus = networkStatuses,
|
||||
maybeYieldBalance = yieldBalances,
|
||||
)
|
||||
},
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinForSingleWalletWithTokenSync(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
val currency = getNetworkCoinForSingleWalletWithToken(userWalletId, networkId)
|
||||
|
||||
return getCurrencyStatusSync(userWalletId, currency.id)
|
||||
}
|
||||
|
||||
suspend fun getPrimaryCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getPrimaryCurrency(userWalletId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency, includeQuotes)
|
||||
}
|
||||
|
||||
suspend fun getCurrenciesStatusesSync(userWalletId: UserWalletId): Either<Error, List<CryptoCurrencyStatus>> {
|
||||
return either {
|
||||
catch(
|
||||
block = {
|
||||
val nonEmptyCurrencies =
|
||||
currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId).toNonEmptyListOrNull()
|
||||
?: return emptyList<CryptoCurrencyStatus>().right()
|
||||
val (networks, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
val rawIds = currenciesIds.mapNotNull { it.rawCurrencyId }.toSet()
|
||||
val quotes = quotesRepository.getQuotesSync(rawIds, false).right()
|
||||
val networkStatuses =
|
||||
networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right()
|
||||
val yieldBalances = getYieldBalancesSync(userWalletId, nonEmptyCurrencies)
|
||||
|
||||
return currencyStatusProxyCreator.createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeQuotes = quotes,
|
||||
maybeNetworkStatuses = networkStatuses,
|
||||
maybeYieldBalances = yieldBalances,
|
||||
)
|
||||
},
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getPrimaryCurrencyStatusSync(userWalletId: UserWalletId): Either<Error, CryptoCurrencyStatus> = either {
|
||||
val currency = catch(
|
||||
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 networkStatus = catch(
|
||||
block = {
|
||||
networksRepository.getNetworkStatusesSync(userWalletId, setOf(currency.network))
|
||||
.firstOrNull { it.network == currency.network }
|
||||
.right()
|
||||
},
|
||||
catch = { Error.DataError(it).left() },
|
||||
)
|
||||
val yieldBalances = getYieldBalanceSync(userWalletId, currency)
|
||||
|
||||
return currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
maybeQuote = quotes,
|
||||
maybeNetworkStatus = networkStatus,
|
||||
maybeYieldBalance = yieldBalances,
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getMultiCurrencyWalletCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = currencyId)
|
||||
}
|
||||
.mapLeft(Error::DataError)
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getSingleCurrencyWalletWithCardTokensCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch { currenciesRepository.getSingleCurrencyWalletWithCardCurrency(userWalletId, currencyId) }
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private fun getYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): EitherFlow<Error, YieldBalance> {
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoin(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): CryptoCurrency {
|
||||
return Either.catch { currenciesRepository.getNetworkCoin(userWalletId, networkId, derivationPath) }
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoinForSingleWalletWithToken(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getSingleCurrencyWalletWithCardCurrencies(userWalletId)
|
||||
.find { it.network.id == networkId && it is CryptoCurrency.Coin }
|
||||
?: raise(Error.DataError(IllegalStateException("Coin with network $networkId not found for this card")))
|
||||
}
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalancesSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
return catch(
|
||||
block = {
|
||||
stakingRepository.getMultiYieldBalanceSync(
|
||||
userWalletId,
|
||||
cryptoCurrencies,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalance> {
|
||||
return catch(
|
||||
block = {
|
||||
stakingRepository.getSingleYieldBalanceSync(
|
||||
userWalletId,
|
||||
cryptoCurrency,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getPrimaryCurrency(userWalletId: UserWalletId): CryptoCurrency {
|
||||
return catch(
|
||||
block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) },
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
|
||||
protected fun getIds(currencies: List<CryptoCurrency>): Pair<NonEmptySet<Network>, NonEmptySet<CryptoCurrency.ID>> {
|
||||
val currencyIdToNetworkId = currencies.associate { currency ->
|
||||
currency.id to currency.network
|
||||
}
|
||||
val currenciesIds = currencyIdToNetworkId.keys.toNonEmptySetOrNull()
|
||||
val networks = currencyIdToNetworkId.values.toNonEmptySetOrNull()
|
||||
|
||||
requireNotNull(currenciesIds) { "Currencies IDs cannot be empty" }
|
||||
requireNotNull(networks) { "Networks IDs cannot be empty" }
|
||||
|
||||
return networks to currenciesIds
|
||||
}
|
||||
}
|
||||
|
|
@ -16,108 +16,28 @@ import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
|||
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.tokens.utils.extractAddress
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
@Suppress("LargeClass")
|
||||
internal class CurrenciesStatusesCachedOperations(
|
||||
class CachedCurrenciesStatusesOperations(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
) : BaseCurrenciesStatusesOperations,
|
||||
BaseCurrencyStatusOperations(currenciesRepository, quotesRepository, networksRepository, stakingRepository) {
|
||||
|
||||
fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
override fun getCurrenciesStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
return transformToCurrenciesStatuses(
|
||||
userWalletId = userWalletId,
|
||||
currenciesFlow = getCurrencies(userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getMultiCurrencyWalletCurrency(userWalletId = userWalletId, currencyId = currencyId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId = userWalletId, currency = currency, includeQuotes = includeQuotes)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinFlow(
|
||||
userWalletId: UserWalletId,
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val operations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
userWalletId = userWalletId,
|
||||
)
|
||||
|
||||
val currency = recover(
|
||||
block = {
|
||||
with(operations) { getNetworkCoin(networkId, derivationPath) }
|
||||
},
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(userWalletId, currency, includeQuotes)
|
||||
}
|
||||
|
||||
private fun getCurrencyStatusFlow(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val rawCurrencyId = currency.id.rawCurrencyId
|
||||
|
||||
val quoteFlow = if (includeQuotes && rawCurrencyId != null) {
|
||||
getQuotes(rawCurrencyId)
|
||||
.map { maybeQuotes ->
|
||||
maybeQuotes.flatMap { quotes ->
|
||||
quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// don't use emptyFlow()
|
||||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(userWalletId = userWalletId, network = currency.network)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
|
||||
val yieldBalanceFlow = getYieldBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
|
||||
return combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
createCurrencyStatus(currency, maybeQuote, maybeNetworkStatus, maybeYieldBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getMultiCurrencyWalletCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId = userWalletId, id = currencyId)
|
||||
}
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private fun transformToCurrenciesStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
currenciesFlow: EitherFlow<TokenListError, List<CryptoCurrency>>,
|
||||
|
|
@ -213,7 +133,7 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
||||
val yieldBalance = findYieldBalanceOrNull(yieldBalances, currency, networkStatus)
|
||||
|
||||
val currencyStatus = createCurrencyStatus(
|
||||
val currencyStatus = currencyStatusProxyCreator.createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
|
|
@ -225,30 +145,6 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
maybeQuote: Either<Error, Quote?>,
|
||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
var quoteRetrievingFailed = false
|
||||
|
||||
val networkStatus = maybeNetworkStatus.bind()
|
||||
val quote = recover({ maybeQuote.bind() }) {
|
||||
quoteRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
val yieldBalance = maybeYieldBalance?.getOrNull()
|
||||
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quoteRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
|
||||
private fun findYieldBalanceOrNull(
|
||||
yieldBalances: YieldBalanceList?,
|
||||
currency: CryptoCurrency,
|
||||
|
|
@ -266,24 +162,6 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
)
|
||||
}
|
||||
|
||||
private fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
quote: Quote?,
|
||||
networkStatus: NetworkStatus?,
|
||||
yieldBalance: YieldBalance?,
|
||||
ignoreQuote: Boolean,
|
||||
): CryptoCurrencyStatus {
|
||||
val currencyStatusOperations = CurrencyStatusOperations(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
yieldBalance = yieldBalance,
|
||||
ignoreQuote = ignoreQuote,
|
||||
)
|
||||
|
||||
return currencyStatusOperations.createTokenStatus()
|
||||
}
|
||||
|
||||
private fun getCurrencies(userWalletId: UserWalletId): EitherFlow<TokenListError, List<CryptoCurrency>> {
|
||||
return currenciesRepository.getWalletCurrenciesUpdates(userWalletId)
|
||||
.map<List<CryptoCurrency>, Either<TokenListError, List<CryptoCurrency>>> { it.right() }
|
||||
|
|
@ -303,7 +181,7 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>> {
|
||||
override fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>> {
|
||||
return quotesRepository.getQuotesUpdates(setOf(id))
|
||||
.map<Set<Quote>, Either<Error, Set<Quote>>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
|
|
@ -315,6 +193,21 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
override fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return networksRepository.getNetworkStatusesUpdates(userWalletId, setOf(network))
|
||||
.map<Set<NetworkStatus>, Either<Error, Set<NetworkStatus>>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
emit(Error.DataError(cause).left())
|
||||
// adding delay before retry to avoid spam when flow restarted
|
||||
delay(RETRY_DELAY)
|
||||
true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
networks: NonEmptySet<Network>,
|
||||
|
|
@ -330,21 +223,6 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return networksRepository.getNetworkStatusesUpdates(userWalletId, setOf(network))
|
||||
.map<Set<NetworkStatus>, Either<Error, Set<NetworkStatus>>> { it.right() }
|
||||
.retryWhen { cause, _ ->
|
||||
emit(Error.DataError(cause).left())
|
||||
// adding delay before retry to avoid spam when flow restarted
|
||||
delay(RETRY_DELAY)
|
||||
true
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getYieldBalances(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
@ -360,40 +238,6 @@ internal class CurrenciesStatusesCachedOperations(
|
|||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
private fun getYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): EitherFlow<Error, YieldBalance> {
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getIds(currencies: List<CryptoCurrency>): Pair<NonEmptySet<Network>, NonEmptySet<CryptoCurrency.ID>> {
|
||||
val currencyIdToNetworkId = currencies.associate { currency ->
|
||||
currency.id to currency.network
|
||||
}
|
||||
val currenciesIds = currencyIdToNetworkId.keys.toNonEmptySetOrNull()
|
||||
val networks = currencyIdToNetworkId.values.toNonEmptySetOrNull()
|
||||
|
||||
requireNotNull(currenciesIds) { "Currencies IDs cannot be empty" }
|
||||
requireNotNull(networks) { "Networks IDs cannot be empty" }
|
||||
|
||||
return networks to currenciesIds
|
||||
}
|
||||
|
||||
private fun extractAddress(networkStatus: NetworkStatus?): String? {
|
||||
return when (val value = networkStatus?.value) {
|
||||
is NetworkStatus.NoAccount -> value.address.defaultAddress.value
|
||||
is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value
|
||||
is NetworkStatus.Verified -> value.address.defaultAddress.value
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val RETRY_DELAY = 2000L
|
||||
}
|
||||
|
|
@ -1,355 +1,29 @@
|
|||
package com.tangem.domain.tokens.operations
|
||||
|
||||
import arrow.core.*
|
||||
import arrow.core.raise.*
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
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.flow.*
|
||||
|
||||
// FIXME: Refactor - [REDACTED_JIRA]
|
||||
@Suppress("LargeClass")
|
||||
internal class CurrenciesStatusesOperations(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
class CurrenciesStatusesOperations(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val userWalletId: UserWalletId,
|
||||
) {
|
||||
stakingRepository: StakingRepository,
|
||||
) : BaseCurrencyStatusOperations(currenciesRepository, quotesRepository, networksRepository, stakingRepository) {
|
||||
|
||||
suspend fun getCurrenciesStatusesSync(): Either<Error, List<CryptoCurrencyStatus>> {
|
||||
return either {
|
||||
catch(
|
||||
block = {
|
||||
val nonEmptyCurrencies =
|
||||
currenciesRepository.getMultiCurrencyWalletCurrenciesSync(userWalletId).toNonEmptyListOrNull()
|
||||
?: return emptyList<CryptoCurrencyStatus>().right()
|
||||
val (networks, currenciesIds) = getIds(nonEmptyCurrencies)
|
||||
val rawIds = currenciesIds.mapNotNull { it.rawCurrencyId }.toSet()
|
||||
val quotes = quotesRepository.getQuotesSync(rawIds, false).right()
|
||||
val networkStatuses =
|
||||
networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right()
|
||||
val yieldBalances = getYieldBalancesSync(nonEmptyCurrencies)
|
||||
|
||||
return createCurrenciesStatuses(
|
||||
nonEmptyCurrencies,
|
||||
quotes,
|
||||
networkStatuses,
|
||||
yieldBalances,
|
||||
)
|
||||
},
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusSync(
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
isSingleWalletWithTokens: Boolean = false,
|
||||
): Either<Error, CryptoCurrencyStatus> {
|
||||
return either {
|
||||
catch(
|
||||
block = {
|
||||
val currency = if (isSingleWalletWithTokens) {
|
||||
currenciesRepository.getSingleCurrencyWalletWithCardCurrency(userWalletId, cryptoCurrencyId)
|
||||
} else {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(userWalletId, cryptoCurrencyId)
|
||||
}
|
||||
val quote = cryptoCurrencyId.rawCurrencyId?.let { quotesRepository.getQuoteSync(it) }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
val networkStatuses =
|
||||
networksRepository.getNetworkStatusesSync(
|
||||
userWalletId,
|
||||
setOf(currency.network),
|
||||
false,
|
||||
).firstOrNull {
|
||||
it.network == currency.network
|
||||
}.right()
|
||||
val yieldBalances = getYieldBalanceSync(currency)
|
||||
|
||||
return createCurrencyStatus(currency, quote, networkStatuses, yieldBalances)
|
||||
},
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinSync(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): Either<Error, CryptoCurrencyStatus> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoin(networkId, derivationPath) },
|
||||
recover = { return it.left() },
|
||||
)
|
||||
|
||||
return getCurrencyStatusSync(currency.id)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinForSingleWalletWithTokenSync(
|
||||
networkId: Network.ID,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
val currency = getNetworkCoinForSingleWalletWithToken(networkId)
|
||||
|
||||
return getCurrencyStatusSync(currency.id)
|
||||
}
|
||||
|
||||
suspend fun getPrimaryCurrencyStatusSync(): Either<Error, CryptoCurrencyStatus> = either {
|
||||
val currency = catch(
|
||||
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 networkStatus = catch(
|
||||
block = {
|
||||
networksRepository.getNetworkStatusesSync(userWalletId, setOf(currency.network))
|
||||
.firstOrNull { it.network == currency.network }
|
||||
.right()
|
||||
},
|
||||
catch = { Error.DataError(it).left() },
|
||||
)
|
||||
val yieldBalances = getYieldBalanceSync(currency)
|
||||
|
||||
return createCurrencyStatus(currency, quotes, networkStatus, yieldBalances)
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusFlow(currencyId: CryptoCurrency.ID): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getMultiCurrencyWalletCurrency(currencyId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency)
|
||||
}
|
||||
|
||||
suspend fun getCurrencyStatusSingleWalletWithTokensFlow(
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getSingleCurrencyWalletWithCardTokensCurrency(currencyId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinFlow(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoin(networkId, derivationPath) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency, includeQuotes)
|
||||
}
|
||||
|
||||
suspend fun getNetworkCoinForSingleWalletWithTokenFlow(
|
||||
networkId: Network.ID,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getNetworkCoinForSingleWalletWithToken(networkId) },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency)
|
||||
}
|
||||
|
||||
suspend fun getPrimaryCurrencyStatusFlow(includeQuotes: Boolean = true): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val currency = recover(
|
||||
block = { getPrimaryCurrency() },
|
||||
recover = { return flowOf(it.left()) },
|
||||
)
|
||||
|
||||
return getCurrencyStatusFlow(currency, includeQuotes)
|
||||
}
|
||||
|
||||
fun getCurrencyStatusFlow(
|
||||
currency: CryptoCurrency,
|
||||
includeQuotes: Boolean = true,
|
||||
): Flow<Either<Error, CryptoCurrencyStatus>> {
|
||||
val (networks, currenciesIds) = getIds(nonEmptyListOf(currency))
|
||||
|
||||
val quoteFlow = if (includeQuotes) {
|
||||
getQuotes(currenciesIds)
|
||||
.map { maybeQuotes ->
|
||||
maybeQuotes.flatMap { quotes ->
|
||||
quotes.singleOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }?.right()
|
||||
?: Error.EmptyQuotes.left()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// don't use emptyFlow()
|
||||
flow { emit(Error.EmptyQuotes.left()) }
|
||||
}
|
||||
|
||||
val statusFlow = getNetworksStatuses(networks)
|
||||
.map { maybeStatuses ->
|
||||
maybeStatuses.flatMap { statuses ->
|
||||
statuses.singleOrNull { it.network == currency.network }?.right()
|
||||
?: Error.EmptyNetworksStatuses.left()
|
||||
}
|
||||
}
|
||||
|
||||
val yieldBalanceFlow = getYieldBalance(currency)
|
||||
|
||||
return combine(quoteFlow, statusFlow, yieldBalanceFlow) { maybeQuote, maybeNetworkStatus, maybeYieldBalance ->
|
||||
createCurrencyStatus(currency, maybeQuote, maybeNetworkStatus, maybeYieldBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCurrenciesStatuses(
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
maybeQuotes: Either<Error, Set<Quote>>?,
|
||||
maybeNetworkStatuses: Either<Error, Set<NetworkStatus>>?,
|
||||
maybeYieldBalances: Either<Error, YieldBalanceList>?,
|
||||
): Either<Error, List<CryptoCurrencyStatus>> = either {
|
||||
var quotesRetrievingFailed = false
|
||||
|
||||
val networksStatuses = maybeNetworkStatuses?.bind()?.toNonEmptySetOrNull()
|
||||
val quotes: Set<Quote>? = maybeQuotes?.fold(
|
||||
ifLeft = {
|
||||
quotesRetrievingFailed = true
|
||||
null
|
||||
},
|
||||
ifRight = {
|
||||
it.ifEmpty {
|
||||
quotesRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val yieldBalances = maybeYieldBalances?.getOrNull()
|
||||
|
||||
currencies.map { currency ->
|
||||
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
||||
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
||||
val address = extractAddress(networkStatus)
|
||||
|
||||
val supportedIntegration = stakingRepository.getSupportedIntegrationId(currency.id)
|
||||
val yieldBalance = if (supportedIntegration.isNullOrEmpty().not()) {
|
||||
(yieldBalances as? YieldBalanceList.Data)?.getBalance(
|
||||
address = address,
|
||||
integrationId = supportedIntegration,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quotesRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
maybeQuote: Either<Error, Quote?>,
|
||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
var quoteRetrievingFailed = false
|
||||
|
||||
val networkStatus = maybeNetworkStatus.bind()
|
||||
val quote = recover({ maybeQuote.bind() }) {
|
||||
quoteRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
val yieldBalance = maybeYieldBalance?.getOrNull()
|
||||
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quoteRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
quote: Quote?,
|
||||
networkStatus: NetworkStatus?,
|
||||
ignoreQuote: Boolean,
|
||||
yieldBalance: YieldBalance?,
|
||||
): CryptoCurrencyStatus {
|
||||
val currencyStatusOperations = CurrencyStatusOperations(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = ignoreQuote,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
|
||||
return currencyStatusOperations.createTokenStatus()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getMultiCurrencyWalletCurrency(currencyId: CryptoCurrency.ID): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getMultiCurrencyWalletCurrency(
|
||||
userWalletId = userWalletId,
|
||||
id = currencyId,
|
||||
)
|
||||
}
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getSingleCurrencyWalletWithCardTokensCurrency(
|
||||
currencyId: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return Either.catch { currenciesRepository.getSingleCurrencyWalletWithCardCurrency(userWalletId, currencyId) }
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
suspend fun Raise<Error>.getNetworkCoin(
|
||||
networkId: Network.ID,
|
||||
derivationPath: Network.DerivationPath,
|
||||
): CryptoCurrency {
|
||||
return Either.catch { currenciesRepository.getNetworkCoin(userWalletId, networkId, derivationPath) }
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getNetworkCoinForSingleWalletWithToken(networkId: Network.ID): CryptoCurrency {
|
||||
return Either.catch {
|
||||
currenciesRepository.getSingleCurrencyWalletWithCardCurrencies(userWalletId)
|
||||
.find { it.network.id == networkId && it is CryptoCurrency.Coin }
|
||||
?: raise(Error.DataError(IllegalStateException("Coin with network $networkId not found for this card")))
|
||||
}
|
||||
.mapLeft { Error.DataError(it) }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private suspend fun Raise<Error>.getPrimaryCurrency(): CryptoCurrency {
|
||||
return catch(
|
||||
block = { currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId) },
|
||||
catch = { raise(Error.DataError(it)) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun getQuotes(tokensIds: NonEmptySet<CryptoCurrency.ID>): Flow<Either<Error, Set<Quote>>> {
|
||||
val rawIds = tokensIds.mapNotNull { it.rawCurrencyId }.toSet()
|
||||
return quotesRepository.getQuotesUpdatesLegacy(rawIds)
|
||||
override fun getQuotes(id: CryptoCurrency.RawID): Flow<Either<Error, Set<Quote>>> {
|
||||
return quotesRepository.getQuotesUpdatesLegacy(setOf(id))
|
||||
.map<Set<Quote>, Either<Error, Set<Quote>>> { quotes ->
|
||||
if (quotes.isEmpty()) Error.EmptyQuotes.left() else quotes.right()
|
||||
}
|
||||
|
|
@ -359,78 +33,16 @@ internal class CurrenciesStatusesOperations(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getNetworksStatuses(networks: NonEmptySet<Network>): Flow<Either<Error, Set<NetworkStatus>>> {
|
||||
return networksRepository.getNetworkStatusesUpdatesLegacy(userWalletId, networks)
|
||||
override fun getNetworksStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): EitherFlow<Error, Set<NetworkStatus>> {
|
||||
return networksRepository.getNetworkStatusesUpdatesLegacy(userWalletId, setOf(network))
|
||||
.map<Set<NetworkStatus>, Either<Error, Set<NetworkStatus>>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalancesSync(
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
return catch(
|
||||
block = {
|
||||
stakingRepository.getMultiYieldBalanceSync(
|
||||
userWalletId,
|
||||
cryptoCurrencies,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalanceSync(
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalance> {
|
||||
return catch(
|
||||
block = {
|
||||
stakingRepository.getSingleYieldBalanceSync(
|
||||
userWalletId,
|
||||
cryptoCurrency,
|
||||
).right()
|
||||
},
|
||||
catch = {
|
||||
Error.EmptyYieldBalances.left()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun getYieldBalance(cryptoCurrency: CryptoCurrency): EitherFlow<Error, YieldBalance> {
|
||||
return stakingRepository.getSingleYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).map<YieldBalance, Either<Error, YieldBalance>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private fun getIds(
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
): Pair<NonEmptySet<Network>, NonEmptySet<CryptoCurrency.ID>> {
|
||||
val currencyIdToNetworkId = currencies.associate { currency ->
|
||||
currency.id to currency.network
|
||||
}
|
||||
val currenciesIds = currencyIdToNetworkId.keys.toNonEmptySetOrNull()
|
||||
val networks = currencyIdToNetworkId.values.toNonEmptySetOrNull()
|
||||
|
||||
requireNotNull(currenciesIds) { "Currencies IDs cannot be empty" }
|
||||
requireNotNull(networks) { "Networks IDs cannot be empty" }
|
||||
|
||||
return networks to currenciesIds
|
||||
}
|
||||
|
||||
private fun extractAddress(networkStatus: NetworkStatus?): String? {
|
||||
return when (val value = networkStatus?.value) {
|
||||
is NetworkStatus.NoAccount -> value.address.defaultAddress.value
|
||||
is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value
|
||||
is NetworkStatus.Verified -> value.address.defaultAddress.value
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
sealed class Error {
|
||||
|
||||
data object EmptyCurrencies : Error()
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
||||
internal class CurrenciesStatusesLceOperations(
|
||||
class LceCurrenciesStatusesOperations(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val quotesRepository: QuotesRepository,
|
||||
private val networksRepository: NetworksRepository,
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
) : BaseCurrenciesStatusesOperations {
|
||||
|
||||
fun getCurrenciesStatuses(userWalletId: UserWalletId): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
override fun getCurrenciesStatuses(
|
||||
userWalletId: UserWalletId,
|
||||
): LceFlow<TokenListError, List<CryptoCurrencyStatus>> {
|
||||
return transformToCurrenciesStatuses(
|
||||
userWalletId = userWalletId,
|
||||
currenciesFlow = getWalletCurrencies(userWalletId),
|
||||
|
|
@ -217,7 +219,7 @@ internal class CurrenciesStatusesLceOperations(
|
|||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val RETRY_QUOTES_DELAY = 2000L
|
||||
private companion object {
|
||||
const val RETRY_QUOTES_DELAY = 2000L
|
||||
}
|
||||
}
|
||||
|
|
@ -20,11 +20,11 @@ internal class TokenListOperations(
|
|||
|
||||
fun getTokenListFlow(): Flow<Either<Error, TokenList>> {
|
||||
return combine(
|
||||
getIsGrouped(),
|
||||
getIsSortedByBalance(),
|
||||
flow = getIsGrouped(),
|
||||
flow2 = getIsSortedByBalance(),
|
||||
) { isGrouped, isSortedByBalance ->
|
||||
either {
|
||||
createTokenList(isGrouped.bind(), isSortedByBalance.bind())
|
||||
createTokenList(isGrouped = isGrouped.bind(), isSortedByBalance = isSortedByBalance.bind())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.NonEmptyList
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.toNonEmptySetOrNull
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
import com.tangem.domain.tokens.model.Quote
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations.Error
|
||||
import com.tangem.domain.tokens.operations.CurrencyStatusOperations
|
||||
|
||||
/**
|
||||
* Proxy creator of [CryptoCurrencyStatus]. Used [CurrencyStatusOperations] to create statuses.
|
||||
*
|
||||
* @property stakingRepository staking repository
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class CurrencyStatusProxyCreator(
|
||||
private val stakingRepository: StakingRepository,
|
||||
) {
|
||||
|
||||
fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
maybeQuote: Either<Error, Quote?>,
|
||||
maybeNetworkStatus: Either<Error, NetworkStatus?>,
|
||||
maybeYieldBalance: Either<Error, YieldBalance>?,
|
||||
): Either<Error, CryptoCurrencyStatus> = either {
|
||||
var quoteRetrievingFailed = false
|
||||
|
||||
val networkStatus = maybeNetworkStatus.bind()
|
||||
val quote = arrow.core.raise.recover({ maybeQuote.bind() }) {
|
||||
quoteRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
val yieldBalance = maybeYieldBalance?.getOrNull()
|
||||
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quoteRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
|
||||
fun createCurrenciesStatuses(
|
||||
currencies: NonEmptyList<CryptoCurrency>,
|
||||
maybeQuotes: Either<Error, Set<Quote>>?,
|
||||
maybeNetworkStatuses: Either<Error, Set<NetworkStatus>>?,
|
||||
maybeYieldBalances: Either<Error, YieldBalanceList>?,
|
||||
): Either<Error, List<CryptoCurrencyStatus>> = either {
|
||||
var quotesRetrievingFailed = false
|
||||
|
||||
val networksStatuses = maybeNetworkStatuses?.bind()?.toNonEmptySetOrNull()
|
||||
val quotes: Set<Quote>? = maybeQuotes?.fold(
|
||||
ifLeft = {
|
||||
quotesRetrievingFailed = true
|
||||
null
|
||||
},
|
||||
ifRight = {
|
||||
it.ifEmpty {
|
||||
quotesRetrievingFailed = true
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val yieldBalances = maybeYieldBalances?.getOrNull()
|
||||
|
||||
currencies.map { currency ->
|
||||
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
|
||||
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
|
||||
val address = extractAddress(networkStatus)
|
||||
|
||||
val supportedIntegration = stakingRepository.getSupportedIntegrationId(currency.id)
|
||||
val yieldBalance = if (supportedIntegration.isNullOrEmpty().not()) {
|
||||
(yieldBalances as? YieldBalanceList.Data)?.getBalance(
|
||||
address = address,
|
||||
integrationId = supportedIntegration,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
createCurrencyStatus(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = quotesRetrievingFailed,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun createCurrencyStatus(
|
||||
currency: CryptoCurrency,
|
||||
quote: Quote?,
|
||||
networkStatus: NetworkStatus?,
|
||||
ignoreQuote: Boolean,
|
||||
yieldBalance: YieldBalance?,
|
||||
): CryptoCurrencyStatus {
|
||||
val currencyStatusOperations = CurrencyStatusOperations(
|
||||
currency = currency,
|
||||
quote = quote,
|
||||
networkStatus = networkStatus,
|
||||
ignoreQuote = ignoreQuote,
|
||||
yieldBalance = yieldBalance,
|
||||
)
|
||||
|
||||
return currencyStatusOperations.createTokenStatus()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.tokens.utils
|
||||
|
||||
import com.tangem.domain.tokens.model.NetworkStatus
|
||||
|
||||
/** Extract address from [networkStatus] */
|
||||
internal fun extractAddress(networkStatus: NetworkStatus?): String? {
|
||||
return when (val value = networkStatus?.value) {
|
||||
is NetworkStatus.NoAccount -> value.address.defaultAddress.value
|
||||
is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value
|
||||
is NetworkStatus.Verified -> value.address.defaultAddress.value
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ import com.tangem.domain.tokens.mock.MockQuotes
|
|||
import com.tangem.domain.tokens.mock.MockTokens
|
||||
import com.tangem.domain.tokens.mock.MockTokensStates
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
|
||||
import com.tangem.domain.tokens.repository.MockCurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.MockNetworksRepository
|
||||
import com.tangem.domain.tokens.repository.MockQuotesRepository
|
||||
|
|
@ -162,17 +163,19 @@ internal class GetPrimaryCurrencyStatusUpdatesUseCaseTest {
|
|||
quotes: Flow<Either<DataError, Set<Quote>>> = flowOf(MockQuotes.quotes.right()),
|
||||
statuses: Flow<Either<DataError, Set<NetworkStatus>>> = flowOf(MockNetworks.verifiedNetworksStatuses.right()),
|
||||
) = GetPrimaryCurrencyStatusUpdatesUseCase(
|
||||
dispatchers = dispatchers,
|
||||
currenciesRepository = MockCurrenciesRepository(
|
||||
sortTokensResult = Unit.right(),
|
||||
removeCurrencyResult = removeCurrencyResult,
|
||||
token = token,
|
||||
tokens = flowOf(),
|
||||
isGrouped = flowOf(),
|
||||
isSortedByBalance = flowOf(),
|
||||
currencyStatusOperations = CurrenciesStatusesOperations(
|
||||
currenciesRepository = MockCurrenciesRepository(
|
||||
sortTokensResult = Unit.right(),
|
||||
removeCurrencyResult = removeCurrencyResult,
|
||||
token = token,
|
||||
tokens = flowOf(),
|
||||
isGrouped = flowOf(),
|
||||
isSortedByBalance = flowOf(),
|
||||
),
|
||||
quotesRepository = MockQuotesRepository(quotes),
|
||||
networksRepository = MockNetworksRepository(statuses),
|
||||
stakingRepository = MockStakingRepository(),
|
||||
),
|
||||
quotesRepository = MockQuotesRepository(quotes),
|
||||
networksRepository = MockNetworksRepository(statuses),
|
||||
stakingRepository = MockStakingRepository(),
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,13 +1,9 @@
|
|||
package com.tangem.feature.swap.domain.di
|
||||
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
|
||||
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.tokens.operations.BaseCurrencyStatusOperations
|
||||
import com.tangem.feature.swap.domain.*
|
||||
import com.tangem.lib.crypto.TransactionManager
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -40,19 +36,9 @@ internal class SwapDomainModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun providesGetCryptoCurrencyStatusUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
quotesRepository: QuotesRepository,
|
||||
networksRepository: NetworksRepository,
|
||||
stakingRepository: StakingRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
currencyStatusOperations: BaseCurrencyStatusOperations,
|
||||
): GetCryptoCurrencyStatusesSyncUseCase {
|
||||
return GetCryptoCurrencyStatusesSyncUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
quotesRepository = quotesRepository,
|
||||
networksRepository = networksRepository,
|
||||
stakingRepository = stakingRepository,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
return GetCryptoCurrencyStatusesSyncUseCase(currencyStatusOperations)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue