Updated on 2026-08-14

This commit is contained in:
Tangem 2023-07-27 11:44:04 +03:00
parent ce57171f3b
commit ec07825276
22 changed files with 273 additions and 362 deletions

View file

@ -86,7 +86,7 @@ class DefaultWalletManagersFacade(
return try {
if (demoConfig.isDemoCardId(userWallet.scanResponse.card.cardId)) {
updateDemoWalletManager(walletManager, extraTokens)
updateDemoWalletManager(walletManager)
} else {
updateWalletManager(walletManager)
}
@ -95,14 +95,11 @@ class DefaultWalletManagersFacade(
}
}
private fun updateDemoWalletManager(
walletManager: WalletManager,
tokens: Set<CryptoCurrency.Token>,
): UpdateWalletManagerResult {
private fun updateDemoWalletManager(walletManager: WalletManager): UpdateWalletManagerResult {
val amount = demoConfig.getBalance(walletManager.wallet.blockchain)
walletManager.wallet.setAmount(amount)
return resultFactory.getDemoResult(amount, tokens)
return resultFactory.getDemoResult(walletManager, amount)
}
private suspend fun updateWalletManager(walletManager: WalletManager): UpdateWalletManagerResult {
@ -149,7 +146,7 @@ class DefaultWalletManagersFacade(
if (tokens.isEmpty()) return
val tokensToAdd = sdkTokenConverter
.convertList(tokens.toList())
.convertList(tokens)
.filter { it !in walletManager.cardTokens }
walletManager.addTokens(tokensToAdd)

View file

@ -9,6 +9,7 @@ sealed class CryptoCurrencyAmount {
data class Coin(override val value: BigDecimal) : CryptoCurrencyAmount()
data class Token(
val id: String?,
val tokenContractAddress: String,
override val value: BigDecimal,
) : CryptoCurrencyAmount()

View file

@ -1,11 +1,7 @@
package com.tangem.domain.walletmanager.utils
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.TransactionStatus
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.*
import com.tangem.domain.common.extensions.amountToCreateAccount
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.walletmanager.model.CryptoCurrencyAmount
import com.tangem.domain.walletmanager.model.UpdateWalletManagerResult
import timber.log.Timber
@ -26,9 +22,9 @@ internal class UpdateWalletManagerResultFactory {
)
}
fun getDemoResult(demoAmount: Amount, tokens: Set<CryptoCurrency.Token>): UpdateWalletManagerResult.Verified {
fun getDemoResult(walletManager: WalletManager, demoAmount: Amount): UpdateWalletManagerResult.Verified {
return UpdateWalletManagerResult.Verified(
tokensAmounts = getDemoTokensAmounts(demoAmount, tokens),
tokensAmounts = getDemoTokensAmounts(demoAmount, walletManager.cardTokens),
hasTransactionsInProgress = false,
)
}
@ -53,18 +49,19 @@ internal class UpdateWalletManagerResultFactory {
return amounts.mapNotNullTo(mutableAmounts, ::getTokenAmount)
}
private fun getDemoTokensAmounts(demoAmount: Amount, tokens: Set<CryptoCurrency.Token>): Set<CryptoCurrencyAmount> {
private fun getDemoTokensAmounts(demoAmount: Amount, tokens: Set<Token>): Set<CryptoCurrencyAmount> {
val amountValue = demoAmount.value ?: BigDecimal.ZERO
val demoAmounts = hashSetOf<CryptoCurrencyAmount>(CryptoCurrencyAmount.Coin(amountValue))
return tokens.mapTo(demoAmounts) { token ->
CryptoCurrencyAmount.Token(token.contractAddress, amountValue)
CryptoCurrencyAmount.Token(token.id, token.contractAddress, amountValue)
}
}
private fun getTokenAmount(amount: Amount): CryptoCurrencyAmount? {
return when (val type = amount.type) {
is AmountType.Token -> CryptoCurrencyAmount.Token(
id = type.token.id,
tokenContractAddress = type.token.contractAddress,
value = getAmountValue(amount) ?: return null,
)

View file

@ -46,36 +46,43 @@ internal class CurrenciesStatusesOperations<E>(
fun getMultiCurrencyWalletStatusesFlow(): Flow<Set<CryptoCurrencyStatus>> {
return getMultiCurrencyWalletCurrencies().flatMapConcat {
val tokens = it.toNonEmptySetOrNull()
val currencies = it.toNonEmptySetOrNull()
if (tokens == null) {
if (currencies == null) {
flowOf(emptySet())
} else {
val tokensIds = tokens.map { token -> token.id }.toNonEmptySet()
val groupedTokens = groupTokens(tokens)
val currencyIdToNetworkId = currencies.associate { currency ->
currency.id to currency.networkId
}
val currenciesIds = requireNotNull(currencyIdToNetworkId.keys.toNonEmptySetOrNull()) {
"Currencies IDs cannot be empty"
}
val networksIds = requireNotNull(currencyIdToNetworkId.values.toNonEmptySetOrNull()) {
"Networks IDs cannot be empty"
}
combine(getQuotes(tokensIds), getNetworksStatues(groupedTokens)) { quotes, networksStatuses ->
createTokensStatuses(tokens, quotes, networksStatuses)
combine(getQuotes(currenciesIds), getNetworksStatues(networksIds)) { quotes, networksStatuses ->
createTokensStatuses(currencies, quotes, networksStatuses)
}
}
}
}
suspend fun getPrimaryCurrencyStatusFlow(): Flow<CryptoCurrencyStatus> {
val token = getPrimaryCurrency()
val currency = getPrimaryCurrency()
val quoteFlow = getQuotes(nonEmptySetOf(token.id))
val quoteFlow = getQuotes(nonEmptySetOf(currency.id))
.map { quotes ->
quotes.singleOrNull { it.currencyId == token.id }
quotes.singleOrNull { it.currencyId == currency.id }
}
val statusFlow = getNetworksStatues(groupTokens(nonEmptySetOf(token)))
val statusFlow = getNetworksStatues(nonEmptySetOf(currency.networkId))
.map { statuses ->
statuses.singleOrNull { it.networkId == token.networkId }
statuses.singleOrNull { it.networkId == currency.networkId }
}
return combine(quoteFlow, statusFlow) { quote, networkStatus ->
createStatus(token, quote, networkStatus)
createStatus(currency, quote, networkStatus)
}
}
@ -132,30 +139,13 @@ internal class CurrenciesStatusesOperations<E>(
.flowOn(dispatchers.io)
}
private fun getNetworksStatues(
groupedTokens: Map<Network.ID, NonEmptySet<CryptoCurrency.ID>>,
): Flow<Set<NetworkStatus>> {
return networksRepository.getNetworkStatuses(userWalletId, groupedTokens, refresh)
private fun getNetworksStatues(networks: NonEmptySet<Network.ID>): Flow<Set<NetworkStatus>> {
return networksRepository.getNetworkStatuses(userWalletId, networks, refresh)
.catch { raise(Error.DataError(it)) }
.onEmpty { raise(Error.EmptyNetworksStatuses) }
.flowOn(dispatchers.io)
}
private suspend fun groupTokens(
tokens: NonEmptySet<CryptoCurrency>,
): Map<Network.ID, NonEmptySet<CryptoCurrency.ID>> {
return withContext(dispatchers.default) {
tokens
.groupBy { it.networkId }
.mapValues { (_, tokens) ->
// Can not be empty
tokens.toNonEmptySetOrNull()!!
.map { it.id }
.toNonEmptySet()
}
}
}
sealed class Error {
object EmptyCurrencies : Error()

View file

@ -1,6 +1,5 @@
package com.tangem.domain.tokens.repository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.tokens.models.Network
import com.tangem.domain.wallets.models.UserWalletId
@ -23,13 +22,13 @@ interface NetworksRepository {
* Retrieves the statuses of specified blockchain networks for a specific user wallet.
*
* @param userWalletId The unique identifier of the user wallet.
* @param networks A map of network IDs to sets of cryptocurrency IDs, representing the networks for which statuses are to be retrieved.
* @param networks A set of network IDs which statuses are to be retrieved.
* @param refresh A boolean flag indicating whether the data should be refreshed.
* @return A [Flow] emitting a set of [NetworkStatus] objects corresponding to the specified networks.
*/
fun getNetworkStatuses(
userWalletId: UserWalletId,
networks: Map<Network.ID, Set<CryptoCurrency.ID>>,
networks: Set<Network.ID>,
refresh: Boolean,
): Flow<Set<NetworkStatus>>
}

View file

@ -12,9 +12,9 @@ interface QuotesRepository {
/**
* Retrieves the quotes for a set of specified cryptocurrencies, identified by their unique IDs.
*
* @param tokensIds The unique identifiers of the cryptocurrencies for which quotes are to be retrieved.
* @param currenciesIds The unique identifiers of the cryptocurrencies for which quotes are to be retrieved.
* @param refresh A boolean flag indicating whether the data should be refreshed.
* @return A [Flow] emitting a set of quotes corresponding to the specified cryptocurrencies.
*/
fun getQuotes(tokensIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>>
fun getQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>>
}

View file

@ -3,7 +3,6 @@ package com.tangem.domain.tokens.repository
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.domain.core.error.DataError
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.NetworkStatus
import com.tangem.domain.tokens.models.Network
import com.tangem.domain.wallets.models.UserWalletId
@ -21,7 +20,7 @@ internal class MockNetworksRepository(
override fun getNetworkStatuses(
userWalletId: UserWalletId,
networks: Map<Network.ID, Set<CryptoCurrency.ID>>,
networks: Set<Network.ID>,
refresh: Boolean,
): Flow<Set<NetworkStatus>> {
return statuses.map { it.getOrElse { e -> throw e } }

View file

@ -12,7 +12,7 @@ internal class MockQuotesRepository(
private val quotes: Flow<Either<DataError, Set<Quote>>>,
) : QuotesRepository {
override fun getQuotes(tokensIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>> {
override fun getQuotes(currenciesIds: Set<CryptoCurrency.ID>, refresh: Boolean): Flow<Set<Quote>> {
return quotes.map { it.getOrElse { e -> throw e } }
}
}