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

View file

@ -18,6 +18,7 @@ interface TangemTechMarketsApi {
@Query("order") order: String,
@Query("search") search: String?,
@Query("timestamp") timestamp: Long?,
@Query("showNetworks") showNetworks: Boolean? = null,
): ApiResponse<TokenMarketListResponse>
@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 = "staking_opportunities") val stakingOpportunities: List<StakingOpportunities>?,
@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)
data class PriceChangePercentage(
@Json(name = "24h") val h24: BigDecimal?,

View file

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

View file

@ -42,6 +42,13 @@ internal object TokenMarketListConverter : Converter<TokenMarketListResponse, To
tokenCharts = TokenMarket.Charts(h24 = null, week = null, month = null),
yieldRate = stakingRate ?: token.maxYieldApy?.movePointLeft(2),
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)

View file

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

View file

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

View file

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

View file

@ -44,6 +44,13 @@ internal class SwapMarketsTokenItemConverter(
resourceReference(R.string.markets_apy_placeholder, wrappedList(it))
},
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.FeedbackEmailType
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.currency.CryptoCurrency
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.SwapEvents
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.TransactionFeeResult
import com.tangem.feature.swap.domain.TxFeeSealedState
@ -156,7 +156,6 @@ internal class SwapModel @Inject constructor(
private val getMarketsTokenListFlowUseCase: GetMarketsTokenListFlowUseCase,
swapFeatureToggles: SwapFeatureToggles,
private val addToPortfolioManagerFactory: AddToPortfolioManager.Factory,
private val getTokenMarketInfoUseCase: GetTokenMarketInfoUseCase,
private val excludedBlockchains: ExcludedBlockchains,
private val getUserWalletsUseCase: GetWalletsUseCase,
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
@ -2061,23 +2060,25 @@ internal class SwapModel @Inject constructor(
private fun addToPortfolioItem(item: MarketsListItemUM) {
modelScope.launch {
val tokenInfo = getTokenMarketInfoUseCase(
selectedAppCurrencyFlow.value,
item.id,
item.currencySymbol,
).getOrNull() ?: return@launch
val tokenMarket = searchMarketsListManager.getTokenMarketById(item.id) ?: return@launch
val converter = TokenMarketInfoToParamsConverter()
val param = converter.convert(tokenInfo)
val param = tokenMarket.toSerializableParam()
val hasOnlyHotWallets = getUserWalletsUseCase.invokeSync().all { it is UserWallet.Hot }
val networks = tokenInfo.networks?.filter { network ->
val networks = tokenMarket.networks?.filter { network ->
BlockchainUtils.isSupportedNetworkId(
blockchainId = network.networkId,
excludedBlockchains = excludedBlockchains,
hotExcludedBlockchains = hotWalletExcludedBlockchains,
hasOnlyHotWallets = hasOnlyHotWallets,
)
}?.map { network ->
TokenMarketInfo.Network(
networkId = network.networkId,
isExchangeable = false,
contractAddress = network.contractAddress,
decimalCount = network.decimalCount,
)
}.orEmpty()
addToPortfolioManager = addToPortfolioManagerFactory

View file

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