From 69deadf5fe11b08dae5a28d56405a473b2b3a1de Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 13 Oct 2025 14:22:04 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../GetAccountCurrencyStatusUseCase.kt | 58 ++---------- .../GetCryptoCurrencyActionsUseCaseV2.kt | 53 +++++++++++ .../AccountCryptoCurrencyStatusFinder.kt | 88 +++++++++++++++++++ 3 files changed, 147 insertions(+), 52 deletions(-) create mode 100644 domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetCryptoCurrencyActionsUseCaseV2.kt create mode 100644 domain/account/status/src/main/java/com/tangem/domain/account/status/utils/AccountCryptoCurrencyStatusFinder.kt diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetAccountCurrencyStatusUseCase.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetAccountCurrencyStatusUseCase.kt index 51abc977a6..730bff6aa4 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetAccountCurrencyStatusUseCase.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetAccountCurrencyStatusUseCase.kt @@ -3,19 +3,14 @@ package com.tangem.domain.account.status.usecase import arrow.core.Option import arrow.core.none import arrow.core.toOption -import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchainsdk.utils.fromNetworkId import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier -import com.tangem.domain.models.account.Account -import com.tangem.domain.models.account.AccountStatus -import com.tangem.domain.models.account.DerivationIndex +import com.tangem.domain.account.status.utils.AccountCryptoCurrencyStatusFinder import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId -import com.tangem.lib.crypto.derivation.AccountNodeRecognizer import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapNotNull @@ -100,51 +95,10 @@ class GetAccountCurrencyStatusUseCase( currencyId: CryptoCurrency.ID, network: Network?, ): AccountCryptoCurrencyStatus? { - return getExpectedAccountStatuses(network) - .asSequence() - .filterIsInstance() - .mapNotNull { accountStatus -> - val status = accountStatus.flattenCurrencies().firstOrNull { it.currency.id == currencyId } - ?: return@mapNotNull null - - AccountCryptoCurrencyStatus(account = accountStatus.account, status = status) - } - .firstOrNull() - } - - /** - * Retrieves the expected account statuses based on the provided [network]. - * If the [network] is null, all account statuses are returned. - * If the network has a specific derivation index, it filters the accounts accordingly. - * - * @param network the network to filter accounts by, can be null. - * @return a set of [AccountStatus] that match the expected criteria. - */ - private fun AccountStatusList.getExpectedAccountStatuses(network: Network?): Set { - val possibleAccountIndex = network?.getAccountIndexOrNull() - - return when (possibleAccountIndex) { - // currency can be in any account - null -> accountStatuses - // currency only in the main account - DerivationIndex.Main.value -> setOf(mainAccount) - // currency only in the account with specific derivation index or in the main account - else -> { - val accountStatus = accountStatuses.firstOrNull { - val cryptoPortfolio = it.account as? Account.CryptoPortfolio ?: return@firstOrNull false - - cryptoPortfolio.derivationIndex.value == possibleAccountIndex - } - - setOfNotNull(accountStatus, mainAccount) - } - } - } - - private fun Network.getAccountIndexOrNull(): Int? { - val blockchain = Blockchain.fromNetworkId(networkId = rawId) ?: return null - val recognizer = AccountNodeRecognizer(blockchain) - - return recognizer.recognize(derivationPath)?.toInt() + return AccountCryptoCurrencyStatusFinder( + accountStatusList = this, + currencyId = currencyId, + network = network, + ) } } \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetCryptoCurrencyActionsUseCaseV2.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetCryptoCurrencyActionsUseCaseV2.kt new file mode 100644 index 0000000000..9c7c078cd8 --- /dev/null +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/GetCryptoCurrencyActionsUseCaseV2.kt @@ -0,0 +1,53 @@ +package com.tangem.domain.account.status.usecase + +import com.tangem.domain.account.repository.AccountsCRUDRepository +import com.tangem.domain.account.status.producer.SingleAccountStatusListProducer +import com.tangem.domain.account.status.supplier.SingleAccountStatusListSupplier +import com.tangem.domain.account.status.utils.AccountCryptoCurrencyStatusFinder +import com.tangem.domain.models.account.AccountId +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.tokens.GetCryptoCurrencyActionsUseCase +import com.tangem.domain.tokens.model.TokenActionsState +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.transformLatest + +/** + * Use case to retrieve the available actions for a specific cryptocurrency associated with an account. + * + * @property accountsCRUDRepository repository for account CRUD operations. + * @property singleAccountStatusListSupplier supplier to get the list of account statuses. + * @property getCryptoCurrencyActionsUseCase use case to get the actions for a specific cryptocurrency status. + * +[REDACTED_AUTHOR] + */ +class GetCryptoCurrencyActionsUseCaseV2( + private val accountsCRUDRepository: AccountsCRUDRepository, + private val singleAccountStatusListSupplier: SingleAccountStatusListSupplier, + private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase, +) { + + @OptIn(ExperimentalCoroutinesApi::class) + operator fun invoke(accountId: AccountId, currency: CryptoCurrency): Flow { + return singleAccountStatusListSupplier( + params = SingleAccountStatusListProducer.Params(userWalletId = accountId.userWalletId), + ) + .transformLatest { accountStatusList -> + val accountCurrencyStatus = AccountCryptoCurrencyStatusFinder( + accountStatusList = accountStatusList, + currency = currency, + ) + + if (accountCurrencyStatus != null) { + val userWallet = accountsCRUDRepository.getUserWallet(userWalletId = accountId.userWalletId) + val actionsFlow = getCryptoCurrencyActionsUseCase( + userWallet = userWallet, + cryptoCurrencyStatus = accountCurrencyStatus.status, + ) + + emitAll(actionsFlow) + } + } + } +} \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/AccountCryptoCurrencyStatusFinder.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/AccountCryptoCurrencyStatusFinder.kt new file mode 100644 index 0000000000..6f29996eab --- /dev/null +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/utils/AccountCryptoCurrencyStatusFinder.kt @@ -0,0 +1,88 @@ +package com.tangem.domain.account.status.utils + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.fromNetworkId +import com.tangem.domain.account.models.AccountStatusList +import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus +import com.tangem.domain.models.account.Account +import com.tangem.domain.models.account.AccountStatus +import com.tangem.domain.models.account.DerivationIndex +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.network.Network +import com.tangem.lib.crypto.derivation.AccountNodeRecognizer + +/** + * Finds the status of a specific cryptocurrency associated with an account from the provided account status list. + * +[REDACTED_AUTHOR] + */ +internal object AccountCryptoCurrencyStatusFinder { + + /** + * Retrieves the [AccountCryptoCurrencyStatus] for the specified [currency] from the given [accountStatusList]. + * + * @param accountStatusList the list of account statuses to search within. + * @param currency the cryptocurrency whose status is to be retrieved. + * @return the [AccountCryptoCurrencyStatus] if found, otherwise null. + */ + operator fun invoke(accountStatusList: AccountStatusList, currency: CryptoCurrency): AccountCryptoCurrencyStatus? { + return invoke( + accountStatusList = accountStatusList, + currencyId = currency.id, + network = currency.network, + ) + } + + operator fun invoke( + accountStatusList: AccountStatusList, + currencyId: CryptoCurrency.ID, + network: Network?, + ): AccountCryptoCurrencyStatus? { + return accountStatusList.getExpectedAccountStatuses(network) + .asSequence() + .filterIsInstance() + .mapNotNull { accountStatus -> + val status = accountStatus.flattenCurrencies().firstOrNull { it.currency.id == currencyId } + ?: return@mapNotNull null + + AccountCryptoCurrencyStatus(account = accountStatus.account, status = status) + } + .firstOrNull() + } + + /** + * Retrieves the expected account statuses based on the provided [network]. + * If the [network] is null, all account statuses are returned. + * If the network has a specific derivation index, it filters the accounts accordingly. + * + * @param network the network to filter accounts by, can be null. + * @return a set of [AccountStatus] that match the expected criteria. + */ + private fun AccountStatusList.getExpectedAccountStatuses(network: Network?): Set { + val possibleAccountIndex = network?.getAccountIndexOrNull() + + return when (possibleAccountIndex) { + // currency can be in any account + null -> accountStatuses + // currency only in the main account + DerivationIndex.Main.value -> setOf(mainAccount) + // currency only in the account with specific derivation index or in the main account + else -> { + val accountStatus = accountStatuses.firstOrNull { + val cryptoPortfolio = it.account as? Account.CryptoPortfolio ?: return@firstOrNull false + + cryptoPortfolio.derivationIndex.value == possibleAccountIndex + } + + setOfNotNull(accountStatus, mainAccount) + } + } + } + + private fun Network.getAccountIndexOrNull(): Int? { + val blockchain = Blockchain.fromNetworkId(networkId = rawId) ?: return null + val recognizer = AccountNodeRecognizer(blockchain) + + return recognizer.recognize(derivationPath)?.toInt() + } +} \ No newline at end of file