From 7d087423e98df85aa9b744b3fb6fd01b6e86754f Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 18 Dec 2023 12:02:54 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../feature/swap/domain/SwapInteractor.kt | 7 --- .../feature/swap/domain/SwapInteractorImpl.kt | 45 ++++++++++--------- .../swap/viewmodels/SwapProcessDataState.kt | 1 - .../feature/swap/viewmodels/SwapViewModel.kt | 30 ++++++------- 4 files changed, 39 insertions(+), 44 deletions(-) diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt index 765647a01e..d3ec1058b9 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -2,7 +2,6 @@ package com.tangem.feature.swap.domain 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.wallets.models.UserWallet import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.IncludeFeeInAmount @@ -15,8 +14,6 @@ interface SwapInteractor { suspend fun getTokensDataState(currency: CryptoCurrency): TokensDataStateExpress - fun initDerivationPathAndNetwork(derivationPath: String?, network: Network) - /** * Gives permission to swap, this starts scan card process * @@ -30,7 +27,6 @@ interface SwapInteractor { * Find best quote for given tokens to swap * under the hood calls different methods to receive data, depends on permission for given token * - * @param networkId network for tokens * @param fromToken [Currency] from which want to swap * @param toToken [Currency] that receive after swap * @param amountToSwap amount you want to swap @@ -39,7 +35,6 @@ interface SwapInteractor { */ @Throws(IllegalStateException::class) suspend fun findBestQuote( - networkId: String, fromToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus, providers: List, @@ -62,7 +57,6 @@ interface SwapInteractor { @Throws(IllegalStateException::class) suspend fun onSwap( swapProvider: SwapProvider, - networkId: String, swapData: SwapDataModel?, currencyToSend: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus, @@ -76,7 +70,6 @@ interface SwapInteractor { selectedFee: FeeType, fromToken: CryptoCurrencyStatus, amountToSwap: String, - networkId: String, ): SwapState.QuotesLoadedState /** diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index 631d3e6d51..443fa9f71e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -62,7 +62,6 @@ internal class SwapInteractorImpl @Inject constructor( private val swapCurrencyConverter = SwapCurrencyConverter() private val amountFormatter = AmountFormatter() - private var derivationPath: String? = null private var network: Network? = null override suspend fun getTokensDataState(currency: CryptoCurrency): TokensDataStateExpress { @@ -182,14 +181,9 @@ internal class SwapInteractorImpl @Inject constructor( return repository.getPairs(initialCurrency, currenciesList) } - @Deprecated("used in old swap mechanism") - override fun initDerivationPathAndNetwork(derivationPath: String?, network: Network) { - this.derivationPath = derivationPath - this.network = network - } - @Deprecated("used in old swap mechanism") override suspend fun givePermissionToSwap(networkId: String, permissionOptions: PermissionOptions): TxState { + val derivationPath = permissionOptions.fromToken.network.derivationPath.value val dataToSign = if (permissionOptions.approveType == SwapApproveType.UNLIMITED) { getApproveData( networkId = networkId, @@ -233,7 +227,6 @@ internal class SwapInteractorImpl @Inject constructor( @Deprecated("used in old swap mechanism") override suspend fun findBestQuote( - networkId: String, fromToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus, providers: List, @@ -249,7 +242,7 @@ internal class SwapInteractorImpl @Inject constructor( } val amount = SwapAmount(amountDecimal, getTokenDecimals(fromToken.currency)) val isBalanceWithoutFeeEnough = isBalanceEnough(fromToken, amount, null) - + val networkId = fromToken.currency.network.backendId when (provider.type) { ExchangeProviderType.DEX -> { manageDex( @@ -310,7 +303,10 @@ internal class SwapInteractorImpl @Inject constructor( if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) { allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress) - transactionManager.updateWalletManager(networkId, derivationPath) + transactionManager.updateWalletManager( + networkId, + fromToken.currency.network.derivationPath.value, + ) } return if (isAllowedToSpend && isBalanceWithoutFeeEnough) { provider to loadDexSwapData( @@ -361,7 +357,6 @@ internal class SwapInteractorImpl @Inject constructor( override suspend fun onSwap( swapProvider: SwapProvider, - networkId: String, swapData: SwapDataModel?, currencyToSend: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus, @@ -389,7 +384,7 @@ internal class SwapInteractorImpl @Inject constructor( } ExchangeProviderType.DEX -> { onSwapDex( - networkId = networkId, + networkId = currencyToSend.currency.network.backendId, swapData = requireNotNull(swapData), currencyToSend = currencyToSend.currency, currencyToGet = currencyToGet.currency, @@ -405,7 +400,6 @@ internal class SwapInteractorImpl @Inject constructor( selectedFee: FeeType, fromToken: CryptoCurrencyStatus, amountToSwap: String, - networkId: String, ): SwapState.QuotesLoadedState { val amountDecimal = toBigDecimalOrNull(amountToSwap) if (amountDecimal == null || amountDecimal.signum() == 0) { @@ -413,7 +407,7 @@ internal class SwapInteractorImpl @Inject constructor( } val amount = SwapAmount(amountDecimal, getTokenDecimals(fromToken.currency)) val includeFeeInAmount = getIncludeFeeInAmount( - networkId = networkId, + networkId = fromToken.currency.network.backendId, txFee = state.txFee, amount = amount, fromToken = fromToken.currency, @@ -422,6 +416,7 @@ internal class SwapInteractorImpl @Inject constructor( return state.copy( permissionState = PermissionDataState.Empty, preparedSwapConfigState = state.preparedSwapConfigState.copy( + isFeeEnough = includeFeeInAmount !is IncludeFeeInAmount.BalanceNotEnough, isBalanceEnough = includeFeeInAmount !is IncludeFeeInAmount.BalanceNotEnough, includeFeeInAmount = includeFeeInAmount, ), @@ -438,6 +433,7 @@ internal class SwapInteractorImpl @Inject constructor( ): TxState { val amountDecimal = requireNotNull(toBigDecimalOrNull(amountToSwap)) { "wrong amount format" } val amount = SwapAmount(amountDecimal, getTokenDecimals(currencyToSend)) + val derivationPath = currencyToSend.network.derivationPath.value val result = transactionManager.sendTransaction( txData = SwapTxData( networkId = networkId, @@ -481,6 +477,7 @@ internal class SwapInteractorImpl @Inject constructor( } } + @Suppress("LongMethod") private suspend fun onSwapCex( currencyToSend: CryptoCurrencyStatus, currencyToGet: CryptoCurrencyStatus, @@ -519,6 +516,7 @@ internal class SwapInteractorImpl @Inject constructor( val externalUrl = (exchangeData.transaction as? ExpressTransactionModel.CEX)?.externalTxUrl + val derivationPath = currencyToSend.currency.network.derivationPath.value return result.fold( ifLeft = { when (it) { @@ -659,7 +657,7 @@ internal class SwapInteractorImpl @Inject constructor( val allowance = repository.getAllowance( userWalletId = userWallet.walletId, networkId = networkId, - derivationPath = derivationPath, + derivationPath = fromToken.network.derivationPath.value, tokenDecimalCount = getTokenDecimals(fromToken), tokenAddress = getTokenAddress(fromToken), spenderAddress = spenderAddress, @@ -832,7 +830,10 @@ internal class SwapInteractorImpl @Inject constructor( } val tokenForFeeBalance = - userWalletManager.getNativeTokenBalance(networkId, derivationPath) ?: ProxyAmount.empty() + userWalletManager.getNativeTokenBalance( + networkId, + fromToken.network.derivationPath.value, + ) ?: ProxyAmount.empty() if (amount.value > tokenForFeeBalance.value) { return IncludeFeeInAmount.BalanceNotEnough @@ -907,7 +908,7 @@ internal class SwapInteractorImpl @Inject constructor( destinationAddress = swapData.transaction.txTo, increaseBy = INCREASE_GAS_LIMIT_BY, data = (swapData.transaction as ExpressTransactionModel.DEX).txData, - derivationPath = derivationPath, + derivationPath = fromToken.currency.network.derivationPath.value, ) val txFeeState = when (feeData) { is ProxyFees.MultipleFees -> feeData.proxyFeesToFeeState(networkId) @@ -1048,6 +1049,7 @@ internal class SwapInteractorImpl @Inject constructor( permissionState = PermissionDataState.PermissionLoading, ) } + val derivationPath = fromToken.network.derivationPath.value // setting up amount for approve with given amount for swap [SwapApproveType.Limited] val transactionData = getApproveData( networkId = networkId, @@ -1091,7 +1093,7 @@ internal class SwapInteractorImpl @Inject constructor( permissionState = PermissionDataState.PermissionReadyForRequest( currency = fromToken.symbol, amount = INFINITY_SYMBOL, - walletAddress = getWalletAddress(networkId), + walletAddress = getWalletAddress(networkId, derivationPath), spenderAddress = getTokenAddress(fromToken), requestApproveData = RequestApproveStateData( fee = feeState, @@ -1262,7 +1264,7 @@ internal class SwapInteractorImpl @Inject constructor( } } - private suspend fun getWalletAddress(networkId: String): String { + private suspend fun getWalletAddress(networkId: String, derivationPath: String?): String { return userWalletManager.getWalletAddress(networkId, derivationPath) } @@ -1286,7 +1288,10 @@ internal class SwapInteractorImpl @Inject constructor( if (fee == null) { return false } - val nativeTokenBalance = userWalletManager.getNativeTokenBalance(networkId, derivationPath) + val nativeTokenBalance = userWalletManager.getNativeTokenBalance( + networkId, + fromToken.network.derivationPath.value, + ) val percentsToFeeIncrease = BigDecimal.ONE return when (fromToken) { is CryptoCurrency.Coin -> { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt index 7b5bd446fa..7623970edf 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapProcessDataState.kt @@ -11,7 +11,6 @@ import com.tangem.feature.swap.models.ApproveType data class SwapProcessDataState( // Initial network id - val networkId: String, val fromCryptoCurrency: CryptoCurrencyStatus? = null, val toCryptoCurrency: CryptoCurrencyStatus? = null, // Amount from input diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 399f3b6f79..b1438e8115 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -79,7 +79,7 @@ internal class SwapViewModel @Inject constructor( private val amountDebouncer = Debouncer() private val singleTaskScheduler = SingleTaskScheduler>() - private var dataState by mutableStateOf(SwapProcessDataState(networkId = initialCryptoCurrency.network.backendId)) + private var dataState by mutableStateOf(SwapProcessDataState()) var uiState: SwapStateHolder by mutableStateOf( stateBuilder.createInitialLoadingState( @@ -103,11 +103,6 @@ internal class SwapViewModel @Inject constructor( requireNotNull(getCryptoCurrencyStatusUseCase(it.walletId, initialCryptoCurrency.id).getOrNull()) { "Failed to get initial crypto currency status" } - - swapInteractor.initDerivationPathAndNetwork( - derivationPath = initialCryptoCurrency.network.derivationPath.value, - network = initialCryptoCurrency.network, - ) initTokens() } } @@ -278,7 +273,6 @@ internal class SwapViewModel @Inject constructor( approveDataModel = null, ) swapInteractor.findBestQuote( - networkId = dataState.networkId, fromToken = fromToken, toToken = toToken, providers = toProvidersList, @@ -438,13 +432,13 @@ internal class SwapViewModel @Inject constructor( Timber.e("Last loaded quotes state is null") return } + val fromCurrency = requireNotNull(dataState.fromCryptoCurrency) viewModelScope.launch(dispatchers.main) { runCatching(dispatchers.io) { swapInteractor.onSwap( swapProvider = provider, - networkId = dataState.networkId, swapData = dataState.swapDataModel, - currencyToSend = requireNotNull(dataState.fromCryptoCurrency), + currencyToSend = fromCurrency, currencyToGet = requireNotNull(dataState.toCryptoCurrency), amountToSwap = requireNotNull(dataState.amount), includeFeeInAmount = lastLoadedQuotesState.preparedSwapConfigState.includeFeeInAmount, @@ -454,7 +448,7 @@ internal class SwapViewModel @Inject constructor( when (it) { is TxState.TxSent -> { val url = blockchainInteractor.getExplorerTransactionLink( - networkId = dataState.networkId, + networkId = fromCurrency.currency.network.backendId, txAddress = it.txAddress, ) uiState = stateBuilder.createSuccessState( @@ -528,17 +522,18 @@ internal class SwapViewModel @Inject constructor( is TxFeeState.SingleFeeState -> fee.fee null -> error("Fee should not be null") } + val fromToken = requireNotNull(dataState.fromCryptoCurrency?.currency) { + "dataState.fromCurrency might not be null" + } swapInteractor.givePermissionToSwap( - networkId = dataState.networkId, + networkId = fromToken.network.backendId, permissionOptions = PermissionOptions( approveData = requireNotNull(dataState.approveDataModel) { "dataState.approveDataModel might not be null" }, forTokenContractAddress = (dataState.fromCryptoCurrency?.currency as? CryptoCurrency.Token) ?.contractAddress ?: "", - fromToken = requireNotNull(dataState.fromCryptoCurrency?.currency) { - "dataState.fromCurrency might not be null" - }, + fromToken = fromToken, approveType = requireNotNull(dataState.approveType) { "uiState.permissionState should not be null" }.toDomainApproveType(), @@ -805,7 +800,6 @@ internal class SwapViewModel @Inject constructor( selectedFee = it.feeType, fromToken = fromToken, amountToSwap = amountToSwap, - networkId = dataState.networkId, ) setupLoadedState(selectedProvider, updatedState, fromToken) } @@ -839,7 +833,11 @@ internal class SwapViewModel @Inject constructor( }, onBuyClick = { swapInteractor.getSelectedWallet()?.let { - swapRouter.openTokenDetails(it.walletId, swapInteractor.getNativeToken(dataState.networkId)) + val fromToken = dataState.fromCryptoCurrency ?: return@let + swapRouter.openTokenDetails( + it.walletId, + swapInteractor.getNativeToken(fromToken.currency.network.backendId), + ) } }, onRetryClick = {