Updated on 2026-08-14

This commit is contained in:
Tangem 2024-07-16 19:59:07 +05:00
parent 3c8fb7f668
commit ebfa4fed41
8 changed files with 160 additions and 39 deletions

View file

@ -51,12 +51,18 @@ interface StakeKitApi {
@POST("actions/exit")
suspend fun createExitAction(@Body body: ActionRequestBody): ApiResponse<EnterActionResponse>
@POST("actions/pending")
suspend fun createPendingAction(@Body body: PendingActionRequestBody): ApiResponse<EnterActionResponse>
@POST("actions/enter/estimate-gas")
suspend fun estimateGasOnEnter(@Body body: ActionRequestBody): ApiResponse<StakingGasEstimateDTO>
@POST("actions/exit/estimate-gas")
suspend fun estimateGasOnExit(@Body body: ActionRequestBody): ApiResponse<StakingGasEstimateDTO>
@POST("actions/pending/estimate-gas")
suspend fun estimateGasOnPending(@Body body: PendingActionRequestBody): ApiResponse<StakingGasEstimateDTO>
@PATCH("transactions/{transactionId}")
suspend fun constructTransaction(
@Path("transactionId") transactionId: String,

View file

@ -4,6 +4,20 @@ import com.squareup.moshi.Json
import com.tangem.datasource.api.stakekit.models.request.ConstructTransactionRequestBody.GasArgs
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.datasource.api.stakekit.models.response.model.TokenDTO
import com.tangem.domain.staking.model.action.StakingActionType
data class PendingActionRequestBody(
@Json(name = "type")
val type: StakingActionType,
@Json(name = "integrationId")
val integrationId: String,
@Json(name = "passthrough")
val passthrough: String,
@Json(name = "args")
val args: ActionRequestBodyArgs,
@Json(name = "gasArgs")
val gasArgs: GasArgs? = null, // used only in estimate_gas request
)
data class ActionRequestBody(
@Json(name = "integrationId")
@ -11,40 +25,39 @@ data class ActionRequestBody(
@Json(name = "addresses")
val addresses: Address,
@Json(name = "args")
val args: EnterActionRequestBodyArgs,
val args: ActionRequestBodyArgs,
@Json(name = "referralCode")
val referralCode: String? = null,
@Json(name = "gasArgs")
val gasArgs: GasArgs? = null, // used only in estimate_gas request
) {
)
data class EnterActionRequestBodyArgs(
@Json(name = "amount")
val amount: String,
@Json(name = "validatorAddress")
val validatorAddress: String? = null,
@Json(name = "validatorAddresses")
val validatorAddresses: List<String>? = null,
@Json(name = "providerId")
val providerId: String? = null,
@Json(name = "duration")
val duration: String? = null,
@Json(name = "nfts")
val nfts: List<BalanceDTO.PendingAction.PendingActionArgs.Nft>? = null,
@Json(name = "ledgerWalletAPICompatible")
val ledgerWalletAPICompatible: Boolean? = null,
@Json(name = "tronResource")
val tronResource: String? = null,
@Json(name = "signatureVerification")
val signatureVerification: SignatureVerification? = null,
@Json(name = "inputToken")
val inputToken: TokenDTO? = null,
)
data class ActionRequestBodyArgs(
@Json(name = "amount")
val amount: String,
@Json(name = "validatorAddress")
val validatorAddress: String? = null,
@Json(name = "validatorAddresses")
val validatorAddresses: List<String>? = null,
@Json(name = "providerId")
val providerId: String? = null,
@Json(name = "duration")
val duration: String? = null,
@Json(name = "nfts")
val nfts: List<BalanceDTO.PendingAction.PendingActionArgs.Nft>? = null,
@Json(name = "ledgerWalletAPICompatible")
val ledgerWalletAPICompatible: Boolean? = null,
@Json(name = "tronResource")
val tronResource: String? = null,
@Json(name = "signatureVerification")
val signatureVerification: SignatureVerification? = null,
@Json(name = "inputToken")
val inputToken: TokenDTO? = null,
)
data class SignatureVerification(
@Json(name = "message")
val message: String,
@Json(name = "signed")
val signed: String,
)
}
data class SignatureVerification(
@Json(name = "message")
val message: String,
@Json(name = "signed")
val signed: String,
)

View file

@ -26,6 +26,7 @@ import com.tangem.domain.core.lce.lceFlow
import com.tangem.domain.staking.model.*
import com.tangem.domain.staking.model.action.StakingAction
import com.tangem.domain.staking.model.action.StakingActionCommonType
import com.tangem.domain.staking.model.action.StakingActionType
import com.tangem.domain.staking.model.transaction.ActionParams
import com.tangem.domain.staking.model.transaction.StakingGasEstimate
import com.tangem.domain.staking.model.transaction.StakingTransaction
@ -158,10 +159,12 @@ internal class DefaultStakingRepository(
override suspend fun createAction(params: ActionParams): StakingAction {
return withContext(dispatchers.io) {
val body = createActionRequestBody(params)
val response = when (params.actionCommonType) {
StakingActionCommonType.ENTER -> stakeKitApi.createEnterAction(body)
StakingActionCommonType.EXIT -> stakeKitApi.createExitAction(body)
StakingActionCommonType.ENTER -> stakeKitApi.createEnterAction(createActionRequestBody(params))
StakingActionCommonType.EXIT -> stakeKitApi.createExitAction(createActionRequestBody(params))
StakingActionCommonType.PENDING -> stakeKitApi.createPendingAction(
createPendingActionRequestBody(params),
)
}
enterActionResponseConverter.convert(response.getOrThrow())
@ -170,11 +173,12 @@ internal class DefaultStakingRepository(
override suspend fun estimateGas(params: ActionParams): StakingGasEstimate {
return withContext(dispatchers.io) {
val body = createActionRequestBody(params)
val gasEstimateDTO = when (params.actionCommonType) {
StakingActionCommonType.ENTER -> stakeKitApi.estimateGasOnEnter(body)
StakingActionCommonType.EXIT -> stakeKitApi.estimateGasOnExit(body)
StakingActionCommonType.ENTER -> stakeKitApi.estimateGasOnEnter(createActionRequestBody(params))
StakingActionCommonType.EXIT -> stakeKitApi.estimateGasOnExit(createActionRequestBody(params))
StakingActionCommonType.PENDING -> stakeKitApi.estimateGasOnPending(
createPendingActionRequestBody(params),
)
}
gasEstimateConverter.convert(gasEstimateDTO.getOrThrow())
@ -432,7 +436,7 @@ internal class DefaultStakingRepository(
return ActionRequestBody(
integrationId = params.integrationId,
addresses = Address(params.address),
args = ActionRequestBody.EnterActionRequestBodyArgs(
args = ActionRequestBodyArgs(
amount = params.amount.toFormattedString(params.token.decimals),
inputToken = tokenConverter.convertBack(params.token),
validatorAddress = params.validatorAddress,
@ -440,6 +444,18 @@ internal class DefaultStakingRepository(
)
}
private fun createPendingActionRequestBody(params: ActionParams): PendingActionRequestBody {
return PendingActionRequestBody(
integrationId = params.integrationId,
type = params.type ?: StakingActionType.UNKNOWN,
passthrough = params.passthrough.orEmpty(),
args = ActionRequestBodyArgs(
amount = params.amount.toFormattedString(params.token.decimals),
validatorAddress = params.validatorAddress,
),
)
}
override fun isStakeMoreAvailable(networkId: Network.ID): Boolean {
val blockchain = Blockchain.fromId(networkId.value)
return when (blockchain) {

View file

@ -1,5 +1,6 @@
package com.tangem.data.staking.converters
import com.tangem.data.staking.converters.action.PendingActionConverter
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.domain.staking.model.BalanceItem
import com.tangem.domain.staking.model.BalanceType
@ -9,6 +10,8 @@ import com.tangem.utils.converter.Converter
internal class YieldBalanceConverter : Converter<YieldBalanceConverter.Data, YieldBalance> {
private val pendingActionConverter by lazy(LazyThreadSafetyMode.NONE) { PendingActionConverter() }
override fun convert(value: Data): YieldBalance {
return if (value.balance.isEmpty()) {
YieldBalance.Empty
@ -22,6 +25,7 @@ internal class YieldBalanceConverter : Converter<YieldBalanceConverter.Data, Yie
pricePerShare = item.pricePerShare,
rawCurrencyId = item.tokenDTO.coinGeckoId,
validatorAddress = item.validatorAddress,
pendingActions = pendingActionConverter.convertList(item.pendingActions),
)
},
integrationId = value.integrationId,

View file

@ -0,0 +1,44 @@
package com.tangem.data.staking.converters.action
import com.tangem.datasource.api.stakekit.models.response.model.BalanceDTO
import com.tangem.domain.staking.model.PendingAction
import com.tangem.utils.converter.Converter
internal class PendingActionConverter : Converter<BalanceDTO.PendingAction, PendingAction> {
private val stakingActionTypeConverter by lazy(LazyThreadSafetyMode.NONE) { StakingActionTypeConverter() }
override fun convert(value: BalanceDTO.PendingAction): PendingAction {
return PendingAction(
type = stakingActionTypeConverter.convert(value.type),
passthrough = value.passthrough,
args = with(value.args) {
PendingAction.PendingActionArgs(
amount = this?.amount?.let {
PendingAction.PendingActionArgs.Amount(
required = it.required,
minimum = it.minimum,
maximum = it.maximum,
)
},
duration = this?.duration?.let {
PendingAction.PendingActionArgs.Duration(
required = it.required,
minimum = it.minimum,
maximum = it.maximum,
)
},
validatorAddress = this?.validatorAddress?.required,
validatorAddresses = this?.validatorAddresses?.required,
tronResource = this?.tronResource?.let {
PendingAction.PendingActionArgs.TronResource(
required = it.required,
options = it.options,
)
},
signatureVerification = this?.signatureVerification?.required,
)
},
)
}
}

View file

@ -1,5 +1,6 @@
package com.tangem.domain.staking.model
import com.tangem.domain.staking.model.action.StakingActionType
import java.math.BigDecimal
sealed class YieldBalance {
@ -36,8 +37,41 @@ data class BalanceItem(
val pricePerShare: BigDecimal,
val rawCurrencyId: String?,
val validatorAddress: String?,
val pendingActions: List<PendingAction>,
)
data class PendingAction(
val type: StakingActionType,
val passthrough: String,
val args: PendingActionArgs?,
) {
data class PendingActionArgs(
val amount: Amount?,
val duration: Duration?,
val validatorAddress: Boolean?,
val validatorAddresses: Boolean?,
val tronResource: TronResource?,
val signatureVerification: Boolean?,
) {
data class Amount(
val required: Boolean,
val minimum: BigDecimal?,
val maximum: BigDecimal?,
)
data class Duration(
val required: Boolean,
val minimum: Int?,
val maximum: Int?,
)
data class TronResource(
val required: Boolean,
val options: List<String>,
)
}
}
enum class BalanceType {
AVAILABLE,
STAKED,

View file

@ -3,4 +3,5 @@ package com.tangem.domain.staking.model.action
enum class StakingActionCommonType {
ENTER,
EXIT,
PENDING,
}

View file

@ -2,6 +2,7 @@ package com.tangem.domain.staking.model.transaction
import com.tangem.domain.staking.model.Token
import com.tangem.domain.staking.model.action.StakingActionCommonType
import com.tangem.domain.staking.model.action.StakingActionType
import java.math.BigDecimal
data class ActionParams(
@ -11,4 +12,6 @@ data class ActionParams(
val address: String,
val validatorAddress: String,
val token: Token,
val passthrough: String? = null,
val type: StakingActionType? = null,
)