Updated on 2026-08-14

This commit is contained in:
Tangem 2024-10-15 18:50:21 +03:00
parent 29915a8224
commit e77c292230
4 changed files with 87 additions and 68 deletions

View file

@ -9,31 +9,31 @@ data class YieldDTO(
@Json(name = "id")
val id: String,
@Json(name = "token")
val token: TokenDTO,
val token: TokenDTO?,
@Json(name = "tokens")
val tokens: List<TokenDTO>,
val tokens: List<TokenDTO>?,
@Json(name = "args")
val args: ArgsDTO,
val args: ArgsDTO?,
@Json(name = "status")
val status: StatusDTO,
val status: StatusDTO?,
@Json(name = "apy")
val apy: BigDecimal,
val apy: BigDecimal?,
@Json(name = "rewardRate")
val rewardRate: Double,
val rewardRate: Double?,
@Json(name = "rewardType")
val rewardType: RewardTypeDTO,
val rewardType: RewardTypeDTO?,
@Json(name = "metadata")
val metadata: MetadataDTO,
val metadata: MetadataDTO?,
@Json(name = "validators")
val validators: List<ValidatorDTO>,
val validators: List<ValidatorDTO>?,
@Json(name = "isAvailable")
val isAvailable: Boolean,
val isAvailable: Boolean?,
) {
@JsonClass(generateAdapter = true)
data class StatusDTO(
@Json(name = "enter")
val enter: Boolean,
val enter: Boolean?,
@Json(name = "exit")
val exit: Boolean?,
)
@ -41,21 +41,21 @@ data class YieldDTO(
@JsonClass(generateAdapter = true)
data class ArgsDTO(
@Json(name = "enter")
val enter: Enter,
val enter: Enter?,
@Json(name = "exit")
val exit: Enter?,
) {
@JsonClass(generateAdapter = true)
data class Enter(
@Json(name = "addresses")
val addresses: Addresses,
val addresses: Addresses?,
@Json(name = "args")
val args: Map<String, AddressArgumentDTO>,
val args: Map<String, AddressArgumentDTO>?,
) {
@JsonClass(generateAdapter = true)
data class Addresses(
@Json(name = "address")
val address: AddressArgumentDTO,
val address: AddressArgumentDTO?,
@Json(name = "additionalAddresses")
val additionalAddresses: Map<String, AddressArgumentDTO>? = null,
)
@ -65,7 +65,7 @@ data class YieldDTO(
@JsonClass(generateAdapter = true)
data class ValidatorDTO(
@Json(name = "address")
val address: String,
val address: String?,
@Json(name = "status")
val status: ValidatorStatusDTO,
@Json(name = "name")
@ -106,51 +106,51 @@ data class YieldDTO(
@JsonClass(generateAdapter = true)
data class MetadataDTO(
@Json(name = "name")
val name: String,
val name: String?,
@Json(name = "logoURI")
val logoUri: String,
val logoUri: String?,
@Json(name = "description")
val description: String,
val description: String?,
@Json(name = "documentation")
val documentation: String?,
@Json(name = "gasFeeToken")
val gasFeeTokenDTO: TokenDTO,
val gasFeeTokenDTO: TokenDTO?,
@Json(name = "token")
val tokenDTO: TokenDTO,
val tokenDTO: TokenDTO?,
@Json(name = "tokens")
val tokensDTO: List<TokenDTO>,
val tokensDTO: List<TokenDTO>?,
@Json(name = "type")
val type: String,
val type: String?,
@Json(name = "rewardSchedule")
val rewardSchedule: RewardScheduleDTO,
val rewardSchedule: RewardScheduleDTO?,
@Json(name = "cooldownPeriod")
val cooldownPeriod: PeriodDTO?,
@Json(name = "warmupPeriod")
val warmupPeriod: PeriodDTO,
val warmupPeriod: PeriodDTO?,
@Json(name = "rewardClaiming")
val rewardClaiming: RewardClaimingDTO,
val rewardClaiming: RewardClaimingDTO?,
@Json(name = "defaultValidator")
val defaultValidator: String?,
@Json(name = "minimumStake")
val minimumStake: Int?,
@Json(name = "supportsMultipleValidators")
val supportsMultipleValidators: Boolean,
val supportsMultipleValidators: Boolean?,
@Json(name = "revshare")
val revshare: EnabledDTO,
val revshare: EnabledDTO?,
@Json(name = "fee")
val fee: EnabledDTO,
val fee: EnabledDTO?,
) {
@JsonClass(generateAdapter = true)
data class PeriodDTO(
@Json(name = "days")
val days: Int,
val days: Int?,
)
@JsonClass(generateAdapter = true)
data class EnabledDTO(
@Json(name = "enabled")
val enabled: Boolean,
val enabled: Boolean?,
)
enum class RewardScheduleDTO {

View file

@ -11,4 +11,19 @@ interface Converter<I : Any, O : Any?> {
fun convertSet(input: Collection<I>): Set<O> {
return input.mapTo(hashSetOf(), ::convert)
}
fun convertListIgnoreErrors(input: Collection<I>, onError: ((Throwable) -> Unit)? = null): List<O> {
return input.mapNotNull {
try {
convert(it)
} catch (throwable: Throwable) {
onError?.invoke(throwable)
null
}
}
}
fun <T> T?.asMandatory(name: String): T {
return this ?: error("$name must not be null")
}
}

View file

@ -126,7 +126,7 @@ internal class DefaultStakingRepository(
val stakingTokensWithYields = stakeKitApi.getEnabledYields(preferredValidatorsOnly = false)
.getOrThrow()
stakingYieldsStore.store(stakingTokensWithYields.data.filter { it.isAvailable })
stakingYieldsStore.store(stakingTokensWithYields.data.filter { it.isAvailable ?: false })
},
)
}
@ -579,9 +579,10 @@ internal class DefaultStakingRepository(
}
private fun getEnabledYields(): List<Yield> {
return stakingYieldsStore
.get()
.map { yieldConverter.convert(it) }
return yieldConverter.convertListIgnoreErrors(
input = stakingYieldsStore.get(),
onError = { Timber.e("Error converting enabled yields list: $it") },
)
}
private fun getBalanceRequestData(address: String, integrationId: String): YieldBalanceRequestBody {

View file

@ -17,37 +17,37 @@ class YieldConverter(
override fun convert(value: YieldDTO): Yield {
return Yield(
id = value.id,
token = tokenConverter.convert(value.token),
tokens = value.tokens.map { tokenConverter.convert(it) },
args = convertArgs(value.args),
status = convertStatus(value.status),
apy = value.apy,
rewardRate = value.rewardRate,
rewardType = convertRewardType(value.rewardType),
metadata = convertMetadata(value.metadata),
validators = value.validators
id = value.id.asMandatory("id"),
token = tokenConverter.convert(value.token.asMandatory("token")),
tokens = value.tokens.asMandatory("tokens").map { tokenConverter.convert(it) },
args = convertArgs(value.args.asMandatory("args")),
status = convertStatus(value.status.asMandatory("status")),
apy = value.apy.asMandatory("apy"),
rewardRate = value.rewardRate.asMandatory("rewardRate"),
rewardType = convertRewardType(value.rewardType.asMandatory("rewardType")),
metadata = convertMetadata(value.metadata.asMandatory("metadata")),
validators = value.validators.asMandatory("validators")
.asSequence()
.filter { it.status == ValidatorStatusDTO.ACTIVE }
.map { convertValidator(it) }
.sortedByDescending { it.isStrategicPartner }
.sortedByDescending { it.apr }
.toImmutableList(),
isAvailable = value.isAvailable,
isAvailable = value.isAvailable.asMandatory("isAvailable"),
)
}
private fun convertArgs(argsDTO: YieldDTO.ArgsDTO): Yield.Args {
return Yield.Args(
enter = convertEnter(argsDTO.enter),
enter = convertEnter(argsDTO.enter.asMandatory("enter")),
exit = argsDTO.exit?.let { convertEnter(it) },
)
}
private fun convertEnter(enterDTO: YieldDTO.ArgsDTO.Enter): Yield.Args.Enter {
return Yield.Args.Enter(
addresses = convertAddresses(enterDTO.addresses),
args = enterDTO.args
addresses = convertAddresses(enterDTO.addresses.asMandatory("addresses")),
args = enterDTO.args.asMandatory("args")
.mapKeys { convertArgType(it.key) }
.mapValues { convertAddressArgument(it.value) },
)
@ -55,7 +55,7 @@ class YieldConverter(
private fun convertAddresses(addressesDTO: YieldDTO.ArgsDTO.Enter.Addresses): Yield.Args.Enter.Addresses {
return Yield.Args.Enter.Addresses(
address = convertAddressArgument(addressesDTO.address),
address = convertAddressArgument(addressesDTO.address.asMandatory("address")),
additionalAddresses = addressesDTO.additionalAddresses
?.mapKeys { convertArgType(it.key) }
?.mapValues { convertAddressArgument(it.value) },
@ -73,48 +73,51 @@ class YieldConverter(
private fun convertStatus(statusDTO: YieldDTO.StatusDTO): Yield.Status {
return Yield.Status(
enter = statusDTO.enter,
enter = statusDTO.enter.asMandatory("enter"),
exit = statusDTO.exit,
)
}
private fun convertMetadata(metadataDTO: YieldDTO.MetadataDTO): Yield.Metadata {
return Yield.Metadata(
name = metadataDTO.name,
logoUri = metadataDTO.logoUri,
description = metadataDTO.description,
name = metadataDTO.name.asMandatory("name"),
logoUri = metadataDTO.logoUri.asMandatory("logoUri"),
description = metadataDTO.description.asMandatory("description"),
documentation = metadataDTO.documentation,
gasFeeToken = tokenConverter.convert(metadataDTO.gasFeeTokenDTO),
token = tokenConverter.convert(metadataDTO.tokenDTO),
tokens = metadataDTO.tokensDTO.map { tokenConverter.convert(it) },
type = metadataDTO.type,
rewardSchedule = convertRewardSchedule(metadataDTO.rewardSchedule),
gasFeeToken = tokenConverter.convert(metadataDTO.gasFeeTokenDTO.asMandatory("gasFeeTokenDTO")),
token = tokenConverter.convert(metadataDTO.tokenDTO.asMandatory("tokenDTO")),
tokens = metadataDTO.tokensDTO.asMandatory("tokensDTO").map { tokenConverter.convert(it) },
type = metadataDTO.type.asMandatory("type"),
rewardSchedule = convertRewardSchedule(metadataDTO.rewardSchedule.asMandatory("rewardSchedule")),
cooldownPeriod = metadataDTO.cooldownPeriod?.let { convertPeriod(it) },
warmupPeriod = convertPeriod(metadataDTO.warmupPeriod),
rewardClaiming = convertRewardClaiming(metadataDTO.rewardClaiming),
warmupPeriod = convertPeriod(metadataDTO.warmupPeriod.asMandatory("warmupPeriod")),
rewardClaiming = convertRewardClaiming(metadataDTO.rewardClaiming.asMandatory("rewardClaiming")),
defaultValidator = metadataDTO.defaultValidator,
minimumStake = metadataDTO.minimumStake,
supportsMultipleValidators = metadataDTO.supportsMultipleValidators,
revshare = convertEnabled(metadataDTO.revshare),
fee = convertEnabled(metadataDTO.fee),
supportsMultipleValidators = metadataDTO.supportsMultipleValidators.asMandatory(
"supportsMultipleValidators",
),
revshare = convertEnabled(metadataDTO.revshare.asMandatory("revshare")),
fee = convertEnabled(metadataDTO.fee.asMandatory("fee")),
)
}
private fun convertPeriod(periodDTO: YieldDTO.MetadataDTO.PeriodDTO): Yield.Metadata.Period {
return Yield.Metadata.Period(
days = periodDTO.days,
days = periodDTO.days.asMandatory("days"),
)
}
private fun convertEnabled(enabledDTO: YieldDTO.MetadataDTO.EnabledDTO): Yield.Metadata.Enabled {
return Yield.Metadata.Enabled(
enabled = enabledDTO.enabled,
enabled = enabledDTO.enabled.asMandatory("enabled"),
)
}
private fun convertValidator(validatorDTO: YieldDTO.ValidatorDTO): Yield.Validator {
val address = validatorDTO.address.asMandatory("address")
return Yield.Validator(
address = validatorDTO.address,
address = address,
status = convertValidatorStatus(validatorDTO.status),
name = validatorDTO.name,
image = validatorDTO.image,
@ -124,7 +127,7 @@ class YieldConverter(
stakedBalance = validatorDTO.stakedBalance,
votingPower = validatorDTO.votingPower,
preferred = validatorDTO.preferred,
isStrategicPartner = isStrategicPartner(validatorDTO.address),
isStrategicPartner = isStrategicPartner(address),
)
}