Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-27 16:47:56 +04:00
parent 9bf6583723
commit 3631ceda60
4 changed files with 76 additions and 9 deletions

View file

@ -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<Account.CryptoPortfolio, List<CryptoCurrencyStatus>>
/**
* Combines an [Account] with its corresponding [CryptoCurrencyStatus].
*

View file

@ -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<AccountCryptoCurrencyStatus> {
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<CryptoCurrency>,
): Option<AccountCryptoCurrencyStatuses> {
if (currencies.isEmpty()) return emptyMap<Account.CryptoPortfolio, List<CryptoCurrencyStatus>>().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?,

View file

@ -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<CryptoCurrency>,
): 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<AccountStatus.CryptoPortfolio>()
.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<Network>): List<AccountStatus> {
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)

View file

@ -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<UserWalletId, AvailableToAddWallet> = balances
.map {
val (wallet, balance) = it
val (wallet, _) = it
val availableToAddWallet = getAvailableToAddWallet(it)
wallet.walletId to availableToAddWallet
}