diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/model/AccountCryptoCurrencyStatus.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/model/AccountCryptoCurrencyStatus.kt index 221fe1d49d..99ef55d0bf 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/model/AccountCryptoCurrencyStatus.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/model/AccountCryptoCurrencyStatus.kt @@ -4,6 +4,8 @@ import com.tangem.domain.models.account.Account import com.tangem.domain.models.currency.CryptoCurrencyStatus import kotlinx.serialization.Serializable +typealias AccountCryptoCurrencyStatuses = Map> + /** * Combines an [Account] with its corresponding [CryptoCurrencyStatus]. * 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 730bff6aa4..3a6fed2955 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 @@ -2,13 +2,17 @@ package com.tangem.domain.account.status.usecase import arrow.core.Option import arrow.core.none +import arrow.core.some import arrow.core.toOption import com.tangem.domain.account.models.AccountStatusList import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus +import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatuses 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.Account import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.network.Network import com.tangem.domain.models.wallet.UserWalletId import kotlinx.coroutines.flow.Flow @@ -50,15 +54,28 @@ class GetAccountCurrencyStatusUseCase( currencyId: CryptoCurrency.ID, network: Network?, ): Option { - val accountStatusList = singleAccountStatusListSupplier.getSyncOrNull( - params = SingleAccountStatusListProducer.Params(userWalletId), - ) ?: return none() + val accountStatusList = getAccountStatusListSync(userWalletId) ?: return none() return accountStatusList .toAccountCryptoCurrencyStatus(currencyId, network) .toOption() } + suspend fun invokeSync( + userWalletId: UserWalletId, + currencies: List, + ): Option { + if (currencies.isEmpty()) return emptyMap>().some() + + val accountStatusList = getAccountStatusListSync(userWalletId) ?: return none() + + return AccountCryptoCurrencyStatusFinder( + accountStatusList = accountStatusList, + currencies = currencies, + ) + .toOption() + } + /** * Retrieves the status of a specific cryptocurrency for a given user wallet as a [Flow]. * @@ -91,6 +108,12 @@ class GetAccountCurrencyStatusUseCase( } } + private suspend fun getAccountStatusListSync(userWalletId: UserWalletId): AccountStatusList? { + return singleAccountStatusListSupplier.getSyncOrNull( + params = SingleAccountStatusListProducer.Params(userWalletId), + ) + } + private fun AccountStatusList.toAccountCryptoCurrencyStatus( currencyId: CryptoCurrency.ID, network: Network?, 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 index 3d4f973735..f00df7290d 100644 --- 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 @@ -4,6 +4,7 @@ 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.model.AccountCryptoCurrencyStatuses import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.AccountStatus import com.tangem.domain.models.account.DerivationIndex @@ -50,6 +51,26 @@ internal object AccountCryptoCurrencyStatusFinder { .firstOrNull() } + operator fun invoke( + accountStatusList: AccountStatusList, + currencies: List, + ): AccountCryptoCurrencyStatuses { + if (currencies.isEmpty()) return emptyMap() + + val currencyIds = currencies.map(CryptoCurrency::id).toSet() + val networks = currencies.map(CryptoCurrency::network).distinct() + + return accountStatusList.getExpectedAccountStatuses(networks) + .asSequence() + .filterIsInstance() + .associate { accountStatus -> + val statuses = accountStatus.flattenCurrencies() + .filter { it.currency.id in currencyIds } + + accountStatus.account to statuses + } + } + /** * Retrieves the expected account statuses based on the provided [network]. * If the [network] is null, all account statuses are returned. @@ -79,6 +100,20 @@ internal object AccountCryptoCurrencyStatusFinder { } } + private fun AccountStatusList.getExpectedAccountStatuses(networks: List): List { + val possibleAccountIndexes = networks.mapNotNull { it.getAccountIndexOrNull() } + + if (possibleAccountIndexes.isEmpty()) return this@getExpectedAccountStatuses.accountStatuses + + val accountStatuses = this@getExpectedAccountStatuses.accountStatuses.filter { + val cryptoPortfolio = it.account as? Account.CryptoPortfolio ?: return@filter false + + cryptoPortfolio.derivationIndex.value in possibleAccountIndexes + } + + return accountStatuses + listOf(mainAccount) + } + private fun Network.getAccountIndexOrNull(): Int? { val blockchain = Blockchain.fromNetworkId(networkId = rawId) ?: return null val recognizer = AccountNodeRecognizer(blockchain) diff --git a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/add/impl/converter/AvailableToAddDataConverter.kt b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/add/impl/converter/AvailableToAddDataConverter.kt index 904a43744f..34cf4cd075 100644 --- a/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/add/impl/converter/AvailableToAddDataConverter.kt +++ b/features/markets/impl/src/main/kotlin/com/tangem/features/markets/portfolio/add/impl/converter/AvailableToAddDataConverter.kt @@ -29,12 +29,19 @@ internal class AvailableToAddDataConverter @Inject constructor( marketParams: TokenMarketParams, ): AvailableToAddData { suspend fun AccountStatus.getAvailableToAddAccount(wallet: UserWallet): AvailableToAddAccount { - val addedNetworks = availableNetworks + val currencies = availableNetworks .mapNotNull { createCryptoCurrency(wallet, it, marketParams, this.account) } - // todo account poor performance, investigate, e.g 20 accounts and USDC token for adding - .mapNotNull { getAccountCurrencyStatusUseCase.invokeSync(wallet.walletId, it) } - .mapNotNull { it.getOrNull()?.status?.currency?.network } - .toSet() + + val addedNetworks = getAccountCurrencyStatusUseCase.invokeSync(wallet.walletId, currencies) + .fold( + ifEmpty = { emptySet() }, + ifSome = { map -> + map.values.flatMapTo(hashSetOf()) { statuses -> + statuses.map { it.currency.network } + } + }, + ) + return AvailableToAddAccount( account = this, availableNetworks = availableNetworks, @@ -62,7 +69,7 @@ internal class AvailableToAddDataConverter @Inject constructor( val availableToAddWallets: Map = balances .map { - val (wallet, balance) = it + val (wallet, _) = it val availableToAddWallet = getAvailableToAddWallet(it) wallet.walletId to availableToAddWallet }