Updated on 2026-08-14

This commit is contained in:
Tangem 2024-09-16 19:14:30 +03:00
parent f39e22c82e
commit bb32493ab0
13 changed files with 100 additions and 75 deletions

View file

@ -5,10 +5,13 @@ sealed class YieldBalanceList {
data class Data(
val balances: List<YieldBalance>,
) : YieldBalanceList() {
fun getBalance(rawCurrencyId: String?): YieldBalance {
return balances.firstOrNull { yield ->
(yield as? YieldBalance.Data)?.balance?.items
?.any { rawCurrencyId == it.rawCurrencyId } == true
fun getBalance(address: String?, rawCurrencyId: String?): YieldBalance {
return balances.firstOrNull { yieldBalance ->
val data = yieldBalance as? YieldBalance.Data
data?.balance?.items?.any {
address == data.address && rawCurrencyId == it.rawCurrencyId
} == true
} ?: YieldBalance.Error
}
}

View file

@ -1,31 +0,0 @@
package com.tangem.domain.staking
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.tangem.domain.core.utils.EitherFlow
import com.tangem.domain.staking.model.stakekit.StakingError
import com.tangem.domain.staking.model.stakekit.YieldBalance
import com.tangem.domain.staking.repositories.StakingErrorResolver
import com.tangem.domain.staking.repositories.StakingRepository
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
class GetStakingYieldBalanceUseCase(
private val stakingRepository: StakingRepository,
private val stakingErrorResolver: StakingErrorResolver,
) {
operator fun invoke(
userWalletId: UserWalletId,
cryptoCurrency: CryptoCurrency,
): EitherFlow<StakingError, YieldBalance> {
return stakingRepository.getSingleYieldBalanceFlow(
userWalletId = userWalletId,
cryptoCurrency = cryptoCurrency,
).map<YieldBalance, Either<StakingError, YieldBalance>> { it.right() }
.catch { emit(stakingErrorResolver.resolve(it).left()) }
}
}

View file

@ -44,7 +44,7 @@ class GetCurrencyStatusUpdatesUseCase(
): Flow<Either<CurrencyStatusError, CryptoCurrencyStatus>> {
return flow {
emitAll(
getCurrency(
getCurrencyStatus(
userWalletId = userWalletId,
currencyId = currencyId,
isSingleWalletWithTokens = isSingleWalletWithTokens,
@ -53,7 +53,7 @@ class GetCurrencyStatusUpdatesUseCase(
}.flowOn(dispatchers.io)
}
private suspend fun getCurrency(
private suspend fun getCurrencyStatus(
userWalletId: UserWalletId,
currencyId: CryptoCurrency.ID,
isSingleWalletWithTokens: Boolean,

View file

@ -56,7 +56,7 @@ class GetNodlTokenListUseCase(
stakingRepository = stakingRepository,
)
return operations.getNodlCurrencyStatusesFlow()
return operations.getCardCurrenciesStatusesFlow()
.map { maybeCurrenciesStatuses ->
maybeCurrenciesStatuses.mapLeft(CurrenciesStatusesOperations.Error::mapToTokenListError)
}

View file

@ -4,7 +4,7 @@ import com.tangem.domain.tokens.model.TokenList
sealed class TokenListError {
object EmptyTokens : TokenListError()
data object EmptyTokens : TokenListError()
data class UnableToSortTokenList(val unsortedTokenList: TokenList.Ungrouped) : TokenListError()

View file

@ -10,6 +10,7 @@ internal fun CurrenciesStatusesOperations.Error.mapToCurrencyError(): CurrencySt
is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses,
is CurrenciesStatusesOperations.Error.EmptyQuotes,
is CurrenciesStatusesOperations.Error.EmptyCurrencies,
is CurrenciesStatusesOperations.Error.EmptyAddresses,
is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus,
-> CurrencyStatusError.UnableToCreateCurrency
}

View file

@ -10,6 +10,7 @@ internal fun CurrenciesStatusesOperations.Error.mapToTokenListError(): TokenList
is CurrenciesStatusesOperations.Error.EmptyNetworksStatuses,
is CurrenciesStatusesOperations.Error.EmptyQuotes,
is CurrenciesStatusesOperations.Error.EmptyCurrencies,
is CurrenciesStatusesOperations.Error.EmptyAddresses,
is CurrenciesStatusesOperations.Error.UnableToCreateCurrencyStatus,
is CurrenciesStatusesOperations.Error.EmptyYieldBalances,
-> TokenListError.EmptyTokens

View file

@ -73,6 +73,7 @@ internal class CurrenciesStatusesLceOperations(
getQuotes(currenciesIds),
getNetworksStatuses(userWalletId, networks),
getYieldBalances(userWalletId, nonEmptyCurrencies),
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
val statuses = createCurrenciesStatuses(
currencies = nonEmptyCurrencies,
@ -144,11 +145,15 @@ internal class CurrenciesStatusesLceOperations(
currencies.map { currency ->
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
val address = extractAddress(networkStatus)
val isStakingSupported = stakingRepository.isStakingSupported(
stakingRepository.getIntegrationKey(currency.id),
)
val yieldBalance = if (isStakingSupported) {
(yieldBalances as? YieldBalanceList.Data)?.getBalance(currency.id.rawCurrencyId)
(yieldBalances as? YieldBalanceList.Data)?.getBalance(
address = address,
rawCurrencyId = currency.id.rawCurrencyId,
)
} else {
null
}
@ -221,4 +226,13 @@ internal class CurrenciesStatusesLceOperations(
return networks to currenciesIds
}
private fun extractAddress(networkStatus: NetworkStatus?): String? {
return when (val value = networkStatus?.value) {
is NetworkStatus.NoAccount -> value.address.defaultAddress.value
is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value
is NetworkStatus.Verified -> value.address.defaultAddress.value
else -> null
}
}
}

View file

@ -36,7 +36,12 @@ internal class CurrenciesStatusesOperations(
networksRepository.getNetworkStatusesSync(userWalletId, networks, false).right()
val yieldBalances = getYieldBalancesSync(nonEmptyCurrencies)
return createCurrenciesStatuses(nonEmptyCurrencies, quotes, networkStatuses, yieldBalances)
return createCurrenciesStatuses(
nonEmptyCurrencies,
quotes,
networkStatuses,
yieldBalances,
)
},
catch = { raise(Error.DataError(it)) },
)
@ -115,8 +120,7 @@ internal class CurrenciesStatusesOperations(
return createCurrencyStatus(currency, quotes, networkStatus, yieldBalances)
}
/** Get flow of currency statuses for NODL card */
fun getNodlCurrencyStatusesFlow(): Flow<Either<Error, List<CryptoCurrencyStatus>>> {
fun getCardCurrenciesStatusesFlow(): Flow<Either<Error, List<CryptoCurrencyStatus>>> {
return flow {
val nonEmptyCurrencies = recover(
block = { getCurrenciesFromCard(userWalletId) },
@ -147,12 +151,13 @@ internal class CurrenciesStatusesOperations(
val currenciesFlow = combine(
getQuotes(currenciesIds),
getNetworksStatuses(networks),
) { maybeQuotes, maybeNetworksStatuses ->
getYieldBalances(nonEmptyCurrencies),
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
createCurrenciesStatuses(
currencies = nonEmptyCurrencies,
maybeQuotes = maybeQuotes,
maybeNetworkStatuses = maybeNetworksStatuses,
maybeYieldBalances = null,
maybeYieldBalances = maybeYieldBalances,
)
}
@ -265,11 +270,16 @@ internal class CurrenciesStatusesOperations(
currencies.map { currency ->
val quote = quotes?.firstOrNull { it.rawCurrencyId == currency.id.rawCurrencyId }
val networkStatus = networksStatuses?.firstOrNull { it.network == currency.network }
val address = extractAddress(networkStatus)
val isStakingSupported = stakingRepository.isStakingSupported(
stakingRepository.getIntegrationKey(currency.id),
)
val yieldBalance = if (isStakingSupported) {
(yieldBalances as? YieldBalanceList.Data)?.getBalance(currency.id.rawCurrencyId)
(yieldBalances as? YieldBalanceList.Data)?.getBalance(
address = address,
rawCurrencyId = currency.id.rawCurrencyId,
)
} else {
null
}
@ -393,6 +403,15 @@ internal class CurrenciesStatusesOperations(
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
}
private fun getYieldBalances(cryptoCurrencies: List<CryptoCurrency>): Flow<Either<Error, YieldBalanceList>> {
return stakingRepository.getMultiYieldBalanceFlow(
userWalletId = userWalletId,
cryptoCurrencies = cryptoCurrencies,
).map<YieldBalanceList, Either<Error, YieldBalanceList>> { it.right() }
.catch { emit(Error.DataError(it).left()) }
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
}
private suspend fun getYieldBalancesSync(
cryptoCurrencies: List<CryptoCurrency>,
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
@ -449,6 +468,15 @@ internal class CurrenciesStatusesOperations(
return networks to currenciesIds
}
private fun extractAddress(networkStatus: NetworkStatus?): String? {
return when (val value = networkStatus?.value) {
is NetworkStatus.NoAccount -> value.address.defaultAddress.value
is NetworkStatus.Unreachable -> value.address?.defaultAddress?.value
is NetworkStatus.Verified -> value.address.defaultAddress.value
else -> null
}
}
sealed class Error {
data object EmptyCurrencies : Error()
@ -457,6 +485,8 @@ internal class CurrenciesStatusesOperations(
data object EmptyNetworksStatuses : Error()
data object EmptyAddresses : Error()
data object UnableToCreateCurrencyStatus : Error()
data class DataError(val cause: Throwable) : Error()