Updated on 2026-08-14
This commit is contained in:
parent
0f9a5e4dad
commit
3f17293336
14 changed files with 121 additions and 81 deletions
|
|
@ -10,8 +10,8 @@ internal object PendingTransactionItemConverter : Converter<PendingTransaction,
|
|||
override fun convert(value: PendingTransaction): BalanceItem? {
|
||||
return BalanceItem(
|
||||
groupId = value.groupId ?: return null,
|
||||
type = value.type ?: return null,
|
||||
amount = value.amount ?: return null,
|
||||
type = value.type,
|
||||
amount = value.amount,
|
||||
rawCurrencyId = value.rawCurrencyId,
|
||||
validatorAddress = value.validator?.address,
|
||||
date = DateTime.now(),
|
||||
|
|
|
|||
|
|
@ -11,9 +11,10 @@ android {
|
|||
|
||||
dependencies {
|
||||
api(projects.domain.staking.models)
|
||||
|
||||
api(projects.domain.core)
|
||||
|
||||
implementation(deps.kotlin.serialization)
|
||||
implementation(deps.jodatime)
|
||||
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.wallets.models)
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import java.math.BigDecimal
|
|||
|
||||
data class PendingTransaction(
|
||||
val groupId: String?,
|
||||
val type: BalanceType?,
|
||||
val amount: BigDecimal?,
|
||||
val type: BalanceType,
|
||||
val amount: BigDecimal,
|
||||
val rawCurrencyId: String?,
|
||||
val validator: Yield.Validator?,
|
||||
val balancesId: Int,
|
||||
)
|
||||
|
|
@ -1,14 +1,7 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class SubmitHashData(
|
||||
val transactionHash: String,
|
||||
val transactionId: String,
|
||||
val validator: Yield.Validator?,
|
||||
val amount: BigDecimal?,
|
||||
val balanceType: BalanceType?,
|
||||
val rawCurrencyId: String?,
|
||||
val pendingTransaction: PendingTransaction,
|
||||
)
|
||||
|
|
@ -32,6 +32,11 @@ sealed class YieldBalance {
|
|||
.distinctBy { it.validatorAddress }
|
||||
.size
|
||||
}
|
||||
|
||||
fun getBalancesUniqueId(): Int {
|
||||
// need to exclude rewards because their amount may change frequently
|
||||
return balance.items.filter { it.type != BalanceType.REWARDS }.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
data object Empty : YieldBalance()
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package com.tangem.domain.staking
|
|||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
|
||||
import java.util.UUID
|
||||
|
||||
class InvalidatePendingTransactionsUseCase(
|
||||
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
|
||||
|
|
@ -17,7 +19,7 @@ class InvalidatePendingTransactionsUseCase(
|
|||
return Either.catch {
|
||||
if (yieldBalance is YieldBalance.Data) {
|
||||
val (balancesToDisplay, transactionsToRemove) = mergeRealAndPendingTransactions(
|
||||
real = yieldBalance.balance.items,
|
||||
yieldBalance = yieldBalance,
|
||||
pending = stakingPendingTransactionRepository.getTransactionsWithBalanceItems(),
|
||||
)
|
||||
|
||||
|
|
@ -33,22 +35,41 @@ class InvalidatePendingTransactionsUseCase(
|
|||
}
|
||||
|
||||
private fun mergeRealAndPendingTransactions(
|
||||
real: List<BalanceItem>,
|
||||
yieldBalance: YieldBalance.Data,
|
||||
pending: List<Pair<PendingTransaction, BalanceItem>>,
|
||||
): Pair<List<BalanceItem>, List<PendingTransaction>> {
|
||||
val map = real.associateBy { Triple(it.groupId, it.type, it.amount) }.toMutableMap()
|
||||
val balances = yieldBalance.balance.items.associateBy { Triple(it.groupId, it.type, it.amount) }.toMutableMap()
|
||||
val newBalancesId = yieldBalance.getBalancesUniqueId()
|
||||
|
||||
val toRemove = mutableListOf<PendingTransaction>()
|
||||
val transactionsToRemove = mutableListOf<PendingTransaction>()
|
||||
|
||||
pending.forEach { (pendingTransaction, balanceItem) ->
|
||||
val key = Triple(balanceItem.groupId, balanceItem.type, balanceItem.amount)
|
||||
if (map.containsKey(key)) {
|
||||
map[key] = balanceItem
|
||||
} else {
|
||||
toRemove.add(pendingTransaction)
|
||||
val oldBalancesId = pendingTransaction.balancesId
|
||||
|
||||
when {
|
||||
newBalancesId != oldBalancesId -> {
|
||||
transactionsToRemove.add(pendingTransaction)
|
||||
}
|
||||
balances.containsKey(key) -> {
|
||||
balances[key] = balanceItem
|
||||
}
|
||||
else -> {
|
||||
val groupId = UUID.randomUUID().toString()
|
||||
balances[Triple(groupId, BalanceType.STAKED, pendingTransaction.amount)] = BalanceItem(
|
||||
groupId = groupId,
|
||||
type = pendingTransaction.type,
|
||||
amount = pendingTransaction.amount,
|
||||
rawCurrencyId = pendingTransaction.rawCurrencyId,
|
||||
validatorAddress = pendingTransaction.validator?.address,
|
||||
date = null,
|
||||
pendingActions = emptyList(),
|
||||
isPending = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map.values.toList() to toRemove
|
||||
return balances.values.toList() to transactionsToRemove
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.ui.components.list.RoundedListWithDividersItemData
|
|||
import com.tangem.core.ui.event.StateEvent
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.core.ui.pullToRefresh.PullToRefreshConfig
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.PendingAction
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionCommonType
|
||||
import com.tangem.features.staking.impl.presentation.state.bottomsheet.InfoType
|
||||
|
|
@ -98,7 +99,7 @@ internal sealed class StakingStates {
|
|||
val transactionDoneState: TransactionDoneState,
|
||||
val isApprovalNeeded: Boolean,
|
||||
val reduceAmountBy: BigDecimal?,
|
||||
val balanceState: BalanceState?,
|
||||
val possiblePendingTransaction: PendingTransaction?,
|
||||
) : ConfirmationState()
|
||||
|
||||
data class Empty(
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
|
|||
import com.tangem.domain.staking.*
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.SubmitHashData
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.PendingAction
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
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
|
||||
|
|
@ -35,6 +32,7 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class StakingTransactionSender @AssistedInject constructor(
|
||||
|
|
@ -91,12 +89,16 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
|
||||
sendStakingTransaction(
|
||||
fullTransactionsData = fullTransactionsData,
|
||||
balanceState = confirmationState.balanceState,
|
||||
possiblePendingTransaction = composePendingTransaction(confirmationState),
|
||||
onSendSuccess = onSendSuccess,
|
||||
onSendError = onSendError,
|
||||
)
|
||||
}
|
||||
|
||||
private fun composePendingTransaction(confirmationState: StakingStates.ConfirmationState.Data): PendingTransaction {
|
||||
return confirmationState.possiblePendingTransaction ?: composeStakeTransaction(confirmationState)
|
||||
}
|
||||
|
||||
private suspend fun getStakingTransactions(
|
||||
state: StakingUiState,
|
||||
confirmationState: StakingStates.ConfirmationState.Data,
|
||||
|
|
@ -204,7 +206,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
|
||||
private suspend fun sendStakingTransaction(
|
||||
fullTransactionsData: List<FullTransactionData>,
|
||||
balanceState: BalanceState?,
|
||||
possiblePendingTransaction: PendingTransaction,
|
||||
onSendSuccess: (txUrl: String) -> Unit,
|
||||
onSendError: (SendTransactionError?) -> Unit,
|
||||
) {
|
||||
|
|
@ -218,13 +220,9 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
},
|
||||
ifRight = { transactionHashes ->
|
||||
submitHash(
|
||||
transactionIds = fullTransactionsData.map { it.stakeKitTransaction.id },
|
||||
transactions = fullTransactionsData.map { it.stakeKitTransaction },
|
||||
transactionHashes = transactionHashes,
|
||||
groupId = balanceState?.groupId,
|
||||
validator = balanceState?.validator,
|
||||
amount = balanceState?.cryptoDecimal,
|
||||
balanceType = balanceState?.type,
|
||||
rawCurrencyId = balanceState?.rawCurrencyId,
|
||||
pendingTransaction = possiblePendingTransaction,
|
||||
)
|
||||
val txUrl = getExplorerTransactionUrlUseCase(
|
||||
txHash = transactionHashes.last(),
|
||||
|
|
@ -238,25 +236,18 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
}
|
||||
|
||||
private suspend fun submitHash(
|
||||
transactionIds: List<String>,
|
||||
transactions: List<StakingTransaction>,
|
||||
transactionHashes: List<String>,
|
||||
groupId: String?,
|
||||
validator: Yield.Validator?,
|
||||
amount: BigDecimal?,
|
||||
balanceType: BalanceType?,
|
||||
rawCurrencyId: String?,
|
||||
pendingTransaction: PendingTransaction,
|
||||
) {
|
||||
transactionIds
|
||||
transactions
|
||||
.zip(transactionHashes)
|
||||
.forEach { (transactionId, transactionHash) ->
|
||||
.forEach { (transaction, transactionHash) ->
|
||||
submitHashUseCase(
|
||||
SubmitHashData(
|
||||
transactionId = transactionId,
|
||||
transactionId = transaction.id,
|
||||
transactionHash = transactionHash,
|
||||
validator = validator,
|
||||
amount = amount,
|
||||
balanceType = balanceType,
|
||||
rawCurrencyId = rawCurrencyId,
|
||||
pendingTransaction = pendingTransaction,
|
||||
),
|
||||
)
|
||||
.onLeft { error ->
|
||||
|
|
@ -267,20 +258,14 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
),
|
||||
)
|
||||
saveUnsubmittedHashUseCase.invoke(
|
||||
transactionId = transactionId,
|
||||
transactionId = transaction.id,
|
||||
transactionHash = transactionHash,
|
||||
)
|
||||
}.onRight {
|
||||
Timber.d("Successful hash submission")
|
||||
savePendingTransactionUseCase.invoke(
|
||||
PendingTransaction(
|
||||
groupId = groupId,
|
||||
type = balanceType,
|
||||
amount = amount,
|
||||
rawCurrencyId = rawCurrencyId,
|
||||
validator = validator,
|
||||
),
|
||||
)
|
||||
if (transaction.type != StakingTransactionType.FREEZE_ENERGY) {
|
||||
savePendingTransactionUseCase.invoke(pendingTransaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,6 +284,19 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun composeStakeTransaction(confirmationState: StakingStates.ConfirmationState.Data): PendingTransaction {
|
||||
val state = stateController.value
|
||||
|
||||
return PendingTransaction(
|
||||
groupId = UUID.randomUUID().toString(),
|
||||
type = BalanceType.STAKED,
|
||||
amount = (state.amountState as? AmountState.Data)?.amountTextField?.cryptoAmount?.value ?: BigDecimal.ZERO,
|
||||
rawCurrencyId = cryptoCurrencyStatus.currency.id.rawCurrencyId,
|
||||
validator = (confirmationState.validatorState as? ValidatorState.Content)?.chosenValidator,
|
||||
balancesId = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.getBalancesUniqueId() ?: 0,
|
||||
)
|
||||
}
|
||||
|
||||
private data class FullTransactionData(
|
||||
val stakeKitTransaction: StakingTransaction,
|
||||
val tangemTransaction: TransactionData.Compiled,
|
||||
|
|
|
|||
|
|
@ -93,6 +93,6 @@ internal object ConfirmationStatePreviewData {
|
|||
isApprovalNeeded = false,
|
||||
reduceAmountBy = null,
|
||||
pendingActions = null,
|
||||
balanceState = null,
|
||||
possiblePendingTransaction = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetBalanceStateTransformer(
|
||||
private val balanceState: BalanceState? = null,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val possibleConfirmationState = prevState.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
?: return prevState
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = possibleConfirmationState.copy(balanceState = balanceState),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ internal class SetConfirmationStateLoadingTransformer(
|
|||
pendingActions = possibleConfirmationState?.pendingActions,
|
||||
isApprovalNeeded = false,
|
||||
reduceAmountBy = null,
|
||||
balanceState = null,
|
||||
possiblePendingTransaction = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ internal class SetInitialDataStateTransformer(
|
|||
pendingActions = null,
|
||||
isApprovalNeeded = isApprovalNeeded,
|
||||
reduceAmountBy = null,
|
||||
balanceState = null,
|
||||
possiblePendingTransaction = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetPossiblePendingTransactionTransformer(
|
||||
private val balanceState: BalanceState,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
||||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val possibleConfirmationState =
|
||||
prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||
|
||||
val balancesId = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.getBalancesUniqueId() ?: 0
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = possibleConfirmationState.copy(
|
||||
possiblePendingTransaction = PendingTransaction(
|
||||
groupId = balanceState.groupId,
|
||||
type = balanceState.type,
|
||||
amount = balanceState.cryptoDecimal,
|
||||
rawCurrencyId = balanceState.rawCurrencyId,
|
||||
validator = balanceState.validator,
|
||||
balancesId = balancesId,
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -219,12 +219,17 @@ internal class StakingViewModel @Inject constructor(
|
|||
when {
|
||||
isInitState() -> {
|
||||
stateController.update(SetConfirmationStateLoadingTransformer(yield, appCurrency))
|
||||
stateController.update(SetBalanceStateTransformer(balanceState))
|
||||
if (balanceState != null) {
|
||||
stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
|
||||
}
|
||||
|
||||
onRefreshSwipe(isRefreshing = false)
|
||||
}
|
||||
isAssentState() -> {
|
||||
getFee(pendingAction, pendingActions)
|
||||
stateController.update(SetBalanceStateTransformer(balanceState))
|
||||
if (balanceState != null) {
|
||||
stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
|
||||
}
|
||||
val amountState = value.amountState as? AmountState.Data
|
||||
if (amountState?.amountTextField?.isWarning == true) {
|
||||
stateController.update(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue