From 2f7ed460ff178bbe98b72660c253ca97146d6b6f Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 21 Apr 2022 19:38:58 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tap/common/extensions/Specific.kt | 4 +- .../com/tangem/tap/domain/TapWalletManager.kt | 31 ++++---- .../features/details/redux/DetailsAction.kt | 4 +- .../details/redux/DetailsMiddleware.kt | 13 ++-- .../features/details/redux/DetailsState.kt | 4 +- .../details/ui/CurrencySelectionDialog.kt | 10 +-- .../compose/SelectTokenNetworkDialog.kt | 2 +- .../compose/test/TestAddCostomTokenActions.kt | 41 +--------- .../tap/features/wallet/redux/WalletAction.kt | 2 +- .../middlewares/MultiWalletMiddleware.kt | 22 +++--- .../redux/middlewares/WalletMiddleware.kt | 17 ++--- .../persistence/FiatCurrenciesPrefStorage.kt | 8 +- .../java/com/tangem/domain/DomainDialog.kt | 6 +- .../addCustomToken/AddCustomTokenService.kt | 42 ++++------ .../addCustomToken/redux/AddCustomTokenHub.kt | 30 ++++---- .../redux/AddCustomTokenState.kt | 2 +- .../network/api/tangemTech/Responses.kt | 76 ++++++++----------- .../network/api/tangemTech/TangemTechApi.kt | 26 +++---- .../api/tangemTech/TangemTechService.kt | 72 ++++++------------ 19 files changed, 160 insertions(+), 252 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt index 1b0d1de783..4b978e18f6 100644 --- a/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt +++ b/app/src/main/java/com/tangem/tap/common/extensions/Specific.kt @@ -1,7 +1,7 @@ package com.tangem.tap.common.extensions import com.tangem.common.extensions.isZero -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.tap.common.redux.global.FiatCurrencyName import java.math.BigDecimal import java.math.RoundingMode @@ -52,7 +52,7 @@ fun BigDecimal.toFormattedFiatValue(fiatCurrencyName: FiatCurrencyName): String return "≈ ${fiatCurrencyName}  $this" } -fun Coins.CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}" +fun CurrenciesResponse.Currency.toFormattedString(): String = "${this.name} (${this.code}) - ${this.unit}" fun BigDecimal.stripZeroPlainString(): String = this.stripTrailingZeros().toPlainString() diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index e1cd14ba2f..aa0b8d6ed6 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -87,22 +87,21 @@ class TapWalletManager { return newResult } - suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, wallet: Wallet) { - val currencies = wallet.getTokens() + suspend fun loadFiatRate(currencyId: FiatCurrencyName, wallet: Wallet) { + val coinsList = wallet.getTokens() .map { Currency.Token(it, wallet.blockchain, wallet.publicKey.derivationPath?.rawPath) } .plus(Currency.Blockchain(wallet.blockchain, wallet.publicKey.derivationPath?.rawPath)) - loadFiatRate(fiatCurrency, currencies) + loadFiatRate(currencyId, coinsList) } - suspend fun loadFiatRate(fiatCurrency: FiatCurrencyName, currencies: List) { + suspend fun loadFiatRate(currencyId: FiatCurrencyName, coinsList: List) { suspend fun handleFiatRatesResult(rates: Map?>) { rates.forEach { (currency, priceResult) -> when (priceResult) { is Result.Success -> { - dispatchOnMain( - WalletAction.LoadFiatRate.Success( - currency to priceResult.data - )) + dispatchOnMain(WalletAction.LoadFiatRate.Success( + currency to priceResult.data + )) } is Result.Failure -> dispatchOnMain(WalletAction.LoadFiatRate.Failure) null -> {} @@ -111,26 +110,26 @@ class TapWalletManager { } // get and submit previous result of equivalents. - val throttledResult = currencies.filter { fiatRatesThrottler.isStillThrottled(it) }.map { + val throttledResult = coinsList.filter { fiatRatesThrottler.isStillThrottled(it) }.map { Pair(it, fiatRatesThrottler.geValue(it)) } if (throttledResult.isNotEmpty()) { handleFiatRatesResult(throttledResult.toMap()) } - val toUpdateCurrencies = currencies.filter { !fiatRatesThrottler.isStillThrottled(it) } - val toUpdateIds = toUpdateCurrencies.mapNotNull { it.coinId }.distinct() - if (toUpdateIds.isEmpty()) return + val currenciesToUpdate = coinsList.filter { !fiatRatesThrottler.isStillThrottled(it) } + val coinIds = currenciesToUpdate.mapNotNull { it.coinId }.distinct() + if (coinIds.isEmpty()) return //TODO: refactoring: move fiatRatesThrottler to the TangemTechRepository - when (val result = tangemTechService.coins.prices(fiatCurrency, toUpdateIds)) { + when (val result = tangemTechService.rates(currencyId, coinIds)) { is Result.Success -> { - val priceResultList: Map> = result.data.prices.mapValues { + val ratesResultList: Map> = result.data.rates.mapValues { Result.Success(it.value.toBigDecimal()) } val updatedCurrencies = mutableMapOf?>() - toUpdateCurrencies.forEach { currency -> - priceResultList[currency.coinId]?.let { + currenciesToUpdate.forEach { currency -> + ratesResultList[currency.coinId]?.let { updatedCurrencies[currency] = it fiatRatesThrottler.updateThrottlingTo(currency) fiatRatesThrottler.setValue(currency, it) diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 2077ee8e4d..5b572f8fff 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -4,7 +4,7 @@ import com.tangem.blockchain.common.Wallet import com.tangem.common.card.Card import com.tangem.domain.common.ScanResponse import com.tangem.domain.common.TwinCardNumber -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.network.api.tangemTech.TangemTechService import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.tap.common.redux.NotificationAction @@ -48,7 +48,7 @@ sealed class DetailsAction : Action { object CreateBackup : DetailsAction() sealed class AppCurrencyAction : DetailsAction() { - data class SetCurrencies(val currencies: List) : AppCurrencyAction() + data class SetCurrencies(val currencies: List) : AppCurrencyAction() object ChooseAppCurrency : AppCurrencyAction() object Cancel : AppCurrencyAction() data class SelectAppCurrency(val fiatCurrencyName: FiatCurrencyName) : AppCurrencyAction() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 03a3298d90..3bd207b288 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -4,7 +4,6 @@ import com.tangem.common.CompletionResult import com.tangem.common.card.FirmwareVersion import com.tangem.common.core.TangemSdkError import com.tangem.common.services.Result -import com.tangem.network.api.tangemTech.Coins import com.tangem.operations.pins.CheckUserCodesResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.Analytics @@ -77,14 +76,12 @@ class DetailsMiddleware { scope.launch { val tangemTechService = action.tangemTechService - when (val result = tangemTechService.coins.currencies()) { + when (val result = tangemTechService.currencies()) { is Result.Success -> { - val fiatCurrencies = result.data.currencies.filter { - it.type == Coins.CurrenciesResponse.CurrencyType.Fiat.type - } - if (fiatCurrencies.isNotEmpty() && fiatCurrencies.toSet() != storedFiatCurrencies.toSet()) { - fiatCurrenciesPrefStorage.save(fiatCurrencies) - dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(fiatCurrencies)) + val currenciesList = result.data.currencies + if (currenciesList.isNotEmpty() && currenciesList.toSet() != storedFiatCurrencies.toSet()) { + fiatCurrenciesPrefStorage.save(currenciesList) + dispatchOnMain(DetailsAction.AppCurrencyAction.SetCurrencies(currenciesList)) } } is Result.Failure -> {} diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index bcf176341b..0d2cf689d5 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -3,7 +3,7 @@ package com.tangem.tap.features.details.redux import android.net.Uri import com.tangem.blockchain.common.Wallet import com.tangem.domain.common.ScanResponse -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.tap.common.entities.Button import com.tangem.tap.common.entities.TapCurrency.Companion.DEFAULT_FIAT_CURRENCY import com.tangem.tap.common.redux.global.FiatCurrencyName @@ -55,5 +55,5 @@ enum class SecurityOption { LongTap, PassCode, AccessCode } data class AppCurrencyState( val fiatCurrencyName: FiatCurrencyName = DEFAULT_FIAT_CURRENCY, val showAppCurrencyDialog: Boolean = false, - val fiatCurrencies: List? = null, + val fiatCurrencies: List? = null, ) \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt b/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt index d55e321dd6..d7248b75c8 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/CurrencySelectionDialog.kt @@ -2,7 +2,7 @@ package com.tangem.tap.features.details.ui import android.content.Context import androidx.appcompat.app.AlertDialog -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CurrenciesResponse import com.tangem.tap.common.extensions.toFormattedString import com.tangem.tap.common.redux.global.FiatCurrencyName import com.tangem.tap.features.details.redux.DetailsAction @@ -13,11 +13,11 @@ class CurrencySelectionDialog { var dialog: AlertDialog? = null - fun show(currencies: List, currentAppCurrency: FiatCurrencyName, context: Context) { + fun show(currenciesList: List, currentAppCurrency: FiatCurrencyName, context: Context) { if (dialog == null) { - val currenciesToShow = currencies.map { it.toFormattedString() }.toTypedArray() - var currentSelection = currencies.indexOfFirst { it.code == currentAppCurrency } + val currenciesToShow = currenciesList.map { it.toFormattedString() }.toTypedArray() + var currentSelection = currenciesList.indexOfFirst { it.code == currentAppCurrency } dialog = AlertDialog.Builder(context) .setTitle(context.getString(R.string.details_row_title_currency)) @@ -25,7 +25,7 @@ class CurrencySelectionDialog { store.dispatch(DetailsAction.AppCurrencyAction.Cancel) } .setPositiveButton(context.getString(R.string.common_done)) { _, _ -> - val selectedCurrency = currencies[currentSelection] + val selectedCurrency = currenciesList[currentSelection] store.dispatch(DetailsAction.AppCurrencyAction.SelectAppCurrency(selectedCurrency.code)) } .setOnDismissListener { diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt index 946690c107..83a62fc380 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/SelectTokenNetworkDialog.kt @@ -17,5 +17,5 @@ fun SelectTokenNetworkDialog(dialog: DomainDialog.SelectTokenDialog, onDismissRe items = dialog.items, onSelect = dialog.onSelect, onDismissRequest = onDismissRequest - ) { contract -> TitleSubtitle(dialog.networkIdConverter(contract.networkId), contract.address) } + ) { network -> TitleSubtitle(dialog.networkIdConverter(network.networkId), network.address ?: "") } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestAddCostomTokenActions.kt b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestAddCostomTokenActions.kt index 981e2a1b74..3ec8accff4 100644 --- a/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestAddCostomTokenActions.kt +++ b/app/src/main/java/com/tangem/tap/features/tokens/addCustomToken/compose/test/TestAddCostomTokenActions.kt @@ -12,14 +12,10 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.tangem.blockchain.common.Blockchain import com.tangem.common.extensions.VoidCallback -import com.tangem.common.services.Result import com.tangem.domain.common.form.Field -import com.tangem.domain.features.addCustomToken.AddCustomTokenService import com.tangem.domain.features.addCustomToken.redux.AddCustomTokenAction import com.tangem.domain.redux.domainStore -import com.tangem.network.api.tangemTech.TangemTechService import com.tangem.wallet.BuildConfig -import timber.log.Timber /** [REDACTED_AUTHOR] @@ -40,7 +36,7 @@ fun TestAddCustomTokenActions() { ActionRow("All in one") { AllInOne() } // Any action -// ActionRow("CustomActions - find tokens active=false, decimals != null") { CustomActions() } +// ActionRow("CustomActions - find coins active=false, decimals != null") { CustomActions() } } } @@ -147,41 +143,6 @@ private fun UnknownContracts() { @Composable private fun CustomActions() { - - CustomActionButton( - name = "Find tokens in several networks", - action = { - val manager = AddCustomTokenService(TangemTechService()) - val currencies = manager.tokens() - val asdfsd = mutableMapOf>() - val contractAddresses = currencies.mapNotNull { currency -> - currency.contracts?.map { it.address } - }.flatten() - contractAddresses.take(500).forEachIndexed() { index, address -> - when (val result = manager.checkAddress(address)) { - is Result.Success -> { - val contractList = mutableListOf() - result.data.forEach { token -> - token.contracts.forEach { contract -> - if (!contract.active && contract.decimalCount != null) { - contractList.add(contract) - } - } - } - if (contractList.isNotEmpty()) { - val list = asdfsd[address] ?: mutableListOf() - list.addAll(contractList) - asdfsd[address] = list - } - Timber.e("Success. handle $index item from size ${contractAddresses.size}. Result = ${asdfsd.size}") - } - is Result.Failure -> {} - } - } - val result = asdfsd.filter { it.value.size > 1 } - if (result.isEmpty()) return@CustomActionButton - } - ) } @Composable 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 ecb46e6e21..6d4553f16a 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 @@ -96,7 +96,7 @@ sealed class WalletAction : Action { } data class LoadFiatRate( - val wallet: Wallet? = null, val currencyList: List? = null, + val wallet: Wallet? = null, val coinsList: List? = null, ) : WalletAction() { data class Success(val fiatRate: Pair) : WalletAction() object Failure : WalletAction() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt index 193f133b26..d4c605ca78 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/MultiWalletMiddleware.kt @@ -57,19 +57,17 @@ class MultiWalletMiddleware { blockchainNetwork = action.blockchain ) } - store.dispatch( - WalletAction.LoadFiatRate( - currencyList = listOf( - Currency.Blockchain( - action.blockchain.blockchain, - action.blockchain.derivationPath - ) + store.dispatch(WalletAction.LoadFiatRate( + coinsList = listOf( + Currency.Blockchain( + action.blockchain.blockchain, + action.blockchain.derivationPath ) ) - ) - store.dispatch( - WalletAction.LoadWallet(action.blockchain, action.walletManager) - ) + )) + store.dispatch(WalletAction.LoadWallet( + action.blockchain, action.walletManager + )) } is WalletAction.MultiWallet.SaveCurrencies -> { globalState.scanResponse?.card?.cardId?.let { @@ -227,7 +225,7 @@ class MultiWalletMiddleware { store.dispatch(WalletAction.MultiWallet.AddBlockchain(blockchainNetwork, it)) } ?: return - store.dispatch(WalletAction.LoadFiatRate(currencyList = tokens.map { token -> + store.dispatch(WalletAction.LoadFiatRate(coinsList = tokens.map { token -> Currency.Token( token, blockchainNetwork.blockchain, blockchainNetwork.derivationPath ) diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt index 428ef7b4b5..b77bbb3b08 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WalletMiddleware.kt @@ -101,27 +101,26 @@ class WalletMiddleware { warningsMiddleware.tryToShowAppRatingWarning(action.wallet) } is WalletAction.LoadFiatRate -> { - val tapWalletManager = globalState.tapWalletManager - val fiatAppCurrency = globalState.appCurrency + val appCurrencyId = globalState.appCurrency scope.launch { when { action.wallet != null -> { globalState.tapWalletManager.loadFiatRate( - fiatCurrency = fiatAppCurrency, + currencyId = appCurrencyId, wallet = action.wallet, ) } - action.currencyList != null -> { + action.coinsList != null -> { globalState.tapWalletManager.loadFiatRate( - fiatCurrency = fiatAppCurrency, - currencies = action.currencyList, + currencyId = appCurrencyId, + coinsList = action.coinsList, ) } else -> { - val currencyList = walletState.walletsData.map { it.currency } + val coinsList = walletState.walletsData.map { it.currency } globalState.tapWalletManager.loadFiatRate( - fiatCurrency = fiatAppCurrency, - currencies = currencyList, + currencyId = appCurrencyId, + coinsList = coinsList, ) } } diff --git a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt index 79a010075e..3af9991f25 100644 --- a/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt +++ b/app/src/main/java/com/tangem/tap/persistence/FiatCurrenciesPrefStorage.kt @@ -3,7 +3,7 @@ package com.tangem.tap.persistence import android.content.SharedPreferences import androidx.core.content.edit import com.tangem.common.json.MoshiJsonConverter -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CurrenciesResponse /** [REDACTED_AUTHOR] @@ -21,14 +21,14 @@ class FiatCurrenciesPrefStorage( } } - fun save(currencies: List) { + fun save(currencies: List) { val json: String = converter.toJson(currencies) return preferences.edit().putString(FIAT_CURRENCIES_KEY, json).apply() } - fun restore(): List { + fun restore(): List { val json = preferences.getString(FIAT_CURRENCIES_KEY, "") - val type = converter.typedList(Coins.CurrenciesResponse.Currency::class.java) + val type = converter.typedList(CurrenciesResponse.Currency::class.java) if (json.isNullOrBlank()) return emptyList() return converter.fromJson(json, type) ?: emptyList() diff --git a/domain/src/main/java/com/tangem/domain/DomainDialog.kt b/domain/src/main/java/com/tangem/domain/DomainDialog.kt index e95abd7626..3e956b77da 100644 --- a/domain/src/main/java/com/tangem/domain/DomainDialog.kt +++ b/domain/src/main/java/com/tangem/domain/DomainDialog.kt @@ -1,7 +1,7 @@ package com.tangem.domain import com.tangem.common.extensions.VoidCallback -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CoinsResponse /** [REDACTED_AUTHOR] @@ -11,9 +11,9 @@ sealed interface DomainDialog { data class DialogError(val error: DomainError) : DomainDialog data class SelectTokenDialog( - val items: List, + val items: List, val networkIdConverter: (String) -> String, - val onSelect: (Coins.CheckAddressResponse.Token.Contract) -> Unit, + val onSelect: (CoinsResponse.Coin.Network) -> Unit, val onClose: VoidCallback = {} ) : DomainDialog } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt index 464dec0abd..cf5ab1ceb3 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/AddCustomTokenService.kt @@ -1,7 +1,7 @@ package com.tangem.domain.features.addCustomToken import com.tangem.common.services.Result -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CoinsResponse import com.tangem.network.api.tangemTech.TangemTechService /** @@ -11,41 +11,31 @@ class AddCustomTokenService( private val tangemTechService: TangemTechService ) { - suspend fun checkAddress( + suspend fun findToken( contractAddress: String, - networkId: String? = null - ): Result> { - val result = tangemTechService.coins.checkAddress(contractAddress, networkId) + networkId: String? = null, + active: Boolean? = null, + ): Result> { + val result = tangemTechService.coins(contractAddress, networkId, active) return when (result) { is Result.Success -> { - val resultTokens = result.data.tokens - var tokensList = mutableListOf() - resultTokens.forEach { token -> - val contractsWithTheSameAddress = token.contracts + var coinsList = mutableListOf() + result.data.coins.forEach { coin -> + val networksWithTheSameAddress = coin.networks + .filter { it.address != null || it.decimalCount != null } .filter { it.address == contractAddress } - .filter { it.decimalCount != null } - if (contractsWithTheSameAddress.isNotEmpty()) { - val newToken = token.copy(contracts = contractsWithTheSameAddress) - tokensList.add(newToken) + if (networksWithTheSameAddress.isNotEmpty()) { + val newToken = coin.copy(networks = networksWithTheSameAddress) + coinsList.add(newToken) } } - if (tokensList.size > 1) { + if (coinsList.size > 1) { // https://tangem.slack.com/archives/GMXC6PP71/p1649672562078679 - tokensList = mutableListOf(tokensList[0]) + coinsList = mutableListOf(coinsList[0]) } - Result.Success(tokensList) + Result.Success(coinsList) } is Result.Failure -> result } } - - suspend fun tokens(): List { - return when (val result = tangemTechService.coins.tokens()) { - is Result.Success -> { - val tokens = result.data.tokens - tokens.filter { it.contracts.isNullOrEmpty() } - } - is Result.Failure -> emptyList() - } - } } \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt index 33084f8cb8..71f94ee687 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenHub.kt @@ -23,7 +23,7 @@ import com.tangem.domain.redux.DomainState import com.tangem.domain.redux.dispatchOnMain import com.tangem.domain.redux.domainStore import com.tangem.domain.redux.global.DomainGlobalAction -import com.tangem.network.api.tangemTech.Coins +import com.tangem.network.api.tangemTech.CoinsResponse import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -153,7 +153,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } /** - * This feature is only needed until Solana tokens are added. + * This feature is only needed until Solana coins are added. * While they are not there - this function excludes the Solana blockchain if the user has * filled in at least one field of the token. */ @@ -197,7 +197,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT private suspend fun requestInfoAboutToken( contractAddress: String, - ): List { + ): List { val tangemTechServiceManager = requireNotNull(hubState.tangemTechServiceManager) dispatchOnMain(Screen.UpdateTokenFields(listOf(ContractAddress to ViewStates.TokenField(isLoading = true)))) @@ -210,7 +210,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT // got the result faster than 500ms and the delay would only be the difference between them. delay(500) - val foundTokensResult = tangemTechServiceManager.checkAddress(contractAddress, selectedNetworkId) + val foundTokensResult = tangemTechServiceManager.findToken(contractAddress, selectedNetworkId) val result = when (foundTokensResult) { is Result.Success -> foundTokensResult.data is Result.Failure -> { @@ -223,7 +223,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT return result } - private suspend fun manageFoundTokenChanges(foundTokens: List) { + private suspend fun manageFoundTokenChanges(foundTokens: List) { if (foundTokens.isEmpty()) { // token not found - it's completely custom TokenAlreadyAdded.remove() @@ -240,12 +240,12 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT val foundToken = foundTokens[0] dispatchOnMain(SetFoundTokenId(foundToken.id)) when { - foundToken.contracts.isEmpty() -> { + foundToken.networks.isEmpty() -> { Timber.e("Unexpected state -> throw to FB") } - foundToken.contracts.size == 1 -> { + foundToken.networks.size == 1 -> { // token with single contract address - val singleTokenContract = foundToken.contracts[0] + val singleTokenContract = foundToken.networks[0] fillTokenFields(foundToken, singleTokenContract) val isInAppSavedTokens = isTokenPersistIntoAppSavedTokensList() @@ -254,8 +254,8 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT lockAddButton() PotentialScamToken.replace(TokenAlreadyAdded) } else { - // not in the saved tokens list - if (singleTokenContract.active) { + // not in the saved coins list + if (foundToken.active) { lockTokenFields() unlockAddButton() if (hubState.derivationPathIsSelected()) { @@ -274,7 +274,7 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT PotentialScamToken.replace(TokenAlreadyAdded) val dialog = DomainDialog.SelectTokenDialog( - items = foundToken.contracts, + items = foundToken.networks, networkIdConverter = { networkId -> val blockchain = Blockchain.fromNetworkId(networkId) if (blockchain == null || blockchain == Blockchain.Unknown) { @@ -490,14 +490,14 @@ internal class AddCustomTokenHub : BaseStoreHub("AddCustomT } private suspend fun fillTokenFields( - token: Coins.CheckAddressResponse.Token, - contract: Coins.CheckAddressResponse.Token.Contract, + token: CoinsResponse.Coin, + coinNetwork: CoinsResponse.Coin.Network, ) { - val blockchain = Blockchain.fromNetworkId(contract.networkId) ?: Blockchain.Unknown + val blockchain = Blockchain.fromNetworkId(coinNetwork.networkId) ?: Blockchain.Unknown Network.setFieldValue(Field.Data(blockchain, false)) Name.setFieldValue(Field.Data(token.name, false)) Symbol.setFieldValue(Field.Data(token.symbol, false)) - Decimals.setFieldValue(Field.Data(contract.decimalCount.toString(), false)) + Decimals.setFieldValue(Field.Data(coinNetwork.decimalCount.toString(), false)) dispatchOnMain(UpdateForm(hubState)) } diff --git a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt index f7f01351ec..4569963405 100644 --- a/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt +++ b/domain/src/main/java/com/tangem/domain/features/addCustomToken/redux/AddCustomTokenState.kt @@ -176,7 +176,7 @@ data class AddCustomTokenState( Blockchain.Polygon, Blockchain.Avalanche, Blockchain.Fantom, - Blockchain.Solana, // should be unsupported for tokens until they are added to the Blockchain SDK + Blockchain.Solana, // should be unsupported for coins until they are added to the Blockchain SDK ) if (type == CustomTokenType.Token) networks.remove(Blockchain.Solana) diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt b/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt index 02e15c4672..d5c4644c6e 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt +++ b/network/src/main/java/com/tangem/network/api/tangemTech/Responses.kt @@ -8,53 +8,43 @@ import java.math.BigDecimal interface HttpResponse sealed interface TangemTechResponse : HttpResponse -sealed class Coins : TangemTechResponse { - data class PricesResponse(val prices: Map) : Coins() +data class CoinsResponse( + val imageHost: String, + val coins: List, + val total: Int +) : TangemTechResponse { - data class CheckAddressResponse(val imageHost: String?, val tokens: List, val total: Int) : Coins() { - data class Token( - val id: String, - val name: String, - val symbol: String, - val active: Boolean, - val contracts: List - ) { - data class Contract( - val networkId: String, - val address: String, - val decimalCount: BigDecimal?, - val active: Boolean - ) - } + data class Coin( + val id: String, + val name: String, + val symbol: String, + val active: Boolean, + val networks: List = listOf() + ) : TangemTechResponse { + + data class Network( + val networkId: String, + val address: String? = null, + val decimalCount: BigDecimal? = null, + ) : TangemTechResponse } +} - data class TokensResponse(val imageHost: String, val tokens: List, val total: Int) : Coins() { - data class Token( - val id: String, - val name: String, - val symbol: String, - val contracts: List? - ) { - data class Contract( - val networkId: String, - val address: String, - val decimalCount: BigDecimal?, - ) - } - } +//rates.keys = networkId's +data class RatesResponse(val rates: Map) : TangemTechResponse - data class CurrenciesResponse(val currencies: List) { - data class Currency( - val id: String, - val code: String, // this is an uppercase id - val name: String, - val rateBTC: String, - val unit: String, // $, €, ₽ - val type: String, - ) +data class CurrenciesResponse(val currencies: List) { - enum class CurrencyType(val type: String) { - Fiat("fiat"), Crypto("crypto") - } + data class Currency( + val id: String, + val code: String, // this is an uppercase id + val name: String, + val rateBTC: String, + val unit: String, // $, €, ₽ + val type: CurrencyType, + ) : TangemTechResponse + + enum class CurrencyType(val type: String) { + Fiat("fiat"), Crypto("crypto") } } \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt b/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt index 622f2a299a..693109cb18 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt +++ b/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechApi.kt @@ -8,22 +8,20 @@ import retrofit2.http.Query */ interface TangemTechApi { - @GET("coins/prices") - suspend fun coinsPrices( - @Query("currency") currency: String, - @Query("ids") ids: String, - ): Coins.PricesResponse - - @GET("coins/check-address") - suspend fun coinsCheckAddress( - @Query("contractAddress") contractAddress: String, + @GET("coins") + suspend fun coins( + @Query("contractAddress") contractAddress: String? = null, @Query("networkId") networkId: String? = null, - ): Coins.CheckAddressResponse + @Query("active") active: Boolean? = null, + ): CoinsResponse - @GET("coins/currencies") - suspend fun coinsCurrencies(): Coins.CurrenciesResponse + @GET("rates") + suspend fun rates( + @Query("currencyId") currencyId: String, + @Query("coinIds") coinIds: String, + ): RatesResponse - @GET("coins/tokens") - suspend fun coinsTokens(): Coins.TokensResponse + @GET("currencies") + suspend fun currencies(): CurrenciesResponse } \ No newline at end of file diff --git a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt b/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt index d6c5f5b66a..e4c3321f3b 100644 --- a/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt +++ b/network/src/main/java/com/tangem/network/api/tangemTech/TangemTechService.kt @@ -12,19 +12,33 @@ import kotlinx.coroutines.withContext [REDACTED_AUTHOR] */ class TangemTechService { - - val coins: CoinsRoute = CoinsRoute() - - private val techRoutes: List = listOf( - coins - ) - private val headerInterceptors = mutableListOf( CacheControlHttpInterceptor(cacheMaxAge) ) - + private var api: TangemTechApi = createApi() + suspend fun coins( + contractAddress: String? = null, + networkId: String? = null, + active: Boolean? = null, + ): Result = withContext(Dispatchers.IO) { + performRequest { api.coins(contractAddress, networkId, active) } + } + + suspend fun rates( + currency: String, + ids: List + ): Result = withContext(Dispatchers.IO) { + performRequest { + api.rates(currency.lowercase(), ids.joinToString(",")) + } + } + + suspend fun currencies(): Result = withContext(Dispatchers.IO) { + performRequest { api.currencies() } + } + fun addHeaderInterceptors(interceptors: List) { headerInterceptors.removeAll(interceptors) headerInterceptors.addAll(interceptors) @@ -37,49 +51,11 @@ class TangemTechService { interceptors = headerInterceptors.toList(), // logEnabled = true, ) - return retrofit.create(TangemTechApi::class.java).apply { - techRoutes.forEach { it.setApi(this) } - } + return retrofit.create(TangemTechApi::class.java) } companion object { - const val baseUrl = "https://api.tangem-tech.com/" + const val baseUrl = "https://api.tangem-tech.com/v1/" const val cacheMaxAge = 600 } -} - -private interface TangemTechRoute { - fun setApi(api: TangemTechApi) -} - -class CoinsRoute : TangemTechRoute { - private lateinit var api: TangemTechApi - - override fun setApi(api: TangemTechApi) { - this.api = api - } - - suspend fun prices( - currency: String, - ids: List - ): Result = withContext(Dispatchers.IO) { - performRequest { - api.coinsPrices(currency.lowercase(), ids.joinToString(",")) - } - } - - suspend fun checkAddress( - contractAddress: String, - networkId: String? = null - ): Result = withContext(Dispatchers.IO) { - performRequest { api.coinsCheckAddress(contractAddress, networkId) } - } - - suspend fun currencies(): Result = withContext(Dispatchers.IO) { - performRequest { api.coinsCurrencies() } - } - - suspend fun tokens(): Result = withContext(Dispatchers.IO) { - performRequest { api.coinsTokens() } - } } \ No newline at end of file