Updated on 2026-08-14
This commit is contained in:
parent
51c7e4e10b
commit
173ee13120
21 changed files with 155 additions and 44 deletions
|
|
@ -63,6 +63,12 @@ internal class YieldSupply(
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun createHeaders(apiEnvironment: ApiEnvironment) = buildMap {
|
private fun createHeaders(apiEnvironment: ApiEnvironment) = buildMap {
|
||||||
|
put(
|
||||||
|
key = "Authorization",
|
||||||
|
value = ProviderSuspend {
|
||||||
|
"Bearer " + environmentConfigStorage.getConfigSync().yieldModuleApiKey
|
||||||
|
},
|
||||||
|
)
|
||||||
put(key = "api-key", value = ProviderSuspend { getApiKey(apiEnvironment) })
|
put(key = "api-key", value = ProviderSuspend { getApiKey(apiEnvironment) })
|
||||||
putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values)
|
putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values)
|
||||||
putAll(from = RequestHeader.AuthenticationHeader(authProvider).values)
|
putAll(from = RequestHeader.AuthenticationHeader(authProvider).values)
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,42 @@ package com.tangem.datasource.api.tangemTech
|
||||||
|
|
||||||
import com.tangem.datasource.api.common.response.ApiResponse
|
import com.tangem.datasource.api.common.response.ApiResponse
|
||||||
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
import com.tangem.datasource.api.tangemTech.models.YieldMarketsResponse
|
||||||
|
import com.tangem.datasource.api.tangemTech.models.YieldModuleStatusResponse
|
||||||
|
import com.tangem.datasource.api.tangemTech.models.YieldSupplyChangeTokenStatusBody
|
||||||
import com.tangem.datasource.api.tangemTech.models.YieldTokenStatusResponse
|
import com.tangem.datasource.api.tangemTech.models.YieldTokenStatusResponse
|
||||||
import com.tangem.datasource.api.tangemTech.models.YieldTokenChartResponse
|
import com.tangem.datasource.api.tangemTech.models.YieldTokenChartResponse
|
||||||
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.Path
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
interface YieldSupplyApi {
|
interface YieldSupplyApi {
|
||||||
|
|
||||||
@GET("api/v1/yield/markets")
|
@GET("api/v1/yield/markets")
|
||||||
suspend fun getYieldMarkets(): ApiResponse<YieldMarketsResponse>
|
suspend fun getYieldMarkets(@Query("chainId") chainId: Int? = null): ApiResponse<YieldMarketsResponse>
|
||||||
|
|
||||||
@GET("api/v1/yield/token/{tokenAddress}")
|
@GET("api/v1/yield/token/{chainId}/{tokenAddress}")
|
||||||
suspend fun getYieldTokenStatus(@Path("tokenAddress") tokenAddress: String): ApiResponse<YieldTokenStatusResponse>
|
suspend fun getYieldTokenStatus(
|
||||||
|
@Path("chainId") chainId: Int,
|
||||||
|
@Path("tokenAddress") tokenAddress: String,
|
||||||
|
): ApiResponse<YieldTokenStatusResponse>
|
||||||
|
|
||||||
@GET("api/v1/yield/token/{tokenAddress}/chart")
|
@GET("api/v1/yield/token/{chainId}/{tokenAddress}/chart")
|
||||||
suspend fun getYieldTokenChart(@Path("tokenAddress") tokenAddress: String): ApiResponse<YieldTokenChartResponse>
|
suspend fun getYieldTokenChart(
|
||||||
|
@Path("chainId") chainId: Int,
|
||||||
|
@Path("tokenAddress") tokenAddress: String,
|
||||||
|
@Query("window") window: String? = null,
|
||||||
|
@Query("bucketSizeDays") bucketSizeDays: Int? = null,
|
||||||
|
): ApiResponse<YieldTokenChartResponse>
|
||||||
|
|
||||||
|
@POST("api/v1/module/activate")
|
||||||
|
suspend fun activateYieldModule(
|
||||||
|
@Body body: YieldSupplyChangeTokenStatusBody,
|
||||||
|
): ApiResponse<YieldModuleStatusResponse>
|
||||||
|
|
||||||
|
@POST("api/v1/module/deactivate")
|
||||||
|
suspend fun deactivateYieldModule(
|
||||||
|
@Body body: YieldSupplyChangeTokenStatusBody,
|
||||||
|
): ApiResponse<YieldModuleStatusResponse>
|
||||||
}
|
}
|
||||||
|
|
@ -12,10 +12,11 @@ data class YieldMarketsResponse(
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MarketDto(
|
data class MarketDto(
|
||||||
@Json(name = "tokenAddress") val tokenAddress: String,
|
@Json(name = "tokenAddress") val tokenAddress: String? = null,
|
||||||
@Json(name = "tokenSymbol") val tokenSymbol: String,
|
@Json(name = "tokenSymbol") val tokenSymbol: String? = null,
|
||||||
@Json(name = "tokenName") val tokenName: String,
|
@Json(name = "tokenName") val tokenName: String? = null,
|
||||||
@Json(name = "apy") val apy: BigDecimal,
|
@Json(name = "apy") val apy: BigDecimal,
|
||||||
@Json(name = "isActive") val isActive: Boolean,
|
@Json(name = "isActive") val isActive: Boolean,
|
||||||
|
@Json(name = "chainId") val chainId: Int? = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.tangem.datasource.api.tangemTech.models
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class YieldModuleStatusResponse(
|
||||||
|
@Json(name = "tokenAddress") val tokenAddress: String,
|
||||||
|
@Json(name = "chainId") val chainId: Int,
|
||||||
|
@Json(name = "isActive") val isActive: Boolean,
|
||||||
|
@Json(name = "activatedAt") val activatedAt: String?,
|
||||||
|
@Json(name = "deactivatedAt") val deactivatedAt: String?,
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.tangem.datasource.api.tangemTech.models
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class YieldSupplyChangeTokenStatusBody(
|
||||||
|
@Json(name = "tokenAddress") val tokenAddress: String,
|
||||||
|
@Json(name = "chainId") val chainId: Int,
|
||||||
|
)
|
||||||
|
|
@ -6,9 +6,12 @@ import java.math.BigDecimal
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class YieldTokenStatusResponse(
|
data class YieldTokenStatusResponse(
|
||||||
@Json(name = "tokenAddress") val tokenAddress: String,
|
@Json(name = "tokenAddress") val tokenAddress: String? = null,
|
||||||
@Json(name = "tokenSymbol") val tokenSymbol: String,
|
@Json(name = "tokenSymbol") val tokenSymbol: String? = null,
|
||||||
@Json(name = "tokenName") val tokenName: String,
|
@Json(name = "tokenName") val tokenName: String? = null,
|
||||||
@Json(name = "apy") val apy: BigDecimal,
|
@Json(name = "apy") val apy: BigDecimal? = null,
|
||||||
@Json(name = "isActive") val isActive: Boolean,
|
@Json(name = "isActive") val isActive: Boolean? = null,
|
||||||
|
@Json(name = "chainId") val chainId: Int? = null,
|
||||||
|
@Json(name = "maxFeeNative") val maxFeeNative: String? = null,
|
||||||
|
@Json(name = "maxFeeUSD") val maxFeeUSD: String? = null,
|
||||||
)
|
)
|
||||||
|
|
@ -20,4 +20,5 @@ data class EnvironmentConfig(
|
||||||
val tangemApiKey: String? = null,
|
val tangemApiKey: String? = null,
|
||||||
val tangemApiKeyDev: String? = null,
|
val tangemApiKeyDev: String? = null,
|
||||||
val tangemApiKeyStage: String? = null,
|
val tangemApiKeyStage: String? = null,
|
||||||
|
val yieldModuleApiKey: String? = null,
|
||||||
)
|
)
|
||||||
|
|
@ -29,6 +29,7 @@ internal object EnvironmentConfigConverter : Converter<EnvironmentConfigModel, E
|
||||||
tangemApiKey = value.tangemApiKey,
|
tangemApiKey = value.tangemApiKey,
|
||||||
tangemApiKeyDev = value.tangemApiKeyDev,
|
tangemApiKeyDev = value.tangemApiKeyDev,
|
||||||
tangemApiKeyStage = value.tangemApiKeyStage,
|
tangemApiKeyStage = value.tangemApiKeyStage,
|
||||||
|
yieldModuleApiKey = value.yieldModuleApiKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +44,7 @@ class EnvironmentConfigModel(
|
||||||
@Json(name = "tangemApiKeyDev") val tangemApiKeyDev: String?,
|
@Json(name = "tangemApiKeyDev") val tangemApiKeyDev: String?,
|
||||||
@Json(name = "tangemApiKeyStage") val tangemApiKeyStage: String?,
|
@Json(name = "tangemApiKeyStage") val tangemApiKeyStage: String?,
|
||||||
@Json(name = "etherscanApiKey") val etherScanApiKey: String?,
|
@Json(name = "etherscanApiKey") val etherScanApiKey: String?,
|
||||||
|
@Json(name = "yieldModuleApiKey") val yieldModuleApiKey: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
|
||||||
tangemApiKey = TANGEM_API_KEY,
|
tangemApiKey = TANGEM_API_KEY,
|
||||||
tangemApiKeyDev = TANGEM_API_KEY_DEV,
|
tangemApiKeyDev = TANGEM_API_KEY_DEV,
|
||||||
tangemApiKeyStage = TANGEM_API_KEY_STAGE,
|
tangemApiKeyStage = TANGEM_API_KEY_STAGE,
|
||||||
|
yieldModuleApiKey = YIELD_MODULE_KEY,
|
||||||
)
|
)
|
||||||
|
|
||||||
override suspend fun initialize() = environmentConfig
|
override suspend fun initialize() = environmentConfig
|
||||||
|
|
@ -32,5 +33,6 @@ internal class MockEnvironmentConfigStorage : EnvironmentConfigStorage {
|
||||||
const val TANGEM_API_KEY = "tangem_api_key"
|
const val TANGEM_API_KEY = "tangem_api_key"
|
||||||
const val TANGEM_API_KEY_DEV = "tangem_api_key_dev"
|
const val TANGEM_API_KEY_DEV = "tangem_api_key_dev"
|
||||||
const val TANGEM_API_KEY_STAGE = "tangem_api_key_stage"
|
const val TANGEM_API_KEY_STAGE = "tangem_api_key_stage"
|
||||||
|
const val YIELD_MODULE_KEY = "yield_module_api_key"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,6 +198,7 @@ internal class ProdApiConfigsManagerTest {
|
||||||
environment = ApiEnvironment.PROD,
|
environment = ApiEnvironment.PROD,
|
||||||
baseUrl = "https://yield.tangem.org/",
|
baseUrl = "https://yield.tangem.org/",
|
||||||
headers = mapOf(
|
headers = mapOf(
|
||||||
|
"Authorization" to ProviderSuspend { "Bearer " + MockEnvironmentConfigStorage.YIELD_MODULE_KEY },
|
||||||
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
|
"api-key" to ProviderSuspend { MockEnvironmentConfigStorage.TANGEM_API_KEY },
|
||||||
"card_id" to ProviderSuspend { APP_CARD_ID },
|
"card_id" to ProviderSuspend { APP_CARD_ID },
|
||||||
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
|
"card_public_key" to ProviderSuspend { APP_CARD_PUBLIC_KEY },
|
||||||
|
|
@ -276,6 +277,6 @@ internal class ProdApiConfigsManagerTest {
|
||||||
const val EXPRESS_SESSION_ID = "express_session_id"
|
const val EXPRESS_SESSION_ID = "express_session_id"
|
||||||
const val STAKE_KIT_API_KEY = "stake_kit_api_key"
|
const val STAKE_KIT_API_KEY = "stake_kit_api_key"
|
||||||
const val APP_CARD_ID = "app_card_id"
|
const val APP_CARD_ID = "app_card_id"
|
||||||
const val APP_CARD_PUBLIC_KEY = "app_public_key"
|
const val APP_CARD_PUBLIC_KEY = "Bearer app_public_key"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +1,24 @@
|
||||||
package com.tangem.data.yield.supply
|
package com.tangem.data.yield.supply
|
||||||
|
|
||||||
|
import com.tangem.blockchain.common.Blockchain
|
||||||
|
import com.tangem.blockchainsdk.utils.fromNetworkId
|
||||||
|
import com.tangem.blockchainsdk.utils.toNetworkId
|
||||||
import com.tangem.datasource.api.common.response.getOrThrow
|
import com.tangem.datasource.api.common.response.getOrThrow
|
||||||
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
import com.tangem.datasource.local.yieldsupply.YieldMarketsStore
|
||||||
import com.tangem.data.yield.supply.converters.YieldMarketTokenConverter
|
import com.tangem.data.yield.supply.converters.YieldMarketTokenConverter
|
||||||
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
import com.tangem.datasource.api.tangemTech.YieldSupplyApi
|
||||||
import com.tangem.data.yield.supply.converters.YieldTokenStatusConverter
|
import com.tangem.data.yield.supply.converters.YieldTokenStatusConverter
|
||||||
import com.tangem.data.yield.supply.converters.YieldTokenChartConverter
|
import com.tangem.data.yield.supply.converters.YieldTokenChartConverter
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
|
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
|
||||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||||
|
import com.tangem.domain.yield.supply.models.YieldMarketTokenStatus
|
||||||
import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData
|
import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlin.collections.map
|
||||||
|
|
||||||
internal class DefaultYieldSupplyMarketRepository(
|
internal class DefaultYieldSupplyMarketRepository(
|
||||||
private val yieldSupplyApi: YieldSupplyApi,
|
private val yieldSupplyApi: YieldSupplyApi,
|
||||||
|
|
@ -20,7 +27,7 @@ internal class DefaultYieldSupplyMarketRepository(
|
||||||
) : YieldSupplyMarketRepository {
|
) : YieldSupplyMarketRepository {
|
||||||
|
|
||||||
override suspend fun getCachedMarkets(): List<YieldMarketToken>? = withContext(dispatchers.io) {
|
override suspend fun getCachedMarkets(): List<YieldMarketToken>? = withContext(dispatchers.io) {
|
||||||
store.getSyncOrNull()
|
store.getSyncOrNull()?.enrichNetworkIds()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateMarkets(): List<YieldMarketToken> = withContext(dispatchers.io) {
|
override suspend fun updateMarkets(): List<YieldMarketToken> = withContext(dispatchers.io) {
|
||||||
|
|
@ -30,15 +37,28 @@ internal class DefaultYieldSupplyMarketRepository(
|
||||||
domain
|
domain
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getMarketsFlow(): Flow<List<YieldMarketToken>> = store.get()
|
override fun getMarketsFlow(): Flow<List<YieldMarketToken>> = store.get().map {
|
||||||
|
it.enrichNetworkIds()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getTokenStatus(contractAddress: String): YieldMarketToken {
|
override suspend fun getTokenStatus(cryptoCurrencyToken: CryptoCurrency.Token): YieldMarketTokenStatus {
|
||||||
val response = yieldSupplyApi.getYieldTokenStatus(contractAddress).getOrThrow()
|
val chainId = Blockchain.fromNetworkId(cryptoCurrencyToken.network.backendId)?.getChainId()
|
||||||
|
?: error("Chain id is required for evm's")
|
||||||
|
val response = yieldSupplyApi.getYieldTokenStatus(chainId, cryptoCurrencyToken.contractAddress).getOrThrow()
|
||||||
return YieldTokenStatusConverter.convert(response)
|
return YieldTokenStatusConverter.convert(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getTokenChart(contractAddress: String): YieldSupplyMarketChartData {
|
override suspend fun getTokenChart(cryptoCurrencyToken: CryptoCurrency.Token): YieldSupplyMarketChartData {
|
||||||
val response = yieldSupplyApi.getYieldTokenChart(contractAddress).getOrThrow()
|
val chainId = Blockchain.fromNetworkId(cryptoCurrencyToken.network.backendId)?.getChainId()
|
||||||
|
?: error("Chain id is required for evm's")
|
||||||
|
val response = yieldSupplyApi.getYieldTokenChart(chainId, cryptoCurrencyToken.contractAddress).getOrThrow()
|
||||||
return YieldTokenChartConverter.convert(response)
|
return YieldTokenChartConverter.convert(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun List<YieldMarketToken>.enrichNetworkIds(): List<YieldMarketToken> {
|
||||||
|
val chainIdMap = Blockchain.entries.associate { it.getChainId() to it.toNetworkId() }
|
||||||
|
return this.map { token ->
|
||||||
|
token.copy(backendId = chainIdMap[token.chainId])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,11 +7,10 @@ import com.tangem.utils.converter.Converter
|
||||||
internal object YieldMarketTokenConverter : Converter<YieldMarketsResponse.MarketDto, YieldMarketToken> {
|
internal object YieldMarketTokenConverter : Converter<YieldMarketsResponse.MarketDto, YieldMarketToken> {
|
||||||
override fun convert(value: YieldMarketsResponse.MarketDto): YieldMarketToken {
|
override fun convert(value: YieldMarketsResponse.MarketDto): YieldMarketToken {
|
||||||
return YieldMarketToken(
|
return YieldMarketToken(
|
||||||
tokenAddress = value.tokenAddress,
|
tokenAddress = value.tokenAddress.orEmpty(),
|
||||||
tokenSymbol = value.tokenSymbol,
|
|
||||||
tokenName = value.tokenName,
|
|
||||||
apy = value.apy,
|
apy = value.apy,
|
||||||
isActive = value.isActive,
|
isActive = value.isActive,
|
||||||
|
chainId = value.chainId ?: -1,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +1,21 @@
|
||||||
package com.tangem.data.yield.supply.converters
|
package com.tangem.data.yield.supply.converters
|
||||||
|
|
||||||
import com.tangem.datasource.api.tangemTech.models.YieldTokenStatusResponse
|
import com.tangem.datasource.api.tangemTech.models.YieldTokenStatusResponse
|
||||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
import com.tangem.domain.models.serialization.SerializedBigDecimal
|
||||||
|
import com.tangem.domain.yield.supply.models.YieldMarketTokenStatus
|
||||||
import com.tangem.utils.converter.Converter
|
import com.tangem.utils.converter.Converter
|
||||||
|
|
||||||
internal object YieldTokenStatusConverter : Converter<YieldTokenStatusResponse, YieldMarketToken> {
|
internal object YieldTokenStatusConverter : Converter<YieldTokenStatusResponse, YieldMarketTokenStatus> {
|
||||||
override fun convert(value: YieldTokenStatusResponse): YieldMarketToken {
|
override fun convert(value: YieldTokenStatusResponse): YieldMarketTokenStatus {
|
||||||
return YieldMarketToken(
|
return YieldMarketTokenStatus(
|
||||||
tokenAddress = value.tokenAddress,
|
tokenAddress = value.tokenAddress.orEmpty(),
|
||||||
tokenSymbol = value.tokenSymbol,
|
tokenSymbol = value.tokenSymbol.orEmpty(),
|
||||||
tokenName = value.tokenName,
|
tokenName = value.tokenName.orEmpty(),
|
||||||
apy = value.apy,
|
apy = value.apy ?: SerializedBigDecimal.ZERO,
|
||||||
isActive = value.isActive,
|
isActive = value.isActive ?: false,
|
||||||
|
chainId = value.chainId ?: -1,
|
||||||
|
maxFeeUSD = value.maxFeeUSD.orEmpty(),
|
||||||
|
maxFeeNative = value.maxFeeNative.orEmpty(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -9,8 +9,12 @@ import kotlinx.serialization.Serializable
|
||||||
@Serializable
|
@Serializable
|
||||||
data class YieldMarketToken(
|
data class YieldMarketToken(
|
||||||
val tokenAddress: String,
|
val tokenAddress: String,
|
||||||
val tokenSymbol: String,
|
val chainId: Int,
|
||||||
val tokenName: String,
|
|
||||||
val apy: SerializedBigDecimal,
|
val apy: SerializedBigDecimal,
|
||||||
val isActive: Boolean,
|
val isActive: Boolean,
|
||||||
)
|
val backendId: String? = null,
|
||||||
|
) {
|
||||||
|
|
||||||
|
val yieldSupplyKey: String
|
||||||
|
get() = "${backendId}_$tokenAddress"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.tangem.domain.yield.supply.models
|
||||||
|
|
||||||
|
import com.tangem.domain.models.serialization.SerializedBigDecimal
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Domain model representing a token entry in the Yield Markets list.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
data class YieldMarketTokenStatus(
|
||||||
|
val tokenAddress: String,
|
||||||
|
val tokenSymbol: String,
|
||||||
|
val tokenName: String,
|
||||||
|
val chainId: Int,
|
||||||
|
val apy: SerializedBigDecimal,
|
||||||
|
val isActive: Boolean,
|
||||||
|
val maxFeeNative: String,
|
||||||
|
val maxFeeUSD: String,
|
||||||
|
)
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.tangem.domain.yield.supply
|
package com.tangem.domain.yield.supply
|
||||||
|
|
||||||
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
||||||
|
import com.tangem.domain.yield.supply.models.YieldMarketTokenStatus
|
||||||
import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData
|
import com.tangem.domain.yield.supply.models.YieldSupplyMarketChartData
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
|
@ -26,11 +28,11 @@ interface YieldSupplyMarketRepository {
|
||||||
* Get yield token status by contract address.
|
* Get yield token status by contract address.
|
||||||
*/
|
*/
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun getTokenStatus(contractAddress: String): YieldMarketToken
|
suspend fun getTokenStatus(cryptoCurrencyToken: CryptoCurrency.Token): YieldMarketTokenStatus
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get yield token APY chart by contract address.
|
* Get yield token APY chart by contract address.
|
||||||
*/
|
*/
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun getTokenChart(contractAddress: String): YieldSupplyMarketChartData
|
suspend fun getTokenChart(cryptoCurrencyToken: CryptoCurrency.Token): YieldSupplyMarketChartData
|
||||||
}
|
}
|
||||||
|
|
@ -18,8 +18,8 @@ class YieldSupplyApyFlowUseCase(
|
||||||
operator fun invoke(): Flow<Map<String, String>> {
|
operator fun invoke(): Flow<Map<String, String>> {
|
||||||
return yieldSupplyMarketRepository.getMarketsFlow()
|
return yieldSupplyMarketRepository.getMarketsFlow()
|
||||||
.map { yieldMarketTokenList ->
|
.map { yieldMarketTokenList ->
|
||||||
yieldMarketTokenList.filter { it.isActive }.associate {
|
yieldMarketTokenList.filter { it.isActive }.associate { token ->
|
||||||
it.tokenAddress to it.apy.toString()
|
token.yieldSupplyKey to token.apy.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ package com.tangem.domain.yield.supply.usecase
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import com.tangem.domain.models.currency.CryptoCurrency
|
import com.tangem.domain.models.currency.CryptoCurrency
|
||||||
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
|
import com.tangem.domain.yield.supply.YieldSupplyMarketRepository
|
||||||
import com.tangem.domain.yield.supply.models.YieldMarketToken
|
import com.tangem.domain.yield.supply.models.YieldMarketTokenStatus
|
||||||
|
|
||||||
class YieldSupplyGetTokenStatusUseCase(
|
class YieldSupplyGetTokenStatusUseCase(
|
||||||
private val yieldSupplyMarketRepository: YieldSupplyMarketRepository,
|
private val yieldSupplyMarketRepository: YieldSupplyMarketRepository,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
suspend operator fun invoke(token: CryptoCurrency.Token): Either<Throwable, YieldMarketToken> = Either.catch {
|
suspend operator fun invoke(token: CryptoCurrency.Token): Either<Throwable, YieldMarketTokenStatus> = Either.catch {
|
||||||
yieldSupplyMarketRepository.getTokenStatus(token.contractAddress)
|
yieldSupplyMarketRepository.getTokenStatus(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,7 +213,8 @@ internal class TokenListStateConverter(
|
||||||
?.contractAddress
|
?.contractAddress
|
||||||
?.lowercase() ?: return null
|
?.lowercase() ?: return null
|
||||||
|
|
||||||
return apyMap[contract]
|
val yieldSupplyKey = "${cryptoCurrencyStatus.currency.network.backendId}_$contract"
|
||||||
|
return apyMap[yieldSupplyKey]
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getOrganizeTokensButtonState(tokenList: TokenList): WalletOrganizeTokensButtonConfig? {
|
private fun getOrganizeTokensButtonState(tokenList: TokenList): WalletOrganizeTokensButtonConfig? {
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ internal class YieldSupplyModel @Inject constructor(
|
||||||
YieldSupplyUM.Initial(
|
YieldSupplyUM.Initial(
|
||||||
title = resourceReference(
|
title = resourceReference(
|
||||||
id = R.string.yield_module_token_details_earn_notification_title,
|
id = R.string.yield_module_token_details_earn_notification_title,
|
||||||
formatArgs = wrappedList("5.1"),
|
formatArgs = wrappedList(tokenStatus.apy),
|
||||||
),
|
),
|
||||||
onClick = ::onStartEarningClick,
|
onClick = ::onStartEarningClick,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue