From a09aae7e41ae14827badc96fb988fa1e830a358a Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 25 Feb 2025 17:17:19 +0500 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/tap/domain/TangemSigner.kt | 36 +++++++++ .../tap/domain/tasks/MultiSignHashTask.kt | 80 +++++++++++++++++++ common/ui/build.gradle.kts | 1 + .../ui/notifications/NotificationsFactory.kt | 1 + .../ui/tokens/TokenItemStateConverter.kt | 14 +++- .../data/staking/DefaultStakingRepository.kt | 13 ++- .../stakekit/action/StakingActionType.kt | 8 ++ .../TokenListFiatBalanceOperations.kt | 24 ++++-- .../operations/TokenListSortingOperations.kt | 7 +- .../impl/presentation/model/StakingModel.kt | 45 ++++++----- .../presentation/state/StakingNotification.kt | 8 ++ .../SetConfirmationStateInitTransformer.kt | 9 +-- .../SetInitialDataStateTransformer.kt | 18 +++-- .../AddStakingNotificationsTransformer.kt | 14 +--- .../StakingInfoNotificationsFactory.kt | 57 ++++++++++++- .../state/utils/StakingPendingActionUtils.kt | 13 +-- .../ui/StakingConfirmationContent.kt | 2 + ...TokenDetailsBalanceSelectStateConverter.kt | 29 ++++--- .../TokenDetailsLoadedBalanceConverter.kt | 12 ++- .../tokendetails/state/utils/BalanceUtils.kt | 8 +- .../CryptoCurrencyToDraggableItemConverter.kt | 8 +- gradle/tangem_dependencies.toml | 4 +- .../com/tangem/lib/crypto/BlockchainUtils.kt | 13 +++ 23 files changed, 337 insertions(+), 87 deletions(-) create mode 100644 app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt index 7f5f095079..dffd82ec11 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSigner.kt @@ -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, + publicKey: Wallet.PublicKey, + ): CompletionResult> { + 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( diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt new file mode 100644 index 0000000000..d1d0d3dc53 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/tasks/MultiSignHashTask.kt @@ -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, + val totalSignedHashes: Int?, + val remainingSignatures: Int?, + val batchId: String?, +) : CommandResponse + +class MultiSignHashTask( + private val dataToSign: List, + private val publicKey: Wallet.PublicKey, + private val pairWalletPublicKey: ByteArray?, +) : CardSessionRunnable { + + override fun run(session: CardSession, callback: CompletionCallback) { + 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, + ) { + 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)) + } + } + } + } +} \ No newline at end of file diff --git a/common/ui/build.gradle.kts b/common/ui/build.gradle.kts index a59d399816..42a053ad9b 100644 --- a/common/ui/build.gradle.kts +++ b/common/ui/build.gradle.kts @@ -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) diff --git a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt index 78d11c9b2f..69f181a806 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/notifications/NotificationsFactory.kt @@ -364,6 +364,7 @@ object NotificationsFactory { ) } } + else -> return } } diff --git a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt index d209e29338..481946ed6b 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/tokens/TokenItemStateConverter.kt @@ -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()) { diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 25634c3787..750d106745 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -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 } } diff --git a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt index 01e02cea2f..467bb051aa 100644 --- a/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt +++ b/domain/staking/models/src/main/kotlin/com/tangem/domain/staking/model/stakekit/action/StakingActionType.kt @@ -39,4 +39,12 @@ enum class StakingActionType { MIGRATE -> "Migrate" UNKNOWN -> "Unknown" } + + val isRestake + get() = when (this) { + RESTAKE, + STAKE, + -> true + else -> false + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt index e4d319c4ff..a761548539 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListFiatBalanceOperations.kt @@ -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, diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt index 6e27d5c2d7..be9623f89e 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/operations/TokenListSortingOperations.kt @@ -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() } diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt index b57e0256f7..b180a8eaa3 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/model/StakingModel.kt @@ -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 = 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 { diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt index d9fd203280..ef6fe9940e 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/StakingNotification.kt @@ -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( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt index 8a2f781acc..dcc57f1a99 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetConfirmationStateInitTransformer.kt @@ -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) - } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt index 873626c210..e168a4db08 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/SetInitialDataStateTransformer.kt @@ -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) diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt index 7e8f2c875d..c388dff746 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/AddStakingNotificationsTransformer.kt @@ -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, 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.addStakeExceedBalanceNotification( diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt index a88e7ace69..ddff3c0e73 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/transformers/notifications/StakingInfoNotificationsFactory.kt @@ -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.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.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.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.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() + } } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt index 9287657626..70f2a487aa 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/state/utils/StakingPendingActionUtils.kt @@ -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) } \ No newline at end of file diff --git a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt index 866458c643..49d1aa49dd 100644 --- a/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt +++ b/features/staking/impl/src/main/java/com/tangem/features/staking/impl/presentation/ui/StakingConfirmationContent.kt @@ -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) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt index 4a76d6f1c9..5ab5994819 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsBalanceSelectStateConverter.kt @@ -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) } } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt index c8b17e62c5..76a4e08cd5 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsLoadedBalanceConverter.kt @@ -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) } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt index fe714ff2ca..25b4f3ecc1 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/utils/BalanceUtils.kt @@ -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 diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt index 15ca6ab348..c7302dd54a 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/organizetokens/utils/converter/items/CryptoCurrencyToDraggableItemConverter.kt @@ -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) } diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 422608e325..c341dfec4e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -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 ^ diff --git a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt index d34ef3b532..619324480d 100644 --- a/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt +++ b/libs/crypto/src/main/java/com/tangem/lib/crypto/BlockchainUtils.kt @@ -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"