From e77c29223021b2a75be0248bfdec76e0cd8e07b8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 15 Oct 2024 18:50:21 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../models/response/model/YieldDTO.kt | 62 ++++++++--------- .../com/tangem/utils/converter/Converter.kt | 15 ++++ .../data/staking/DefaultStakingRepository.kt | 9 +-- .../data/staking/converters/YieldConverter.kt | 69 ++++++++++--------- 4 files changed, 87 insertions(+), 68 deletions(-) diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt index 330df3c666..951d60ddf7 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/stakekit/models/response/model/YieldDTO.kt @@ -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, + val tokens: List?, @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, + val validators: List?, @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, + val args: Map?, ) { @JsonClass(generateAdapter = true) data class Addresses( @Json(name = "address") - val address: AddressArgumentDTO, + val address: AddressArgumentDTO?, @Json(name = "additionalAddresses") val additionalAddresses: Map? = 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, + val tokensDTO: List?, @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 { diff --git a/core/utils/src/main/java/com/tangem/utils/converter/Converter.kt b/core/utils/src/main/java/com/tangem/utils/converter/Converter.kt index b818478a45..603ebf1fcd 100644 --- a/core/utils/src/main/java/com/tangem/utils/converter/Converter.kt +++ b/core/utils/src/main/java/com/tangem/utils/converter/Converter.kt @@ -11,4 +11,19 @@ interface Converter { fun convertSet(input: Collection): Set { return input.mapTo(hashSetOf(), ::convert) } + + fun convertListIgnoreErrors(input: Collection, onError: ((Throwable) -> Unit)? = null): List { + return input.mapNotNull { + try { + convert(it) + } catch (throwable: Throwable) { + onError?.invoke(throwable) + null + } + } + } + + fun T?.asMandatory(name: String): T { + return this ?: error("$name must not be null") + } } \ No newline at end of file diff --git a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt index 729477a5cc..71bd21a01e 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/DefaultStakingRepository.kt @@ -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 { - 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 { diff --git a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt index 8489a8772d..7ed9eb23e3 100644 --- a/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt +++ b/data/staking/src/main/java/com/tangem/data/staking/converters/YieldConverter.kt @@ -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), ) }