Updated on 2026-08-14
This commit is contained in:
commit
652159dbce
316 changed files with 6242 additions and 3084 deletions
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.model.stakekit.NetworkType
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.staking.repositories.StakingActionRepository
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Use case for getting pending actions list.
|
||||
*/
|
||||
class FetchActionsUseCase(
|
||||
private val stakingRepository: StakingRepository,
|
||||
private val stakingActionRepository: StakingActionRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
networkType: NetworkType,
|
||||
stakingActionStatus: StakingActionStatus,
|
||||
): Either<StakingError, Unit> {
|
||||
return Either
|
||||
.catch {
|
||||
val actions = stakingRepository.getActions(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
networkType = networkType,
|
||||
stakingActionStatus = stakingActionStatus,
|
||||
)
|
||||
|
||||
stakingActionRepository.store(userWalletId, cryptoCurrency.id, actions)
|
||||
}
|
||||
.mapLeft { stakingErrorResolver.resolve(it) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.staking.repositories.StakingActionRepository
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/**
|
||||
* Use case for getting pending actions list.
|
||||
*/
|
||||
class GetActionsUseCase(
|
||||
private val stakingActionRepository: StakingActionRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencyId: CryptoCurrency.ID,
|
||||
): EitherFlow<StakingError, List<StakingAction>> {
|
||||
return stakingActionRepository.get(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
).map<List<StakingAction>, Either<StakingError, List<StakingAction>>> { it.right() }
|
||||
.catch { emit(stakingErrorResolver.resolve(it).left()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Use case for getting saved staking pending transactions.
|
||||
*/
|
||||
class GetStakingPendingTransactionsUseCase(
|
||||
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId): Either<StakingError, List<BalanceItem>> {
|
||||
return Either.catch {
|
||||
stakingPendingTransactionRepository.getTransactionsWithBalanceItems(userWalletId).map { it.second }
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +1,85 @@
|
|||
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.action.StakingAction
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionType
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
import java.util.UUID
|
||||
|
||||
class InvalidatePendingTransactionsUseCase(
|
||||
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
balanceItems: List<BalanceItem>,
|
||||
balancesId: Int,
|
||||
processingActions: List<StakingAction>,
|
||||
): Either<StakingError, List<BalanceItem>> {
|
||||
return Either.catch {
|
||||
val (balancesToDisplay, transactionsToRemove) = mergeRealAndPendingTransactions(
|
||||
realData = balanceItems,
|
||||
newBalancesId = balancesId,
|
||||
pendingData = stakingPendingTransactionRepository.getTransactionsWithBalanceItems(userWalletId),
|
||||
val balancesToDisplay = mergeBalancesAndProcessingActions(
|
||||
realBalances = balanceItems,
|
||||
processingActions = processingActions,
|
||||
)
|
||||
|
||||
stakingPendingTransactionRepository.removeTransactions(userWalletId, transactionsToRemove.toSet())
|
||||
|
||||
balancesToDisplay
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun mergeRealAndPendingTransactions(
|
||||
realData: List<BalanceItem>,
|
||||
newBalancesId: Int,
|
||||
pendingData: List<Pair<PendingTransaction, BalanceItem>>,
|
||||
): Pair<List<BalanceItem>, List<PendingTransaction>> {
|
||||
val balances = realData.groupBy { BalanceIdentity(it.groupId, it.type, it.amount, it.date) }
|
||||
.mapValues { it.value.toMutableList() }
|
||||
.toMutableMap()
|
||||
private fun mergeBalancesAndProcessingActions(
|
||||
realBalances: List<BalanceItem>,
|
||||
processingActions: List<StakingAction>,
|
||||
): List<BalanceItem> {
|
||||
val balances = realBalances.toMutableList()
|
||||
|
||||
val transactionsToRemove = mutableListOf<PendingTransaction>()
|
||||
|
||||
pendingData.forEach { (pendingTransaction, balanceItem) ->
|
||||
val key = BalanceIdentity(balanceItem.groupId, balanceItem.type, balanceItem.amount, balanceItem.date)
|
||||
val oldBalancesId = pendingTransaction.balancesId
|
||||
|
||||
when {
|
||||
newBalancesId != oldBalancesId -> {
|
||||
transactionsToRemove.add(pendingTransaction)
|
||||
processingActions.forEach { action ->
|
||||
when (action.type) {
|
||||
StakingActionType.STAKE, StakingActionType.VOTE, StakingActionType.VOTE_LOCKED -> {
|
||||
processEnterAction(balances, action)
|
||||
}
|
||||
balances.containsKey(key) -> {
|
||||
val removed = balances[key]?.removeIf { !it.isPending } ?: false
|
||||
if (removed) {
|
||||
balances[key]?.add(balanceItem)
|
||||
}
|
||||
StakingActionType.WITHDRAW -> {
|
||||
modifyBalancesByStatus(balances, action, BalanceType.UNSTAKED)
|
||||
}
|
||||
StakingActionType.UNLOCK_LOCKED -> {
|
||||
modifyBalancesByStatus(balances, action, BalanceType.LOCKED)
|
||||
}
|
||||
StakingActionType.UNSTAKE -> {
|
||||
modifyBalancesByStatus(balances, action, BalanceType.STAKED)
|
||||
}
|
||||
else -> {
|
||||
val groupId = UUID.randomUUID().toString()
|
||||
val now = DateTime.now()
|
||||
|
||||
balances[BalanceIdentity(groupId, BalanceType.STAKED, pendingTransaction.amount, now)] =
|
||||
mutableListOf(
|
||||
BalanceItem(
|
||||
groupId = groupId,
|
||||
type = pendingTransaction.type,
|
||||
amount = pendingTransaction.amount,
|
||||
rawCurrencyId = pendingTransaction.rawCurrencyId,
|
||||
validatorAddress = pendingTransaction.validator?.address,
|
||||
date = null,
|
||||
pendingActions = emptyList(),
|
||||
token = pendingTransaction.token,
|
||||
isPending = true,
|
||||
),
|
||||
)
|
||||
|
||||
balances.entries.find {
|
||||
it.key.type == BalanceType.STAKED &&
|
||||
it.key.amount == pendingTransaction.amount &&
|
||||
!it.value.any { it.isPending }
|
||||
}
|
||||
?.key
|
||||
?.let { balances.remove(it) }
|
||||
// intentionally do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return balances.values.flatten() to transactionsToRemove
|
||||
return balances
|
||||
}
|
||||
|
||||
private data class BalanceIdentity(
|
||||
val groupId: String,
|
||||
val type: BalanceType,
|
||||
val amount: BigDecimal,
|
||||
val date: DateTime?,
|
||||
)
|
||||
private fun processEnterAction(balances: MutableList<BalanceItem>, action: StakingAction) {
|
||||
balances.add(
|
||||
BalanceItem(
|
||||
groupId = UUID.randomUUID().toString(),
|
||||
token = balances[0].token,
|
||||
type = BalanceType.STAKED,
|
||||
amount = action.amount,
|
||||
rawCurrencyId = null,
|
||||
validatorAddress = action.validatorAddress ?: action.validatorAddresses?.get(0) ?: "",
|
||||
date = null,
|
||||
pendingActions = emptyList(),
|
||||
isPending = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun modifyBalancesByStatus(balances: MutableList<BalanceItem>, action: StakingAction, type: BalanceType) {
|
||||
val index = balances.indexOfFirst {
|
||||
!it.isPending && it.amount == action.amount && it.type == type
|
||||
}
|
||||
|
||||
if (index != -1) {
|
||||
balances[index] = balances[index].copy(isPending = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
import com.tangem.domain.staking.repositories.StakingErrorResolver
|
||||
import com.tangem.domain.staking.repositories.StakingPendingTransactionRepository
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
/**
|
||||
* Use case for saving hash that failed to submit during staking confirmation
|
||||
*/
|
||||
class SavePendingTransactionUseCase(
|
||||
private val stakingPendingTransactionRepository: StakingPendingTransactionRepository,
|
||||
private val stakingErrorResolver: StakingErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId, transaction: PendingTransaction): Either<StakingError, Unit> {
|
||||
return Either.catch {
|
||||
stakingPendingTransactionRepository.saveTransaction(
|
||||
userWalletId = userWalletId,
|
||||
transaction = transaction,
|
||||
)
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.staking.repositories
|
||||
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface StakingActionRepository {
|
||||
|
||||
suspend fun store(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID, actions: List<StakingAction>)
|
||||
|
||||
fun get(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID): Flow<List<StakingAction>>
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
package com.tangem.domain.staking.repositories
|
||||
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
|
||||
interface StakingPendingTransactionRepository {
|
||||
|
||||
fun getTransactionsWithBalanceItems(userWalletId: UserWalletId): List<Pair<PendingTransaction, BalanceItem>>
|
||||
|
||||
fun saveTransaction(userWalletId: UserWalletId, transaction: PendingTransaction)
|
||||
|
||||
fun removeTransactions(userWalletId: UserWalletId, transactions: Set<PendingTransaction>)
|
||||
}
|
||||
|
|
@ -3,14 +3,15 @@ package com.tangem.domain.staking.repositories
|
|||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.core.lce.LceFlow
|
||||
import com.tangem.domain.staking.model.StakingApproval
|
||||
import com.tangem.domain.staking.model.StakingAvailability
|
||||
import com.tangem.domain.staking.model.StakingEntryInfo
|
||||
import com.tangem.domain.staking.model.stakekit.NetworkType
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceList
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingAction
|
||||
import com.tangem.domain.staking.model.stakekit.action.StakingActionStatus
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.ActionParams
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingGasEstimate
|
||||
import com.tangem.domain.staking.model.stakekit.transaction.StakingTransaction
|
||||
|
|
@ -34,6 +35,13 @@ interface StakingRepository {
|
|||
|
||||
fun getStakingAvailability(userWalletId: UserWalletId, cryptoCurrency: CryptoCurrency): StakingAvailability
|
||||
|
||||
suspend fun getActions(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
networkType: NetworkType,
|
||||
stakingActionStatus: StakingActionStatus,
|
||||
): List<StakingAction>
|
||||
|
||||
suspend fun fetchSingleYieldBalance(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
|
|
@ -50,16 +58,11 @@ interface StakingRepository {
|
|||
refresh: Boolean = false,
|
||||
)
|
||||
|
||||
fun getMultiYieldBalanceFlow(
|
||||
fun getMultiYieldBalanceUpdates(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Flow<YieldBalanceList>
|
||||
|
||||
fun getMultiYieldBalanceLce(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): LceFlow<Throwable, YieldBalanceList>
|
||||
|
||||
suspend fun getMultiYieldBalanceSync(
|
||||
userWalletId: UserWalletId,
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue