From bb9d49e2e6e508689d612ecc4d8d8138c70d9c97 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Sep 2020 12:20:32 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/common/redux/global/GlobalAction.kt | 2 + .../tap/common/redux/global/GlobalReducer.kt | 5 +++ .../tap/common/redux/global/GlobalState.kt | 9 ++++ .../tap/features/home/redux/HomeMiddleware.kt | 1 + .../tap/features/wallet/redux/WalletAction.kt | 5 +++ .../features/wallet/redux/WalletMiddleware.kt | 32 +++++++++++++++ .../features/wallet/redux/WalletReducer.kt | 26 +++++++++++- .../network/coinmarketcap/CoinMarketCapApi.kt | 38 +++++++++++++++++ .../coinmarketcap/CoinMarketCapService.kt | 17 ++++++++ .../tap/network/coinmarketcap/Response.kt | 41 +++++++++++++++++++ 10 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt create mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt create mode 100644 app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 69c71cca29..26e4b46f87 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -3,9 +3,11 @@ package com.tangem.tap.common.redux.global import com.tangem.blockchain.common.WalletManager import com.tangem.commands.Card import org.rekotlin.Action +import java.math.BigDecimal sealed class GlobalAction : Action { data class LoadCard(val card: Card) : GlobalAction() data class LoadWalletManager(val walletManager: WalletManager) : GlobalAction() + data class SetFiatRate(val fiatRates: Pair) : GlobalAction() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt index fb3feefe6d..6236a643d6 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalReducer.kt @@ -11,6 +11,11 @@ fun globalReducer(action: Action, state: AppState): GlobalState { when (action) { is GlobalAction.LoadCard -> newState = newState.copy(card = action.card) + is GlobalAction.SetFiatRate -> { + val rates = newState.fiatRates.rates.toMutableMap() + rates[action.fiatRates.first] = action.fiatRates.second + newState = newState.copy(fiatRates = FiatRates(rates)) + } is GlobalAction.LoadWalletManager -> newState = newState.copy(walletManager = action.walletManager) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt index d8bf5b2c3e..ad3f0ec8e4 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalState.kt @@ -3,11 +3,20 @@ package com.tangem.tap.common.redux.global import com.tangem.blockchain.common.WalletManager import com.tangem.commands.Card import org.rekotlin.StateType +import java.math.BigDecimal data class GlobalState( val card: Card? = null, val walletManager: WalletManager? = null, + val fiatRates: FiatRates = FiatRates(emptyMap()), ) : StateType +data class FiatRates( + val rates: Map +) { + fun getRateForCryptoCurrency(currency: String): BigDecimal? { + return rates[currency] + } +} diff --git a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt index 70273c894c..8904e3c22a 100644 --- a/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/home/redux/HomeMiddleware.kt @@ -30,6 +30,7 @@ val homeMiddleware: Middleware = { dispatch, state -> store.dispatch(GlobalAction.LoadCard(result.data.card)) store.dispatch(GlobalAction.LoadWalletManager(result.data.walletManager)) store.dispatch(WalletAction.LoadWallet) + store.dispatch(WalletAction.LoadFiatRate) store.dispatch(WalletAction.LoadPayId) store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt index 9b38d5f4c5..88630c1f31 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletAction.kt @@ -7,12 +7,17 @@ import com.tangem.tap.common.redux.NotificationAction import com.tangem.tap.domain.TapError import com.tangem.wallet.R import org.rekotlin.Action +import java.math.BigDecimal sealed class WalletAction : Action { object LoadWallet : WalletAction() { data class Success(val wallet: Wallet): WalletAction() object Failure: WalletAction() } + object LoadFiatRate : WalletAction() { + data class Success(val fiatRates: Pair) : WalletAction() + object Failure: WalletAction() + } object LoadPayId : WalletAction() { data class Success(val payId: String): WalletAction() object NotCreated: WalletAction() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt index f89d07818f..dbd6616e4f 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletMiddleware.kt @@ -13,6 +13,7 @@ import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.PayIdManager import com.tangem.tap.domain.TapError import com.tangem.tap.domain.isPayIdSupported +import com.tangem.tap.network.coinmarketcap.CoinMarketCapService import com.tangem.tap.scope import com.tangem.tap.store import com.tangem.tap.tangemSdkManager @@ -47,6 +48,36 @@ val walletMiddleware: Middleware = { dispatch, state -> } } } + is WalletAction.LoadFiatRate -> { + scope.launch { + val blockchainCurrency = store.state.globalState.walletManager?.wallet?.blockchain?.currency + val tokenCurrency = store.state.globalState.walletManager?.wallet?.token?.symbol + + val blockchainRate = blockchainCurrency?.let { CoinMarketCapService().getRate(it) } + val tokenRate = tokenCurrency?.let { CoinMarketCapService().getRate(it) } + + withContext(Dispatchers.Main) { + when (blockchainRate) { + is Result.Success -> { + store.dispatch(GlobalAction.SetFiatRate(blockchainCurrency to blockchainRate.data) + ) + store.dispatch(WalletAction.LoadFiatRate.Success(blockchainCurrency to blockchainRate.data) + ) + } + is Result.Failure, null -> store.dispatch(WalletAction.LoadFiatRate.Failure) + } + when (tokenRate) { + is Result.Success -> { + store.dispatch(GlobalAction.SetFiatRate(tokenCurrency to tokenRate.data) + ) + store.dispatch(WalletAction.LoadFiatRate.Success(tokenCurrency to tokenRate.data) + ) + } + is Result.Failure, null -> store.dispatch(WalletAction.LoadFiatRate.Failure) + } + } + } + } is WalletAction.LoadPayId -> { if (!TapConfig.usePayId || store.state.walletState.payIdData.payIdState == PayIdState.Disabled || @@ -107,6 +138,7 @@ val walletMiddleware: Middleware = { dispatch, state -> store.dispatch(GlobalAction.LoadCard(result.data.card)) store.dispatch(GlobalAction.LoadWalletManager(result.data.walletManager)) store.dispatch(WalletAction.LoadWallet) + store.dispatch(WalletAction.LoadFiatRate) store.dispatch(WalletAction.LoadPayId) } } diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt index 472b46b2af..7041021ace 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletReducer.kt @@ -1,6 +1,7 @@ package com.tangem.tap.features.wallet.redux import com.tangem.blockchain.common.AmountType +import com.tangem.tap.common.extensions.toFiatString import com.tangem.tap.common.extensions.toFormattedString import com.tangem.tap.common.extensions.toQrCode import com.tangem.tap.common.redux.AppState @@ -26,22 +27,45 @@ fun walletReducer(action: Action, state: AppState): WalletState { is WalletAction.LoadWallet.Success -> { val token = action.wallet.amounts[AmountType.Token] val tokenData = if (token != null) { + val tokenFiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(token.currencySymbol) + val tokenFiatAmount = tokenFiatRate?.let { token.value?.toFiatString(it) } TokenData( token.value?.toFormattedString(action.wallet.blockchain) ?: "", - token.currencySymbol) + token.currencySymbol, tokenFiatAmount) } else { null } val amount = action.wallet.amounts[AmountType.Coin]?.value + val fiatRate = state.globalState.fiatRates.getRateForCryptoCurrency(action.wallet.blockchain.currency) + val fiatAmount = fiatRate?.let { amount?.toFiatString(it) } newState = newState.copy( state = ProgressState.Done, wallet = action.wallet, currencyData = BalanceWidgetData( BalanceStatus.VerifiedOnline, action.wallet.blockchain.fullName, amount?.toFormattedString(action.wallet.blockchain), token = tokenData, + fiatAmount = fiatAmount ) ) } + is WalletAction.LoadFiatRate.Success -> { + val rate = action.fiatRates.second + val currency = action.fiatRates.first + val fiatAmount = if (currency == newState.wallet?.blockchain?.currency) { + newState.wallet?.amounts?.get(AmountType.Coin)?.value?.toFiatString(rate) + } else { + null + } + val tokenFiatAmount = if (currency == newState.wallet?.token?.symbol) { + newState.wallet?.amounts?.get(AmountType.Token)?.value?.toFiatString(rate) + } else { + null + } + newState = newState.copy(currencyData = newState.currencyData.copy( + fiatAmount = fiatAmount, + token = newState.currencyData.token?.copy(fiatAmount = tokenFiatAmount) + )) + } is WalletAction.LoadWallet.Failure -> newState = newState.copy( state = ProgressState.Done, currencyData = newState.currencyData.copy(status = BalanceStatus.Unreachable) diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt new file mode 100644 index 0000000000..0c356d478e --- /dev/null +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapApi.kt @@ -0,0 +1,38 @@ +package com.tangem.tap.network.coinmarketcap + +import com.tangem.tap.TapConfig +import com.tangem.tap.network.createRetrofitInstance +import okhttp3.Interceptor +import okhttp3.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface CoinMarketCapApi { + + @GET("v1/tools/price-conversion") + suspend fun getRateInfo( + @Query("amount") amount: Int, + @Query("symbol") cryptoId: String + ): RateInfoResponse + + companion object { + private const val baseUrl = "https://pro-api.coinmarketcap.com/" + + fun create(): CoinMarketCapApi { + return createRetrofitInstance( + baseUrl, + listOf(createCoinMarketRequestInterceptor()), + ).create(CoinMarketCapApi::class.java) + } + } +} + +private fun createCoinMarketRequestInterceptor(): Interceptor { + return object : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val requestBuilder = chain.request().newBuilder() + requestBuilder.addHeader("X-CMC_PRO_API_KEY", TapConfig.coinMarketCapKey) + return chain.proceed(requestBuilder.build()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt new file mode 100644 index 0000000000..f76dc20cf8 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/CoinMarketCapService.kt @@ -0,0 +1,17 @@ +package com.tangem.tap.network.coinmarketcap + +import com.tangem.commands.common.network.Result +import com.tangem.commands.common.network.performRequest +import java.math.BigDecimal + +class CoinMarketCapService { + private val api: CoinMarketCapApi by lazy { CoinMarketCapApi.create() } + + suspend fun getRate(currency: String): Result { + val response = performRequest { api.getRateInfo(1, currency) } + return when (response) { + is Result.Success -> Result.Success(response.data.data.quote.usd.price) + is Result.Failure -> response + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt b/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt new file mode 100644 index 0000000000..f4ec9fa804 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/network/coinmarketcap/Response.kt @@ -0,0 +1,41 @@ +package com.tangem.tap.network.coinmarketcap + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import java.math.BigDecimal + +@JsonClass(generateAdapter = true) +data class RateInfoResponse( + val status: Status, + val data: RateData +) + +@JsonClass(generateAdapter = true) +data class RateData( + val quote: Quote +) + +@JsonClass(generateAdapter = true) +data class Quote( + @Json(name = "USD") + val usd: CurrencyRate +) + +@JsonClass(generateAdapter = true) +data class CurrencyRate( + val price: BigDecimal +) + + +@JsonClass(generateAdapter = true) +data class Status( + val timestamp: String, + @Json(name = "error_code") + val errorCode: Int, + @Json(name = "error_message") + val errorMessage: String?, + val elapsed: Int, + @Json(name = "credit_count") + val creditCount: Int, + val notice: String? +) \ No newline at end of file