Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-26 23:06:21 +07:00
parent 1806ddc31d
commit fa3b07b066
5 changed files with 16 additions and 38 deletions

View file

@ -9,9 +9,7 @@ import com.squareup.moshi.Moshi
import com.tangem.blockchain.common.Approver
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError
import com.tangem.datasource.api.common.response.getOrThrow
@ -25,7 +23,6 @@ import com.tangem.datasource.api.express.models.response.TxDetails
import com.tangem.datasource.crypto.DataSignatureVerifier
import com.tangem.datasource.exchangeservice.swap.ExpressUtils
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.models.currency.CryptoCurrency
@ -53,19 +50,16 @@ internal class DefaultSwapRepository(
private val tangemExpressApi: TangemExpressApi,
private val coroutineDispatcher: CoroutineDispatcherProvider,
private val walletManagersFacade: WalletManagersFacade,
private val userWalletsListRepository: UserWalletsListRepository,
private val errorsDataConverter: ErrorsDataConverter,
private val dataSignatureVerifier: DataSignatureVerifier,
private val appPreferencesStore: AppPreferencesStore,
private val rampStateManager: RampStateManager,
moshi: Moshi,
excludedBlockchains: ExcludedBlockchains,
) : SwapRepository {
private val expressDataConverter = ExpressDataConverter()
private val leastTokenInfoConverter = LeastTokenInfoConverter()
private val swapPairInfoConverter = SwapPairInfoConverter()
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
private val exchangeStatusConverter = ExchangeStatusConverter()
private val txDetailsMoshiAdapter = moshi.adapter(TxDetails::class.java)
@ -445,18 +439,6 @@ internal class DefaultSwapRepository(
)
}
override suspend fun getNativeTokenForNetwork(networkId: String): CryptoCurrency {
val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" }
return requireNotNull(
cryptoCurrencyFactory.createCoin(
blockchain = blockchain,
extraDerivationPath = null,
userWallet = requireNotNull(userWalletsListRepository.selectedUserWalletSync()),
),
)
}
private fun getDataError(ex: Exception): ExpressDataError {
return if (ex is ApiResponseError.HttpException) {
errorsDataConverter.convert(ex.errorBody.orEmpty())

View file

@ -1,7 +1,6 @@
package com.tangem.feature.swap.di
import com.squareup.moshi.Moshi
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.common.network.NetworkFactory
import com.tangem.datasource.api.express.TangemExpressApi
@ -11,7 +10,6 @@ import com.tangem.datasource.di.NetworkMoshi
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.exchange.RampStateManager
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.feature.swap.DefaultSwapRepository
@ -37,10 +35,8 @@ internal class SwapDataModule {
coroutineDispatcher: CoroutineDispatcherProvider,
dataSignature: DataSignatureVerifier,
walletManagerFacade: WalletManagersFacade,
userWalletsListRepository: UserWalletsListRepository,
errorsDataConverter: ErrorsDataConverter,
@NetworkMoshi moshi: Moshi,
excludedBlockchains: ExcludedBlockchains,
appPreferencesStore: AppPreferencesStore,
rampStateManager: RampStateManager,
): SwapRepository {
@ -48,11 +44,9 @@ internal class SwapDataModule {
tangemExpressApi = tangemExpressApi,
coroutineDispatcher = coroutineDispatcher,
walletManagersFacade = walletManagerFacade,
userWalletsListRepository = userWalletsListRepository,
errorsDataConverter = errorsDataConverter,
dataSignatureVerifier = dataSignature,
moshi = moshi,
excludedBlockchains = excludedBlockchains,
appPreferencesStore = appPreferencesStore,
rampStateManager = rampStateManager,
)

View file

@ -6,6 +6,7 @@ import com.tangem.domain.express.models.ExpressOperationType
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.transaction.error.GetFeeError
import com.tangem.domain.transaction.models.TransactionFeeExtended
@ -123,7 +124,7 @@ interface SwapInteractor {
isReverseFromTo: Boolean,
): AccountSwapCurrency?
suspend fun getNativeToken(networkId: String): CryptoCurrency
suspend fun getNativeToken(network: Network): CryptoCurrency
@Suppress("LongParameterList")
suspend fun storeSwapTransaction(

View file

@ -1355,8 +1355,13 @@ internal class SwapInteractorImpl @AssistedInject constructor(
}
}
override suspend fun getNativeToken(networkId: String): CryptoCurrency {
return repository.getNativeTokenForNetwork(networkId)
override suspend fun getNativeToken(network: Network): CryptoCurrency {
return multiWalletCryptoCurrenciesSupplier.getSyncOrNull(
params = MultiWalletCryptoCurrenciesProducer.Params(userWalletId),
)
?.filterIsInstance<CryptoCurrency.Coin>()
?.firstOrNull { it.network.id == network.id && it.network.derivationPath == network.derivationPath }
?: error("Unable to create network coin with ID: ${network.id}")
}
private suspend fun isAllowedToSpend(
@ -1505,7 +1510,6 @@ internal class SwapInteractorImpl @AssistedInject constructor(
return quoteDataModel.fold(
ifRight = { quoteModel ->
val swapState = updateBalances(
networkId = networkId,
fromTokenStatus = fromToken,
fromAccount = fromAccount,
toTokenStatus = toToken,
@ -1753,10 +1757,12 @@ internal class SwapInteractorImpl @AssistedInject constructor(
}
else -> {
if (feeValue < amount.value) {
val nativeCoinDecimals = Blockchain.fromNetworkId(networkId)?.decimals()
?: error("Blockchain not found")
IncludeFeeInAmount.Included(
amountSubtractFee = SwapAmount(
reducedBalance - feeValue,
getNativeToken(fromToken.network.backendId).decimals,
nativeCoinDecimals,
),
)
} else {
@ -1773,7 +1779,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
)
val feeCurrencyId: CryptoCurrency.ID = when (feePaidCurrency) {
is FeePaidCurrency.Token -> feePaidCurrency.tokenId
else -> getNativeToken(networkId = fromToken.network.backendId).id
else -> getNativeToken(network = fromToken.network).id
}
val rates = getQuotes(feeCurrencyId)
return rates[feeCurrencyId]?.let { rate ->
@ -1869,7 +1875,6 @@ internal class SwapInteractorImpl @AssistedInject constructor(
includeFeeInAmount = includeFeeInAmount,
)
val swapState = updateBalances(
networkId = networkId,
fromTokenStatus = fromToken,
fromAccount = fromAccount,
toTokenStatus = toToken,
@ -2037,7 +2042,6 @@ internal class SwapInteractorImpl @AssistedInject constructor(
@Suppress("LongParameterList", "MaxChainedCallsOnSameLine")
private suspend fun updateBalances(
provider: SwapProvider,
networkId: String,
fromTokenStatus: CryptoCurrencyStatus,
fromAccount: Account.CryptoPortfolio?,
toTokenStatus: CryptoCurrencyStatus,
@ -2049,7 +2053,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
): SwapState.QuotesLoadedState {
val fromToken = fromTokenStatus.currency
val toToken = toTokenStatus.currency
val nativeToken = repository.getNativeTokenForNetwork(networkId)
val nativeToken = getNativeToken(fromToken.network)
val rates = getQuotes(fromToken.id, toToken.id, nativeToken.id)
return SwapState.QuotesLoadedState(
fromTokenInfo = TokenSwapInfo(
@ -2478,7 +2482,7 @@ internal class SwapInteractorImpl @AssistedInject constructor(
if (balanceToCheck > fee.multiply(percentsToFeeIncrease)) {
SwapFeeState.Enough
} else {
val nativeToken = getNativeToken(fromTokenStatus.currency.network.backendId)
val nativeToken = getNativeToken(fromTokenStatus.currency.network)
SwapFeeState.NotEnough(
feeCurrency = nativeToken,
currencyName = nativeToken.network.name,
@ -2522,11 +2526,10 @@ internal class SwapInteractorImpl @AssistedInject constructor(
}
}
is FeePaidCurrency.FeeResource -> {
val network = repository.getNativeTokenForNetwork(networkId).network
val isFeeResourceEnough = currencyChecksRepository.checkIfFeeResourceEnough(
amount = spendAmount.value,
userWalletId = userWalletId,
network = network,
network = fromTokenStatus.currency.network,
)
if (isFeeResourceEnough) {

View file

@ -83,6 +83,4 @@ interface SwapRepository {
txHash: String,
payInExtraId: String?,
): Either<ExpressDataError, Unit>
suspend fun getNativeTokenForNetwork(networkId: String): CryptoCurrency
}