Updated on 2026-08-14
This commit is contained in:
parent
6d7ae39ba2
commit
a09aae7e41
23 changed files with 337 additions and 87 deletions
|
|
@ -7,6 +7,8 @@ import com.tangem.blockchain.common.Wallet
|
|||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.domain.card.models.TwinKey
|
||||
import com.tangem.domain.models.scan.isRing
|
||||
import com.tangem.operations.sign.SignData
|
||||
import com.tangem.tap.domain.tasks.MultiSignHashTask
|
||||
import com.tangem.tap.domain.tasks.SignHashesTask
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlin.coroutines.resume
|
||||
|
|
@ -64,6 +66,40 @@ class TangemSigner(
|
|||
is CompletionResult.Failure -> CompletionResult.Failure(result.error)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun multiSign(
|
||||
dataToSign: List<SignData>,
|
||||
publicKey: Wallet.PublicKey,
|
||||
): CompletionResult<Map<ByteArray, ByteArray>> {
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val task = MultiSignHashTask(dataToSign, publicKey, twinKey?.getPairKey(publicKey.seedKey))
|
||||
|
||||
tangemSdk.startSessionWithRunnable(
|
||||
runnable = task,
|
||||
cardId = cardId,
|
||||
initialMessage = initialMessage,
|
||||
) { result ->
|
||||
when (result) {
|
||||
is CompletionResult.Success -> {
|
||||
signerCallback(
|
||||
TangemSignerResponse(
|
||||
totalSignedHashes = result.data.totalSignedHashes,
|
||||
remainingSignatures = result.data.remainingSignatures,
|
||||
isRing = result.data.batchId?.let(::isRing) ?: false,
|
||||
),
|
||||
)
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(CompletionResult.Success(result.data.signatures))
|
||||
}
|
||||
}
|
||||
is CompletionResult.Failure ->
|
||||
if (continuation.isActive) {
|
||||
continuation.resume(CompletionResult.Failure(result.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class TangemSignerResponse(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.tap.domain.tasks
|
||||
|
||||
import com.tangem.blockchain.common.Wallet
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.CompletionCallback
|
||||
import com.tangem.common.core.TangemSdkError
|
||||
import com.tangem.operations.CommandResponse
|
||||
import com.tangem.operations.sign.MultipleSignCommand
|
||||
import com.tangem.operations.sign.SignData
|
||||
|
||||
class TangemMultiSignHashResponse(
|
||||
val signatures: Map<ByteArray, ByteArray>,
|
||||
val totalSignedHashes: Int?,
|
||||
val remainingSignatures: Int?,
|
||||
val batchId: String?,
|
||||
) : CommandResponse
|
||||
|
||||
class MultiSignHashTask(
|
||||
private val dataToSign: List<SignData>,
|
||||
private val publicKey: Wallet.PublicKey,
|
||||
private val pairWalletPublicKey: ByteArray?,
|
||||
) : CardSessionRunnable<TangemMultiSignHashResponse> {
|
||||
|
||||
override fun run(session: CardSession, callback: CompletionCallback<TangemMultiSignHashResponse>) {
|
||||
MultipleSignCommand(dataToSign, publicKey.seedKey).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = session.environment.card
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemMultiSignHashResponse(
|
||||
signatures = response.data.associate { it.walletPublicKey to it.signature },
|
||||
totalSignedHashes = response.data.last().totalSignedHashes,
|
||||
remainingSignatures = card?.wallet(publicKey.seedKey)?.remainingSignatures,
|
||||
batchId = card?.batchId,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
when {
|
||||
response.error is TangemSdkError.WalletNotFound && pairWalletPublicKey != null -> {
|
||||
sign(session, pairWalletPublicKey, callback)
|
||||
}
|
||||
else -> callback(CompletionResult.Failure(response.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sign(
|
||||
session: CardSession,
|
||||
publicKey: ByteArray,
|
||||
callback: CompletionCallback<TangemMultiSignHashResponse>,
|
||||
) {
|
||||
MultipleSignCommand(dataToSign, publicKey).run(session) { response ->
|
||||
when (response) {
|
||||
is CompletionResult.Success -> {
|
||||
val card = session.environment.card
|
||||
callback(
|
||||
CompletionResult.Success(
|
||||
TangemMultiSignHashResponse(
|
||||
signatures = response.data.associate { it.walletPublicKey to it.signature },
|
||||
totalSignedHashes = response.data.last().totalSignedHashes,
|
||||
remainingSignatures = card?.wallet(publicKey)?.remainingSignatures,
|
||||
batchId = card?.batchId,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
is CompletionResult.Failure -> {
|
||||
callback(CompletionResult.Failure(response.error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
/** Project - Common */
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.libs.crypto)
|
||||
|
||||
/** Project - Domain */
|
||||
implementation(projects.domain.appCurrency.models)
|
||||
|
|
|
|||
|
|
@ -364,6 +364,7 @@ object NotificationsFactory {
|
|||
)
|
||||
}
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.domain.appcurrency.model.AppCurrency
|
|||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.isZero
|
||||
|
|
@ -199,7 +200,11 @@ class TokenItemStateConverter(
|
|||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.Subtitle2State.TextContent(
|
||||
text = status.getFormattedCryptoAmount(includeStaking = true),
|
||||
text = status.getFormattedCryptoAmount(
|
||||
includeStaking = BlockchainUtils.isIncludeStakingTotalBalance(
|
||||
status.currency.network.id.value,
|
||||
),
|
||||
),
|
||||
isFlickering = status.value.isFlickering(),
|
||||
)
|
||||
}
|
||||
|
|
@ -222,7 +227,12 @@ class TokenItemStateConverter(
|
|||
is CryptoCurrencyStatus.NoAccount,
|
||||
-> {
|
||||
TokenItemState.FiatAmountState.Content(
|
||||
text = status.getFormattedFiatAmount(appCurrency = appCurrency, includeStaking = true),
|
||||
text = status.getFormattedFiatAmount(
|
||||
appCurrency = appCurrency,
|
||||
includeStaking = BlockchainUtils.isIncludeStakingTotalBalance(
|
||||
status.currency.network.id.value,
|
||||
),
|
||||
),
|
||||
isFlickering = status.value.isFlickering(),
|
||||
icons = buildList {
|
||||
if (!status.getStakedBalance().isZero()) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.tangem.datasource.local.token.StakingBalanceStore
|
|||
import com.tangem.datasource.local.token.StakingYieldsStore
|
||||
import com.tangem.datasource.local.token.converter.StakingNetworkTypeConverter
|
||||
import com.tangem.datasource.local.token.converter.TokenConverter
|
||||
import com.tangem.domain.common.TapWorkarounds.isWallet2
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.model.StakingEntryInfo
|
||||
|
|
@ -55,6 +56,7 @@ import com.tangem.domain.tokens.model.Network
|
|||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isCardano
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
|
@ -219,14 +221,11 @@ internal class DefaultStakingRepository(
|
|||
val userWallet = getUserWalletUseCase(userWalletId).getOrElse {
|
||||
error("Failed to get user wallet")
|
||||
}
|
||||
|
||||
val blockchainId = cryptoCurrency.network.id.value
|
||||
return when {
|
||||
isSolana(cryptoCurrency.network.id.value) -> {
|
||||
INVALID_BATCHES_FOR_SOLANA.contains(userWallet.scanResponse.card.batchId)
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
isSolana(blockchainId) -> INVALID_BATCHES_FOR_SOLANA.contains(userWallet.scanResponse.card.batchId)
|
||||
isCardano(blockchainId) -> !userWallet.scanResponse.card.isWallet2
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,4 +39,12 @@ enum class StakingActionType {
|
|||
MIGRATE -> "Migrate"
|
||||
UNKNOWN -> "Unknown"
|
||||
}
|
||||
|
||||
val isRestake
|
||||
get() = when (this) {
|
||||
RESTAKE,
|
||||
STAKE,
|
||||
-> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.staking.model.stakekit.YieldBalance
|
|||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.tokens.model.TotalFiatBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isIncludeStakingTotalBalance
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -21,6 +22,8 @@ internal class TokenListFiatBalanceOperations(
|
|||
if (isAnyTokenLoading) return fiatBalance
|
||||
|
||||
for (token in currencies) {
|
||||
val networkId = token.currency.network.id.value
|
||||
val includeStakingBalance = isIncludeStakingTotalBalance(networkId)
|
||||
when (val status = token.value) {
|
||||
is CryptoCurrencyStatus.Loading -> {
|
||||
fiatBalance = TotalFiatBalance.Loading
|
||||
|
|
@ -35,7 +38,7 @@ internal class TokenListFiatBalanceOperations(
|
|||
is CryptoCurrencyStatus.Unreachable,
|
||||
is CryptoCurrencyStatus.NoAmount,
|
||||
-> {
|
||||
if (BlockchainUtils.isIncludeToBalanceOnError(token.currency.network.id.value)) {
|
||||
if (BlockchainUtils.isIncludeToBalanceOnError(networkId)) {
|
||||
fiatBalance = recalculateNoAccountBalance(status, fiatBalance)
|
||||
} else {
|
||||
fiatBalance = TotalFiatBalance.Failed
|
||||
|
|
@ -46,10 +49,10 @@ internal class TokenListFiatBalanceOperations(
|
|||
fiatBalance = recalculateNoAccountBalance(status, fiatBalance)
|
||||
}
|
||||
is CryptoCurrencyStatus.Loaded -> {
|
||||
fiatBalance = recalculateBalance(status, fiatBalance)
|
||||
fiatBalance = recalculateBalance(status, fiatBalance, includeStakingBalance)
|
||||
}
|
||||
is CryptoCurrencyStatus.Custom -> {
|
||||
fiatBalance = recalculateBalance(status, fiatBalance)
|
||||
fiatBalance = recalculateBalance(status, fiatBalance, includeStakingBalance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,12 +77,16 @@ internal class TokenListFiatBalanceOperations(
|
|||
private fun recalculateBalance(
|
||||
status: CryptoCurrencyStatus.Loaded,
|
||||
currentBalance: TotalFiatBalance,
|
||||
includeStakingBalance: Boolean,
|
||||
): TotalFiatBalance {
|
||||
return with(currentBalance) {
|
||||
val yieldBalance = status.yieldBalance as? YieldBalance.Data
|
||||
val stakingBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero()
|
||||
val fiatStakingBalance = status.fiatRate.times(stakingBalance)
|
||||
|
||||
val fiatStakingBalance = if (includeStakingBalance) {
|
||||
status.fiatRate.times(stakingBalance)
|
||||
} else {
|
||||
BigDecimal.ZERO
|
||||
}
|
||||
(this as? TotalFiatBalance.Loaded)?.copy(
|
||||
amount = this.amount + status.fiatAmount + fiatStakingBalance,
|
||||
) ?: TotalFiatBalance.Loaded(
|
||||
|
|
@ -93,11 +100,16 @@ internal class TokenListFiatBalanceOperations(
|
|||
private fun recalculateBalance(
|
||||
status: CryptoCurrencyStatus.Custom,
|
||||
currentBalance: TotalFiatBalance,
|
||||
includeStakingBalance: Boolean,
|
||||
): TotalFiatBalance {
|
||||
return with(currentBalance) {
|
||||
val isTokenAmountCanBeSummarized = status.fiatAmount != null
|
||||
val yieldBalance = (status.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance().orZero()
|
||||
val fiatYieldBalance = status.fiatRate?.times(yieldBalance).orZero()
|
||||
val fiatYieldBalance = if (includeStakingBalance) {
|
||||
status.fiatRate?.times(yieldBalance).orZero()
|
||||
} else {
|
||||
BigDecimal.ZERO
|
||||
}
|
||||
(this as? TotalFiatBalance.Loaded)?.copy(
|
||||
amount = this.amount + status.fiatAmount.orZero() + fiatYieldBalance,
|
||||
isAllAmountsSummarized = isTokenAmountCanBeSummarized,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import arrow.core.raise.ensureNotNull
|
|||
import arrow.core.toNonEmptyListOrNull
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.*
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -99,7 +100,11 @@ internal class TokenListSortingOperations(
|
|||
private fun CryptoCurrencyStatus.getTotalBalance(): BigDecimal {
|
||||
val yieldBalance = value.yieldBalance as? YieldBalance.Data
|
||||
val totalYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance().orZero()
|
||||
val totalFiatYieldBalance = totalYieldBalance.multiply(value.fiatRate.orZero())
|
||||
val totalFiatYieldBalance = if (!BlockchainUtils.isIncludeStakingTotalBalance(currency.network.id.value)) {
|
||||
totalYieldBalance.multiply(value.fiatRate.orZero())
|
||||
} else {
|
||||
BigDecimal.ZERO
|
||||
}
|
||||
|
||||
return value.fiatAmount?.plus(totalFiatYieldBalance).orZero()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import com.tangem.domain.staking.model.StakingApproval
|
|||
import com.tangem.domain.staking.model.stakekit.*
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.tokens.*
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -45,8 +44,6 @@ import com.tangem.domain.transaction.error.GetFeeError
|
|||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetAllowanceUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.ValidateTransactionUseCase
|
||||
import com.tangem.domain.utils.convertToSdkAmount
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import com.tangem.domain.wallets.usecase.GetUserWalletUseCase
|
||||
|
|
@ -72,6 +69,7 @@ import com.tangem.features.staking.impl.presentation.state.transformers.validato
|
|||
import com.tangem.features.staking.impl.presentation.state.utils.checkAndCalculateSubtractedAmount
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.isSingleAction
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.withStubUnstakeAction
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.*
|
||||
import com.tangem.utils.extensions.isSingleItem
|
||||
|
|
@ -108,7 +106,6 @@ internal class StakingModel @Inject constructor(
|
|||
private val getCardInfoUseCase: GetCardInfoUseCase,
|
||||
private val saveBlockchainErrorUseCase: SaveBlockchainErrorUseCase,
|
||||
private val getBalanceNotEnoughForFeeWarningUseCase: GetBalanceNotEnoughForFeeWarningUseCase,
|
||||
private val validateTransactionUseCase: ValidateTransactionUseCase,
|
||||
private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase,
|
||||
private val isAmountSubtractAvailableUseCase: IsAmountSubtractAvailableUseCase,
|
||||
private val isAnyTokenStakedUseCase: IsAnyTokenStakedUseCase,
|
||||
|
|
@ -123,7 +120,7 @@ internal class StakingModel @Inject constructor(
|
|||
private val shareManager: ShareManager,
|
||||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
private val innerRouter: InnerStakingRouter,
|
||||
private val appRouter: AppRouter,
|
||||
appRouter: AppRouter,
|
||||
) : Model(), StakingClickIntents {
|
||||
|
||||
val uiState: StateFlow<StakingUiState> = stateController.uiState
|
||||
|
|
@ -239,7 +236,7 @@ internal class StakingModel @Inject constructor(
|
|||
return
|
||||
}
|
||||
isInitialInfoStep && noBalanceState -> {
|
||||
stateController.update(
|
||||
val list = buildList {
|
||||
SetConfirmationStateInitTransformer(
|
||||
isEnter = true,
|
||||
isExplicitExit = false,
|
||||
|
|
@ -248,8 +245,27 @@ internal class StakingModel @Inject constructor(
|
|||
stakingApproval = stakingApproval,
|
||||
stakingAllowance = stakingAllowance,
|
||||
yieldArgs = yield.args,
|
||||
),
|
||||
)
|
||||
).let(::add)
|
||||
if (BlockchainUtils.isSkipAmountEnter(uiState.value.cryptoCurrencyBlockchainId)) {
|
||||
ValidatorSelectChangeTransformer(
|
||||
selectedValidator = yield.preferredValidators.firstOrNull(),
|
||||
yield = yield,
|
||||
).let(::add)
|
||||
SetAmountDataTransformer(
|
||||
clickIntents = this@StakingModel,
|
||||
cryptoCurrencyStatusProvider = Provider { cryptoCurrencyStatus },
|
||||
userWalletProvider = Provider { userWallet },
|
||||
appCurrencyProvider = Provider { appCurrency },
|
||||
).let(::add)
|
||||
AmountMaxValueStateTransformer(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
actionType = uiState.value.actionType,
|
||||
yield = yield,
|
||||
).let(::add)
|
||||
}
|
||||
}
|
||||
stateController.updateAll(*list.toTypedArray())
|
||||
}
|
||||
}
|
||||
stakingStateRouter.onNextClick()
|
||||
|
|
@ -633,16 +649,6 @@ internal class StakingModel @Inject constructor(
|
|||
} else {
|
||||
null
|
||||
}
|
||||
val validation = amount?.let {
|
||||
validateTransactionUseCase(
|
||||
userWalletId = userWalletId,
|
||||
amount = amount.convertToSdkAmount(cryptoCurrencyStatus.currency),
|
||||
fee = feeState?.fee,
|
||||
memo = null,
|
||||
destination = "",
|
||||
network = cryptoCurrencyStatus.currency.network,
|
||||
).leftOrNull()
|
||||
}
|
||||
|
||||
val balanceAfterTransaction = calculateBalanceAfterTransaction(
|
||||
amount = amount.orZero(),
|
||||
|
|
@ -663,7 +669,6 @@ internal class StakingModel @Inject constructor(
|
|||
appCurrencyProvider = Provider { appCurrency },
|
||||
feeCryptoCurrencyStatus = feeCryptoCurrencyStatus,
|
||||
currencyWarning = currencyWarning,
|
||||
validatorError = validation,
|
||||
currencyCheck = currencyStatus,
|
||||
isSubtractAvailable = isAmountSubtractAvailable,
|
||||
feeError = feeError,
|
||||
|
|
@ -1021,7 +1026,7 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun isExplicitExit(balanceType: BalanceType, pendingAction: PendingAction?): Boolean {
|
||||
return balanceType == BalanceType.STAKED && pendingAction?.type != StakingActionType.RESTAKE
|
||||
return balanceType == BalanceType.STAKED && pendingAction?.type?.isRestake == false
|
||||
}
|
||||
|
||||
private fun isAssentState(): Boolean {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,14 @@ internal object StakingNotification {
|
|||
title = resourceReference(R.string.common_error),
|
||||
subtitle = subtitle,
|
||||
)
|
||||
|
||||
data class CardanoMinimumBalance(
|
||||
val title: TextReference,
|
||||
val subtitle: TextReference,
|
||||
) : StakingNotification.Error(
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Warning(
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.tangem.features.staking.impl.presentation.state.*
|
|||
import com.tangem.features.staking.impl.presentation.state.utils.isCompositePendingActions
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.isTronStakedBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSkipAmountEnter
|
||||
import com.tangem.utils.extensions.isPositive
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -45,12 +46,12 @@ internal class SetConfirmationStateInitTransformer(
|
|||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val actionType = when {
|
||||
isEnter -> StakingActionCommonType.Enter(
|
||||
skipEnterAmount = isAmountEnterSkipped(prevState),
|
||||
skipEnterAmount = isSkipAmountEnter(prevState.cryptoCurrencyBlockchainId),
|
||||
)
|
||||
isImplicitExit || isExplicitExit -> StakingActionCommonType.Exit(isPartiallyUnstakeDisabled(prevState))
|
||||
else -> when (pendingAction?.type) {
|
||||
StakingActionType.STAKE -> StakingActionCommonType.Enter(
|
||||
skipEnterAmount = isAmountEnterSkipped(prevState),
|
||||
skipEnterAmount = isSkipAmountEnter(prevState.cryptoCurrencyBlockchainId),
|
||||
)
|
||||
StakingActionType.UNSTAKE -> StakingActionCommonType.Exit(
|
||||
partiallyUnstakeDisabled = isPartiallyUnstakeDisabled(prevState),
|
||||
|
|
@ -100,8 +101,4 @@ internal class SetConfirmationStateInitTransformer(
|
|||
val max = exitAmount.maximum ?: return false
|
||||
return !min.isPositive() && !max.isPositive()
|
||||
}
|
||||
|
||||
private fun isAmountEnterSkipped(state: StakingUiState): Boolean {
|
||||
return BlockchainUtils.isCardano(state.cryptoCurrencyBlockchainId)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,33 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.extensions.remove
|
||||
import com.tangem.common.ui.amountScreen.converters.AmountStateConverter
|
||||
import com.tangem.common.ui.amountScreen.models.AmountParameters
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter
|
||||
import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStep
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import com.tangem.features.staking.impl.presentation.state.converters.RewardsValidatorStateConverter
|
||||
import com.tangem.features.staking.impl.presentation.state.converters.YieldBalancesConverter
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardScheduleText
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isPolkadot
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.isNullOrZero
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -145,7 +148,8 @@ internal class SetInitialDataStateTransformer(
|
|||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): RoundedListWithDividersItemData? {
|
||||
val minimumCryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum ?: return null
|
||||
if (!isPolkadot(cryptoCurrencyStatus.currency.network.id.value)) return null
|
||||
val blockchainId = cryptoCurrencyStatus.currency.network.id.value
|
||||
if (!showMinimumRequirementInfo(blockchainId)) return null
|
||||
|
||||
val formattedAmount = minimumCryptoAmount.format { crypto(cryptoCurrencyStatus.currency) }
|
||||
|
||||
|
|
@ -239,6 +243,10 @@ internal class SetInitialDataStateTransformer(
|
|||
return resourceReference(R.string.common_range, wrappedList(formattedMinApr, formattedMaxApr))
|
||||
}
|
||||
|
||||
private fun showMinimumRequirementInfo(blockchainId: String): Boolean {
|
||||
return blockchainId == Blockchain.Polkadot.id || blockchainId == Blockchain.Cardano.id
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val EQUALITY_THRESHOLD = BigDecimal(1E-10)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.notifications
|
||||
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.common.ui.amountScreen.models.AmountState
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addDustWarningNotification
|
||||
|
|
@ -11,7 +10,6 @@ import com.tangem.common.ui.notifications.NotificationsFactory.addFeeUnreachable
|
|||
import com.tangem.common.ui.notifications.NotificationsFactory.addRentExemptionNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addReserveAmountErrorNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addTransactionLimitErrorNotification
|
||||
import com.tangem.common.ui.notifications.NotificationsFactory.addValidateTransactionNotifications
|
||||
import com.tangem.core.ui.extensions.networkIconResId
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
|
|
@ -40,7 +38,6 @@ internal class AddStakingNotificationsTransformer(
|
|||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val feeCryptoCurrencyStatus: CryptoCurrencyStatus?,
|
||||
private val currencyWarning: CryptoCurrencyWarning?,
|
||||
private val validatorError: Throwable?,
|
||||
private val feeError: GetFeeError?,
|
||||
private val currencyCheck: CryptoCurrencyCheck,
|
||||
private val isSubtractAvailable: Boolean,
|
||||
|
|
@ -81,7 +78,7 @@ internal class AddStakingNotificationsTransformer(
|
|||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
).max(minimumRequirement)
|
||||
)
|
||||
} else {
|
||||
// No amount is taken from account balance on exit or pending actions
|
||||
BigDecimal.ZERO
|
||||
|
|
@ -212,15 +209,6 @@ internal class AddStakingNotificationsTransformer(
|
|||
appCurrency = appCurrency,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
)
|
||||
|
||||
// blockchain specific
|
||||
addValidateTransactionNotifications(
|
||||
dustValue = currencyCheck.dustValue.orZero(),
|
||||
minAdaValue = (feeState?.fee as? Fee.CardanoToken)?.minAdaValue,
|
||||
validationError = validatorError,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
onReduceClick = prevState.clickIntents::onAmountReduceToClick,
|
||||
)
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addStakeExceedBalanceNotification(
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.tangem.features.staking.impl.R
|
|||
import com.tangem.features.staking.impl.presentation.state.StakingNotification
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isCardano
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isCosmos
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTron
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -46,7 +47,10 @@ internal class StakingInfoNotificationsFactory(
|
|||
when (prevState.actionType) {
|
||||
is StakingActionCommonType.Enter -> addEnterInfoNotifications(sendingAmount, feeValue)
|
||||
is StakingActionCommonType.Exit -> addExitInfoNotifications()
|
||||
is StakingActionCommonType.Pending -> addPendingInfoNotifications(prevState)
|
||||
is StakingActionCommonType.Pending -> {
|
||||
addCardanoRestakeMinimumAmountNotification(feeValue)
|
||||
addPendingInfoNotifications(prevState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +74,9 @@ internal class StakingInfoNotificationsFactory(
|
|||
sendingAmount: BigDecimal,
|
||||
feeValue: BigDecimal,
|
||||
) {
|
||||
addCardanoStakeMinimumAmountNotification(feeValue)
|
||||
addTronRevoteNotification()
|
||||
addCardanoStakeNotification()
|
||||
addStakingEntireBalanceNotification(sendingAmount, feeValue)
|
||||
}
|
||||
|
||||
|
|
@ -149,6 +155,48 @@ internal class StakingInfoNotificationsFactory(
|
|||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addCardanoStakeNotification() {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value)
|
||||
|
||||
if (isCardano) {
|
||||
add(
|
||||
StakingNotification.Info.Ordinary(
|
||||
title = resourceReference(R.string.staking_notification_additional_ada_deposit_title),
|
||||
text = resourceReference(R.string.staking_notification_additional_ada_deposit_text),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addCardanoStakeMinimumAmountNotification(feeValue: BigDecimal) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value)
|
||||
val balance = cryptoCurrencyStatus.value.amount.orZero()
|
||||
if (isCardano && balance - feeValue < MINIMUM_STAKE_BALANCE) {
|
||||
add(
|
||||
StakingNotification.Error.CardanoMinimumBalance(
|
||||
title = resourceReference(R.string.staking_notification_minimum_balance_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_minimum_stake_ada_text),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addCardanoRestakeMinimumAmountNotification(feeValue: BigDecimal) {
|
||||
val cryptoCurrencyStatus = cryptoCurrencyStatusProvider()
|
||||
val isCardano = isCardano(cryptoCurrencyStatus.currency.network.id.value)
|
||||
val balance = cryptoCurrencyStatus.value.amount.orZero()
|
||||
if (isCardano && balance - feeValue < MINIMUM_RESTAKE_BALANCE) {
|
||||
add(
|
||||
StakingNotification.Error.CardanoMinimumBalance(
|
||||
title = resourceReference(R.string.staking_notification_minimum_restake_ada_title),
|
||||
subtitle = resourceReference(R.string.staking_notification_minimum_restake_ada_text),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addStakingEntireBalanceNotification(
|
||||
sendingAmount: BigDecimal,
|
||||
feeValue: BigDecimal,
|
||||
|
|
@ -158,7 +206,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
|
||||
val isEntireBalance = sendingAmount.plus(feeValue) == balance
|
||||
|
||||
if (isEntireBalance && isSubtractAvailable) {
|
||||
if (isEntireBalance && isSubtractAvailable && !isCardano(cryptoCurrencyStatus.currency.network.id.value)) {
|
||||
add(StakingNotification.Info.StakeEntireBalance)
|
||||
}
|
||||
}
|
||||
|
|
@ -179,4 +227,9 @@ internal class StakingInfoNotificationsFactory(
|
|||
add(StakingNotification.Warning.LowStakedBalance)
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val MINIMUM_STAKE_BALANCE = "5".toBigDecimal()
|
||||
val MINIMUM_RESTAKE_BALANCE = "3".toBigDecimal()
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.staking.model.stakekit.PendingAction
|
|||
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isBSC
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isCardano
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isTron
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
|
@ -37,14 +38,12 @@ internal fun StakingActionType?.getPendingActionTitle(): TextReference = when (t
|
|||
internal fun isSingleAction(networkId: String, activeStake: BalanceState): Boolean {
|
||||
val isSingleAction = activeStake.pendingActions.size <= 1 // Either single or none pending actions
|
||||
val isCompositePendingActions = isCompositePendingActions(networkId, activeStake.pendingActions)
|
||||
val isBscRestake = isBSC(networkId) && activeStake.pendingActions.any {
|
||||
it.type == StakingActionType.RESTAKE
|
||||
}
|
||||
val isRestake = activeStake.pendingActions.any { it.type.isRestake }
|
||||
|
||||
return isSingleAction && !isBscRestake || isCompositePendingActions
|
||||
return isSingleAction && !isRestake || isCompositePendingActions
|
||||
}
|
||||
|
||||
internal fun withStubUnstakeAction(networkId: String, activeStake: BalanceState) = if (isBSC(networkId)) {
|
||||
internal fun withStubUnstakeAction(networkId: String, activeStake: BalanceState) = if (isStubUnstakeAction(networkId)) {
|
||||
activeStake.pendingActions.plus(
|
||||
PendingAction(
|
||||
type = StakingActionType.UNSTAKE,
|
||||
|
|
@ -65,4 +64,8 @@ internal fun isCompositePendingActions(networkId: String, pendingActions: Immuta
|
|||
isSolana(networkId) -> pendingActions?.any { it.type == StakingActionType.WITHDRAW } == true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun isStubUnstakeAction(networkId: String): Boolean {
|
||||
return isBSC(networkId) || isCardano(networkId)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
|
|
@ -72,6 +73,7 @@ internal fun StakingConfirmationContent(
|
|||
)
|
||||
StakingFeeBlock(feeState = state.feeState, isTransactionSent = isTransactionSent)
|
||||
NotificationsBlock(notifications = state.notifications)
|
||||
Spacer(Modifier)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.factory
|
||||
|
||||
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.BigDecimalFormatter
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -26,7 +27,8 @@ internal class TokenDetailsBalanceSelectStateConverter(
|
|||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
|
||||
val stakingCryptoAmount = yieldBalance?.getTotalWithRewardsStakingBalance()
|
||||
val stakingFiatAmount = stakingCryptoAmount?.let { cryptoCurrencyStatus.value.fiatRate?.multiply(it) }
|
||||
|
||||
val includeStakingTotalBalance =
|
||||
BlockchainUtils.isIncludeStakingTotalBalance(cryptoCurrencyStatus.currency.network.id.value)
|
||||
copy(
|
||||
tokenBalanceBlockState = if (tokenBalanceBlockState is TokenDetailsBalanceBlockState.Content) {
|
||||
tokenBalanceBlockState.copy(
|
||||
|
|
@ -36,11 +38,13 @@ internal class TokenDetailsBalanceSelectStateConverter(
|
|||
stakingFiatAmount = stakingFiatAmount,
|
||||
selectedBalanceType = value.type,
|
||||
appCurrency = appCurrencyProvider(),
|
||||
includeStaking = includeStakingTotalBalance,
|
||||
),
|
||||
displayCryptoBalance = formatCryptoAmount(
|
||||
status = cryptoCurrencyStatus,
|
||||
stakingCryptoAmount = stakingCryptoAmount,
|
||||
selectedBalanceType = value.type,
|
||||
includeStaking = includeStakingTotalBalance,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
|
|
@ -55,25 +59,26 @@ internal class TokenDetailsBalanceSelectStateConverter(
|
|||
stakingFiatAmount: BigDecimal?,
|
||||
selectedBalanceType: BalanceType,
|
||||
appCurrency: AppCurrency,
|
||||
includeStaking: Boolean,
|
||||
): String {
|
||||
val fiatAmount = status.fiatAmount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount)
|
||||
val fiatAmount = status.fiatAmount?.getBalance(selectedBalanceType, stakingFiatAmount, includeStaking)
|
||||
|
||||
return BigDecimalFormatter.formatFiatAmount(
|
||||
fiatAmount = totalAmount,
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
return fiatAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = appCurrency.code,
|
||||
fiatCurrencySymbol = appCurrency.symbol,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatCryptoAmount(
|
||||
status: CryptoCurrencyStatus,
|
||||
stakingCryptoAmount: BigDecimal?,
|
||||
selectedBalanceType: BalanceType,
|
||||
includeStaking: Boolean,
|
||||
): String {
|
||||
val amount = status.value.amount ?: return BigDecimalFormatter.EMPTY_BALANCE_SIGN
|
||||
val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount)
|
||||
val amount = status.value.amount?.getBalance(selectedBalanceType, stakingCryptoAmount, includeStaking)
|
||||
|
||||
return totalAmount.format { crypto(status.currency) }
|
||||
return amount.format { crypto(status.currency) }
|
||||
}
|
||||
}
|
||||
|
|
@ -19,13 +19,14 @@ import com.tangem.domain.staking.model.stakekit.RewardBlockType
|
|||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.*
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.components.TokenDetailsNotification
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsTxHistoryTransactionStateConverter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.utils.getBalance
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
|
||||
import com.tangem.features.tokendetails.impl.R
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isBSC
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isIncludeStakingTotalBalance
|
||||
import com.tangem.lib.crypto.BlockchainUtils.isSolana
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.StringsSigns.DASH_SIGN
|
||||
|
|
@ -98,6 +99,7 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
val stakingCryptoAmount = (status.value.yieldBalance as? YieldBalance.Data)?.getTotalWithRewardsStakingBalance()
|
||||
val stakingFiatAmount = stakingCryptoAmount?.let { status.value.fiatRate?.multiply(it) }
|
||||
val isBalanceSelectorEnabled = !stakingCryptoAmount.isNullOrZero()
|
||||
val includeStakingTotalBalance = isIncludeStakingTotalBalance(status.currency.network.id.value)
|
||||
return when (status.value) {
|
||||
is CryptoCurrencyStatus.NoQuote,
|
||||
is CryptoCurrencyStatus.Loaded,
|
||||
|
|
@ -112,11 +114,13 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
stakingFiatAmount,
|
||||
currentState.selectedBalanceType,
|
||||
appCurrencyProvider(),
|
||||
includeStakingTotalBalance,
|
||||
),
|
||||
displayCryptoBalance = formatCryptoAmount(
|
||||
status,
|
||||
stakingCryptoAmount,
|
||||
currentState.selectedBalanceType,
|
||||
includeStakingTotalBalance,
|
||||
),
|
||||
balanceSegmentedButtonConfig = currentState.balanceSegmentedButtonConfig,
|
||||
onBalanceSelect = clickIntents::onBalanceSelect,
|
||||
|
|
@ -298,9 +302,10 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
stakingFiatAmount: BigDecimal?,
|
||||
selectedBalanceType: BalanceType,
|
||||
appCurrency: AppCurrency,
|
||||
includeStaking: Boolean,
|
||||
): String {
|
||||
val fiatAmount = status.fiatAmount ?: return DASH_SIGN
|
||||
val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount)
|
||||
val totalAmount = fiatAmount.getBalance(selectedBalanceType, stakingFiatAmount, includeStaking)
|
||||
|
||||
return totalAmount.format {
|
||||
fiat(
|
||||
|
|
@ -314,9 +319,10 @@ internal class TokenDetailsLoadedBalanceConverter(
|
|||
status: CryptoCurrencyStatus,
|
||||
stakingCryptoAmount: BigDecimal?,
|
||||
selectedBalanceType: BalanceType,
|
||||
includeStaking: Boolean,
|
||||
): String {
|
||||
val amount = status.value.amount ?: return DASH_SIGN
|
||||
val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount)
|
||||
val totalAmount = amount.getBalance(selectedBalanceType, stakingCryptoAmount, includeStaking)
|
||||
|
||||
return totalAmount.format { crypto(status.currency) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,12 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.state.utils
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.BalanceType
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal fun BigDecimal.getBalance(selectedBalanceType: BalanceType, stakingAmount: BigDecimal?): BigDecimal {
|
||||
return if (selectedBalanceType == BalanceType.ALL && stakingAmount != null) {
|
||||
internal fun BigDecimal.getBalance(
|
||||
selectedBalanceType: BalanceType,
|
||||
stakingAmount: BigDecimal?,
|
||||
includeStaking: Boolean,
|
||||
): BigDecimal {
|
||||
return if (selectedBalanceType == BalanceType.ALL && stakingAmount != null && includeStaking) {
|
||||
this.plus(stakingAmount)
|
||||
} else {
|
||||
this
|
||||
|
|
|
|||
|
|
@ -12,8 +12,10 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.feature.wallet.presentation.organizetokens.model.DraggableItem
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getGroupHeaderId
|
||||
import com.tangem.feature.wallet.presentation.organizetokens.utils.common.getTokenItemId
|
||||
import com.tangem.lib.crypto.BlockchainUtils
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.orZero
|
||||
import java.math.BigDecimal
|
||||
|
||||
internal class CryptoCurrencyToDraggableItemConverter(
|
||||
|
|
@ -63,7 +65,11 @@ internal class CryptoCurrencyToDraggableItemConverter(
|
|||
private fun getFormattedFiatAmount(currency: CryptoCurrencyStatus, appCurrency: AppCurrency): String {
|
||||
val yieldBalance = currency.value.yieldBalance as? YieldBalance.Data
|
||||
val fiatRate = currency.value.fiatRate ?: BigDecimal.ZERO
|
||||
val fiatYieldBalance = yieldBalance?.getTotalWithRewardsStakingBalance()?.multiply(fiatRate) ?: BigDecimal.ZERO
|
||||
val fiatYieldBalance = if (BlockchainUtils.isIncludeStakingTotalBalance(currency.currency.network.id.value)) {
|
||||
yieldBalance?.getTotalWithRewardsStakingBalance()?.multiply(fiatRate).orZero()
|
||||
} else {
|
||||
BigDecimal.ZERO
|
||||
}
|
||||
|
||||
val fiatAmount = currency.value.fiatAmount ?: return BigDecimalFormatConstants.EMPTY_BALANCE_SIGN
|
||||
return (fiatAmount + fiatYieldBalance).format { fiat(appCurrency.code, appCurrency.symbol) }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[versions]
|
||||
tangemBlockchainSdk = "develop-965"
|
||||
tangemBlockchainSdk = "develop-967"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-434"
|
||||
tangemCardSdk = "develop-437"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
tangemVico = "2.0.0-alpha.25-tangem-developments8"
|
||||
#tangemVico = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.math.BigDecimal
|
|||
* Temporary solution for domain specific logic for Blockchain.
|
||||
* Instead of creating repositories and unnecessary and overkill use cases
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
object BlockchainUtils {
|
||||
|
||||
private const val XRP_X_ADDRESS = 'X'
|
||||
|
|
@ -137,6 +138,18 @@ object BlockchainUtils {
|
|||
}
|
||||
}
|
||||
|
||||
fun isIncludeStakingTotalBalance(blockchainId: String): Boolean {
|
||||
val blockchain = Blockchain.fromId(blockchainId)
|
||||
|
||||
return blockchain != Blockchain.Cardano
|
||||
}
|
||||
|
||||
fun isSkipAmountEnter(blockchainId: String): Boolean {
|
||||
val blockchain = Blockchain.fromId(blockchainId)
|
||||
|
||||
return blockchain == Blockchain.Cardano
|
||||
}
|
||||
|
||||
private fun getNetworkStandardName(blockchain: Blockchain): String {
|
||||
return when (blockchain) {
|
||||
Blockchain.Ethereum, Blockchain.EthereumTestnet -> "ERC20"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue