From 3416b28b13c0d638efed164dcebd44615051da5d Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Nov 2023 15:43:29 +0300 Subject: [PATCH 1/3] Updated on 2026-08-14 --- .../com/tangem/data/tokens/utils/TokensOperations.kt | 4 +--- .../tangem/feature/swap/domain/SwapInteractorImpl.kt | 11 ++++++++--- .../tangem/feature/swap/viewmodels/SwapViewModel.kt | 11 ++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt index 13dcd79a67..54f468860b 100644 --- a/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt +++ b/data/tokens/src/main/kotlin/com/tangem/data/tokens/utils/TokensOperations.kt @@ -4,7 +4,6 @@ import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.IconsUtil import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.domain.common.extensions.toCoinId -import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrency.ID import com.tangem.domain.tokens.model.Network @@ -55,8 +54,7 @@ internal fun getTokenIconUrl(blockchain: Blockchain, token: SdkToken): String? { internal fun getCoinIconUrl(blockchain: Blockchain): String? { val coinId = when (blockchain) { Blockchain.Unknown -> null - Blockchain.TerraV1, Blockchain.TerraV2, Blockchain.Near -> blockchain.toCoinId() - else -> blockchain.toNetworkId() + else -> blockchain.toCoinId() } return coinId?.let(::getTokenIconUrlFromDefaultHost) 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 46ace65b78..90d0ca8442 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 @@ -785,9 +785,14 @@ internal class SwapInteractorImpl @Inject constructor( userWalletId = userWalletId, cryptoCurrency = fromToken.currency, ).firstOrNull() - txFeeResult?.getOrNull()?.let { txFee -> - return txFee.toTxFeeState(networkId) - } + return txFeeResult?.fold( + ifLeft = { + TxFeeState.Empty + }, + ifRight = { txFee -> + txFee.toTxFeeState(networkId) + } + ) ?: TxFeeState.Empty } return TxFeeState.Empty } 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 41287a8bc6..cfd88bd3c6 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 @@ -295,7 +295,7 @@ internal class SwapViewModel @Inject constructor( } private fun updateLoadedQuotes(state: Map): Pair { - val selectedSwapProvider = dataState.selectedProvider ?: state.keys.first() + val selectedSwapProvider = selectProvider(state) dataState = dataState.copy( selectedProvider = selectedSwapProvider, lastLoadedSwapStates = state, @@ -303,6 +303,15 @@ internal class SwapViewModel @Inject constructor( return state.entries.first { it.key == selectedSwapProvider }.toPair() } + private fun selectProvider(state: Map): SwapProvider { + val currentSelected = dataState.selectedProvider + return if (currentSelected != null && state.keys.contains(currentSelected)) { + currentSelected + } else { + state.keys.first() + } + } + private fun fillLoadedDataState( state: SwapState.QuotesLoadedState, permissionState: PermissionDataState, From 2a5649c94129f3d47d594939499c492837e251c6 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Nov 2023 18:33:34 +0300 Subject: [PATCH 2/3] Updated on 2026-08-14 --- .../tangem/feature/swap/SwapRepositoryImpl.kt | 5 +- .../swap/converters/QuotesConverter.kt | 15 --- .../feature/swap/domain/SwapInteractorImpl.kt | 94 ++++++++++++++----- .../feature/swap/domain/SwapRepository.kt | 4 + .../domain/models/domain/PermissionOptions.kt | 1 + .../swap/domain/models/domain/QuoteModel.kt | 1 + .../swap/domain/models/ui/SwapState.kt | 1 + .../feature/swap/models/SwapStateHolder.kt | 1 - .../tangem/feature/swap/models/UiActions.kt | 1 - .../states/GivePermissionBottomSheetConfig.kt | 2 +- .../tangem/feature/swap/ui/StateBuilder.kt | 10 +- .../swap/viewmodels/SwapProcessDataState.kt | 2 + .../feature/swap/viewmodels/SwapViewModel.kt | 26 ++--- 13 files changed, 101 insertions(+), 62 deletions(-) delete mode 100644 features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt index b5d8b00f73..43010d791d 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/SwapRepositoryImpl.kt @@ -161,6 +161,7 @@ internal class SwapRepositoryImpl @Inject constructor( AggregatedSwapDataModel( dataModel = QuoteModel( toTokenAmount = createFromAmountWithOffset(response.toAmount, response.toDecimals), + allowanceContract = response.allowanceContract, ), ) } catch (ex: Exception) { @@ -218,6 +219,7 @@ internal class SwapRepositoryImpl @Inject constructor( derivationPath: String?, tokenDecimalCount: Int, tokenAddress: String, + spenderAddress: String, ): BigDecimal { val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" } val walletManager = walletManagersFacade.getOrCreateWalletManager( @@ -225,7 +227,6 @@ internal class SwapRepositoryImpl @Inject constructor( blockchain = blockchain, derivationPath = derivationPath, ) - val spenderAddress = addressForTrust(networkId) val result = (walletManager as? Approver)?.getAllowance( spenderAddress, @@ -248,6 +249,7 @@ internal class SwapRepositoryImpl @Inject constructor( derivationPath: String?, currency: CryptoCurrency, amount: BigDecimal?, + spenderAddress: String, ): String { val blockchain = requireNotNull(Blockchain.fromNetworkId(networkId)) { "blockchain not found" } @@ -256,7 +258,6 @@ internal class SwapRepositoryImpl @Inject constructor( blockchain = blockchain, derivationPath = derivationPath, ) - val spenderAddress = addressForTrust(networkId) return (walletManager as? Approver)?.getApproveData( spenderAddress, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt deleted file mode 100644 index 4352341538..0000000000 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/QuotesConverter.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.tangem.feature.swap.converters - -import com.tangem.datasource.api.oneinch.models.QuoteResponse -import com.tangem.feature.swap.domain.models.createFromAmountWithOffset -import com.tangem.feature.swap.domain.models.domain.QuoteModel -import com.tangem.utils.converter.Converter - -class QuotesConverter : Converter { - - override fun convert(value: QuoteResponse): QuoteModel { - return QuoteModel( - toTokenAmount = createFromAmountWithOffset(value.toTokenAmount, value.toToken.decimals), - ) - } -} \ No newline at end of file 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 90d0ca8442..7b8944fe0a 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 @@ -197,6 +197,7 @@ internal class SwapInteractorImpl @Inject constructor( networkId = networkId, derivationPath = derivationPath, fromToken = permissionOptions.fromToken, + spenderAddress = permissionOptions.spenderAddress, ) } else { permissionOptions.approveData.approveData @@ -289,8 +290,22 @@ internal class SwapInteractorImpl @Inject constructor( amount: SwapAmount, isBalanceWithoutFeeEnough: Boolean, ): Pair { + val quotes = repository.findBestQuote( + fromContractAddress = fromToken.currency.getContractAddress(), + fromNetwork = fromToken.currency.network.backendId, + toContractAddress = toToken.currency.getContractAddress(), + toNetwork = toToken.currency.network.backendId, + fromAmount = amount.toStringWithRightOffset(), + fromDecimals = amount.decimals, + providerId = provider.providerId, + rateType = RateType.FLOAT, + ) + val fromTokenAddress = getTokenAddress(fromToken.currency) - val isAllowedToSpend = isAllowedToSpend(networkId, fromToken.currency, amount) + val isAllowedToSpend = quotes.dataModel?.allowanceContract?.let { + isAllowedToSpend(networkId, fromToken.currency, amount, it) + } ?: false + if (isAllowedToSpend && allowPermissionsHandler.isAddressAllowanceInProgress(fromTokenAddress)) { allowPermissionsHandler.removeAddressFromProgress(fromTokenAddress) transactionManager.updateWalletManager(networkId, derivationPath) @@ -305,15 +320,16 @@ internal class SwapInteractorImpl @Inject constructor( selectedFee = selectedFee, ) } else { - provider to loadQuoteData( + provider to getQuotesState( exchangeProviderType = ExchangeProviderType.DEX, - networkId = networkId, + quoteDataModel = quotes, amount = amount, - fromTokenStatus = fromToken, - toTokenStatus = toToken, + fromToken = fromToken, + toToken = toToken, + networkId = networkId, isAllowedToSpend = isAllowedToSpend, isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough, - provider = provider, + providerType = provider.type, selectedFee = selectedFee, ) } @@ -501,16 +517,22 @@ internal class SwapInteractorImpl @Inject constructor( } } - private suspend fun isAllowedToSpend(networkId: String, fromToken: CryptoCurrency, amount: SwapAmount): Boolean { + private suspend fun isAllowedToSpend( + networkId: String, + fromToken: CryptoCurrency, + amount: SwapAmount, + spenderAddress: String, + ): Boolean { if (fromToken is CryptoCurrency.Coin) return true return getSelectedWalletSyncUseCase().fold( ifRight = { userWallet -> val allowance = repository.getAllowance( - userWallet.walletId, - networkId, - derivationPath, - getTokenDecimals(fromToken), - getTokenAddress(fromToken), + userWalletId = userWallet.walletId, + networkId = networkId, + derivationPath = derivationPath, + tokenDecimalCount = getTokenDecimals(fromToken), + tokenAddress = getTokenAddress(fromToken), + spenderAddress = spenderAddress, ) allowance >= amount.value }, @@ -620,6 +642,8 @@ internal class SwapInteractorImpl @Inject constructor( fromToken = fromToken.currency, swapAmount = amount, quotesLoadedState = swapState, + isAllowedToSpend = isAllowedToSpend, + spenderAddress = requireNotNull(quoteModel.allowanceContract) { "Allowance contract is null" }, ) state.copy( preparedSwapConfigState = state.preparedSwapConfigState.copy( @@ -791,19 +815,26 @@ internal class SwapInteractorImpl @Inject constructor( }, ifRight = { txFee -> txFee.toTxFeeState(networkId) - } + }, ) ?: TxFeeState.Empty } return TxFeeState.Empty } - @Suppress("LongParameterList") + @Suppress("LongParameterList", "LongMethod") private suspend fun updatePermissionState( networkId: String, fromToken: CryptoCurrency, swapAmount: SwapAmount, quotesLoadedState: SwapState.QuotesLoadedState, + spenderAddress: String, + isAllowedToSpend: Boolean, ): SwapState.QuotesLoadedState { + if (isAllowedToSpend) { + return quotesLoadedState.copy( + permissionState = PermissionDataState.Empty, + ) + } // if token balance ZERO not show permission state to avoid user to spend money for fee val isTokenZeroBalance = getTokenBalance(networkId, fromToken).value.signum() == 0 if (isTokenZeroBalance) { @@ -822,20 +853,28 @@ internal class SwapInteractorImpl @Inject constructor( derivationPath = derivationPath, fromToken = fromToken, swapAmount = swapAmount, + spenderAddress = spenderAddress, ) - val feeData = transactionManager.getFee( - networkId = networkId, - amountToSend = BigDecimal.ZERO, - currencyToSend = swapCurrencyConverter.convert(repository.getNativeTokenForNetwork(networkId)), - destinationAddress = getTokenAddress(fromToken), - increaseBy = INCREASE_GAS_LIMIT_BY, - data = transactionData, - derivationPath = derivationPath, - ) - val feeState = when (feeData) { - is ProxyFees.MultipleFees -> feeData.proxyFeesToFeeState(networkId) - is ProxyFees.SingleFee -> feeData.proxyFeesToFeeState(networkId) + val feeData = try { + transactionManager.getFee( + networkId = networkId, + amountToSend = BigDecimal.ZERO, + currencyToSend = swapCurrencyConverter.convert(repository.getNativeTokenForNetwork(networkId)), + destinationAddress = fromToken.getContractAddress(), + increaseBy = INCREASE_GAS_LIMIT_BY, + data = transactionData, + derivationPath = derivationPath, + ) + } catch (e: Exception) { + Timber.e(e, "Failed to get fee") + null } + val feeState = feeData?.let { + when (feeData) { + is ProxyFees.MultipleFees -> feeData.proxyFeesToFeeState(networkId) + is ProxyFees.SingleFee -> feeData.proxyFeesToFeeState(networkId) + } + } ?: TxFeeState.Empty val fee = when (feeState) { TxFeeState.Empty -> BigDecimal.ZERO is TxFeeState.MultipleFeeState -> feeState.normalFee.feeValue @@ -857,6 +896,7 @@ internal class SwapInteractorImpl @Inject constructor( fee = feeState, approveData = transactionData, fromTokenAmount = swapAmount, + spenderAddress = spenderAddress, ), ), preparedSwapConfigState = quotesLoadedState.preparedSwapConfigState.copy( @@ -1089,6 +1129,7 @@ internal class SwapInteractorImpl @Inject constructor( derivationPath: String?, fromToken: CryptoCurrency, swapAmount: SwapAmount? = null, + spenderAddress: String, ): String { return getSelectedWalletSyncUseCase().fold( ifRight = { userWallet -> @@ -1098,6 +1139,7 @@ internal class SwapInteractorImpl @Inject constructor( derivationPath = derivationPath, currency = fromToken, amount = swapAmount?.value, + spenderAddress = spenderAddress, ) }, ifLeft = { diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt index dd2d72e7df..13650fe4fe 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapRepository.kt @@ -39,6 +39,7 @@ interface SwapRepository { */ fun getTangemFee(): Double + @Suppress("LongParameterList") @Throws(IllegalStateException::class) suspend fun getAllowance( userWalletId: UserWalletId, @@ -46,8 +47,10 @@ interface SwapRepository { derivationPath: String?, tokenDecimalCount: Int, tokenAddress: String, + spenderAddress: String, ): BigDecimal + @Suppress("LongParameterList") @Throws(IllegalStateException::class) suspend fun getApproveData( userWalletId: UserWalletId, @@ -55,6 +58,7 @@ interface SwapRepository { derivationPath: String?, currency: CryptoCurrency, amount: BigDecimal?, + spenderAddress: String, ): String @Suppress("LongParameterList") diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt index 88d57a301f..bd1d290190 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/PermissionOptions.kt @@ -17,6 +17,7 @@ data class PermissionOptions( val approveData: RequestApproveStateData, val forTokenContractAddress: String, val fromToken: CryptoCurrency, + val spenderAddress: String, val approveType: SwapApproveType, val txFee: TxFee, ) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/QuoteModel.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/QuoteModel.kt index 5e5d782666..df74da7af3 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/QuoteModel.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/domain/QuoteModel.kt @@ -9,4 +9,5 @@ import com.tangem.feature.swap.domain.models.SwapAmount */ data class QuoteModel( val toTokenAmount: SwapAmount, + val allowanceContract: String?, ) \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt index 78ccdccca5..0c98986dc1 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/models/ui/SwapState.kt @@ -61,6 +61,7 @@ data class RequestApproveStateData( val fee: TxFeeState, val approveData: String, val fromTokenAmount: SwapAmount, + val spenderAddress: String, ) // data class SwapStateData( diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt index a685079175..2335991b5e 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/SwapStateHolder.kt @@ -36,7 +36,6 @@ data class SwapStateHolder( val onSuccess: (() -> Unit)? = null, val onMaxAmountSelected: (() -> Unit)? = null, val onShowPermissionBottomSheet: () -> Unit = {}, - val onCancelPermissionBottomSheet: () -> Unit = {}, ) sealed class SwapCardState { diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt index 76efb65203..76844c8cd2 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/UiActions.kt @@ -13,7 +13,6 @@ data class UiActions( val onBackClicked: () -> Unit, val onMaxAmountSelected: () -> Unit, val openPermissionBottomSheet: () -> Unit, - val hidePermissionBottomSheet: () -> Unit, val onChangeApproveType: (ApproveType) -> Unit, // region new actions val onClickFee: () -> Unit, diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/GivePermissionBottomSheetConfig.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/GivePermissionBottomSheetConfig.kt index 57628ded51..9a8bd7a519 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/GivePermissionBottomSheetConfig.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/models/states/GivePermissionBottomSheetConfig.kt @@ -3,7 +3,7 @@ package com.tangem.feature.swap.models.states import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent import com.tangem.feature.swap.models.SwapPermissionState -class GivePermissionBottomSheetConfig( +data class GivePermissionBottomSheetConfig( val data: SwapPermissionState.ReadyForRequest, val onCancel: () -> Unit, ) : TangemBottomSheetConfigContent \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt index b6a1ec961e..6a730aef6e 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/ui/StateBuilder.kt @@ -81,7 +81,6 @@ internal class StateBuilder( onMaxAmountSelected = actions.onMaxAmountSelected, updateInProgress = true, onShowPermissionBottomSheet = actions.openPermissionBottomSheet, - onCancelPermissionBottomSheet = actions.hidePermissionBottomSheet, providerState = ProviderState.Empty(), ) } @@ -381,10 +380,13 @@ internal class StateBuilder( } fun updateApproveType(uiState: SwapStateHolder, approveType: ApproveType): SwapStateHolder { - return if (uiState.permissionState is SwapPermissionState.ReadyForRequest) { + val config = uiState.bottomSheetConfig?.content as? GivePermissionBottomSheetConfig + return if (config != null) { uiState.copy( - permissionState = uiState.permissionState.copy( - approveType = approveType, + bottomSheetConfig = uiState.bottomSheetConfig.copy( + content = config.copy( + data = config.data.copy(approveType = approveType), + ), ), ) } else { 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 191d36f5de..7b5bd446fa 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 @@ -7,6 +7,7 @@ import com.tangem.feature.swap.domain.models.ui.RequestApproveStateData import com.tangem.feature.swap.domain.models.ui.SwapState import com.tangem.feature.swap.domain.models.ui.TokensDataStateExpress import com.tangem.feature.swap.domain.models.ui.TxFee +import com.tangem.feature.swap.models.ApproveType data class SwapProcessDataState( // Initial network id @@ -16,6 +17,7 @@ data class SwapProcessDataState( // Amount from input val amount: String? = null, val approveDataModel: RequestApproveStateData? = null, + val approveType: ApproveType? = null, val swapDataModel: SwapDataModel? = null, val selectedFee: TxFee? = null, // todo val tokensDataState: TokensDataStateExpress? = null, 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 cfd88bd3c6..901ef4daa7 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 @@ -22,10 +22,7 @@ import com.tangem.feature.swap.domain.models.domain.SwapDataModel import com.tangem.feature.swap.domain.models.domain.SwapProvider import com.tangem.feature.swap.domain.models.formatToUIRepresentation import com.tangem.feature.swap.domain.models.ui.* -import com.tangem.feature.swap.models.SwapPermissionState -import com.tangem.feature.swap.models.SwapStateHolder -import com.tangem.feature.swap.models.UiActions -import com.tangem.feature.swap.models.toDomainApproveType +import com.tangem.feature.swap.models.* import com.tangem.feature.swap.presentation.SwapFragment import com.tangem.feature.swap.router.SwapNavScreen import com.tangem.feature.swap.router.SwapRouter @@ -320,6 +317,7 @@ internal class SwapViewModel @Inject constructor( dataState = if (permissionState is PermissionDataState.PermissionReadyForRequest) { dataState.copy( approveDataModel = permissionState.requestApproveData, + approveType = dataState.approveType ?: ApproveType.UNLIMITED, ) } else { dataState.copy( @@ -407,12 +405,15 @@ internal class SwapViewModel @Inject constructor( fromToken = requireNotNull(dataState.fromCryptoCurrency?.currency) { "dataState.fromCurrency might not be null" }, - approveType = requireNotNull(uiState.permissionState as? SwapPermissionState.ReadyForRequest) { - "uiState.permissionState should be SwapPermissionState.ReadyForRequest" - }.approveType.toDomainApproveType(), + approveType = requireNotNull(dataState.approveType) { + "uiState.permissionState should not be null" + }.toDomainApproveType(), txFee = requireNotNull(dataState.selectedFee) { "dataState.selectedFee shouldn't be null" }, + spenderAddress = requireNotNull(dataState.approveDataModel?.spenderAddress) { + "dataState.approveDataModel.spenderAddress shouldn't be null" + }, ), ) } @@ -604,15 +605,16 @@ internal class SwapViewModel @Inject constructor( openPermissionBottomSheet = { singleTaskScheduler.cancelTask() analyticsEventHandler.send(SwapEvents.ButtonGivePermissionClicked) - uiState = stateBuilder.showPermissionBottomSheet(uiState) { stateBuilder.dismissBottomSheet(uiState) } - }, - hidePermissionBottomSheet = { - startLoadingQuotesFromLastState() - analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked) + uiState = stateBuilder.showPermissionBottomSheet(uiState) { + startLoadingQuotesFromLastState() + analyticsEventHandler.send(SwapEvents.ButtonPermissionCancelClicked) + stateBuilder.dismissBottomSheet(uiState) + } }, onAmountSelected = { onAmountSelected(it) }, onChangeApproveType = { approveType -> uiState = stateBuilder.updateApproveType(uiState, approveType) + dataState = dataState.copy(approveType = approveType) }, onClickFee = { val selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL From e39af03b9dfef3c4c7862fb58fdf8ec2644dae0c Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 27 Nov 2023 18:51:29 +0300 Subject: [PATCH 3/3] Updated on 2026-08-14 --- .../feature/swap/viewmodels/SwapViewModel.kt | 36 +++++++++++++++---- 1 file changed, 29 insertions(+), 7 deletions(-) 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 901ef4daa7..ddf91d7e31 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 @@ -437,14 +437,35 @@ internal class SwapViewModel @Inject constructor( } private fun onSearchEntered(searchQuery: String) { - viewModelScope.launch(dispatchers.main) { - runCatching(dispatchers.io) { - swapInteractor.searchTokens(dataState.networkId, searchQuery) + viewModelScope.launch(dispatchers.io) { + val tokenDataState = dataState.tokensDataState ?: return@launch + val group = if (isOrderReversed) { + tokenDataState.fromGroup + } else { + tokenDataState.toGroup } - .onSuccess { - // updateTokensState(it) - } - .onFailure { } + val available = group.available.filter { + it.currencyStatus.currency.name.contains(searchQuery, ignoreCase = true) + } + val unavailable = group.unavailable.filter { + it.currencyStatus.currency.name.contains(searchQuery, ignoreCase = true) + } + val filteredTokenDataState = if (isOrderReversed) { + tokenDataState.copy( + fromGroup = tokenDataState.fromGroup.copy( + available = available, + unavailable = unavailable, + ), + ) + } else { + tokenDataState.copy( + toGroup = tokenDataState.toGroup.copy( + available = available, + unavailable = unavailable, + ), + ) + } + updateTokensState(filteredTokenDataState) } } @@ -485,6 +506,7 @@ internal class SwapViewModel @Inject constructor( toProvidersList = findSwapProviders(fromToken, toToken), ) swapRouter.openScreen(SwapNavScreen.Main) + updateTokensState(tokens) } }