Updated on 2026-08-14
This commit is contained in:
commit
6b7a309a37
17 changed files with 389 additions and 5 deletions
|
|
@ -31,6 +31,7 @@ dependencies {
|
|||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.onramp.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.features.onramp.api)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(deps.tangem.blockchain)
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ interface TangemTechApi {
|
|||
@Body body: SeedPhraseNotificationDTO,
|
||||
): ApiResponse<Unit>
|
||||
|
||||
@GET("hot_crypto")
|
||||
suspend fun getHotCrypto(@Query("currency") currencyId: String): ApiResponse<HotCryptoResponse>
|
||||
|
||||
companion object {
|
||||
val marketsQuoteFields = listOf(
|
||||
"price",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.datasource.api.tangemTech.models
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import java.math.BigDecimal
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class HotCryptoResponse(
|
||||
@Json(name = "imageHost") val imageHost: String? = null,
|
||||
@Json(name = "tokens") val tokens: List<Token>,
|
||||
) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class Token(
|
||||
@Json(name = "id") val id: String,
|
||||
@Json(name = "symbol") val symbol: String,
|
||||
@Json(name = "name") val name: String,
|
||||
@Json(name = "network_id") val networkId: String,
|
||||
@Json(name = "current_price") val currentPrice: BigDecimal,
|
||||
@Json(name = "price_change_percentage_24h") val priceChangePercentage: BigDecimal,
|
||||
@Json(name = "contractAddress") val contractAddress: String? = null, // specific for token
|
||||
@Json(name = "decimal_count") val decimalCount: Int? = null, // specific for token
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.tangem.datasource.di.exchangeservice
|
||||
|
||||
import com.tangem.datasource.exchangeservice.hotcrypto.DefaultHotCryptoLoader
|
||||
import com.tangem.datasource.exchangeservice.hotcrypto.HotCryptoLoader
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal interface HotCryptoLoaderModule {
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindExpressServiceLoader(defaultHotCryptoLoader: DefaultHotCryptoLoader): HotCryptoLoader
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.tangem.datasource.exchangeservice.hotcrypto
|
||||
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.models.CurrenciesResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.HotCryptoResponse
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.datasource.local.preferences.PreferencesKeys
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.features.onramp.OnrampFeatureToggles
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.coroutines.runCatching
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Default implementation of [HotCryptoLoader]
|
||||
*
|
||||
* @property tangemTechApi tangem tech api
|
||||
* @property hotCryptoResponseStore store of [HotCryptoResponse]
|
||||
* @property appPreferencesStore app preferences store
|
||||
* @property dispatchers dispatchers
|
||||
* @property onrampFeatureToggles onramp feature toggles
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class DefaultHotCryptoLoader @Inject constructor(
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val hotCryptoResponseStore: HotCryptoResponseStore,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val onrampFeatureToggles: OnrampFeatureToggles,
|
||||
) : HotCryptoLoader {
|
||||
|
||||
override suspend fun fetch(tokens: List<UserTokensResponse.Token>) {
|
||||
updateInternal { hotToken ->
|
||||
tokens.none {
|
||||
it.id == hotToken.id && it.contractAddress == hotToken.contractAddress &&
|
||||
it.networkId == hotToken.networkId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun update(currencies: List<CryptoCurrency>) {
|
||||
updateInternal { hotToken ->
|
||||
currencies.none {
|
||||
it.id.rawCurrencyId == hotToken.id &&
|
||||
(it as? CryptoCurrency.Token)?.contractAddress == hotToken.contractAddress &&
|
||||
it.network.id.value == hotToken.networkId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateInternal(filterPredicate: (HotCryptoResponse.Token) -> Boolean) {
|
||||
if (!onrampFeatureToggles.isHotTokensEnabled) return
|
||||
|
||||
runCatching(dispatchers.io) {
|
||||
tangemTechApi.getHotCrypto(currencyId = getAppCurrencyId()).getOrThrow()
|
||||
}
|
||||
.onSuccess {
|
||||
Timber.d("HotCrypto is successfully updated")
|
||||
|
||||
hotCryptoResponseStore.store(
|
||||
value = it.copy(tokens = it.tokens.filter(filterPredicate)),
|
||||
)
|
||||
}
|
||||
.onFailure {
|
||||
Timber.e(it, "Unable to fetch hot crypto")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getAppCurrencyId(): String {
|
||||
return appPreferencesStore.getObjectSyncOrNull<CurrenciesResponse.Currency>(
|
||||
key = PreferencesKeys.SELECTED_APP_CURRENCY_KEY,
|
||||
)
|
||||
?.id
|
||||
?: "usd"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.tangem.datasource.exchangeservice.hotcrypto
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
/**
|
||||
* Hot crypto loader
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
interface HotCryptoLoader {
|
||||
|
||||
/**
|
||||
* Fetch hot crypto
|
||||
*
|
||||
* @param tokens already added tokens
|
||||
*/
|
||||
suspend fun fetch(tokens: List<UserTokensResponse.Token>)
|
||||
|
||||
/**
|
||||
* Update hot crypto
|
||||
*
|
||||
* @param currencies already added crypto currencies
|
||||
*/
|
||||
suspend fun update(currencies: List<CryptoCurrency>)
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.datasource.exchangeservice.hotcrypto
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.HotCryptoResponse
|
||||
import com.tangem.datasource.local.datastore.RuntimeStateStore
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Store of [HotCryptoResponse]
|
||||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
@Singleton
|
||||
class HotCryptoResponseStore @Inject constructor() : RuntimeStateStore<HotCryptoResponse> by RuntimeStateStore(
|
||||
defaultValue = HotCryptoResponse(imageHost = null, tokens = emptyList()),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue