Updated on 2026-08-14
This commit is contained in:
parent
a88572a019
commit
22ba475aae
18 changed files with 80 additions and 17 deletions
|
|
@ -4,12 +4,14 @@ import android.util.Base64
|
|||
import arrow.core.getOrElse
|
||||
import arrow.core.raise.catch
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||
import com.tangem.blockchainsdk.utils.toCoinId
|
||||
import com.tangem.blockchainsdk.utils.toMigratedCointId
|
||||
import com.tangem.common.extensions.hexToBytes
|
||||
import com.tangem.common.extensions.toCompressedPublicKey
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
|
|
@ -269,6 +271,7 @@ internal class DefaultStakingRepository(
|
|||
override suspend fun constructTransaction(
|
||||
networkId: String,
|
||||
fee: Fee,
|
||||
amount: Amount,
|
||||
transactionId: String,
|
||||
): Pair<StakingTransaction, TransactionData.Compiled> {
|
||||
return withContext(dispatchers.io) {
|
||||
|
|
@ -282,6 +285,7 @@ internal class DefaultStakingRepository(
|
|||
val transactionData = TransactionData.Compiled(
|
||||
value = getTransactionDataType(networkId, unsignedTransaction),
|
||||
fee = fee,
|
||||
amount = amount,
|
||||
status = TransactionStatus.Unconfirmed,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ internal object PendingTransactionItemConverter : Converter<PendingTransaction,
|
|||
override fun convert(value: PendingTransaction): BalanceItem? {
|
||||
return BalanceItem(
|
||||
groupId = value.groupId ?: return null,
|
||||
token = value.token,
|
||||
type = value.type,
|
||||
amount = value.amount,
|
||||
rawCurrencyId = value.rawCurrencyId,
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@ package com.tangem.data.staking.converters
|
|||
|
||||
import com.tangem.data.staking.converters.action.PendingActionConverter
|
||||
import com.tangem.datasource.api.stakekit.models.response.model.YieldBalanceWrapperDTO
|
||||
import com.tangem.domain.staking.model.stakekit.*
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceItem
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalance
|
||||
import com.tangem.domain.staking.model.stakekit.YieldBalanceItem
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class YieldBalanceConverter : Converter<YieldBalanceWrapperDTO, YieldBalance> {
|
||||
|
||||
private val pendingActionConverter by lazy(LazyThreadSafetyMode.NONE) { PendingActionConverter() }
|
||||
|
||||
private val networkTypeConverter by lazy(LazyThreadSafetyMode.NONE) { StakingNetworkTypeConverter() }
|
||||
private val tokenConverter by lazy(LazyThreadSafetyMode.NONE) { TokenConverter(networkTypeConverter) }
|
||||
override fun convert(value: YieldBalanceWrapperDTO): YieldBalance {
|
||||
return if (value.balances.isEmpty()) {
|
||||
YieldBalance.Empty
|
||||
|
|
@ -19,6 +23,7 @@ internal class YieldBalanceConverter : Converter<YieldBalanceWrapperDTO, YieldBa
|
|||
items = value.balances.map { item ->
|
||||
BalanceItem(
|
||||
groupId = item.groupId,
|
||||
token = tokenConverter.convert(item.tokenDTO),
|
||||
type = BalanceType.valueOf(item.type.name),
|
||||
amount = item.amount,
|
||||
rawCurrencyId = item.tokenDTO.coinGeckoId,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
package com.tangem.domain.staking.model
|
||||
|
||||
import com.tangem.domain.staking.model.stakekit.BalanceType
|
||||
import com.tangem.domain.staking.model.stakekit.Token
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class PendingTransaction(
|
||||
val groupId: String?,
|
||||
val token: Token,
|
||||
val type: BalanceType,
|
||||
val amount: BigDecimal,
|
||||
val rawCurrencyId: String?,
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ data class Yield(
|
|||
APR, // simple rate
|
||||
UNKNOWN,
|
||||
}
|
||||
|
||||
fun getCurrentToken(rawCurrencyId: String?) = tokens.firstOrNull { rawCurrencyId == it.coinGeckoId } ?: token
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ data class YieldBalanceItem(
|
|||
|
||||
data class BalanceItem(
|
||||
val groupId: String,
|
||||
val token: Token,
|
||||
val type: BalanceType,
|
||||
val amount: BigDecimal,
|
||||
val rawCurrencyId: String?,
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ sealed class YieldBalanceList {
|
|||
val data = yieldBalance as? YieldBalance.Data
|
||||
val balance = data?.balance
|
||||
|
||||
val isCorrectAddress = balance?.items?.any { address == data.address } == true
|
||||
val isCorrectIntegration = balance?.integrationId == integrationId
|
||||
val isCorrectAddress = address != null && address == data?.address
|
||||
val isCorrectIntegration = integrationId != null && balance?.integrationId == integrationId
|
||||
|
||||
isCorrectIntegration && isCorrectAddress
|
||||
} ?: YieldBalance.Error
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.staking
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
import com.tangem.domain.staking.model.stakekit.StakingError
|
||||
|
|
@ -16,9 +17,10 @@ class GetConstructedStakingTransactionUseCase(
|
|||
suspend operator fun invoke(
|
||||
networkId: String,
|
||||
fee: Fee,
|
||||
amount: Amount,
|
||||
transactionId: String,
|
||||
): Either<StakingError, Pair<StakingTransaction, TransactionData.Compiled>> = Either.catch {
|
||||
stakingRepository.constructTransaction(networkId, fee, transactionId)
|
||||
stakingRepository.constructTransaction(networkId, fee, amount, transactionId)
|
||||
}.mapLeft {
|
||||
stakingErrorResolver.resolve(it)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ class InvalidatePendingTransactionsUseCase(
|
|||
validatorAddress = pendingTransaction.validator?.address,
|
||||
date = null,
|
||||
pendingActions = emptyList(),
|
||||
token = pendingTransaction.token,
|
||||
isPending = true,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
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
|
||||
|
|
@ -71,6 +72,7 @@ interface StakingRepository {
|
|||
suspend fun constructTransaction(
|
||||
networkId: String,
|
||||
fee: Fee,
|
||||
amount: Amount,
|
||||
transactionId: String,
|
||||
): Pair<StakingTransaction, TransactionData.Compiled>
|
||||
|
||||
|
|
|
|||
|
|
@ -57,9 +57,20 @@ internal class CurrencyStatusOperations(
|
|||
|
||||
val hasCurrentNetworkTransactions = status.pendingTransactions.isNotEmpty()
|
||||
val currentTransactions = status.pendingTransactions.getOrElse(currency.id, ::emptySet)
|
||||
val isCurrentAddressStaking =
|
||||
(yieldBalance as? YieldBalance.Data)?.address == status.address.defaultAddress.value
|
||||
val currentYieldBalance = yieldBalance.takeIf { isCurrentAddressStaking }
|
||||
val yieldBalanceData = yieldBalance as? YieldBalance.Data
|
||||
val isCurrentAddressStaking = yieldBalanceData?.address == status.address.defaultAddress.value
|
||||
val filteredTokenBalances = yieldBalanceData?.balance?.items?.filter {
|
||||
it.token.coinGeckoId == currency.id.rawCurrencyId
|
||||
}
|
||||
val currentYieldBalance = if (isCurrentAddressStaking && filteredTokenBalances?.isNotEmpty() == true) {
|
||||
yieldBalanceData.copy(
|
||||
balance = yieldBalanceData.balance.copy(
|
||||
items = filteredTokenBalances,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return when {
|
||||
ignoreQuote -> CryptoCurrencyStatus.NoQuote(
|
||||
amount = amount,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.tokens.repository
|
||||
|
||||
import com.tangem.blockchain.common.Amount
|
||||
import com.tangem.blockchain.common.TransactionData
|
||||
import com.tangem.blockchain.common.TransactionStatus
|
||||
import com.tangem.blockchain.common.transaction.Fee
|
||||
|
|
@ -217,6 +218,7 @@ class MockStakingRepository : StakingRepository {
|
|||
override suspend fun constructTransaction(
|
||||
networkId: String,
|
||||
fee: Fee,
|
||||
amount: Amount,
|
||||
transactionId: String,
|
||||
): Pair<StakingTransaction, TransactionData.Compiled> = StakingTransaction(
|
||||
id = "id",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import com.tangem.domain.staking.model.StakingApproval
|
|||
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.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.CryptoCurrencyStatus
|
||||
|
|
@ -66,7 +67,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
val validatorAddress = validatorState.chosenValidator.address
|
||||
|
||||
val approval = stakingApproval as? StakingApproval.Needed
|
||||
if (approval != null) {
|
||||
if (approval != null && state.actionType == StakingActionCommonType.ENTER) {
|
||||
val allowance = getAllowanceUseCase(
|
||||
userWalletId = userWallet.walletId,
|
||||
cryptoCurrency = cryptoCurrencyStatus.currency,
|
||||
|
|
@ -182,7 +183,7 @@ internal class StakingFeeTransactionLoader @AssistedInject constructor(
|
|||
amount = amount,
|
||||
address = sourceAddress,
|
||||
validatorAddress = validatorAddress,
|
||||
token = yield.token,
|
||||
token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
passthrough = action?.passthrough,
|
||||
type = action?.type,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
|
|||
import com.tangem.domain.transaction.error.SendTransactionError
|
||||
import com.tangem.domain.transaction.usecase.SendTransactionUseCase
|
||||
import com.tangem.domain.txhistory.usecase.GetExplorerTransactionUrlUseCase
|
||||
import com.tangem.domain.utils.convertToSdkAmount
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.features.staking.impl.analytics.StakingAnalyticsEvents
|
||||
import com.tangem.features.staking.impl.presentation.state.*
|
||||
|
|
@ -67,6 +68,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
?: error("No confirmation state")
|
||||
val fee = (confirmationState.feeState as? FeeState.Content)?.fee
|
||||
?: error("No fee provided")
|
||||
val amountState = state.amountState as? AmountState.Data ?: error("No amount state")
|
||||
|
||||
val stakingTransactions = getStakingTransactions(
|
||||
state = state,
|
||||
|
|
@ -77,6 +79,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
val fullTransactionsData = getConstructedTransactions(
|
||||
stakingTransactions = stakingTransactions,
|
||||
fee = fee,
|
||||
amount = amountState.amountTextField.cryptoAmount.value.orZero(),
|
||||
onConstructError = onConstructError,
|
||||
)
|
||||
|
||||
|
|
@ -131,6 +134,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
private suspend fun getConstructedTransactions(
|
||||
stakingTransactions: List<StakingTransaction>?,
|
||||
fee: Fee,
|
||||
amount: BigDecimal,
|
||||
onConstructError: (StakingError) -> Unit,
|
||||
) = coroutineScope {
|
||||
stakingTransactions
|
||||
|
|
@ -142,6 +146,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
getConstructedStakingTransactionUseCase(
|
||||
networkId = cryptoCurrencyStatus.currency.network.id.value,
|
||||
fee = fee,
|
||||
amount = amount.convertToSdkAmount(cryptoCurrencyStatus.currency),
|
||||
transactionId = transaction.id,
|
||||
).fold(
|
||||
ifRight = { (constructedTransaction, transactionData) ->
|
||||
|
|
@ -188,7 +193,7 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
amount = amount,
|
||||
address = defaultAddress,
|
||||
validatorAddress = validatorAddress,
|
||||
token = yield.token,
|
||||
token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId),
|
||||
passthrough = action?.passthrough,
|
||||
type = action?.type,
|
||||
),
|
||||
|
|
@ -287,13 +292,17 @@ internal class StakingTransactionSender @AssistedInject constructor(
|
|||
private fun composeStakeTransaction(confirmationState: StakingStates.ConfirmationState.Data): PendingTransaction {
|
||||
val state = stateController.value
|
||||
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
|
||||
val token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId)
|
||||
|
||||
return PendingTransaction(
|
||||
groupId = UUID.randomUUID().toString(),
|
||||
token = token,
|
||||
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,
|
||||
balancesId = yieldBalance?.getBalancesUniqueId() ?: 0,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
package com.tangem.features.staking.impl.presentation.state.transformers
|
||||
|
||||
import com.tangem.domain.staking.model.PendingTransaction
|
||||
import com.tangem.domain.staking.model.stakekit.Yield
|
||||
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.features.staking.impl.presentation.state.BalanceState
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingStates
|
||||
import com.tangem.features.staking.impl.presentation.state.StakingUiState
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
|
||||
internal class SetPossiblePendingTransactionTransformer(
|
||||
private val yield: Yield,
|
||||
private val balanceState: BalanceState,
|
||||
private val cryptoCurrencyStatus: CryptoCurrencyStatus,
|
||||
) : Transformer<StakingUiState> {
|
||||
|
|
@ -14,13 +18,16 @@ internal class SetPossiblePendingTransactionTransformer(
|
|||
override fun transform(prevState: StakingUiState): StakingUiState {
|
||||
val possibleConfirmationState =
|
||||
prevState.confirmationState as? StakingStates.ConfirmationState.Data ?: return prevState
|
||||
val yieldBalance = cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data
|
||||
|
||||
val balancesId = (cryptoCurrencyStatus.value.yieldBalance as? YieldBalance.Data)?.getBalancesUniqueId() ?: 0
|
||||
val balancesId = yieldBalance?.getBalancesUniqueId() ?: 0
|
||||
val token = yield.getCurrentToken(cryptoCurrencyStatus.currency.id.rawCurrencyId)
|
||||
|
||||
return prevState.copy(
|
||||
confirmationState = possibleConfirmationState.copy(
|
||||
possiblePendingTransaction = PendingTransaction(
|
||||
groupId = balanceState.groupId,
|
||||
token = token,
|
||||
type = balanceState.type,
|
||||
amount = balanceState.cryptoDecimal,
|
||||
rawCurrencyId = balanceState.rawCurrencyId,
|
||||
|
|
|
|||
|
|
@ -232,7 +232,9 @@ internal class StakingViewModel @Inject constructor(
|
|||
),
|
||||
)
|
||||
if (balanceState != null) {
|
||||
stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
|
||||
stateController.update(
|
||||
SetPossiblePendingTransactionTransformer(yield, balanceState, cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
|
||||
stateController.update(
|
||||
|
|
@ -252,7 +254,9 @@ internal class StakingViewModel @Inject constructor(
|
|||
isAssentState() -> {
|
||||
getFee(pendingAction, pendingActions)
|
||||
if (balanceState != null) {
|
||||
stateController.update(SetPossiblePendingTransactionTransformer(balanceState, cryptoCurrencyStatus))
|
||||
stateController.update(
|
||||
SetPossiblePendingTransactionTransformer(yield, balanceState, cryptoCurrencyStatus),
|
||||
)
|
||||
}
|
||||
val amountState = value.amountState as? AmountState.Data
|
||||
if (amountState?.amountTextField?.isWarning == true) {
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ markdownComposeView = "0.5.4"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-816"
|
||||
tangemBlockchainSdk = "develop-817"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-387"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
|
||||
|
|
|
|||
|
|
@ -366,6 +366,15 @@ fun Blockchain.toCoinId(): String {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New CoinId to existing coin "id" field.
|
||||
* To support both old and new coin id.
|
||||
*/
|
||||
fun Blockchain.toMigratedCointId(): String = when (this) {
|
||||
Blockchain.Polygon, Blockchain.PolygonTestnet -> "polygon-ecosystem-token"
|
||||
else -> toCoinId()
|
||||
}
|
||||
|
||||
fun Blockchain.isSupportedInApp(): Boolean {
|
||||
return !excludedBlockchains.contains(this)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue