Updated on 2026-08-14
This commit is contained in:
commit
1a1bf8a43b
10 changed files with 81 additions and 51 deletions
|
|
@ -21,7 +21,7 @@ class GetSupportedNetworksUseCase(
|
|||
|
||||
ensureNotNull(networks.takeIf { it.isNotEmpty() }) {
|
||||
SupportedBlockchainException.EmptyList
|
||||
}
|
||||
}.sortedBy(Network::name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,20 @@
|
|||
package com.tangem.domain.staking.model.stakekit.action
|
||||
|
||||
enum class StakingActionType {
|
||||
STAKE,
|
||||
UNSTAKE,
|
||||
CLAIM_REWARDS,
|
||||
RESTAKE_REWARDS,
|
||||
WITHDRAW,
|
||||
RESTAKE,
|
||||
CLAIM_UNSTAKED,
|
||||
UNLOCK_LOCKED,
|
||||
STAKE_LOCKED,
|
||||
VOTE,
|
||||
REVOKE,
|
||||
VOTE_LOCKED,
|
||||
REVOTE,
|
||||
REBOND,
|
||||
MIGRATE,
|
||||
UNKNOWN,
|
||||
enum class StakingActionType(val type: String) {
|
||||
STAKE("Stake"),
|
||||
UNSTAKE("Unstake"),
|
||||
CLAIM_REWARDS("Claim Rewards"),
|
||||
RESTAKE_REWARDS("Restake Rewards"),
|
||||
WITHDRAW("Withdraw"),
|
||||
RESTAKE("Restake"),
|
||||
CLAIM_UNSTAKED("Claim Unstaked"),
|
||||
UNLOCK_LOCKED("Unlock Locked"),
|
||||
STAKE_LOCKED("Stake Locked"),
|
||||
VOTE("Vote"),
|
||||
REVOKE("Revoke"),
|
||||
VOTE_LOCKED("Vote Locked"),
|
||||
REVOTE("Revote"),
|
||||
REBOND("Rebond"),
|
||||
MIGRATE("Migrate"),
|
||||
UNKNOWN("Unknown"),
|
||||
}
|
||||
|
|
@ -151,13 +151,12 @@ internal class CurrenciesStatusesOperations(
|
|||
val currenciesFlow = combine(
|
||||
getQuotes(currenciesIds),
|
||||
getNetworksStatuses(networks),
|
||||
getYieldBalances(nonEmptyCurrencies),
|
||||
) { maybeQuotes, maybeNetworksStatuses, maybeYieldBalances ->
|
||||
) { maybeQuotes, maybeNetworksStatuses ->
|
||||
createCurrenciesStatuses(
|
||||
currencies = nonEmptyCurrencies,
|
||||
maybeQuotes = maybeQuotes,
|
||||
maybeNetworkStatuses = maybeNetworksStatuses,
|
||||
maybeYieldBalances = maybeYieldBalances,
|
||||
maybeYieldBalances = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -403,15 +402,6 @@ internal class CurrenciesStatusesOperations(
|
|||
.onEmpty { emit(Error.EmptyNetworksStatuses.left()) }
|
||||
}
|
||||
|
||||
private fun getYieldBalances(cryptoCurrencies: List<CryptoCurrency>): Flow<Either<Error, YieldBalanceList>> {
|
||||
return stakingRepository.getMultiYieldBalanceFlow(
|
||||
userWalletId = userWalletId,
|
||||
cryptoCurrencies = cryptoCurrencies,
|
||||
).map<YieldBalanceList, Either<Error, YieldBalanceList>> { it.right() }
|
||||
.catch { emit(Error.DataError(it).left()) }
|
||||
.onEmpty { emit(Error.EmptyYieldBalances.left()) }
|
||||
}
|
||||
|
||||
private suspend fun getYieldBalancesSync(
|
||||
cryptoCurrencies: List<CryptoCurrency>,
|
||||
): Either<Error.EmptyYieldBalances, YieldBalanceList> {
|
||||
|
|
|
|||
|
|
@ -47,18 +47,20 @@ internal sealed class StakingAnalyticsEvents(
|
|||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"Validator" to validator,
|
||||
"Action" to action.name,
|
||||
"Action" to action.type,
|
||||
),
|
||||
)
|
||||
|
||||
data class StakeInProgressScreenOpened(
|
||||
val validator: String,
|
||||
val token: String,
|
||||
val action: StakingActionType,
|
||||
) : StakingAnalyticsEvents(
|
||||
event = "Stake In Progress Screen Opened",
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"Validator" to validator,
|
||||
"Action" to action.type,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -136,9 +138,13 @@ internal sealed class StakingAnalyticsEvents(
|
|||
|
||||
data class StakingError(
|
||||
val token: String,
|
||||
val errorType: String,
|
||||
) : StakingAnalyticsEvents(
|
||||
event = "Errors",
|
||||
params = mapOf(AnalyticsParam.TOKEN_PARAM to token),
|
||||
params = mapOf(
|
||||
AnalyticsParam.TOKEN_PARAM to token,
|
||||
"ErrorType" to errorType,
|
||||
),
|
||||
)
|
||||
|
||||
data class TransactionError(
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ internal class StakingAnalyticSender(
|
|||
StakingAnalyticsEvents.StakeInProgressScreenOpened(
|
||||
validator = validatorName,
|
||||
token = value.cryptoCurrencySymbol,
|
||||
action = getStakingActionType(value),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,9 +49,10 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
suspend fun getFee(
|
||||
pendingAction: PendingAction?,
|
||||
pendingActions: ImmutableList<PendingAction>?,
|
||||
onFeeError: (GetFeeError) -> Unit,
|
||||
onStakingFee: (Fee) -> Unit,
|
||||
onStakingFeeError: (StakingError) -> Unit,
|
||||
onApprovalFee: (TransactionFee) -> Unit,
|
||||
onFeeError: (GetFeeError) -> Unit,
|
||||
) {
|
||||
val state = stateController.value
|
||||
val confirmationState = state.confirmationState as? StakingStates.ConfirmationState.Data
|
||||
|
|
@ -85,7 +86,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
pendingActions = pendingActions,
|
||||
amount = amount,
|
||||
validatorAddress = validatorAddress,
|
||||
onFeeError = onFeeError,
|
||||
onStakingFeeError = onStakingFeeError,
|
||||
onStakingFee = onStakingFee,
|
||||
)
|
||||
}
|
||||
|
|
@ -95,7 +96,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
pendingActions = pendingActions,
|
||||
amount = amount,
|
||||
validatorAddress = validatorAddress,
|
||||
onFeeError = onFeeError,
|
||||
onStakingFeeError = onStakingFeeError,
|
||||
onStakingFee = onStakingFee,
|
||||
)
|
||||
}
|
||||
|
|
@ -106,7 +107,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
pendingActions: ImmutableList<PendingAction>?,
|
||||
amount: BigDecimal,
|
||||
validatorAddress: String,
|
||||
onFeeError: (GetFeeError) -> Unit,
|
||||
onStakingFeeError: (StakingError) -> Unit,
|
||||
onStakingFee: (Fee) -> Unit,
|
||||
) {
|
||||
val sourceAddress = cryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value
|
||||
|
|
@ -125,7 +126,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
action = action,
|
||||
)
|
||||
}.getOrElse {
|
||||
onFeeError(GetFeeError.DataError(Throwable(it.toString())))
|
||||
onStakingFeeError(it)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -133,7 +134,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
}
|
||||
|
||||
if (result.isNullOrEmpty()) {
|
||||
onFeeError(GetFeeError.UnknownError)
|
||||
onStakingFeeError(StakingError.UnknownError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +152,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
validatorAddress = validatorAddress,
|
||||
action = pendingAction,
|
||||
).getOrElse {
|
||||
onFeeError(GetFeeError.DataError(Throwable(it.toString())))
|
||||
onStakingFeeError(it)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ 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.CryptoCurrencyStatus
|
||||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
|
|
@ -130,7 +131,10 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
fee: Fee,
|
||||
onConstructError: (StakingError) -> Unit,
|
||||
) = coroutineScope {
|
||||
stakingTransactions?.filterNot { it.type == StakingTransactionType.APPROVAL }
|
||||
stakingTransactions
|
||||
?.filterNot {
|
||||
it.type == StakingTransactionType.APPROVAL || it.status == StakingTransactionStatus.SKIPPED
|
||||
}
|
||||
?.map { transaction ->
|
||||
async {
|
||||
getConstructedStakingTransactionUseCase(
|
||||
|
|
@ -150,7 +154,9 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
},
|
||||
)
|
||||
}
|
||||
}?.awaitAll()?.filterNotNull()
|
||||
}
|
||||
?.awaitAll()
|
||||
?.filterNotNull()
|
||||
}
|
||||
|
||||
private suspend fun getStakingTransaction(
|
||||
|
|
@ -185,7 +191,12 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
type = action?.type,
|
||||
),
|
||||
).getOrElse {
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(state.cryptoCurrencyName))
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingError(
|
||||
token = state.cryptoCurrencyName,
|
||||
errorType = it.javaClass.simpleName,
|
||||
),
|
||||
)
|
||||
onConstructError(it)
|
||||
return emptyList()
|
||||
}
|
||||
|
|
@ -248,9 +259,12 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
rawCurrencyId = rawCurrencyId,
|
||||
),
|
||||
)
|
||||
.onLeft {
|
||||
.onLeft { error ->
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingError(stateController.value.cryptoCurrencyName),
|
||||
StakingAnalyticsEvents.StakingError(
|
||||
token = stateController.value.cryptoCurrencyName,
|
||||
errorType = error.javaClass.simpleName,
|
||||
),
|
||||
)
|
||||
saveUnsubmittedHashUseCase.invoke(
|
||||
transactionId = transactionId,
|
||||
|
|
|
|||
|
|
@ -81,11 +81,11 @@ internal class AddStakingNotificationsTransformer(
|
|||
amountValue = amountValue,
|
||||
feeValue = feeValue,
|
||||
reduceAmountBy = reduceAmountBy,
|
||||
)
|
||||
).max(minimumRequirement)
|
||||
} else {
|
||||
// No amount is taken from account balance on exit or pending actions
|
||||
BigDecimal.ZERO
|
||||
}.max(minimumRequirement)
|
||||
}
|
||||
|
||||
val notifications = buildList {
|
||||
// errors
|
||||
|
|
|
|||
|
|
@ -32,5 +32,5 @@ internal fun StakingActionType?.getPendingActionTitle(): TextReference = when (t
|
|||
internal fun isSolanaWithdraw(networkId: String, pendingActions: ImmutableList<PendingAction>?): Boolean {
|
||||
val isSolana = isSolana(networkId)
|
||||
val isWithdraw = pendingActions?.all { it.type == StakingActionType.WITHDRAW } == true
|
||||
return isSolana && isWithdraw
|
||||
return isSolana && isWithdraw && !pendingActions.isNullOrEmpty()
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
package com.tangem.features.staking.impl.presentation.viewmodel
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.lifecycle.*
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import arrow.core.getOrElse
|
||||
import com.tangem.blockchain.common.transaction.TransactionFee
|
||||
import com.tangem.common.routing.AppRoute
|
||||
|
|
@ -256,8 +259,18 @@ internal class StakingViewModel @Inject constructor(
|
|||
)
|
||||
updateNotifications()
|
||||
},
|
||||
onStakingFeeError = { error ->
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingError(
|
||||
value.cryptoCurrencyName,
|
||||
error.javaClass.simpleName,
|
||||
),
|
||||
)
|
||||
stateController.update(AddStakingErrorTransformer())
|
||||
updateNotifications(GetFeeError.UnknownError)
|
||||
},
|
||||
onFeeError = { error ->
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencyName))
|
||||
stateController.update(AddStakingErrorTransformer())
|
||||
updateNotifications(error)
|
||||
},
|
||||
|
|
@ -285,7 +298,12 @@ internal class StakingViewModel @Inject constructor(
|
|||
},
|
||||
onConstructError = { error ->
|
||||
Timber.e(error.toString())
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
|
||||
analyticsEventHandler.send(
|
||||
StakingAnalyticsEvents.StakingError(
|
||||
token = value.cryptoCurrencyName,
|
||||
errorType = error.javaClass.simpleName,
|
||||
),
|
||||
)
|
||||
stakingEventFactory.createStakingErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
|
|
@ -296,7 +314,7 @@ internal class StakingViewModel @Inject constructor(
|
|||
},
|
||||
onSendError = { error ->
|
||||
Timber.e(error.toString())
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.StakingError(value.cryptoCurrencyName))
|
||||
analyticsEventHandler.send(StakingAnalyticsEvents.TransactionError(value.cryptoCurrencyName))
|
||||
stakingEventFactory.createSendTransactionErrorAlert(error)
|
||||
stateController.update(SetConfirmationStateResetAssentTransformer)
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue