Updated on 2026-08-14
This commit is contained in:
parent
9e0b8b3234
commit
b449775ad8
112 changed files with 979 additions and 740 deletions
|
|
@ -16,7 +16,7 @@ dependencies {
|
|||
|
||||
/** Domain models */
|
||||
api(projects.domain.models)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.staking)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.features.staking.api
|
||||
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.core.decompose.factory.ComponentFactory
|
||||
import com.tangem.core.ui.decompose.ComposableContentComponent
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
|
|
@ -10,7 +11,7 @@ interface StakingComponent : ComposableContentComponent {
|
|||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val cryptoCurrency: CryptoCurrency,
|
||||
val yieldId: String,
|
||||
val integrationId: StakingIntegrationID,
|
||||
)
|
||||
|
||||
interface Factory : ComponentFactory<Params, StakingComponent>
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ internal class StakingAnalyticSender(
|
|||
|
||||
fun initialInfoScreen(value: StakingUiState) {
|
||||
val initialInfoState = value.initialInfoState as? StakingStates.InitialInfoState.Data
|
||||
val validatorState = initialInfoState?.yieldBalance as? InnerYieldBalanceState.Data
|
||||
val validatorCount = validatorState?.balances
|
||||
?.filterNot { it.validator?.address.isNullOrBlank() }
|
||||
?.distinctBy { it.validator?.address }
|
||||
val balanceState = initialInfoState?.yieldBalance as? InnerYieldBalanceState.Data
|
||||
val validatorCount = balanceState?.balances
|
||||
?.filterNot { it.target?.address.isNullOrBlank() }
|
||||
?.distinctBy { it.target?.address }
|
||||
?.size ?: 0
|
||||
|
||||
analyticsEventHandler.send(
|
||||
|
|
@ -34,7 +34,7 @@ internal class StakingAnalyticSender(
|
|||
fun confirmationScreen(value: StakingUiState) {
|
||||
val confirmationState = value.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
val validatorState = value.validatorState as? StakingStates.ValidatorState.Data
|
||||
val validatorName = validatorState?.chosenValidator?.name ?: return
|
||||
val validatorName = validatorState?.chosenTarget?.name ?: return
|
||||
|
||||
if (confirmationState?.innerState == InnerConfirmationStakingState.COMPLETED) return
|
||||
|
||||
|
|
@ -80,7 +80,7 @@ internal class StakingAnalyticSender(
|
|||
|
||||
fun sendTransactionStakingAnalytics(value: StakingUiState, cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
val validatorState = value.validatorState as? StakingStates.ValidatorState.Data
|
||||
val validatorName = validatorState?.chosenValidator?.name ?: return
|
||||
val validatorName = validatorState?.chosenTarget?.name ?: return
|
||||
|
||||
analyticsEventHandler.send(
|
||||
Basic.TransactionSent(
|
||||
|
|
@ -102,7 +102,7 @@ internal class StakingAnalyticSender(
|
|||
|
||||
fun sendTransactionStakingClickedAnalytics(value: StakingUiState) {
|
||||
val validatorState = value.validatorState as? StakingStates.ValidatorState.Data
|
||||
val validatorName = validatorState?.chosenValidator?.name ?: return
|
||||
val validatorName = validatorState?.chosenTarget?.name ?: return
|
||||
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvent.ButtonAction(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.tangem.features.staking.impl.deeplink
|
||||
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.common.routing.AppRoute
|
||||
import com.tangem.common.routing.AppRouter
|
||||
import com.tangem.common.routing.deeplink.DeeplinkConst.NETWORK_ID_KEY
|
||||
|
|
@ -8,7 +7,6 @@ import com.tangem.common.routing.deeplink.DeeplinkConst.TOKEN_ID_KEY
|
|||
import com.tangem.common.routing.deeplink.DeeplinkConst.WALLET_ID_KEY
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.staking.GetStakingAvailabilityUseCase
|
||||
import com.tangem.domain.staking.GetYieldUseCase
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesProducer
|
||||
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesSupplier
|
||||
|
|
@ -28,7 +26,6 @@ internal class DefaultStakingDeepLinkHandler @AssistedInject constructor(
|
|||
private val appRouter: AppRouter,
|
||||
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
|
||||
private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier,
|
||||
private val getYieldUseCase: GetYieldUseCase,
|
||||
private val getStakingAvailabilityUseCase: GetStakingAvailabilityUseCase,
|
||||
) : StakingDeepLinkHandler {
|
||||
|
||||
|
|
@ -73,19 +70,13 @@ internal class DefaultStakingDeepLinkHandler @AssistedInject constructor(
|
|||
return@launch
|
||||
}
|
||||
|
||||
val isStakingEnabled = getStakingAvailabilityUseCase.invokeSync(
|
||||
val availability = getStakingAvailabilityUseCase.invokeSync(
|
||||
userWalletId = selectedUserWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
).getOrNull()
|
||||
|
||||
if (isStakingEnabled !is StakingAvailability.Available) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
val yield = getYieldUseCase.invoke(
|
||||
cryptoCurrencyId = cryptoCurrency.id,
|
||||
symbol = cryptoCurrency.symbol,
|
||||
).getOrElse {
|
||||
val option = (availability as? StakingAvailability.Available)?.option
|
||||
if (option == null) {
|
||||
Timber.e("Staking is unavailable for ${cryptoCurrency.name}")
|
||||
return@launch
|
||||
}
|
||||
|
|
@ -94,7 +85,7 @@ internal class DefaultStakingDeepLinkHandler @AssistedInject constructor(
|
|||
AppRoute.Staking(
|
||||
userWalletId = selectedUserWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
yieldId = yield.id,
|
||||
integrationId = option.integrationId,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.common.ui.amountScreen.AmountScreenClickIntents
|
|||
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import java.math.BigDecimal
|
||||
|
|
@ -35,7 +35,7 @@ internal interface StakingClickIntents : AmountScreenClickIntents {
|
|||
|
||||
fun openValidators()
|
||||
|
||||
fun onValidatorSelect(validator: Yield.Validator)
|
||||
fun onTargetSelect(target: StakingTarget)
|
||||
|
||||
fun openRewardsValidators()
|
||||
|
||||
|
|
|
|||
|
|
@ -45,11 +45,15 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.staking.*
|
||||
import com.tangem.domain.staking.analytics.StakeScreenSource
|
||||
import com.tangem.domain.staking.analytics.StakingAnalyticsEvent
|
||||
import com.tangem.domain.staking.model.P2PEthPoolIntegration
|
||||
import com.tangem.domain.staking.model.StakeKitIntegration
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingIntegrationID
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.staking.repositories.P2PEthPoolRepository
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.staking.utils.getValidatorsCount
|
||||
|
|
@ -134,6 +138,7 @@ internal class StakingModel @Inject constructor(
|
|||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getActionsUseCase: GetActionsUseCase,
|
||||
private val getYieldUseCase: GetYieldUseCase,
|
||||
private val p2pEthPoolRepository: P2PEthPoolRepository,
|
||||
private val checkAccountInitializedUseCase: CheckAccountInitializedUseCase,
|
||||
private val createTransferTransactionUseCase: CreateTransferTransactionUseCase,
|
||||
private val getFeeUseCase: GetFeeUseCase,
|
||||
|
|
@ -164,9 +169,18 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
private val cryptoCurrencyId: CryptoCurrency.ID = params.cryptoCurrency.id
|
||||
private val userWalletId: UserWalletId = params.userWalletId
|
||||
private val yield: Yield = runBlocking {
|
||||
getYieldUseCase(params.yieldId).getOrElse {
|
||||
error("yield must be not null")
|
||||
private val integration: StakingIntegration = runBlocking {
|
||||
when (val integrationId = params.integrationId) {
|
||||
is StakingIntegrationID.StakeKit -> {
|
||||
val yield = getYieldUseCase(integrationId.value).getOrElse {
|
||||
error("yield must be not null")
|
||||
}
|
||||
StakeKitIntegration(integrationId, yield)
|
||||
}
|
||||
StakingIntegrationID.P2PEthPool -> {
|
||||
val vaults = p2pEthPoolRepository.getVaults().getOrElse { emptyList() }
|
||||
P2PEthPoolIntegration(integrationId, vaults)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +208,7 @@ internal class StakingModel @Inject constructor(
|
|||
return invalidatePendingTransactionsUseCase(
|
||||
balanceItems = stakeKitBalance?.balance?.items.orEmpty(),
|
||||
stakingActions = stakingActions,
|
||||
token = yield.token,
|
||||
token = integration.token,
|
||||
).getOrElse { emptyList() }
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +219,7 @@ internal class StakingModel @Inject constructor(
|
|||
stakingBalanceUpdater.create(
|
||||
cryptoCurrencyStatus,
|
||||
userWallet,
|
||||
yield,
|
||||
integration,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +227,7 @@ internal class StakingModel @Inject constructor(
|
|||
stakingFeeTransactionLoader.create(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
userWallet = userWallet,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +235,7 @@ internal class StakingModel @Inject constructor(
|
|||
stakingTransactionLoader.create(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
userWallet = userWallet,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
isAmountSubtractAvailable = isAmountSubtractAvailable,
|
||||
)
|
||||
}
|
||||
|
|
@ -280,7 +294,7 @@ internal class StakingModel @Inject constructor(
|
|||
val hasNoYieldBalanceData = cryptoCurrencyStatus.value.stakingBalance !is StakingBalance.Data.StakeKit
|
||||
|
||||
when {
|
||||
isInitialInfoStep && noBalanceState && yield.allValidatorsFull && hasNoYieldBalanceData -> {
|
||||
isInitialInfoStep && noBalanceState && integration.areAllTargetsFull && hasNoYieldBalanceData -> {
|
||||
stakingEventFactory.createStakingValidatorsUnavailableAlert()
|
||||
return@launch
|
||||
}
|
||||
|
|
@ -293,12 +307,12 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
stakingApproval = stakingApproval,
|
||||
stakingAllowance = stakingAllowance,
|
||||
yieldArgs = yield.args,
|
||||
integration = integration,
|
||||
).let(::add)
|
||||
if (yield.args.enter.isPartialAmountDisabled) {
|
||||
if (integration.isPartialAmountDisabled) {
|
||||
ValidatorSelectChangeTransformer(
|
||||
selectedValidator = yield.preferredValidators.firstOrNull(),
|
||||
yield = yield,
|
||||
selectedTarget = integration.preferredTargets.firstOrNull(),
|
||||
integration = integration,
|
||||
).let(::add)
|
||||
SetAmountDataTransformer(
|
||||
clickIntents = this@StakingModel,
|
||||
|
|
@ -313,7 +327,7 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
actionType = uiState.value.actionType,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
).let(::add)
|
||||
}
|
||||
}
|
||||
|
|
@ -327,7 +341,7 @@ internal class StakingModel @Inject constructor(
|
|||
override fun getFee() {
|
||||
stateController.update(
|
||||
SetConfirmationStateLoadingTransformer(
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
appCurrency = appCurrency,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
),
|
||||
|
|
@ -479,7 +493,7 @@ internal class StakingModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun onAmountEnterClick() {
|
||||
if (yield.preferredValidators.isEmpty()) {
|
||||
if (integration.preferredTargets.isEmpty()) {
|
||||
stateController.updateEvent(
|
||||
StakingEvent.ShowAlert(StakingAlertUM.NoAvailableValidators),
|
||||
)
|
||||
|
|
@ -487,8 +501,8 @@ internal class StakingModel @Inject constructor(
|
|||
if (uiState.value.actionType is StakingActionCommonType.Enter) {
|
||||
stateController.updateAll(
|
||||
ValidatorSelectChangeTransformer(
|
||||
selectedValidator = null,
|
||||
yield = yield,
|
||||
selectedTarget = null,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -502,7 +516,7 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
value = value,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -518,7 +532,7 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
actionType = uiState.value.actionType,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -539,16 +553,16 @@ internal class StakingModel @Inject constructor(
|
|||
stakingStateRouter.showValidators()
|
||||
}
|
||||
|
||||
override fun onValidatorSelect(validator: Yield.Validator) {
|
||||
override fun onTargetSelect(target: StakingTarget) {
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvent.ValidatorChosen(
|
||||
validator = validator.name,
|
||||
validator = target.name,
|
||||
),
|
||||
)
|
||||
stateController.update(
|
||||
ValidatorSelectChangeTransformer(
|
||||
selectedValidator = validator,
|
||||
yield = yield,
|
||||
selectedTarget = target,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -606,7 +620,7 @@ internal class StakingModel @Inject constructor(
|
|||
balanceType = activeStake.type,
|
||||
pendingActions = activeStake.pendingActions,
|
||||
balanceState = activeStake,
|
||||
validator = activeStake.validator,
|
||||
target = activeStake.target,
|
||||
amountValue = activeStake.cryptoValue,
|
||||
)
|
||||
onNextClick(activeStake)
|
||||
|
|
@ -619,7 +633,7 @@ internal class StakingModel @Inject constructor(
|
|||
balanceType = activeStake.type,
|
||||
pendingAction = action,
|
||||
balanceState = activeStake,
|
||||
validator = activeStake.validator,
|
||||
target = activeStake.target,
|
||||
amountValue = activeStake.cryptoValue,
|
||||
)
|
||||
stateController.update(DismissBottomSheetStateTransformer)
|
||||
|
|
@ -788,7 +802,7 @@ internal class StakingModel @Inject constructor(
|
|||
isSubtractAvailable = isAmountSubtractAvailable,
|
||||
feeError = feeError,
|
||||
stakingError = stakingError,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -911,7 +925,7 @@ internal class StakingModel @Inject constructor(
|
|||
val validatorState = uiState.value.validatorState as? StakingStates.ValidatorState.Data
|
||||
val feeState = confirmationState?.feeState as? FeeState.Content
|
||||
|
||||
val validator = validatorState?.chosenValidator
|
||||
val target = validatorState?.chosenTarget
|
||||
val feeAmount = feeState?.fee?.amount
|
||||
val amount = amountState?.amountTextField?.cryptoAmount
|
||||
saveBlockchainErrorUseCase(
|
||||
|
|
@ -919,7 +933,7 @@ internal class StakingModel @Inject constructor(
|
|||
errorMessage = errorMessage,
|
||||
blockchainId = network.rawId,
|
||||
derivationPath = network.derivationPath.value,
|
||||
destinationAddress = validator?.address.orEmpty(),
|
||||
destinationAddress = target?.address.orEmpty(),
|
||||
tokenSymbol = (cryptoCurrencyStatus.currency as? CryptoCurrency.Token)?.symbol,
|
||||
amount = amount?.run { value?.toPlainString() + currencySymbol }.orEmpty(),
|
||||
fee = feeAmount?.run { value?.toPlainString() + currencySymbol }.orEmpty(),
|
||||
|
|
@ -928,7 +942,7 @@ internal class StakingModel @Inject constructor(
|
|||
|
||||
val email = FeedbackEmailType.StakingProblem(
|
||||
walletMetaInfo = metaInfo,
|
||||
validatorName = validator?.name,
|
||||
validatorName = target?.name,
|
||||
transactionTypes = transactionsInProgress.map { it.type.name },
|
||||
unsignedTransactions = transactionsInProgress.map { it.unsignedTransaction },
|
||||
)
|
||||
|
|
@ -1229,7 +1243,7 @@ internal class StakingModel @Inject constructor(
|
|||
stateController.updateAll(
|
||||
SetInitialDataStateTransformer(
|
||||
clickIntents = this@StakingModel,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
isAnyTokenStaked = isAnyTokenStaked,
|
||||
cryptoCurrencyStatus = status,
|
||||
userWalletProvider = Provider { userWallet },
|
||||
|
|
@ -1248,7 +1262,7 @@ internal class StakingModel @Inject constructor(
|
|||
balanceState: BalanceState,
|
||||
pendingActions: ImmutableList<PendingAction> = persistentListOf(),
|
||||
pendingAction: PendingAction? = pendingActions.firstOrNull(),
|
||||
validator: Yield.Validator?,
|
||||
target: StakingTarget?,
|
||||
amountValue: String,
|
||||
) {
|
||||
stateController.updateAll(
|
||||
|
|
@ -1261,11 +1275,11 @@ internal class StakingModel @Inject constructor(
|
|||
pendingActions = pendingActions,
|
||||
pendingAction = pendingAction,
|
||||
stakingAllowance = stakingAllowance,
|
||||
yieldArgs = yield.args,
|
||||
integration = integration,
|
||||
),
|
||||
ValidatorSelectChangeTransformer(
|
||||
selectedValidator = validator,
|
||||
yield = yield,
|
||||
selectedTarget = target,
|
||||
integration = integration,
|
||||
),
|
||||
SetAmountDataTransformer(
|
||||
clickIntents = this,
|
||||
|
|
@ -1280,7 +1294,7 @@ internal class StakingModel @Inject constructor(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
value = amountValue,
|
||||
minimumTransactionAmount = minimumTransactionAmount,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import com.tangem.domain.models.staking.BalanceType
|
|||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.models.staking.PendingActionConstraints
|
||||
import com.tangem.domain.models.staking.RewardBlockType
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -35,10 +35,10 @@ internal data class BalanceState(
|
|||
val fiatAmount: BigDecimal?,
|
||||
val formattedFiatAmount: TextReference,
|
||||
val rawCurrencyId: String?,
|
||||
val validator: Yield.Validator?,
|
||||
val target: StakingTarget?,
|
||||
val pendingActions: ImmutableList<PendingAction>,
|
||||
val isPending: Boolean,
|
||||
val validatorAddress: String?,
|
||||
val targetAddress: String?,
|
||||
)
|
||||
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.tangem.core.ui.event.StateEvent
|
|||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.components.containers.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
import com.tangem.features.staking.impl.presentation.state.events.StakingEvent
|
||||
|
|
@ -97,9 +97,9 @@ internal sealed class StakingStates {
|
|||
override val isPrimaryButtonEnabled: Boolean,
|
||||
override val isClickable: Boolean,
|
||||
val isVisibleOnConfirmation: Boolean,
|
||||
val chosenValidator: Yield.Validator,
|
||||
val activeValidator: Yield.Validator?,
|
||||
val availableValidators: List<Yield.Validator>,
|
||||
val chosenTarget: StakingTarget,
|
||||
val activeTarget: StakingTarget?,
|
||||
val availableTargets: List<StakingTarget>,
|
||||
) : ValidatorState()
|
||||
|
||||
data class Empty(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.tangem.domain.models.staking.BalanceType
|
|||
import com.tangem.domain.models.staking.BalanceType.Companion.isClickable
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.utils.getRewardStakingBalance
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
|
|
@ -29,24 +29,24 @@ import java.util.Calendar
|
|||
internal class BalanceItemConverter(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<BalanceItem, BalanceState?> {
|
||||
|
||||
override fun convert(value: BalanceItem): BalanceState? {
|
||||
val appCurrency = appCurrencyProvider()
|
||||
val cryptoCurrency = cryptoCurrencyStatus.currency
|
||||
|
||||
val validator = yield.validators.firstOrNull {
|
||||
val target = integration.targets.firstOrNull {
|
||||
value.validatorAddress?.contains(it.address, ignoreCase = true) == true
|
||||
}
|
||||
val cryptoAmount = value.getBalanceValue()
|
||||
val fiatAmount = cryptoCurrencyStatus.value.fiatRate?.times(cryptoAmount)
|
||||
|
||||
val title = value.type.getTitle(validator?.name)
|
||||
val title = value.type.getTitle(target?.name)
|
||||
return title?.let {
|
||||
BalanceState(
|
||||
groupId = value.groupId,
|
||||
validator = validator,
|
||||
target = target,
|
||||
title = title,
|
||||
subtitle = getSubtitle(value),
|
||||
type = value.type,
|
||||
|
|
@ -68,7 +68,7 @@ internal class BalanceItemConverter(
|
|||
pendingActions = value.pendingActions.toPersistentList(),
|
||||
isClickable = value.isClickable(),
|
||||
isPending = value.isPending,
|
||||
validatorAddress = value.validatorAddress,
|
||||
targetAddress = value.validatorAddress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ internal class BalanceItemConverter(
|
|||
resourceReference(R.string.staking_tap_to_unlock)
|
||||
}
|
||||
BalanceType.PREPARING -> {
|
||||
val warmupPeriod = yield.metadata.warmupPeriod.days
|
||||
val warmupPeriod = integration.warmupPeriodDays
|
||||
combinedReference(
|
||||
resourceReference(R.string.staking_details_warmup_period),
|
||||
stringReference(" "),
|
||||
|
|
@ -124,7 +124,7 @@ internal class BalanceItemConverter(
|
|||
}
|
||||
|
||||
private fun getUnbondingDate(date: Instant?): TextReference? {
|
||||
val unbondingPeriod = yield.metadata.cooldownPeriod?.days ?: return null
|
||||
val unbondingPeriod = integration.cooldownPeriodDays ?: return null
|
||||
if (date == null) {
|
||||
return combinedReference(
|
||||
resourceReference(R.string.staking_details_unbonding_period),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.staking.BalanceItem
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -21,7 +22,7 @@ import java.math.BigDecimal
|
|||
internal class RewardsValidatorStateConverter(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<Unit, StakingStates.RewardsValidatorsState> {
|
||||
override fun convert(value: Unit): StakingStates.RewardsValidatorsState {
|
||||
val stakingBalance = cryptoCurrencyStatus.value.stakingBalance
|
||||
|
|
@ -42,13 +43,13 @@ internal class RewardsValidatorStateConverter(
|
|||
|
||||
private fun List<BalanceItem>.mapRewardBalances(cryptoCurrencyStatus: CryptoCurrencyStatus) =
|
||||
this.mapNotNull { balance ->
|
||||
val validator = yield.validators.firstOrNull {
|
||||
val target = integration.targets.firstOrNull {
|
||||
it.address.contains(balance.validatorAddress.orEmpty(), ignoreCase = true)
|
||||
}
|
||||
val cryptoValue = balance.amount
|
||||
val fiatValue = cryptoCurrencyStatus.value.fiatRate?.times(cryptoValue)
|
||||
|
||||
validator?.toBalanceState(
|
||||
target?.toBalanceState(
|
||||
balance = balance,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
cryptoValue = cryptoValue,
|
||||
|
|
@ -56,7 +57,7 @@ internal class RewardsValidatorStateConverter(
|
|||
)
|
||||
}
|
||||
|
||||
private fun Yield.Validator.toBalanceState(
|
||||
private fun StakingTarget.toBalanceState(
|
||||
balance: BalanceItem,
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
cryptoValue: BigDecimal,
|
||||
|
|
@ -80,7 +81,7 @@ internal class RewardsValidatorStateConverter(
|
|||
|
||||
return BalanceState(
|
||||
groupId = balance.groupId,
|
||||
validator = this,
|
||||
target = this,
|
||||
title = stringReference(this.name),
|
||||
subtitle = null,
|
||||
cryptoValue = cryptoValue.parseBigDecimal(cryptoCurrency.decimals),
|
||||
|
|
@ -93,7 +94,7 @@ internal class RewardsValidatorStateConverter(
|
|||
isClickable = true,
|
||||
type = balance.type,
|
||||
isPending = balance.isPending,
|
||||
validatorAddress = balance.validatorAddress,
|
||||
targetAddress = balance.validatorAddress,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import com.tangem.domain.models.staking.BalanceType
|
|||
import com.tangem.domain.models.staking.RewardBlockType
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.utils.getRewardStakingBalance
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.YieldReward
|
||||
|
|
@ -25,11 +25,11 @@ internal class YieldBalancesConverter(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val appCurrencyProvider: Provider<AppCurrency>,
|
||||
private val balancesToShowProvider: Provider<List<BalanceItem>>,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Converter<Unit, InnerYieldBalanceState> {
|
||||
|
||||
private val balanceItemConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
BalanceItemConverter(cryptoCurrencyStatus, appCurrencyProvider, yield)
|
||||
BalanceItemConverter(cryptoCurrencyStatus, appCurrencyProvider, integration)
|
||||
}
|
||||
|
||||
override fun convert(value: Unit): InnerYieldBalanceState {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.FetchActionsUseCase
|
||||
import com.tangem.domain.staking.FetchStakingYieldBalanceUseCase
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.tokens.FetchCurrencyStatusUseCase
|
||||
import com.tangem.domain.tokens.FetchPendingTransactionsUseCase
|
||||
|
|
@ -27,7 +27,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
@DelayedWork private val coroutineScope: CoroutineScope,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
@Assisted private val yield: Yield,
|
||||
@Assisted private val integration: StakingIntegration,
|
||||
) {
|
||||
fun updateAfterTransaction() {
|
||||
coroutineScope.launch {
|
||||
|
|
@ -105,7 +105,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
fetchActionsUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
networkType = yield.token.network,
|
||||
networkType = integration.token.network,
|
||||
stakingActionStatus = StakingActionStatus.PROCESSING,
|
||||
)
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ internal class StakingBalanceUpdater @AssistedInject constructor(
|
|||
fun create(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
userWallet: UserWallet,
|
||||
yield: Yield,
|
||||
integration: StakingIntegration,
|
||||
): StakingBalanceUpdater
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,11 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.EstimateGasUseCase
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
||||
import com.tangem.domain.tokens.model.staking.getCurrentToken
|
||||
import com.tangem.domain.transaction.error.GetFeeError
|
||||
import com.tangem.domain.transaction.usecase.CreateApprovalTransactionUseCase
|
||||
import com.tangem.domain.transaction.usecase.GetFeeUseCase
|
||||
|
|
@ -45,7 +44,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
private val createApprovalTransactionUseCase: CreateApprovalTransactionUseCase,
|
||||
@Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val yield: Yield,
|
||||
@Assisted private val integration: StakingIntegration,
|
||||
) {
|
||||
|
||||
suspend fun getFee(
|
||||
|
|
@ -58,9 +57,9 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
val confirmationState = state.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
?: error("Illegal state")
|
||||
|
||||
val validatorAddress = (state.validatorState as? StakingStates.ValidatorState.Data)?.chosenValidator?.address
|
||||
?: state.balanceState?.validatorAddress
|
||||
?: error("No validator address provided")
|
||||
val validatorAddress = (state.validatorState as? StakingStates.ValidatorState.Data)?.chosenTarget?.address
|
||||
?: state.balanceState?.targetAddress
|
||||
?: error("No target address provided")
|
||||
|
||||
val amount = (state.amountState as? AmountState.Data)?.amountTextField?.cryptoAmount?.value
|
||||
?: error("No amount provided")
|
||||
|
|
@ -170,11 +169,11 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
network = cryptoCurrencyStatus.currency.network,
|
||||
params = ActionParams(
|
||||
actionCommonType = stateController.value.actionType,
|
||||
integrationId = yield.id,
|
||||
integrationId = integration.integrationId.value,
|
||||
amount = amount,
|
||||
address = sourceAddress,
|
||||
validatorAddress = validatorAddress,
|
||||
token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
token = integration.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
passthrough = action?.passthrough,
|
||||
type = action?.type,
|
||||
),
|
||||
|
|
@ -234,7 +233,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
fun create(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
userWallet: UserWallet,
|
||||
yield: Yield,
|
||||
integration: StakingIntegration,
|
||||
): StakingFeeTransactionLoader
|
||||
}
|
||||
}
|
||||
|
|
@ -13,15 +13,14 @@ import com.tangem.domain.staking.GetConstructedStakingTransactionUseCase
|
|||
import com.tangem.domain.staking.GetStakingTransactionsUseCase
|
||||
import com.tangem.domain.staking.SaveUnsubmittedHashUseCase
|
||||
import com.tangem.domain.staking.SubmitHashUseCase
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.SubmitHashData
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionStatus
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransactionType
|
||||
import com.tangem.domain.tokens.model.staking.getCurrentToken
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.domain.transaction.usecase.IsFeeApproximateUseCase
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
|
|
@ -56,12 +55,12 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
private val isFeeApproximateUseCase: IsFeeApproximateUseCase,
|
||||
@Assisted private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
@Assisted private val userWallet: UserWallet,
|
||||
@Assisted private val yield: Yield,
|
||||
@Assisted private val integration: StakingIntegration,
|
||||
@Assisted private val isAmountSubtractAvailable: Boolean,
|
||||
) {
|
||||
|
||||
private val balanceUpdater: StakingBalanceUpdater
|
||||
get() = stakingBalanceUpdater.create(cryptoCurrencyStatus, userWallet, yield)
|
||||
get() = stakingBalanceUpdater.create(cryptoCurrencyStatus, userWallet, integration)
|
||||
|
||||
suspend fun constructAndSendTransactions(
|
||||
onConstructSuccess: (List<StakingTransaction>) -> Unit,
|
||||
|
|
@ -193,7 +192,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
val amountState = state.amountState as? AmountState.Data
|
||||
?: error("No amount provided")
|
||||
|
||||
val validatorAddress = validatorState.chosenValidator.address
|
||||
val validatorAddress = validatorState.chosenTarget.address
|
||||
val amount = getAmount(amountState, fee, confirmationState.reduceAmountBy)
|
||||
|
||||
return getStakingTransactionsUseCase(
|
||||
|
|
@ -201,11 +200,11 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
network = cryptoCurrencyStatus.currency.network,
|
||||
params = ActionParams(
|
||||
actionCommonType = state.actionType,
|
||||
integrationId = yield.id,
|
||||
integrationId = integration.integrationId.value,
|
||||
amount = amount,
|
||||
address = defaultAddress,
|
||||
validatorAddress = validatorAddress,
|
||||
token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
token = integration.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
passthrough = action?.passthrough,
|
||||
type = action?.type,
|
||||
),
|
||||
|
|
@ -306,7 +305,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
fun create(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
userWallet: UserWallet,
|
||||
yield: Yield,
|
||||
integration: StakingIntegration,
|
||||
isAmountSubtractAvailable: Boolean,
|
||||
): StakingTransactionSender
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.RewardBlockType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.toStakingTarget
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.InnerYieldBalanceState
|
||||
|
|
@ -81,7 +82,7 @@ internal object InitialStakingStatePreview {
|
|||
fiatAmount = null,
|
||||
formattedFiatAmount = stringReference("100 $"),
|
||||
rawCurrencyId = null,
|
||||
validator = Yield.Validator(
|
||||
target = Yield.Validator(
|
||||
address = "address",
|
||||
status = Yield.Validator.ValidatorStatus.ACTIVE,
|
||||
name = "Binance",
|
||||
|
|
@ -92,13 +93,13 @@ internal object InitialStakingStatePreview {
|
|||
votingPower = null,
|
||||
preferred = false,
|
||||
isStrategicPartner = false,
|
||||
),
|
||||
).toStakingTarget(),
|
||||
pendingActions = persistentListOf(),
|
||||
isClickable = true,
|
||||
type = BalanceType.STAKED,
|
||||
subtitle = null,
|
||||
isPending = false,
|
||||
validatorAddress = "",
|
||||
targetAddress = "",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.previewdata
|
||||
|
||||
import com.tangem.domain.staking.model.common.RewardInfo
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.Yield.Validator.ValidatorStatus
|
||||
import com.tangem.domain.staking.model.toStakingTarget
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
|
@ -13,9 +17,9 @@ internal object ValidatorStatePreviewData {
|
|||
status = ValidatorStatus.ACTIVE,
|
||||
name = "Luganodes",
|
||||
image = "https://assets.stakek.it/validators/luganodes.png",
|
||||
rewardInfo = Yield.RewardInfo(
|
||||
rewardInfo = RewardInfo(
|
||||
rate = BigDecimal("0.054823398040640445"),
|
||||
type = Yield.RewardType.APR,
|
||||
type = RewardType.APR,
|
||||
),
|
||||
commission = 0.1,
|
||||
stakedBalance = "355544384.45009977",
|
||||
|
|
@ -29,9 +33,9 @@ internal object ValidatorStatePreviewData {
|
|||
status = ValidatorStatus.ACTIVE,
|
||||
name = "InfStones",
|
||||
image = "https://assets.stakek.it/validators/infstones.png",
|
||||
rewardInfo = Yield.RewardInfo(
|
||||
rewardInfo = RewardInfo(
|
||||
rate = BigDecimal("0.057786472172836965"),
|
||||
type = Yield.RewardType.APR,
|
||||
type = RewardType.APR,
|
||||
),
|
||||
commission = 0.05,
|
||||
stakedBalance = "12495684.05643019",
|
||||
|
|
@ -45,9 +49,9 @@ internal object ValidatorStatePreviewData {
|
|||
status = ValidatorStatus.ACTIVE,
|
||||
name = "Kiln",
|
||||
image = "https://assets.stakek.it/validators/kiln.png",
|
||||
rewardInfo = Yield.RewardInfo(
|
||||
rewardInfo = RewardInfo(
|
||||
rate = BigDecimal("0.057786472172836965"),
|
||||
type = Yield.RewardType.APR,
|
||||
type = RewardType.APR,
|
||||
),
|
||||
commission = 0.05,
|
||||
stakedBalance = "85400369.96393165",
|
||||
|
|
@ -58,11 +62,13 @@ internal object ValidatorStatePreviewData {
|
|||
),
|
||||
)
|
||||
|
||||
private val targetList: List<StakingTarget> = validatorList.map { it.toStakingTarget() }
|
||||
|
||||
val validatorState = StakingStates.ValidatorState.Data(
|
||||
availableValidators = validatorList,
|
||||
chosenValidator = validatorList.first(),
|
||||
availableTargets = targetList,
|
||||
chosenTarget = targetList.first(),
|
||||
isPrimaryButtonEnabled = true,
|
||||
activeValidator = null,
|
||||
activeTarget = null,
|
||||
isClickable = true,
|
||||
isVisibleOnConfirmation = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.features.staking.impl.presentation.state.stub
|
|||
import com.tangem.common.ui.bottomsheet.permission.state.ApproveType
|
||||
import com.tangem.common.ui.notifications.NotificationUM
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
|
|
@ -40,7 +40,7 @@ internal object StakingClickIntentsStub : StakingClickIntents {
|
|||
|
||||
override fun openValidators() {}
|
||||
|
||||
override fun onValidatorSelect(validator: Yield.Validator) {}
|
||||
override fun onTargetSelect(target: StakingTarget) {}
|
||||
|
||||
override fun openRewardsValidators() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.staking.PendingAction
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.isCompositePendingActions
|
||||
|
|
@ -24,7 +24,7 @@ internal class SetConfirmationStateInitTransformer(
|
|||
private val stakingApproval: StakingApproval,
|
||||
private val stakingAllowance: BigDecimal,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val yieldArgs: Yield.Args,
|
||||
private val integration: StakingIntegration,
|
||||
private val pendingActions: ImmutableList<PendingAction>? = null,
|
||||
private val pendingAction: PendingAction? = pendingActions?.firstOrNull(),
|
||||
) : Transformer<StakingUiState> {
|
||||
|
|
@ -66,7 +66,7 @@ internal class SetConfirmationStateInitTransformer(
|
|||
}
|
||||
|
||||
private fun getActionType(prevState: StakingUiState): StakingActionCommonType {
|
||||
val isPartialEnterAmountDisabled = yieldArgs.enter.isPartialAmountDisabled
|
||||
val isPartialEnterAmountDisabled = integration.isPartialAmountDisabled
|
||||
val isPartialExitAmountDisabled = isPartiallyUnstakeDisabled(prevState)
|
||||
return when {
|
||||
isEnter -> StakingActionCommonType.Enter(isPartialEnterAmountDisabled)
|
||||
|
|
@ -87,12 +87,12 @@ internal class SetConfirmationStateInitTransformer(
|
|||
|
||||
private fun isPartiallyUnstakeDisabled(state: StakingUiState): Boolean {
|
||||
val isSolana = BlockchainUtils.isSolana(state.cryptoCurrencyBlockchainId)
|
||||
val isValidatorPreferred = balanceState?.validator?.preferred == true
|
||||
val isTargetPreferred = balanceState?.target?.isPreferred == true
|
||||
|
||||
return if (isSolana && !isValidatorPreferred) {
|
||||
return if (isSolana && !isTargetPreferred) {
|
||||
true
|
||||
} else {
|
||||
yieldArgs.exit?.isPartialAmountDisabled == true
|
||||
integration.exitArgs?.isPartialAmountDisabled == true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import com.tangem.core.ui.format.bigdecimal.fiat
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.FeeState
|
||||
|
|
@ -18,7 +18,7 @@ import com.tangem.features.staking.impl.presentation.state.utils.getRewardSchedu
|
|||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetConfirmationStateLoadingTransformer(
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
private val appCurrency: AppCurrency,
|
||||
private val cryptoCurrency: CryptoCurrency,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
|
@ -48,7 +48,7 @@ internal class SetConfirmationStateLoadingTransformer(
|
|||
)
|
||||
}
|
||||
val rewardSchedule = getRewardScheduleText(
|
||||
rewardSchedule = yield.metadata.rewardSchedule,
|
||||
rewardSchedule = integration.rewardSchedule,
|
||||
networkId = cryptoCurrency.network.rawId,
|
||||
decapitalize = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import com.tangem.domain.models.account.Account
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.staking.BalanceItem
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
|
|
@ -41,7 +44,7 @@ import java.math.BigDecimal
|
|||
@Suppress("LongParameterList")
|
||||
internal class SetInitialDataStateTransformer(
|
||||
private val clickIntents: StakingClickIntents,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
private val isAnyTokenStaked: Boolean,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val userWalletProvider: Provider<UserWallet>,
|
||||
|
|
@ -55,7 +58,7 @@ internal class SetInitialDataStateTransformer(
|
|||
private val iconStateConverter by lazy(::CryptoCurrencyToIconStateConverter)
|
||||
|
||||
private val rewardsValidatorStateConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
RewardsValidatorStateConverter(cryptoCurrencyStatus, appCurrencyProvider, yield)
|
||||
RewardsValidatorStateConverter(cryptoCurrencyStatus, appCurrencyProvider, integration)
|
||||
}
|
||||
|
||||
private val yieldBalancesConverter by lazy(LazyThreadSafetyMode.NONE) {
|
||||
|
|
@ -63,7 +66,7 @@ internal class SetInitialDataStateTransformer(
|
|||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
appCurrencyProvider = appCurrencyProvider,
|
||||
balancesToShowProvider = balancesToShowProvider,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -116,27 +119,27 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun createAnnualPercentageItem(): RoundedListWithDividersItemData {
|
||||
val validators = yield.preferredValidators
|
||||
val rateRangeInfo = getPercentageRange(validators)
|
||||
val targets = integration.preferredTargets
|
||||
val rateRangeInfo = getPercentageRange(targets)
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_annual_percentage_rate,
|
||||
startText = getRateStartText(rateRangeInfo.first),
|
||||
endText = rateRangeInfo.second,
|
||||
iconClick = {
|
||||
when (rateRangeInfo.first) {
|
||||
Yield.RewardType.APR -> clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_RATE)
|
||||
Yield.RewardType.APY -> clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_YIELD)
|
||||
Yield.RewardType.UNKNOWN -> {}
|
||||
RewardType.APR -> clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_RATE)
|
||||
RewardType.APY -> clickIntents.onInfoClick(InfoType.ANNUAL_PERCENTAGE_YIELD)
|
||||
RewardType.UNKNOWN -> {}
|
||||
}
|
||||
},
|
||||
isEndTextHighlighted = false,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRateStartText(rewardType: Yield.RewardType): TextReference {
|
||||
private fun getRateStartText(rewardType: RewardType): TextReference {
|
||||
return when (rewardType) {
|
||||
Yield.RewardType.APR -> TextReference.Res(R.string.staking_details_annual_percentage_rate)
|
||||
Yield.RewardType.APY -> TextReference.Res(R.string.staking_details_annual_percentage_yield)
|
||||
RewardType.APR -> TextReference.Res(R.string.staking_details_annual_percentage_rate)
|
||||
RewardType.APY -> TextReference.Res(R.string.staking_details_annual_percentage_yield)
|
||||
else -> TextReference.EMPTY
|
||||
}
|
||||
}
|
||||
|
|
@ -153,7 +156,7 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun createUnbondingPeriodItem(): RoundedListWithDividersItemData? {
|
||||
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days ?: return null
|
||||
val cooldownPeriodDays = integration.cooldownPeriodDays ?: return null
|
||||
return RoundedListWithDividersItemData(
|
||||
id = R.string.staking_details_unbonding_period,
|
||||
startText = TextReference.Res(R.string.staking_details_unbonding_period),
|
||||
|
|
@ -169,7 +172,7 @@ internal class SetInitialDataStateTransformer(
|
|||
private fun createMinimumRequirementItem(
|
||||
cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
): RoundedListWithDividersItemData? {
|
||||
val minimumCryptoAmount = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum ?: return null
|
||||
val minimumCryptoAmount = integration.enterMinimumAmount ?: return null
|
||||
val blockchainId = cryptoCurrencyStatus.currency.network.rawId
|
||||
if (!showMinimumRequirementInfo(blockchainId)) return null
|
||||
|
||||
|
|
@ -183,7 +186,7 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun createRewardClaimingItem(): RoundedListWithDividersItemData? {
|
||||
val rewardClaiming = yield.metadata.rewardClaiming
|
||||
val rewardClaiming = integration.rewardClaiming
|
||||
val endTextId = rewardClaimingResources[rewardClaiming] ?: return null
|
||||
|
||||
return RoundedListWithDividersItemData(
|
||||
|
|
@ -195,7 +198,7 @@ internal class SetInitialDataStateTransformer(
|
|||
}
|
||||
|
||||
private fun createWarmupPeriodItem(): RoundedListWithDividersItemData? {
|
||||
val warmupPeriodDays = yield.metadata.warmupPeriod.days
|
||||
val warmupPeriodDays = integration.warmupPeriodDays
|
||||
if (warmupPeriodDays == 0) return null
|
||||
|
||||
return RoundedListWithDividersItemData(
|
||||
|
|
@ -212,7 +215,7 @@ internal class SetInitialDataStateTransformer(
|
|||
|
||||
private fun createRewardScheduleItem(): RoundedListWithDividersItemData? {
|
||||
val endTextReference = getRewardScheduleText(
|
||||
rewardSchedule = yield.metadata.rewardSchedule,
|
||||
rewardSchedule = integration.rewardSchedule,
|
||||
networkId = cryptoCurrencyStatus.currency.network.rawId,
|
||||
decapitalize = false,
|
||||
) ?: return null
|
||||
|
|
@ -252,15 +255,19 @@ internal class SetInitialDataStateTransformer(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getPercentageRange(validators: List<Yield.Validator>): Pair<Yield.RewardType, TextReference> {
|
||||
if (validators.isEmpty()) {
|
||||
return Yield.RewardType.APR to stringReference(DASH_SIGN)
|
||||
private fun getPercentageRange(targets: List<StakingTarget>): Pair<RewardType, TextReference> {
|
||||
if (targets.isEmpty()) {
|
||||
return RewardType.APR to stringReference(DASH_SIGN)
|
||||
}
|
||||
val rewardInfos = validators
|
||||
.filter { it.preferred }
|
||||
val rewardInfos = targets
|
||||
.filter { it.isPreferred }
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?.mapNotNull { it.rewardInfo }
|
||||
?: validators.mapNotNull { it.rewardInfo }
|
||||
?: targets.mapNotNull { it.rewardInfo }
|
||||
|
||||
if (rewardInfos.isEmpty()) {
|
||||
return RewardType.APR to stringReference(DASH_SIGN)
|
||||
}
|
||||
|
||||
val infoWithMinRate = rewardInfos.minBy { it.rate }
|
||||
val infoWithMaxRate = rewardInfos.maxBy { it.rate }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.common.ui.amountScreen.converters.MaxEnterAmountConverter
|
|||
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldChangeTransformer
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -13,7 +13,7 @@ internal class AmountChangeStateTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||
private val value: String,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
private val maxEnterAmountConverter = MaxEnterAmountConverter()
|
||||
|
|
@ -41,7 +41,7 @@ internal class AmountChangeStateTransformer(
|
|||
amountState = AmountRequirementStateTransformer(
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
maxAmount = maxEnterAmount,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
actionType = prevState.actionType,
|
||||
).transform(updatedAmountState),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import com.tangem.common.ui.amountScreen.converters.MaxEnterAmountConverter
|
|||
import com.tangem.common.ui.amountScreen.converters.field.AmountFieldSetMaxAmountTransformer
|
||||
import com.tangem.common.ui.amountScreen.models.EnterAmountBoundary
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
|
@ -13,7 +13,7 @@ internal class AmountMaxValueStateTransformer(
|
|||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val minimumTransactionAmount: EnterAmountBoundary?,
|
||||
private val actionType: StakingActionCommonType,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
private val maxEnterAmountConverter = MaxEnterAmountConverter()
|
||||
|
|
@ -38,7 +38,7 @@ internal class AmountMaxValueStateTransformer(
|
|||
amountState = AmountRequirementStateTransformer(
|
||||
maxAmount = maxEnterAmount,
|
||||
cryptoCurrencyStatus = cryptoCurrencyStatus,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
actionType = prevState.actionType,
|
||||
).transform(updatedAmountState),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.core.ui.format.bigdecimal.crypto
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.utils.parseBigDecimal
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.AddressArgument
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
|
|
@ -26,7 +27,7 @@ import java.math.RoundingMode
|
|||
internal class AmountRequirementStateTransformer(
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
private val maxAmount: EnterAmountBoundary,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
private val actionType: StakingActionCommonType,
|
||||
) : Transformer<AmountState> {
|
||||
override fun transform(prevState: AmountState): AmountState {
|
||||
|
|
@ -96,11 +97,11 @@ internal class AmountRequirementStateTransformer(
|
|||
|
||||
return when (actionType) {
|
||||
is StakingActionCommonType.Enter -> {
|
||||
val enterRequirements = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]
|
||||
val enterRequirements = integration.enterArgs?.args?.get(Yield.Args.ArgType.AMOUNT)
|
||||
enterRequirements?.getError(amountDecimal, R.string.staking_amount_requirement_error)
|
||||
}
|
||||
is StakingActionCommonType.Exit -> {
|
||||
val exitRequirements = yield.args.exit?.args?.get(Yield.Args.ArgType.AMOUNT)
|
||||
val exitRequirements = integration.exitArgs?.args?.get(Yield.Args.ArgType.AMOUNT)
|
||||
exitRequirements?.getError(amountDecimal, R.string.staking_unstake_amount_requirement_error)
|
||||
}
|
||||
else -> null
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ internal class ShowApprovalBottomSheetTransformer(
|
|||
val fee = feeState.fee ?: return prevState
|
||||
|
||||
val walletAddress = cryptoCurrencyValue.networkAddress?.defaultAddress?.value.orEmpty()
|
||||
val validatorAddress = validatorState.chosenValidator.address
|
||||
val targetAddress = validatorState.chosenTarget.address
|
||||
val feeCryptoValue = fee.amount.value.format {
|
||||
crypto(fee.amount.currencySymbol, fee.amount.decimals)
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ internal class ShowApprovalBottomSheetTransformer(
|
|||
amount = amountState.amountTextField.value,
|
||||
approveType = ApproveType.UNLIMITED,
|
||||
walletAddress = walletAddress,
|
||||
spenderAddress = validatorAddress,
|
||||
spenderAddress = targetAddress,
|
||||
fee = resourceReference(
|
||||
R.string.common_crypto_fiat_format,
|
||||
wrappedList(feeCryptoValue, feeFiatValue),
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.domain.appcurrency.model.AppCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.StakingErrors
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck
|
||||
import com.tangem.domain.tokens.model.warnings.CryptoCurrencyWarning
|
||||
|
|
@ -47,12 +47,12 @@ internal class AddStakingNotificationsTransformer(
|
|||
private val stakingError: StakingError?,
|
||||
private val currencyCheck: CryptoCurrencyCheck,
|
||||
private val isSubtractAvailable: Boolean,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
private val stakingInfoNotificationsFactory = StakingInfoNotificationsFactory(
|
||||
cryptoCurrencyStatusProvider = cryptoCurrencyStatusProvider,
|
||||
yield = yield,
|
||||
integration = integration,
|
||||
isSubtractAvailable = isSubtractAvailable,
|
||||
)
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ internal class AddStakingNotificationsTransformer(
|
|||
isSubtractAvailable = isSubtractAvailable,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
)
|
||||
val minimumRequirement = yield.args.enter.args[Yield.Args.ArgType.AMOUNT]?.minimum.orZero()
|
||||
val minimumRequirement = integration.enterMinimumAmount.orZero()
|
||||
val sendingAmount = if (isEnterAction) {
|
||||
checkAndCalculateSubtractedAmount(
|
||||
isAmountSubtractAvailable = isSubtractAvailable,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
|||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.StakingBalance
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.R
|
||||
|
|
@ -26,7 +27,7 @@ import java.math.BigDecimal
|
|||
|
||||
internal class StakingInfoNotificationsFactory(
|
||||
private val cryptoCurrencyStatusProvider: Provider<CryptoCurrencyStatus>,
|
||||
private val yield: Yield,
|
||||
private val integration: StakingIntegration,
|
||||
private val isSubtractAvailable: Boolean,
|
||||
) {
|
||||
|
||||
|
|
@ -94,7 +95,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
resourceReference(R.string.staking_notification_withdraw_text)
|
||||
}
|
||||
StakingActionType.UNLOCK_LOCKED -> {
|
||||
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
|
||||
val cooldownPeriodDays = integration.cooldownPeriodDays
|
||||
if (cooldownPeriodDays != null) {
|
||||
resourceReference(R.string.staking_unlocked_locked) to resourceReference(
|
||||
R.string.staking_notification_unlock_text,
|
||||
|
|
@ -213,7 +214,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
if (prevState.actionType !is StakingActionCommonType.Exit) return
|
||||
|
||||
val maxAmount = prevState.balanceState?.cryptoAmount ?: return
|
||||
val exitRequirements = yield.args.exit?.args?.get(Yield.Args.ArgType.AMOUNT) ?: return
|
||||
val exitRequirements = integration.exitArgs?.args?.get(Yield.Args.ArgType.AMOUNT) ?: return
|
||||
|
||||
val amountLeft = maxAmount - actionAmount
|
||||
val isNotEnoughLeft = !amountLeft.isZero() && amountLeft < exitRequirements.minimum.orZero()
|
||||
|
|
@ -224,7 +225,7 @@ internal class StakingInfoNotificationsFactory(
|
|||
}
|
||||
|
||||
private fun MutableList<NotificationUM>.addUnstakeInfoNotification() {
|
||||
val cooldownPeriodDays = yield.metadata.cooldownPeriod?.days
|
||||
val cooldownPeriodDays = integration.cooldownPeriodDays
|
||||
|
||||
val cryptoCurrencyNetworkIdValue = cryptoCurrencyStatusProvider().currency.network.rawId
|
||||
if (cooldownPeriodDays != null) {
|
||||
|
|
@ -248,18 +249,17 @@ internal class StakingInfoNotificationsFactory(
|
|||
val initialInfoState = prevState.initialInfoState as? StakingStates.InitialInfoState.Data
|
||||
val stakingBalances = (initialInfoState?.yieldBalance as? InnerYieldBalanceState.Data)?.balances
|
||||
|
||||
val validatorAddress = prevState.balanceState?.validator?.address ?: return
|
||||
val targetAddress = prevState.balanceState?.target?.address ?: return
|
||||
|
||||
val stakesCountWithCertainValidator = stakingBalances.orEmpty()
|
||||
.filter {
|
||||
it.type == BalanceType.STAKED ||
|
||||
it.type == BalanceType.PREPARING ||
|
||||
it.type == BalanceType.UNSTAKED
|
||||
val stakesCountWithCertainTarget = stakingBalances.orEmpty()
|
||||
.count { state ->
|
||||
(state.type == BalanceType.STAKED ||
|
||||
state.type == BalanceType.PREPARING ||
|
||||
state.type == BalanceType.UNSTAKED) &&
|
||||
state.target?.address == targetAddress
|
||||
}
|
||||
.filter { it.validator?.address == validatorAddress }
|
||||
.size
|
||||
|
||||
if (stakesCountWithCertainValidator > 1) {
|
||||
if (stakesCountWithCertainTarget > 1) {
|
||||
add(
|
||||
StakingNotification.Info.Ordinary(
|
||||
title = resourceReference(R.string.staking_notification_ton_have_to_unstake_all_title),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers.validator
|
||||
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.StakingIntegration
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.domain.models.staking.action.StakingActionType
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
|
|
@ -9,8 +10,8 @@ import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
|||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class ValidatorSelectChangeTransformer(
|
||||
private val yield: Yield,
|
||||
private val selectedValidator: Yield.Validator?,
|
||||
private val integration: StakingIntegration,
|
||||
private val selectedTarget: StakingTarget?,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
|
|
@ -23,27 +24,27 @@ internal class ValidatorSelectChangeTransformer(
|
|||
val isFromInfoScreen = prevState.currentStep == StakingStep.InitialInfo
|
||||
val isVoteLocked = confirmationState?.pendingAction?.type == StakingActionType.VOTE_LOCKED
|
||||
|
||||
val activeValidator = selectedValidator.takeIf { isFromInfoScreen && isRestake }
|
||||
?: validatorState?.activeValidator
|
||||
val filteredValidators = yield.preferredValidators.filterNot { it == activeValidator }
|
||||
val activeTarget = selectedTarget.takeIf { isFromInfoScreen && isRestake }
|
||||
?: validatorState?.activeTarget
|
||||
val filteredTargets = integration.preferredTargets.filterNot { it == activeTarget }
|
||||
|
||||
val selectedValidator = if (isRestake && isFromInfoScreen) {
|
||||
filteredValidators.firstOrNull()
|
||||
val selectedTarget = if (isRestake && isFromInfoScreen) {
|
||||
filteredTargets.firstOrNull()
|
||||
} else {
|
||||
selectedValidator
|
||||
selectedTarget
|
||||
}
|
||||
|
||||
if (selectedValidator == null && yield.preferredValidators.isEmpty()) {
|
||||
if (selectedTarget == null && integration.preferredTargets.isEmpty()) {
|
||||
return prevState
|
||||
}
|
||||
|
||||
return prevState.copy(
|
||||
validatorState = StakingStates.ValidatorState.Data(
|
||||
chosenValidator = selectedValidator ?: yield.preferredValidators.first(),
|
||||
availableValidators = filteredValidators,
|
||||
chosenTarget = selectedTarget ?: integration.preferredTargets.first(),
|
||||
availableTargets = filteredTargets,
|
||||
isPrimaryButtonEnabled = true,
|
||||
isClickable = yield.preferredValidators.size > 1,
|
||||
activeValidator = activeValidator,
|
||||
isClickable = integration.preferredTargets.size > 1,
|
||||
activeTarget = activeTarget,
|
||||
isVisibleOnConfirmation = isEnter || isRestake || isVoteLocked,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.utils
|
||||
|
||||
import com.tangem.core.ui.extensions.*
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.StakingRewardSchedule.COSMOS_SCHEDULE
|
||||
|
|
@ -52,18 +53,18 @@ internal fun getRewardScheduleText(
|
|||
}
|
||||
}
|
||||
|
||||
internal fun getRewardTypeShortText(rewardType: Yield.RewardType): TextReference {
|
||||
internal fun getRewardTypeShortText(rewardType: RewardType): TextReference {
|
||||
return when (rewardType) {
|
||||
Yield.RewardType.APR -> TextReference.Res(R.string.staking_details_apr)
|
||||
Yield.RewardType.APY -> TextReference.Res(R.string.staking_details_apy)
|
||||
RewardType.APR -> TextReference.Res(R.string.staking_details_apr)
|
||||
RewardType.APY -> TextReference.Res(R.string.staking_details_apy)
|
||||
else -> TextReference.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getRewardTypeLongText(rewardType: Yield.RewardType): TextReference {
|
||||
internal fun getRewardTypeLongText(rewardType: RewardType): TextReference {
|
||||
return when (rewardType) {
|
||||
Yield.RewardType.APR -> TextReference.Res(R.string.staking_details_annual_percentage_rate)
|
||||
Yield.RewardType.APY -> TextReference.Res(R.string.staking_details_annual_percentage_yield)
|
||||
RewardType.APR -> TextReference.Res(R.string.staking_details_annual_percentage_rate)
|
||||
RewardType.APY -> TextReference.Res(R.string.staking_details_annual_percentage_yield)
|
||||
else -> TextReference.EMPTY
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import com.tangem.core.ui.extensions.*
|
|||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
|
|
@ -30,7 +30,7 @@ internal fun StakingClaimRewardsValidatorContent(
|
|||
) {
|
||||
if (state !is StakingStates.RewardsValidatorsState.Data) return
|
||||
Column(
|
||||
modifier = Modifier // Do not put fillMaxSize() in here
|
||||
modifier = modifier // This function shouldn't itself apply fillMaxSize(); callers should avoid passing it here
|
||||
.background(TangemTheme.colors.background.secondary)
|
||||
.padding(horizontal = TangemTheme.dimens.spacing12)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
|
|
@ -42,9 +42,9 @@ internal fun StakingClaimRewardsValidatorContent(
|
|||
caption = item.getAprTextNeutral(),
|
||||
infoTitle = item.formattedFiatAmount,
|
||||
infoSubtitle = item.formattedCryptoAmount,
|
||||
imageUrl = item.validator?.image.orEmpty(),
|
||||
imageUrl = item.target?.image.orEmpty(),
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(index, state.rewards.lastIndex, false)
|
||||
.background(TangemTheme.colors.background.action)
|
||||
.clickable(
|
||||
|
|
@ -65,11 +65,11 @@ internal fun StakingClaimRewardsValidatorContent(
|
|||
@Suppress("UnusedPrivateMember")
|
||||
@Composable
|
||||
private fun BalanceState.getAprTextColored() = combinedReference(
|
||||
getRewardTypeShortText(validator?.rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
getRewardTypeShortText(target?.rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
annotatedReference {
|
||||
appendSpace()
|
||||
appendColored(
|
||||
text = validator?.rewardInfo?.rate?.orZero().format { percent() },
|
||||
text = target?.rewardInfo?.rate?.orZero().format { percent() },
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
|
|
@ -77,6 +77,6 @@ private fun BalanceState.getAprTextColored() = combinedReference(
|
|||
|
||||
@Composable
|
||||
private fun BalanceState.getAprTextNeutral() = combinedReference(
|
||||
getRewardTypeShortText(validator?.rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
stringReference(" " + validator?.rewardInfo?.rate?.orZero().format { percent() }),
|
||||
getRewardTypeShortText(target?.rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
stringReference(" " + target?.rewardInfo?.rate?.orZero().format { percent() }),
|
||||
)
|
||||
|
|
@ -46,7 +46,7 @@ import com.tangem.core.ui.res.TangemThemePreview
|
|||
import com.tangem.core.ui.test.StakingDetailsScreenTestTags
|
||||
import com.tangem.domain.models.staking.BalanceType
|
||||
import com.tangem.domain.models.staking.RewardBlockType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.BalanceState
|
||||
|
|
@ -317,11 +317,11 @@ private fun StakeButtonBlock(buttonState: NavigationButtonsState) {
|
|||
@Suppress("UnusedPrivateMember")
|
||||
@Composable
|
||||
private fun BalanceState.getAprTextColored() = combinedReference(
|
||||
getRewardTypeShortText(validator?.rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
getRewardTypeShortText(target?.rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
annotatedReference {
|
||||
appendSpace()
|
||||
appendColored(
|
||||
text = validator?.rewardInfo?.rate?.orZero().format { percent() },
|
||||
text = target?.rewardInfo?.rate?.orZero().format { percent() },
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
|
|
@ -329,8 +329,8 @@ private fun BalanceState.getAprTextColored() = combinedReference(
|
|||
|
||||
@Composable
|
||||
private fun BalanceState.getAprTextNeutral() = combinedReference(
|
||||
getRewardTypeShortText(validator?.rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
stringReference(" " + validator?.rewardInfo?.rate?.orZero().format { percent() }),
|
||||
getRewardTypeShortText(target?.rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
stringReference(" " + target?.rewardInfo?.rate?.orZero().format { percent() }),
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -347,7 +347,7 @@ private fun BalanceState.getImage() = when (type) {
|
|||
BalanceType.UNSTAKED,
|
||||
BalanceType.LOCKED,
|
||||
-> null
|
||||
else -> validator?.image
|
||||
else -> target?.image
|
||||
}
|
||||
|
||||
private val textGradientColors = listOf(
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.res.TangemThemePreview
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.domain.staking.model.StakingTarget
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.model.StakingClickIntents
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
|
|
@ -54,24 +55,24 @@ internal fun StakingValidatorListContent(
|
|||
.padding(horizontal = TangemTheme.dimens.spacing16),
|
||||
) {
|
||||
if (state is StakingStates.ValidatorState.Data) {
|
||||
val validators = state.availableValidators
|
||||
val targets = state.availableTargets
|
||||
items(
|
||||
count = validators.size,
|
||||
key = { validators[it].address },
|
||||
contentType = { validators[it]::class.java },
|
||||
count = targets.size,
|
||||
key = { targets[it].address },
|
||||
contentType = { targets[it]::class.java },
|
||||
) { index ->
|
||||
val item = validators[index]
|
||||
val item = targets[index]
|
||||
|
||||
InputRowImageSelector(
|
||||
subtitle = stringReference(item.name),
|
||||
caption = item.getAprTextNeutral(),
|
||||
imageUrl = item.image.orEmpty(),
|
||||
isSelected = item == state.chosenValidator,
|
||||
onSelect = { clickIntents.onValidatorSelect(item) },
|
||||
isSelected = item == state.chosenTarget,
|
||||
onSelect = { clickIntents.onTargetSelect(item) },
|
||||
modifier = Modifier
|
||||
.roundedShapeItemDecoration(
|
||||
currentIndex = index,
|
||||
lastIndex = validators.lastIndex,
|
||||
lastIndex = targets.lastIndex,
|
||||
radius = TangemTheme.dimens.radius12,
|
||||
addDefaultPadding =
|
||||
false,
|
||||
|
|
@ -106,21 +107,21 @@ internal fun StakingValidatorListContent(
|
|||
*/
|
||||
@Suppress("UnusedPrivateMember")
|
||||
@Composable
|
||||
private fun Yield.Validator.getAprTextColored() = combinedReference(
|
||||
getRewardTypeLongText(rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
private fun StakingTarget.getAprTextColored() = combinedReference(
|
||||
getRewardTypeLongText(rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
annotatedReference {
|
||||
appendSpace()
|
||||
appendColored(
|
||||
text = rewardInfo?.rate?.orZero().format { percent() },
|
||||
text = rewardInfo?.rate.orZero().format { percent() },
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun Yield.Validator.getAprTextNeutral() = combinedReference(
|
||||
getRewardTypeLongText(rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
stringReference(" " + rewardInfo?.rate?.orZero().format { percent() }),
|
||||
private fun StakingTarget.getAprTextNeutral() = combinedReference(
|
||||
getRewardTypeLongText(rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
stringReference(" " + rewardInfo?.rate.orZero().format { percent() }),
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.core.ui.format.bigdecimal.percent
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.test.StakingSendDetailsScreenTestTags
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.common.RewardType
|
||||
import com.tangem.features.staking.impl.R
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates.ValidatorState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.utils.getRewardTypeShortText
|
||||
import com.tangem.features.staking.impl.presentation.ui.ValidatorImagePlaceholder
|
||||
|
|
@ -63,20 +64,20 @@ internal fun ValidatorBlock(validatorState: StakingStates.ValidatorState, isClic
|
|||
modifier = Modifier.padding(12.dp),
|
||||
) {
|
||||
InputRowAsyncImage(
|
||||
imageUrl = validatorState.chosenValidator.image.orEmpty(),
|
||||
imageUrl = state.chosenTarget.image.orEmpty(),
|
||||
onImageError = { ValidatorImagePlaceholder() },
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.clip(TangemTheme.shapes.roundedCornersXLarge),
|
||||
)
|
||||
Text(
|
||||
text = validatorState.chosenValidator.name,
|
||||
text = state.chosenTarget.name,
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.primary1,
|
||||
)
|
||||
SpacerWMax()
|
||||
Text(
|
||||
text = validatorState.getInfoTitleNeutral().resolveReference(),
|
||||
text = state.getInfoTitleNeutral().resolveReference(),
|
||||
style = TangemTheme.typography.body1,
|
||||
color = TangemTheme.colors.text.tertiary,
|
||||
)
|
||||
|
|
@ -91,16 +92,16 @@ internal fun ValidatorBlock(validatorState: StakingStates.ValidatorState, isClic
|
|||
@Composable
|
||||
private fun StakingStates.ValidatorState.Data.getInfoTitleColored() = combinedReference(
|
||||
annotatedReference {
|
||||
append(getRewardTypeShortText(chosenValidator.rewardInfo?.type ?: Yield.RewardType.UNKNOWN).resolveReference())
|
||||
append(getRewardTypeShortText(chosenTarget.rewardInfo?.type ?: RewardType.UNKNOWN).resolveReference())
|
||||
appendSpace()
|
||||
appendColored(
|
||||
text = chosenValidator.rewardInfo?.rate.orZero().format { percent() },
|
||||
text = chosenTarget.rewardInfo?.rate.orZero().format { percent() },
|
||||
color = TangemTheme.colors.text.accent,
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
private fun StakingStates.ValidatorState.Data.getInfoTitleNeutral() = combinedReference(
|
||||
getRewardTypeShortText(chosenValidator.rewardInfo?.type ?: Yield.RewardType.UNKNOWN),
|
||||
stringReference(" " + chosenValidator.rewardInfo?.rate?.orZero().format { percent() }),
|
||||
getRewardTypeShortText(chosenTarget.rewardInfo?.type ?: RewardType.UNKNOWN),
|
||||
stringReference(" " + chosenTarget.rewardInfo?.rate.orZero().format { percent() }),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue