Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-11 12:43:15 +03:00
parent 0ae9e75e90
commit bbce67bcd2
12 changed files with 68 additions and 11 deletions

View file

@ -22,6 +22,7 @@ data class MarketsListItemUM(
val isUnder100kMarketCap: Boolean, val isUnder100kMarketCap: Boolean,
val stakingRate: TextReference?, val stakingRate: TextReference?,
val updateTimestamp: Long?, val updateTimestamp: Long?,
val networks: List<Network>? = null,
) { ) {
val chartType: MarketChartLook.Type = when (trendType) { val chartType: MarketChartLook.Type = when (trendType) {
PriceChangeType.UP -> MarketChartLook.Type.Growing PriceChangeType.UP -> MarketChartLook.Type.Growing
@ -29,6 +30,13 @@ data class MarketsListItemUM(
PriceChangeType.NEUTRAL -> MarketChartLook.Type.Neutral PriceChangeType.NEUTRAL -> MarketChartLook.Type.Neutral
} }
@Immutable
data class Network(
val networkId: String,
val contractAddress: String?,
val decimalCount: Int?,
)
@Immutable @Immutable
data class Price( data class Price(
val text: String, val text: String,

View file

@ -18,6 +18,7 @@ interface TangemTechMarketsApi {
@Query("order") order: String, @Query("order") order: String,
@Query("search") search: String?, @Query("search") search: String?,
@Query("timestamp") timestamp: Long?, @Query("timestamp") timestamp: Long?,
@Query("showNetworks") showNetworks: Boolean? = null,
): ApiResponse<TokenMarketListResponse> ): ApiResponse<TokenMarketListResponse>
@GET("v1/coins/{coin_id}") @GET("v1/coins/{coin_id}")

View file

@ -27,8 +27,16 @@ data class TokenMarketListResponse(
@Json(name = "is_under_market_cap_limit") val isUnderMarketCapLimit: Boolean?, @Json(name = "is_under_market_cap_limit") val isUnderMarketCapLimit: Boolean?,
@Json(name = "staking_opportunities") val stakingOpportunities: List<StakingOpportunities>?, @Json(name = "staking_opportunities") val stakingOpportunities: List<StakingOpportunities>?,
@Json(name = "max_yield_apy") val maxYieldApy: BigDecimal?, @Json(name = "max_yield_apy") val maxYieldApy: BigDecimal?,
@Json(name = "networks") val networks: List<Network>? = null,
) { ) {
@JsonClass(generateAdapter = true)
data class Network(
@Json(name = "network_id") val networkId: String,
@Json(name = "contract_address") val contractAddress: String?,
@Json(name = "decimal_count") val decimalCount: Int?,
)
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class PriceChangePercentage( data class PriceChangePercentage(
@Json(name = "24h") val h24: BigDecimal?, @Json(name = "24h") val h24: BigDecimal?,

View file

@ -75,6 +75,7 @@ internal class DefaultMarketsTokenRepository(
offset = request.offset, offset = request.offset,
limit = request.limit, limit = request.limit,
timestamp = if (isFirstBatchFetching) null else requestTimeStamp.get(), timestamp = if (isFirstBatchFetching) null else requestTimeStamp.get(),
showNetworks = request.params.shouldNetworks,
).getOrThrow() ).getOrThrow()
} }

View file

@ -42,6 +42,13 @@ internal object TokenMarketListConverter : Converter<TokenMarketListResponse, To
tokenCharts = TokenMarket.Charts(h24 = null, week = null, month = null), tokenCharts = TokenMarket.Charts(h24 = null, week = null, month = null),
yieldRate = stakingRate ?: token.maxYieldApy?.movePointLeft(2), yieldRate = stakingRate ?: token.maxYieldApy?.movePointLeft(2),
updateTimestamp = value.timestamp, updateTimestamp = value.timestamp,
networks = token.networks?.map { network ->
TokenMarket.Network(
networkId = network.networkId,
contractAddress = network.contractAddress,
decimalCount = network.decimalCount,
)
},
) )
} }
return TokenMarketListWithMaxApy(tokens, value.summary?.maxApy) return TokenMarketListWithMaxApy(tokens, value.summary?.maxApy)

View file

@ -14,9 +14,16 @@ data class TokenMarket(
val tokenCharts: Charts, val tokenCharts: Charts,
val yieldRate: BigDecimal?, val yieldRate: BigDecimal?,
val updateTimestamp: Long?, val updateTimestamp: Long?,
val networks: List<Network>?,
private val imageHost: String, private val imageHost: String,
) { ) {
data class Network(
val networkId: String,
val contractAddress: String?,
val decimalCount: Int?,
)
data class Charts( data class Charts(
val h24: TokenChart?, val h24: TokenChart?,
val week: TokenChart?, val week: TokenChart?,

View file

@ -5,6 +5,7 @@ data class TokenMarketListConfig(
val searchText: String?, val searchText: String?,
val priceChangeInterval: Interval, val priceChangeInterval: Interval,
val order: Order, val order: Order,
val shouldNetworks: Boolean? = null,
) { ) {
enum class Order { enum class Order {

View file

@ -184,6 +184,7 @@ internal class SwapMarketsListBatchFlowManager(
}, },
priceChangeInterval = TokenMarketListConfig.Interval.H24, priceChangeInterval = TokenMarketListConfig.Interval.H24,
order = TokenMarketListConfig.Order.ByRating, order = TokenMarketListConfig.Order.ByRating,
shouldNetworks = true,
), ),
), ),
) )

View file

@ -44,6 +44,13 @@ internal class SwapMarketsTokenItemConverter(
resourceReference(R.string.markets_apy_placeholder, wrappedList(it)) resourceReference(R.string.markets_apy_placeholder, wrappedList(it))
}, },
updateTimestamp = value.updateTimestamp, updateTimestamp = value.updateTimestamp,
networks = value.networks?.map { network ->
MarketsListItemUM.Network(
networkId = network.networkId,
contractAddress = network.contractAddress,
decimalCount = network.decimalCount,
)
},
) )
} }

View file

@ -43,7 +43,8 @@ import com.tangem.domain.feedback.SendFeedbackEmailUseCase
import com.tangem.domain.feedback.models.BlockchainErrorInfo import com.tangem.domain.feedback.models.BlockchainErrorInfo
import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase import com.tangem.domain.markets.GetMarketsTokenListFlowUseCase
import com.tangem.domain.markets.GetTokenMarketInfoUseCase import com.tangem.domain.markets.TokenMarketInfo
import com.tangem.domain.markets.toSerializableParam
import com.tangem.domain.models.account.Account import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus import com.tangem.domain.models.currency.CryptoCurrencyStatus
@ -73,7 +74,6 @@ import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.feature.swap.analytics.StoriesEvents import com.tangem.feature.swap.analytics.StoriesEvents
import com.tangem.feature.swap.analytics.SwapEvents import com.tangem.feature.swap.analytics.SwapEvents
import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent import com.tangem.feature.swap.component.SwapFeeSelectorBlockComponent
import com.tangem.feature.swap.converters.TokenMarketInfoToParamsConverter
import com.tangem.feature.swap.domain.SwapInteractor import com.tangem.feature.swap.domain.SwapInteractor
import com.tangem.feature.swap.domain.TransactionFeeResult import com.tangem.feature.swap.domain.TransactionFeeResult
import com.tangem.feature.swap.domain.TxFeeSealedState import com.tangem.feature.swap.domain.TxFeeSealedState
@ -156,7 +156,6 @@ internal class SwapModel @Inject constructor(
private val getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase, private val getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
swapFeatureToggles: SwapFeatureToggles, swapFeatureToggles: SwapFeatureToggles,
private val addToPortfolioManagerFactory: AddToPortfolioManager.Factory, private val addToPortfolioManagerFactory: AddToPortfolioManager.Factory,
private val getTokenMarketInfoUseCase: GetTokenMarketInfoUseCase,
private val excludedBlockchains: ExcludedBlockchains, private val excludedBlockchains: ExcludedBlockchains,
private val getUserWalletsUseCase: GetWalletsUseCase, private val getUserWalletsUseCase: GetWalletsUseCase,
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase, private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
@ -2061,23 +2060,25 @@ internal class SwapModel @Inject constructor(
private fun addToPortfolioItem(item: MarketsListItemUM) { private fun addToPortfolioItem(item: MarketsListItemUM) {
modelScope.launch { modelScope.launch {
val tokenInfo = getTokenMarketInfoUseCase( val tokenMarket = searchMarketsListManager.getTokenMarketById(item.id) ?: return@launch
selectedAppCurrencyFlow.value,
item.id,
item.currencySymbol,
).getOrNull() ?: return@launch
val converter = TokenMarketInfoToParamsConverter() val param = tokenMarket.toSerializableParam()
val param = converter.convert(tokenInfo)
val hasOnlyHotWallets = getUserWalletsUseCase.invokeSync().all { it is UserWallet.Hot } val hasOnlyHotWallets = getUserWalletsUseCase.invokeSync().all { it is UserWallet.Hot }
val networks = tokenInfo.networks?.filter { network -> val networks = tokenMarket.networks?.filter { network ->
BlockchainUtils.isSupportedNetworkId( BlockchainUtils.isSupportedNetworkId(
blockchainId = network.networkId, blockchainId = network.networkId,
excludedBlockchains = excludedBlockchains, excludedBlockchains = excludedBlockchains,
hotExcludedBlockchains = hotWalletExcludedBlockchains, hotExcludedBlockchains = hotWalletExcludedBlockchains,
hasOnlyHotWallets = hasOnlyHotWallets, hasOnlyHotWallets = hasOnlyHotWallets,
) )
}?.map { network ->
TokenMarketInfo.Network(
networkId = network.networkId,
isExchangeable = false,
contractAddress = network.contractAddress,
decimalCount = network.decimalCount,
)
}.orEmpty() }.orEmpty()
addToPortfolioManager = addToPortfolioManagerFactory addToPortfolioManager = addToPortfolioManagerFactory

View file

@ -184,6 +184,7 @@ internal class SwapMarketsListBatchFlowManager(
}, },
priceChangeInterval = TokenMarketListConfig.Interval.H24, priceChangeInterval = TokenMarketListConfig.Interval.H24,
order = TokenMarketListConfig.Order.ByRating, order = TokenMarketListConfig.Order.ByRating,
shouldNetworks = true,
), ),
), ),
) )
@ -236,6 +237,13 @@ internal class SwapMarketsListBatchFlowManager(
.toSet() .toSet()
} }
fun getTokenMarketById(id: CryptoCurrency.RawID): TokenMarket? {
return batchFlow.state.value.data
.asSequence()
.flatMap { it.data }
.firstOrNull { it.id == id }
}
private data class ResultBatches( private data class ResultBatches(
val uiBatches: List<Batch<Int, List<MarketsListItemUM>>> = emptyList(), val uiBatches: List<Batch<Int, List<MarketsListItemUM>>> = emptyList(),
val processedItems: List<Batch<Int, List<TokenMarket>>>? = null, val processedItems: List<Batch<Int, List<TokenMarket>>>? = null,

View file

@ -44,6 +44,13 @@ internal class SwapMarketsTokenItemConverter(
resourceReference(R.string.markets_apy_placeholder, wrappedList(it)) resourceReference(R.string.markets_apy_placeholder, wrappedList(it))
}, },
updateTimestamp = value.updateTimestamp, updateTimestamp = value.updateTimestamp,
networks = value.networks?.map { network ->
MarketsListItemUM.Network(
networkId = network.networkId,
contractAddress = network.contractAddress,
decimalCount = network.decimalCount,
)
},
) )
} }