Updated on 2026-08-14
This commit is contained in:
parent
072d04125d
commit
e00fd4599e
14 changed files with 492 additions and 253 deletions
|
|
@ -199,14 +199,21 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
private var appCurrency: AppCurrency by Delegates.notNull()
|
||||
|
||||
private val balancesToShow: List<BalanceItem>
|
||||
private val balancesToShow: List<StakingBalanceEntry>
|
||||
get() {
|
||||
val stakeKitBalance = cryptoCurrencyStatus.value.stakingBalance as? StakingBalance.Data.StakeKit
|
||||
return invalidatePendingTransactionsUseCase(
|
||||
balanceItems = stakeKitBalance?.balance?.items.orEmpty(),
|
||||
stakingActions = stakingActions,
|
||||
token = integration.token,
|
||||
).getOrElse { emptyList() }
|
||||
val stakingBalance = cryptoCurrencyStatus.value.stakingBalance
|
||||
return when (stakingBalance) {
|
||||
is StakingBalance.Data.StakeKit -> {
|
||||
val invalidatedItems = invalidatePendingTransactionsUseCase(
|
||||
balanceItems = stakingBalance.balance.items,
|
||||
stakingActions = stakingActions,
|
||||
token = integration.token,
|
||||
).getOrElse { emptyList() }
|
||||
invalidatedItems.toStakingBalanceEntries()
|
||||
}
|
||||
is StakingBalance.Data.P2PEthPool -> stakingBalance.entries
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private var isInitialInfoAnalyticSent: Boolean = false
|
||||
|
|
|
|||
|
|
@ -1,177 +0,0 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.converters
|
||||
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.BalanceItem
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.BalanceType.Companion.isClickable
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.utils.getRewardStakingBalance
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTon
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.datetime.Instant
|
||||
import java.math.BigDecimal
|
||||
import java.util.Calendar
|
||||
|
||||
internal class BalanceItemConverter(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<BalanceItem, BalanceState?> {
|
||||
|
||||
override fun convert(value: BalanceItem): BalanceState? {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
||||
val target = integration.targets.firstOrNull {
|
||||
value.validatorAddress?.contains(it.address, ignoreCase = true) == true
|
||||
}
|
||||
val cryptoAmount = value.getBalanceValue()
|
||||
val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
|
||||
|
||||
val title = value.type.getTitle(target?.name)
|
||||
return title?.let {
|
||||
BalanceState(
|
||||
groupId = value.groupId,
|
||||
target = target,
|
||||
title = title,
|
||||
subtitle = getSubtitle(value),
|
||||
type = value.type,
|
||||
cryptoValue = cryptoAmount.parseBigDecimal(cryptoCurrency.decimals),
|
||||
cryptoAmount = cryptoAmount,
|
||||
formattedCryptoAmount = stringReference(
|
||||
cryptoAmount.format { crypto(cryptoCurrency) },
|
||||
),
|
||||
fiatAmount = fiatAmount,
|
||||
formattedFiatAmount = stringReference(
|
||||
fiatAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
),
|
||||
rawCurrencyId = value.rawCurrencyId,
|
||||
pendingActions = value.pendingActions.toPersistentList(),
|
||||
isClickable = value.isClickable(),
|
||||
isPending = value.isPending,
|
||||
targetAddress = value.validatorAddress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BalanceItem.getBalanceValue(): BigDecimal {
|
||||
val isIncludeStakingTotalBalance = BlockchainUtils.isIncludeStakingTotalBalance(
|
||||
blockchainId = cryptoCurrencyStatus.currency.network.rawId,
|
||||
)
|
||||
val stakeKitBalance = cryptoCurrencyStatus.value.stakingBalance as? StakingBalance.Data.StakeKit
|
||||
return if (isIncludeStakingTotalBalance) {
|
||||
amount
|
||||
} else {
|
||||
amount - stakeKitBalance?.getRewardStakingBalance().orZero()
|
||||
}
|
||||
}
|
||||
|
||||
private fun BalanceType.getTitle(validatorName: String?) = when (this) {
|
||||
BalanceType.PREPARING,
|
||||
BalanceType.STAKED,
|
||||
-> validatorName?.let { stringReference(it) }
|
||||
BalanceType.UNSTAKED -> resourceReference(R.string.staking_unstaked)
|
||||
BalanceType.UNSTAKING -> resourceReference(R.string.staking_unstaking)
|
||||
BalanceType.LOCKED -> resourceReference(R.string.staking_locked)
|
||||
BalanceType.AVAILABLE,
|
||||
BalanceType.REWARDS,
|
||||
BalanceType.UNLOCKING,
|
||||
BalanceType.UNKNOWN,
|
||||
-> null
|
||||
}
|
||||
|
||||
private fun getSubtitle(balance: BalanceItem) = when (balance.type) {
|
||||
BalanceType.UNSTAKING -> getUnbondingDate(balance.date)
|
||||
BalanceType.UNSTAKED -> resourceReference(R.string.staking_tap_to_withdraw)
|
||||
BalanceType.LOCKED -> if (balance.pendingActions.any { it.type == StakingActionType.VOTE_LOCKED }) {
|
||||
resourceReference(R.string.staking_tap_to_unlock_or_vote)
|
||||
} else {
|
||||
resourceReference(R.string.staking_tap_to_unlock)
|
||||
}
|
||||
BalanceType.PREPARING -> {
|
||||
val warmupPeriod = integration.warmupPeriodDays
|
||||
combinedReference(
|
||||
resourceReference(R.string.staking_details_warmup_period),
|
||||
stringReference(" "),
|
||||
pluralReference(R.plurals.common_days, warmupPeriod, wrappedList(warmupPeriod)),
|
||||
)
|
||||
}
|
||||
BalanceType.AVAILABLE,
|
||||
BalanceType.STAKED,
|
||||
BalanceType.UNLOCKING,
|
||||
BalanceType.REWARDS,
|
||||
BalanceType.UNKNOWN,
|
||||
-> null
|
||||
}
|
||||
|
||||
private fun getUnbondingDate(date: Instant?): TextReference? {
|
||||
val unbondingPeriod = integration.cooldownPeriodDays ?: return null
|
||||
if (date == null) {
|
||||
return combinedReference(
|
||||
resourceReference(R.string.staking_details_unbonding_period),
|
||||
stringReference(" "),
|
||||
pluralReference(R.plurals.common_days, unbondingPeriod, wrappedList(unbondingPeriod)),
|
||||
)
|
||||
}
|
||||
|
||||
val nowCalendar = Calendar.getInstance()
|
||||
nowCalendar.resetHours()
|
||||
|
||||
val endDate = Calendar.getInstance()
|
||||
endDate.timeInMillis = date.toEpochMilliseconds()
|
||||
endDate.resetHours()
|
||||
|
||||
val days = ((endDate.timeInMillis - nowCalendar.timeInMillis) / DAY_IN_MILLIS).toInt()
|
||||
return if (days > 0) {
|
||||
resourceReference(
|
||||
R.string.common_left,
|
||||
wrappedList(
|
||||
pluralReference(R.plurals.common_days, days, wrappedList(days)),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
resourceReference(R.string.common_today)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BalanceItem.isClickable(): Boolean {
|
||||
val networkId = cryptoCurrencyStatus.currency.network.rawId
|
||||
return when {
|
||||
// TON allows withdrawing funds in the preparing state, unlike other networks.
|
||||
isTon(networkId) && this.type == BalanceType.PREPARING -> {
|
||||
pendingActions.any { it.type == StakingActionType.WITHDRAW }
|
||||
}
|
||||
else -> this.type.isClickable() && !this.isPending
|
||||
}
|
||||
}
|
||||
|
||||
private fun Calendar.resetHours() {
|
||||
this[Calendar.HOUR_OF_DAY] = 0
|
||||
this[Calendar.MINUTE] = 0
|
||||
this[Calendar.SECOND] = 0
|
||||
this[Calendar.MILLISECOND] = 0
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DAY_IN_MILLIS = 24 * 60 * 60 * 1000
|
||||
}
|
||||
}
|
||||
|
|
@ -24,20 +24,22 @@ internal class RewardsValidatorStateConverter(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<Unit, StakingStates.RewardsValidatorsState> {
|
||||
|
||||
override fun convert(value: Unit): StakingStates.RewardsValidatorsState {
|
||||
val stakingBalance = cryptoCurrencyStatus.value.stakingBalance
|
||||
return if (stakingBalance is StakingBalance.Data.StakeKit) {
|
||||
val balances = stakingBalance.balance.items
|
||||
StakingStates.RewardsValidatorsState.Data(
|
||||
isPrimaryButtonEnabled = true,
|
||||
rewards = balances
|
||||
.filter { it.type == BalanceType.REWARDS }
|
||||
.mapRewardBalances(cryptoCurrencyStatus)
|
||||
.toPersistentList(),
|
||||
)
|
||||
} else {
|
||||
// TODO p2p
|
||||
StakingStates.RewardsValidatorsState.Empty()
|
||||
return when (stakingBalance) {
|
||||
is StakingBalance.Data.StakeKit -> {
|
||||
val balances = stakingBalance.balance.items
|
||||
StakingStates.RewardsValidatorsState.Data(
|
||||
isPrimaryButtonEnabled = true,
|
||||
rewards = balances
|
||||
.filter { it.type == BalanceType.REWARDS }
|
||||
.mapRewardBalances(cryptoCurrencyStatus)
|
||||
.toPersistentList(),
|
||||
)
|
||||
}
|
||||
is StakingBalance.Data.P2PEthPool -> StakingStates.RewardsValidatorsState.Empty()
|
||||
else -> StakingStates.RewardsValidatorsState.Empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,227 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.converters
|
||||
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.extensions.pluralReference
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingBalanceEntry
|
||||
import com.tangem.domain.models.staking.StakingEntryActions
|
||||
import com.tangem.domain.models.staking.StakingEntryType
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTon
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toPersistentList
|
||||
import kotlinx.datetime.Instant
|
||||
import java.math.BigDecimal
|
||||
import java.util.Calendar
|
||||
|
||||
internal class StakingBalanceEntryConverter(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<StakingBalanceEntry, BalanceState?> {
|
||||
|
||||
override fun convert(value: StakingBalanceEntry): BalanceState? {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
||||
val target = findTarget(value)
|
||||
val cryptoAmount = value.getBalanceValue()
|
||||
val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
|
||||
|
||||
val title = value.type.getTitle(target?.name ?: value.validator?.name)
|
||||
return title?.let {
|
||||
BalanceState(
|
||||
groupId = value.id,
|
||||
target = target,
|
||||
title = title,
|
||||
subtitle = getSubtitle(value),
|
||||
type = value.type.toBalanceType(),
|
||||
cryptoValue = cryptoAmount.parseBigDecimal(cryptoCurrency.decimals),
|
||||
cryptoAmount = cryptoAmount,
|
||||
formattedCryptoAmount = stringReference(
|
||||
cryptoAmount.format { crypto(cryptoCurrency) },
|
||||
),
|
||||
fiatAmount = fiatAmount,
|
||||
formattedFiatAmount = stringReference(
|
||||
fiatAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
},
|
||||
),
|
||||
rawCurrencyId = value.rawCurrencyId,
|
||||
pendingActions = value.getPendingActions().toPersistentList(),
|
||||
isClickable = value.isClickable(),
|
||||
isPending = value.isPending,
|
||||
targetAddress = value.validator?.address,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun findTarget(entry: StakingBalanceEntry): StakingTarget? {
|
||||
return integration.targets.firstOrNull {
|
||||
entry.validator?.address?.contains(it.address, ignoreCase = true) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun StakingBalanceEntry.getBalanceValue(): BigDecimal {
|
||||
val isIncludeStakingTotalBalance = BlockchainUtils.isIncludeStakingTotalBalance(
|
||||
blockchainId = cryptoCurrencyStatus.currency.network.rawId,
|
||||
)
|
||||
return if (isIncludeStakingTotalBalance) {
|
||||
amount
|
||||
} else {
|
||||
val stakingBalance = cryptoCurrencyStatus.value.stakingBalance
|
||||
if (stakingBalance is StakingBalance.Data.StakeKit) {
|
||||
amount - stakingBalance.totalRewards
|
||||
} else {
|
||||
amount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun StakingEntryType.getTitle(validatorName: String?): TextReference? = when (this) {
|
||||
StakingEntryType.PREPARING,
|
||||
StakingEntryType.STAKED,
|
||||
-> validatorName?.let { stringReference(it) }
|
||||
StakingEntryType.WITHDRAWABLE -> resourceReference(R.string.staking_unstaked)
|
||||
StakingEntryType.UNSTAKING -> resourceReference(R.string.staking_unstaking)
|
||||
StakingEntryType.LOCKED -> resourceReference(R.string.staking_locked)
|
||||
StakingEntryType.AVAILABLE,
|
||||
StakingEntryType.REWARDS,
|
||||
StakingEntryType.UNLOCKING,
|
||||
StakingEntryType.UNKNOWN,
|
||||
-> null
|
||||
}
|
||||
|
||||
private fun getSubtitle(entry: StakingBalanceEntry): TextReference? = when (entry.type) {
|
||||
StakingEntryType.UNSTAKING -> getUnbondingDate(entry.date)
|
||||
StakingEntryType.WITHDRAWABLE -> resourceReference(R.string.staking_tap_to_withdraw)
|
||||
StakingEntryType.LOCKED -> {
|
||||
val hasVoteLocked = entry.getPendingActions().any { it.type == StakingActionType.VOTE_LOCKED }
|
||||
if (hasVoteLocked) {
|
||||
resourceReference(R.string.staking_tap_to_unlock_or_vote)
|
||||
} else {
|
||||
resourceReference(R.string.staking_tap_to_unlock)
|
||||
}
|
||||
}
|
||||
StakingEntryType.PREPARING -> {
|
||||
val warmupPeriod = integration.warmupPeriodDays
|
||||
TextReference.Combined(
|
||||
wrappedList(
|
||||
resourceReference(R.string.staking_details_warmup_period),
|
||||
stringReference(" "),
|
||||
pluralReference(R.plurals.common_days, warmupPeriod, wrappedList(warmupPeriod)),
|
||||
),
|
||||
)
|
||||
}
|
||||
StakingEntryType.AVAILABLE,
|
||||
StakingEntryType.STAKED,
|
||||
StakingEntryType.UNLOCKING,
|
||||
StakingEntryType.REWARDS,
|
||||
StakingEntryType.UNKNOWN,
|
||||
-> null
|
||||
}
|
||||
|
||||
private fun getUnbondingDate(date: Instant?): TextReference? {
|
||||
val unbondingPeriod = integration.cooldownPeriodDays ?: return null
|
||||
if (date == null) {
|
||||
return TextReference.Combined(
|
||||
wrappedList(
|
||||
resourceReference(R.string.staking_details_unbonding_period),
|
||||
stringReference(" "),
|
||||
pluralReference(R.plurals.common_days, unbondingPeriod, wrappedList(unbondingPeriod)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val nowCalendar = Calendar.getInstance()
|
||||
nowCalendar.resetHours()
|
||||
|
||||
val endDate = Calendar.getInstance()
|
||||
endDate.timeInMillis = date.toEpochMilliseconds()
|
||||
endDate.resetHours()
|
||||
|
||||
val days = ((endDate.timeInMillis - nowCalendar.timeInMillis) / DAY_IN_MILLIS).toInt()
|
||||
return if (days > 0) {
|
||||
resourceReference(
|
||||
R.string.common_left,
|
||||
wrappedList(
|
||||
pluralReference(R.plurals.common_days, days, wrappedList(days)),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
resourceReference(R.string.common_today)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StakingBalanceEntry.isClickable(): Boolean {
|
||||
val networkId = cryptoCurrencyStatus.currency.network.rawId
|
||||
return when {
|
||||
// TON allows withdrawing funds in the preparing state, unlike other networks.
|
||||
isTon(networkId) && this.type == StakingEntryType.PREPARING -> {
|
||||
getPendingActions().any { it.type == StakingActionType.WITHDRAW }
|
||||
}
|
||||
else -> this.type.isClickableType() && !this.isPending
|
||||
}
|
||||
}
|
||||
|
||||
private fun StakingEntryType.isClickableType(): Boolean = when (this) {
|
||||
StakingEntryType.STAKED,
|
||||
StakingEntryType.WITHDRAWABLE,
|
||||
StakingEntryType.LOCKED,
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun StakingBalanceEntry.getPendingActions(): List<PendingAction> {
|
||||
return when (val actions = this.actions) {
|
||||
is StakingEntryActions.StakeKit -> actions.pendingActions
|
||||
is StakingEntryActions.P2PEthPool -> persistentListOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun StakingEntryType.toBalanceType(): BalanceType {
|
||||
return when (this) {
|
||||
StakingEntryType.AVAILABLE -> BalanceType.AVAILABLE
|
||||
StakingEntryType.STAKED -> BalanceType.STAKED
|
||||
StakingEntryType.PREPARING -> BalanceType.PREPARING
|
||||
StakingEntryType.LOCKED -> BalanceType.LOCKED
|
||||
StakingEntryType.UNSTAKING -> BalanceType.UNSTAKING
|
||||
StakingEntryType.UNLOCKING -> BalanceType.UNLOCKING
|
||||
StakingEntryType.WITHDRAWABLE -> BalanceType.UNSTAKED
|
||||
StakingEntryType.REWARDS -> BalanceType.REWARDS
|
||||
StakingEntryType.UNKNOWN -> BalanceType.UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
private fun Calendar.resetHours() {
|
||||
this[Calendar.HOUR_OF_DAY] = 0
|
||||
this[Calendar.MINUTE] = 0
|
||||
this[Calendar.SECOND] = 0
|
||||
this[Calendar.MILLISECOND] = 0
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val DAY_IN_MILLIS = 24 * 60 * 60 * 1000
|
||||
}
|
||||
}
|
||||
|
|
@ -6,13 +6,13 @@ import com.tangem.core.ui.format.bigdecimal.fiat
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.BalanceItem
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.RewardBlockType
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.StakingBalanceEntry
|
||||
import com.tangem.domain.models.staking.StakingEntryType
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.utils.getRewardStakingBalance
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.YieldReward
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
|
|
@ -24,23 +24,23 @@ import kotlinx.collections.immutable.toPersistentList
|
|||
internal class YieldBalancesConverter(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val balancesToShowProvider: Provider<List<BalanceItem>>,
|
||||
private val balancesToShowProvider: Provider<List<StakingBalanceEntry>>,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<Unit, InnerYieldBalanceState> {
|
||||
|
||||
private val balanceItemConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
BalanceItemConverter(cryptoCurrencyStatus, appCurrencyProvider, integration)
|
||||
private val balanceEntryConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
StakingBalanceEntryConverter(cryptoCurrencyStatus, appCurrencyProvider, integration)
|
||||
}
|
||||
|
||||
override fun convert(value: Unit): InnerYieldBalanceState {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
val stakeKitBalance = cryptoCurrencyStatus.value.stakingBalance as? StakingBalance.Data.StakeKit
|
||||
val balanceToShowItems = balancesToShowProvider()
|
||||
val stakingBalance = cryptoCurrencyStatus.value.stakingBalance
|
||||
val balanceEntries = balancesToShowProvider()
|
||||
val hasStakingData = stakingBalance is StakingBalance.Data
|
||||
|
||||
return if (stakeKitBalance != null || balanceToShowItems.any { it.isPending }) {
|
||||
val cryptoRewardsValue = stakeKitBalance?.getRewardStakingBalance()
|
||||
return if (hasStakingData || balanceEntries.any { it.isPending }) {
|
||||
val cryptoRewardsValue = (stakingBalance as? StakingBalance.Data)?.totalRewards
|
||||
|
||||
val fiatRate = cryptoCurrencyStatus.value.fiatRate
|
||||
val fiatRewardsValue = if (fiatRate != null && cryptoRewardsValue != null) {
|
||||
|
|
@ -48,14 +48,11 @@ internal class YieldBalancesConverter(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val type = getRewardBlockType()
|
||||
val pendingRewardsConstraints = stakeKitBalance?.balance?.items
|
||||
?.firstOrNull { it.type == BalanceType.REWARDS }
|
||||
?.pendingActionsConstraints
|
||||
?.firstOrNull { it.type == StakingActionType.CLAIM_REWARDS }
|
||||
val type = getRewardBlockType(stakingBalance)
|
||||
val pendingRewardsConstraints = getRewardConstraints(stakingBalance)
|
||||
|
||||
InnerYieldBalanceState.Data(
|
||||
integrationId = stakeKitBalance?.stakingId?.integrationId,
|
||||
integrationId = stakingBalance?.stakingId?.integrationId,
|
||||
reward = YieldReward(
|
||||
rewardsCrypto = cryptoRewardsValue.format { crypto(cryptoCurrency) },
|
||||
rewardsFiat = fiatRewardsValue.format {
|
||||
|
|
@ -68,24 +65,32 @@ internal class YieldBalancesConverter(
|
|||
rewardConstraints = pendingRewardsConstraints,
|
||||
),
|
||||
isActionable = type.isActionable,
|
||||
balances = balanceToShowItems.mapBalances(),
|
||||
balances = balanceEntries.mapBalances(),
|
||||
)
|
||||
} else {
|
||||
// TODO p2p
|
||||
InnerYieldBalanceState.Empty
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<BalanceItem>.mapBalances() = asSequence()
|
||||
.filterNot { it.amount.isZero() || it.type == BalanceType.REWARDS }
|
||||
.mapNotNull(balanceItemConverter::convert)
|
||||
private fun List<StakingBalanceEntry>.mapBalances() = asSequence()
|
||||
.filterNot { it.amount.isZero() || it.type == StakingEntryType.REWARDS }
|
||||
.mapNotNull(balanceEntryConverter::convert)
|
||||
.sortedByDescending { it.cryptoAmount }
|
||||
.sortedBy { it.type.order }
|
||||
.toPersistentList()
|
||||
|
||||
private fun getRewardBlockType(): RewardBlockType {
|
||||
private fun getRewardBlockType(stakingBalance: StakingBalance?): RewardBlockType {
|
||||
val blockchainId = cryptoCurrencyStatus.currency.network.rawId
|
||||
val stakeKitBalance = cryptoCurrencyStatus.value.stakingBalance as? StakingBalance.Data.StakeKit
|
||||
|
||||
if (stakingBalance is StakingBalance.Data.P2PEthPool) {
|
||||
return if (isStakingRewardUnavailable(blockchainId)) {
|
||||
RewardBlockType.RewardUnavailable.DefaultRewardUnavailable
|
||||
} else {
|
||||
RewardBlockType.NoRewards
|
||||
}
|
||||
}
|
||||
|
||||
val stakeKitBalance = stakingBalance as? StakingBalance.Data.StakeKit
|
||||
val rewards = stakeKitBalance?.balance?.items
|
||||
?.filter { it.type == BalanceType.REWARDS && !it.amount.isZero() }
|
||||
|
||||
|
|
@ -105,4 +110,11 @@ internal class YieldBalancesConverter(
|
|||
else -> RewardBlockType.NoRewards
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRewardConstraints(stakingBalance: StakingBalance?) =
|
||||
(stakingBalance as? StakingBalance.Data.StakeKit)
|
||||
?.balance?.items
|
||||
?.firstOrNull { it.type == BalanceType.REWARDS }
|
||||
?.pendingActionsConstraints
|
||||
?.firstOrNull { it.type == StakingActionType.CLAIM_REWARDS }
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import com.tangem.core.ui.format.bigdecimal.percent
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.account.Account
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.BalanceItem
|
||||
import com.tangem.domain.models.staking.StakingBalanceEntry
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
|
|
@ -49,7 +49,7 @@ internal class SetInitialDataStateTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val userWalletProvider: Provider<UserWallet>,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val balancesToShowProvider: Provider<List<BalanceItem>>,
|
||||
private val balancesToShowProvider: Provider<List<StakingBalanceEntry>>,
|
||||
private val isAccountsModeEnabled: Boolean,
|
||||
private val account: Account.CryptoPortfolio?,
|
||||
private val isBalanceHidden: Boolean,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue