Updated on 2026-08-14
This commit is contained in:
parent
4f3ff79ac9
commit
158fd355de
9 changed files with 40 additions and 200 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 827750b5a0ef7202120b0df0ae903d70e18e3d32
|
||||
Subproject commit 636d7a8aa0e330e9b95e91d85f23ad15ac6d913f
|
||||
|
|
@ -11,7 +11,6 @@ import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
|||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.multi.MultiStakingBalanceFetcher
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.CurrencyChecksRepository
|
||||
|
|
@ -29,7 +28,6 @@ import javax.inject.Singleton
|
|||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Suppress("TooManyFunctions", "LargeClass")
|
||||
internal object TokensDomainModule {
|
||||
|
||||
@Provides
|
||||
|
|
@ -46,26 +44,6 @@ internal object TokensDomainModule {
|
|||
return DefaultTokensFeatureToggles(featureTogglesManager = featureTogglesManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideFetchCurrencyStatusUseCase(
|
||||
currenciesRepository: CurrenciesRepository,
|
||||
singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory: StakingIdFactory,
|
||||
): FetchCurrencyStatusUseCase {
|
||||
return FetchCurrencyStatusUseCase(
|
||||
currenciesRepository = currenciesRepository,
|
||||
singleNetworkStatusFetcher = singleNetworkStatusFetcher,
|
||||
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
|
||||
singleStakingBalanceFetcher = singleStakingBalanceFetcher,
|
||||
multiWalletCryptoCurrenciesSupplier = multiWalletCryptoCurrenciesSupplier,
|
||||
stakingIdFactory = stakingIdFactory,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetCryptoCurrencyActionsUseCase(
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ internal object GeneratedEnvironmentConfigConverter {
|
|||
bffStaticTokenDev = GeneratedEnvironmentConfig.bffStaticTokenDev,
|
||||
gaslessTxApiKeyDev = GeneratedEnvironmentConfig.gaslessTxApiKeyDev,
|
||||
gaslessTxApiKey = GeneratedEnvironmentConfig.gaslessTxApiKey,
|
||||
customerIoCdpApiKey = GeneratedEnvironmentConfig.CustomerIO.appApiKey,
|
||||
customerIoCdpApiKey = GeneratedEnvironmentConfig.CustomerIO.androidApiKey,
|
||||
surveySparrowToken = GeneratedEnvironmentConfig.SurveySparrow.apiKey,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ class CryptoCurrencyBalanceFetcher(
|
|||
|
||||
private val mutex = Mutex()
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId, currency: CryptoCurrency) {
|
||||
invoke(userWalletId = userWalletId, currencies = listOf(currency))
|
||||
}
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
if (currencies.isEmpty()) return
|
||||
|
||||
|
|
@ -45,6 +49,18 @@ class CryptoCurrencyBalanceFetcher(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun invokeAndAwait(userWalletId: UserWalletId, currency: CryptoCurrency) {
|
||||
invokeAndAwait(userWalletId = userWalletId, currencies = listOf(currency))
|
||||
}
|
||||
|
||||
suspend fun invokeAndAwait(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
if (currencies.isEmpty()) return
|
||||
|
||||
mutex.withLock {
|
||||
refreshBalances(userWalletId, currencies)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun refreshBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
|
||||
coroutineScope {
|
||||
val results = listOf(
|
||||
|
|
|
|||
|
|
@ -1,161 +0,0 @@
|
|||
package com.tangem.domain.tokens
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.getOrElse
|
||||
import arrow.core.raise.Raise
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.staking.StakingIdFactory
|
||||
import com.tangem.domain.staking.single.SingleStakingBalanceFetcher
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
||||
/**
|
||||
* Use case responsible for fetching currency status information, including network status
|
||||
* and quotes for a given cryptocurrency. It provides methods to fetch currency status either
|
||||
* by providing a specific currency ID or fetching the status of the primary currency.
|
||||
*
|
||||
* @param currenciesRepository The repository for retrieving currency-related data.
|
||||
*/
|
||||
// TODO: Add tests
|
||||
@Suppress("LongParameterList")
|
||||
class FetchCurrencyStatusUseCase(
|
||||
private val currenciesRepository: CurrenciesRepository,
|
||||
private val singleNetworkStatusFetcher: SingleNetworkStatusFetcher,
|
||||
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
|
||||
private val singleStakingBalanceFetcher: SingleStakingBalanceFetcher,
|
||||
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
private val stakingIdFactory: StakingIdFactory,
|
||||
) {
|
||||
|
||||
/**
|
||||
* Fetches the status of a specific cryptocurrency for a given user wallet.
|
||||
*
|
||||
* @param userWalletId The ID of the user's wallet.
|
||||
* @param id The ID of the cryptocurrency.
|
||||
* @return An [Either] representing success (Right) or an error (Left) in fetching the status.
|
||||
*/
|
||||
suspend operator fun invoke(userWalletId: UserWalletId, id: CryptoCurrency.ID): Either<CurrencyStatusError, Unit> {
|
||||
return either {
|
||||
val currency = getCurrency(userWalletId, id)
|
||||
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
val fetchStakingBalance = async {
|
||||
fetchStakingBalance(userWalletId = userWalletId, cryptoCurrency = currency)
|
||||
}
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote, fetchStakingBalance).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the status of the primary cryptocurrency for a given user wallet.
|
||||
*
|
||||
* @param userWalletId The ID of the user's wallet.
|
||||
* @param refresh Indicates whether to force a refresh of the status data.
|
||||
* @return An [Either] representing success (Right) or an error (Left) in fetching the status.
|
||||
*/
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean = false,
|
||||
): Either<CurrencyStatusError, Unit> {
|
||||
return either {
|
||||
val currency = getPrimaryCurrency(userWalletId, refresh)
|
||||
|
||||
return@either coroutineScope {
|
||||
val fetchStatus = async {
|
||||
fetchNetworkStatus(userWalletId = userWalletId, network = currency.network)
|
||||
}
|
||||
|
||||
val fetchQuote = async { fetchQuote(currencyId = currency.id) }
|
||||
|
||||
awaitAll(fetchStatus, fetchQuote).summarizeResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.getCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
id: CryptoCurrency.ID,
|
||||
): CryptoCurrency {
|
||||
return catch(
|
||||
block = {
|
||||
multiWalletCryptoCurrenciesSupplier.getSyncOrNull(
|
||||
params = MultiWalletCryptoCurrenciesProducer.Params(userWalletId),
|
||||
)
|
||||
?.firstOrNull { it.id == id }
|
||||
?: error("Unable to find currency with ID: $id")
|
||||
},
|
||||
) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun Raise<CurrencyStatusError>.getPrimaryCurrency(
|
||||
userWalletId: UserWalletId,
|
||||
refresh: Boolean = false,
|
||||
): CryptoCurrency {
|
||||
return catch({ currenciesRepository.getSingleCurrencyWalletPrimaryCurrency(userWalletId, refresh) }) {
|
||||
raise(CurrencyStatusError.DataError(it))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchNetworkStatus(userWalletId: UserWalletId, network: Network): Either<Throwable, Unit> {
|
||||
return singleNetworkStatusFetcher(
|
||||
params = SingleNetworkStatusFetcher.Params(userWalletId = userWalletId, network = network),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchQuote(currencyId: CryptoCurrency.ID): Either<Throwable, Unit> {
|
||||
return multiQuoteStatusFetcher(
|
||||
params = MultiQuoteStatusFetcher.Params(
|
||||
currenciesIds = setOfNotNull(currencyId.rawCurrencyId),
|
||||
appCurrencyId = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun fetchStakingBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<Throwable, Unit> = either {
|
||||
val stakingId = stakingIdFactory.create(
|
||||
userWalletId = userWalletId,
|
||||
currencyId = cryptoCurrency.id,
|
||||
network = cryptoCurrency.network,
|
||||
)
|
||||
.getOrElse {
|
||||
when (it) {
|
||||
is StakingIdFactory.Error.UnableToGetAddress -> raise(IllegalStateException("$it"))
|
||||
StakingIdFactory.Error.UnsupportedCurrency -> Unit.right()
|
||||
}
|
||||
|
||||
return@either
|
||||
}
|
||||
|
||||
singleStakingBalanceFetcher(
|
||||
params = SingleStakingBalanceFetcher.Params(userWalletId = userWalletId, stakingId = stakingId),
|
||||
)
|
||||
.bind()
|
||||
}
|
||||
|
||||
private fun List<Either<Throwable, Unit>>.summarizeResult(): Either<Throwable, Unit> {
|
||||
return firstOrNull { it.isLeft() } ?: Unit.right()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.helpers
|
||||
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.FetchActionsUseCase
|
||||
import com.tangem.domain.staking.FetchStakingYieldBalanceUseCase
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
|
||||
import com.tangem.features.txhistory.entity.TxHistoryContentUpdateEmitter
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
|
|
@ -22,7 +22,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
private val getTxHistoryItemsCountUseCase: GetTxHistoryItemsCountUseCase,
|
||||
private val fetchActionsUseCase: FetchActionsUseCase,
|
||||
private val txHistoryContentUpdateEmitter: TxHistoryContentUpdateEmitter,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
|
||||
private val fetchStakingYieldBalanceUseCase: FetchStakingYieldBalanceUseCase,
|
||||
private val coroutineScope: AppCoroutineScope,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
|
|
@ -83,9 +83,9 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
|
||||
private suspend fun fetchCurrencyStatus(delayMillis: Long = 0L) {
|
||||
delay(delayMillis)
|
||||
fetchCurrencyStatusUseCase(
|
||||
cryptoCurrencyBalanceFetcher.invokeAndAwait(
|
||||
userWalletId = userWallet.walletId,
|
||||
id = cryptoCurrencyStatus.currency.id,
|
||||
currency = cryptoCurrencyStatus.currency,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import com.tangem.core.ui.format.bigdecimal.fiat
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer
|
||||
import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier
|
||||
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.extenstions.unwrap
|
||||
import com.tangem.domain.appcurrency.repository.AppCurrencyRepository
|
||||
|
|
@ -38,8 +40,10 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.pay.TangemPayWithdrawExchangeState
|
||||
import com.tangem.domain.quotes.QuotesRepository
|
||||
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
|
||||
import com.tangem.domain.account.status.usecase.GetFeePaidCryptoCurrencyStatusSyncUseCase
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.GetAssetRequirementsUseCase
|
||||
import com.tangem.domain.tokens.GetCurrencyCheckUseCase
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
import com.tangem.domain.tokens.model.FeePaidCurrency
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
|
|
@ -75,7 +79,7 @@ import java.math.RoundingMode
|
|||
internal class SwapInteractorImpl @AssistedInject constructor(
|
||||
private val repository: SwapRepository,
|
||||
private val allowPermissionsHandler: AllowPermissionsHandler,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
|
||||
private val sendTransactionUseCase: SendTransactionUseCase,
|
||||
private val createTransactionUseCase: CreateTransactionUseCase,
|
||||
private val createTransferTransactionUseCase: CreateTransferTransactionUseCase,
|
||||
|
|
@ -438,7 +442,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
|
|||
|
||||
if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) {
|
||||
allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress)
|
||||
fetchCurrencyStatusUseCase(userWalletId = userWalletId, id = fromToken.currency.id)
|
||||
cryptoCurrencyBalanceFetcher(userWalletId = userWalletId, currency = fromToken.currency)
|
||||
}
|
||||
return if (isAllowedToSpend && isBalanceWithoutFeeEnough) {
|
||||
provider to loadDexSwapData(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.models.wallet.isLocked
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.notifications.models.NotificationType
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
||||
import com.tangem.domain.tokens.wallet.WalletBalanceFetcher
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.domain.wallets.usecase.SelectWalletUseCase
|
||||
|
|
@ -40,7 +40,7 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
|||
@Assisted private val isFromOnNewIntent: Boolean,
|
||||
private val appRouter: AppRouter,
|
||||
private val selectWalletUseCase: SelectWalletUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
|
||||
private val tokenDetailsDeepLinkActionTrigger: TokenDetailsDeepLinkActionTrigger,
|
||||
private val walletDeepLinkActionTrigger: WalletDeepLinkActionTrigger,
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
|
|
@ -122,9 +122,9 @@ internal class DefaultTokenDetailsDeepLinkHandler @AssistedInject constructor(
|
|||
userWallet is UserWallet.Cold &&
|
||||
userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()
|
||||
when {
|
||||
isMultiCurrency -> fetchCurrencyStatusUseCase.invoke(
|
||||
isMultiCurrency -> cryptoCurrencyBalanceFetcher(
|
||||
userWalletId = userWallet.walletId,
|
||||
id = cryptoCurrency.id,
|
||||
currency = cryptoCurrency,
|
||||
)
|
||||
!isMultiCurrency -> walletBalanceFetcher(
|
||||
params = WalletBalanceFetcher.Params(
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import com.tangem.core.ui.haptic.VibratorHapticManager
|
|||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
|
||||
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase
|
||||
|
|
@ -110,7 +111,7 @@ import javax.inject.Inject
|
|||
internal class TokenDetailsModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val fetchCurrencyStatusUseCase: FetchCurrencyStatusUseCase,
|
||||
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
|
||||
private val getExploreUrlUseCase: GetExploreUrlUseCase,
|
||||
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
|
||||
private val isCryptoCurrencyCoinCouldHideUseCase: IsCryptoCurrencyCoinCouldHideUseCase,
|
||||
|
|
@ -838,7 +839,9 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
|
||||
modelScope.launch(dispatchers.main) {
|
||||
listOf(
|
||||
async { fetchCurrencyStatusUseCase(userWalletId = userWalletId, id = cryptoCurrency.id) },
|
||||
async {
|
||||
cryptoCurrencyBalanceFetcher.invokeAndAwait(userWalletId = userWalletId, currency = cryptoCurrency)
|
||||
},
|
||||
async {
|
||||
updateTxHistory()
|
||||
subscribeOnExpressTransactionsUpdates()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue