Updated on 2026-08-14

This commit is contained in:
Tangem 2023-11-22 22:19:24 +02:00
parent ccc9090907
commit c4b1dceb65
6 changed files with 50 additions and 46 deletions

View file

@ -6,10 +6,13 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.WalletManager
import com.tangem.common.doOnFailure
import com.tangem.common.extensions.guard
import com.tangem.data.tokens.utils.CryptoCurrencyFactory
import com.tangem.domain.common.BlockchainNetwork
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.toCoinId
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.lib.crypto.UserWalletManager
@ -20,6 +23,7 @@ import com.tangem.lib.crypto.models.ProxyAmount
import com.tangem.lib.crypto.models.ProxyFiatCurrency
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletCurrenciesManager
import com.tangem.tap.walletStoresManager
@ -34,6 +38,8 @@ class UserWalletManagerImpl(
private val walletFeatureToggles: WalletFeatureToggles,
) : UserWalletManager {
val cryptoCurrencyFactory = CryptoCurrencyFactory()
override suspend fun getUserTokens(
networkId: String,
derivationPath: String?,
@ -78,13 +84,21 @@ class UserWalletManagerImpl(
}
}
override fun getNativeTokenForNetwork(networkId: String): Currency {
override fun getNativeTokenForNetwork(networkId: String): CryptoCurrency {
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
return NativeToken(
id = blockchain.toCoinId(),
name = blockchain.fullName,
symbol = blockchain.currency,
networkId = networkId,
return requireNotNull(
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
derivationStyleProvider = requireNotNull(
store.state.globalState
.userWalletsListManager
?.selectedUserWalletSync
?.scanResponse
?.derivationStyleProvider,
),
)
)
}

View file

@ -22,6 +22,7 @@ dependencies {
implementation(project(":data:common"))
implementation(project(":libs:auth"))
implementation(project(":libs:crypto"))
implementation(projects.domain.tokens.models)
implementation(deps.material)

View file

@ -6,8 +6,10 @@ import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.Network
import com.tangem.domain.tokens.model.Quote
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.tokens.repository.NetworksRepository
import com.tangem.domain.tokens.repository.QuotesRepository
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
import com.tangem.feature.swap.domain.cache.SwapDataCache
@ -44,6 +46,7 @@ internal class SwapInteractorImpl @Inject constructor(
private val walletFeatureToggles: WalletFeatureToggles,
private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
private val quotesRepository: QuotesRepository,
) : SwapInteractor {
// TODO: Move to DI
@ -389,32 +392,6 @@ internal class SwapInteractorImpl @Inject constructor(
}
}
@Suppress("UnusedPrivateMember")
@Deprecated("used in old swap mechanism")
private fun getTokensWithBalance(
tokens: List<Currency>,
balances: Map<String, SwapAmount>,
rates: Map<String, Double>,
appCurrency: ProxyFiatCurrency,
): List<TokenWithBalance> {
return tokens.map {
val balance = balances[it.symbol]
TokenWithBalance(
token = it,
tokenBalanceData = TokenBalanceData(
amount = balance?.let { amount ->
amountFormatter.formatSwapAmountToUI(amount, it.symbol)
},
amountEquivalent = balance?.value?.toFiatString(
rateValue = rates[it.id]?.toBigDecimal() ?: BigDecimal.ZERO,
fiatCurrencyName = appCurrency.symbol,
formatWithSpaces = true,
),
),
)
}
}
private suspend fun isAllowedToSpend(networkId: String, fromToken: CryptoCurrency, amount: SwapAmount): Boolean {
if (fromToken is CryptoCurrency.Coin) return true
return getSelectedWalletSyncUseCase().fold(
@ -538,8 +515,8 @@ internal class SwapInteractorImpl @Inject constructor(
private suspend fun getFormattedFiatFees(networkId: String, vararg fees: BigDecimal): List<String> {
val appCurrency = userWalletManager.getUserAppCurrency()
val nativeToken = userWalletManager.getNativeTokenForNetwork(networkId)
val rates = repository.getRates(appCurrency.code, listOf(nativeToken.id))
return rates[nativeToken.id]?.toBigDecimal()?.let { rate ->
val rates = getQuotes(nativeToken.id)
return rates[nativeToken.id]?.fiatRate?.let { rate ->
fees.map { fee ->
" (${fee.toFiatString(rate, appCurrency.symbol, true)})"
}
@ -629,28 +606,26 @@ internal class SwapInteractorImpl @Inject constructor(
val toToken = toTokenStatus.currency
val appCurrency = userWalletManager.getUserAppCurrency()
val nativeToken = userWalletManager.getNativeTokenForNetwork(networkId)
val rates = repository.getRates(
appCurrency.code,
listOf(fromToken.network.backendId, toToken.network.backendId, nativeToken.id),
)
val rates = getQuotes(fromToken.id, toToken.id, nativeToken.id)
return SwapState.QuotesLoadedState(
fromTokenInfo = TokenSwapInfo(
tokenAmount = fromTokenAmount,
cryptoCurrencyStatus = fromTokenStatus,
amountFiat = rates[fromToken.network.backendId]?.toBigDecimal()?.multiply(fromTokenAmount.value)
amountFiat = rates[fromToken.id]?.fiatRate?.multiply(fromTokenAmount.value)
?: BigDecimal.ZERO,
),
toTokenInfo = TokenSwapInfo(
tokenAmount = toTokenAmount,
cryptoCurrencyStatus = toTokenStatus,
amountFiat = rates[toToken.network.backendId]?.toBigDecimal()?.multiply(toTokenAmount.value)
amountFiat = rates[toToken.id]?.fiatRate?.multiply(toTokenAmount.value)
?: BigDecimal.ZERO,
),
priceImpact = calculatePriceImpact(
fromTokenAmount = fromTokenAmount.value,
fromRate = rates[fromToken.network.backendId] ?: 0.0,
fromRate = rates[fromToken.id]?.fiatRate?.toDouble() ?: 0.0,
toTokenAmount = toTokenAmount.value,
toRate = rates[toToken.network.backendId] ?: 0.0,
toRate = rates[toToken.id]?.fiatRate?.toDouble() ?: 0.0,
),
networkCurrency = userWalletManager.getNetworkCurrency(networkId),
swapDataModel = swapStateData,
@ -687,7 +662,7 @@ internal class SwapInteractorImpl @Inject constructor(
val feeData = transactionManager.getFee(
networkId = networkId,
amountToSend = BigDecimal.ZERO,
currencyToSend = userWalletManager.getNativeTokenForNetwork(networkId),
currencyToSend = swapCurrencyConverter.convert(userWalletManager.getNativeTokenForNetwork(networkId)),
destinationAddress = getTokenAddress(fromToken),
increaseBy = INCREASE_GAS_LIMIT_BY,
data = transactionData,
@ -863,6 +838,15 @@ internal class SwapInteractorImpl @Inject constructor(
)
}
private suspend fun getQuotes(vararg ids: CryptoCurrency.ID) : Map<CryptoCurrency.ID, Quote> {
val set = quotesRepository.getQuotesSync(ids.toSet(), false)
return ids
.mapNotNull { id -> set.find { it.rawCurrencyId == id.rawCurrencyId }?.let { id to it } }
.toMap()
}
companion object {
private const val DEFAULT_SLIPPAGE = 2

View file

@ -35,6 +35,7 @@ class SwapDomainModule {
walletFeatureToggles: WalletFeatureToggles,
@SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase,
@SwapScope getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase,
quotesRepository: QuotesRepository,
): SwapInteractor {
return SwapInteractorImpl(
transactionManager = transactionManager,
@ -47,6 +48,7 @@ class SwapDomainModule {
walletFeatureToggles = walletFeatureToggles,
getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase,
getMultiCryptoCurrencyStatusUseCase = getCryptoCurrencyStatusUseCase,
quotesRepository = quotesRepository,
)
}

View file

@ -1,10 +1,12 @@
plugins {
alias(deps.plugins.kotlin.jvm)
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
id("configuration")
}
dependencies {
/** Coroutines */
implementation(deps.kotlin.coroutines)
implementation(projects.domain.tokens.models)
}

View file

@ -1,5 +1,6 @@
package com.tangem.lib.crypto
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.lib.crypto.models.Currency
import com.tangem.lib.crypto.models.ProxyAmount
import com.tangem.lib.crypto.models.ProxyFiatCurrency
@ -16,7 +17,7 @@ interface UserWalletManager {
suspend fun getUserTokens(networkId: String, derivationPath: String?, isExcludeCustom: Boolean): List<Currency>
@Throws(IllegalStateException::class)
fun getNativeTokenForNetwork(networkId: String): Currency
fun getNativeTokenForNetwork(networkId: String): CryptoCurrency
/**
* Returns user walletId or empty string