From 94b459d7c29ef59ffe8bafdcee9417228163ae19 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 24 Jul 2025 15:16:52 +0500 Subject: [PATCH 1/2] Updated on 2026-08-14 --- .../converters/AmountStateConverter.kt | 2 +- data/swap/build.gradle.kts | 4 + .../data/swap/DefaultSwapRepositoryV2.kt | 102 +++++++++++------- .../com/tangem/data/swap/di/SwapDataModule.kt | 13 ++- .../tangem/domain/swap/SwapRepositoryV2.kt | 65 +++++------ .../usecase/GetSwapSupportedPairsUseCase.kt | 9 +- features/manage-tokens/impl/build.gradle.kts | 1 + .../converter/SwapAmountFieldConverter.kt | 2 +- .../model/SwapChooseTokenNetworkModel.kt | 2 + .../features/swap/v2/impl/common/SwapUtils.kt | 4 + .../DefaultSendWithSwapComponent.kt | 7 +- .../confirm/SendWithSwapConfirmComponent.kt | 2 +- .../confirm/model/SendWithSwapConfirmModel.kt | 3 +- 13 files changed, 131 insertions(+), 85 deletions(-) diff --git a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/AmountStateConverter.kt b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/AmountStateConverter.kt index 9bef8f3470..a38f516c70 100644 --- a/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/AmountStateConverter.kt +++ b/common/ui/src/main/java/com/tangem/common/ui/amountScreen/converters/AmountStateConverter.kt @@ -125,7 +125,7 @@ class AmountStateConverterV2( resourceReference(R.string.common_crypto_fiat_format, wrappedList(crypto, fiat)) }, tokenName = stringReference(cryptoCurrencyStatus.currency.name), - tokenIconState = iconStateConverter.convert(cryptoCurrencyStatus), + tokenIconState = iconStateConverter.convert(cryptoCurrencyStatus.currency), amountTextField = amountFieldConverter.convert(value.value), isPrimaryButtonEnabled = false, appCurrency = appCurrency, diff --git a/data/swap/build.gradle.kts b/data/swap/build.gradle.kts index 26eb11f40e..f2ff37fff6 100644 --- a/data/swap/build.gradle.kts +++ b/data/swap/build.gradle.kts @@ -31,6 +31,10 @@ dependencies { implementation(projects.domain.tokens) implementation(projects.domain.legacy) implementation(projects.domain.models) + implementation(projects.domain.quotes) + implementation(projects.domain.networks) + implementation(projects.domain.staking.models) + implementation(projects.domain.staking) /** Tangem SDK */ implementation(tangemDeps.blockchain) { diff --git a/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapRepositoryV2.kt b/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapRepositoryV2.kt index d07784d726..51f04d6a97 100644 --- a/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapRepositoryV2.kt +++ b/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapRepositoryV2.kt @@ -1,5 +1,6 @@ package com.tangem.data.swap +import arrow.core.right import com.squareup.moshi.Moshi import com.tangem.data.common.api.safeApiCall import com.tangem.data.swap.converter.SwapDataConverter @@ -21,12 +22,15 @@ import com.tangem.domain.express.models.ExpressProvider import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.express.models.ExpressRateType import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.network.NetworkStatus import com.tangem.domain.models.wallet.UserWallet -import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher +import com.tangem.domain.quotes.single.SingleQuoteStatusProducer +import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier import com.tangem.domain.swap.SwapRepositoryV2 import com.tangem.domain.swap.models.* import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations +import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async @@ -44,8 +48,10 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( private val expressRepository: ExpressRepository, private val coroutineDispatcher: CoroutineDispatcherProvider, private val appPreferencesStore: AppPreferencesStore, - private val currencyStatusOperations: BaseCurrencyStatusOperations, private val dataSignatureVerifier: DataSignatureVerifier, + private val singleQuoteStatusSupplier: SingleQuoteStatusSupplier, + private val singleQuoteStatusFetcher: SingleQuoteStatusFetcher, + private val currencyStatusProxyCreator: CurrencyStatusProxyCreator, @NetworkMoshi moshi: Moshi, ) : SwapRepositoryV2 { @@ -102,10 +108,11 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( }.awaitAll().filterNotNull() } - override suspend fun getPairsOnly( + override suspend fun getSupportedPairs( userWallet: UserWallet, initialCurrency: CryptoCurrency, cryptoCurrencyList: List, + filterProviderTypes: List, ): List = withContext(coroutineDispatcher.io) { val allPairs = getPairsInternal( userWallet = userWallet, @@ -113,6 +120,12 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( cryptoCurrencyList = cryptoCurrencyList, ) + val providers = expressRepository.getProviders( + userWallet = userWallet, + filterProviderTypes = filterProviderTypes, + ) + val mappedProviders = providers.associateBy(ExpressProvider::providerId) + allPairs.map { pair -> async { val statusFromDeferred = async { @@ -130,11 +143,20 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( } } - createPairModelOnly( - currencyFrom = statusFromDeferred.await(), - currencyTo = statusToDeferred.await(), - userWalletId = userWallet.walletId, - ) + val currencyStatusFrom = createSendWithSwapCryptoCurrencyStatus(statusFromDeferred.await()) + val currencyStatusTo = createSendWithSwapCryptoCurrencyStatus(statusToDeferred.await()) + + if (currencyStatusFrom != null && currencyStatusTo != null) { + SwapPairModel( + from = currencyStatusFrom, + to = currencyStatusTo, + providers = pair.providers.mapNotNull { + mappedProviders[it.providerId] + }, + ) + } else { + null + } } }.awaitAll().filterNotNull() } @@ -176,15 +198,14 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( override suspend fun getSwapData( userWallet: UserWallet, fromCryptoCurrencyStatus: CryptoCurrencyStatus, - toCryptoCurrencyStatus: CryptoCurrencyStatus, + toCryptoCurrency: CryptoCurrency, fromAmount: String, - toAddress: String?, + toAddress: String, expressProvider: ExpressProvider, rateType: ExpressRateType, ): SwapDataModel = withContext(coroutineDispatcher.io) { val requestId = UUID.randomUUID().toString() val fromCryptoCurrency = fromCryptoCurrencyStatus.currency - val toCryptoCurrency = toCryptoCurrencyStatus.currency val refundData = when (expressProvider.type) { ExpressProviderType.CEX, @@ -203,7 +224,7 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( fromNetwork = fromCryptoCurrency.network.backendId, toNetwork = toCryptoCurrency.network.backendId, fromAddress = fromCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty(), - toAddress = toAddress ?: toCryptoCurrencyStatus.value.networkAddress?.defaultAddress?.value.orEmpty(), + toAddress = toAddress, fromDecimals = fromCryptoCurrency.decimals, toDecimals = toCryptoCurrency.decimals, fromAmount = fromAmount, @@ -329,33 +350,38 @@ internal class DefaultSwapRepositoryV2 @Inject constructor( }, ) - private suspend fun createPairModelOnly( - currencyFrom: CryptoCurrency?, - currencyTo: CryptoCurrency?, - userWalletId: UserWalletId, - ): SwapPairModel? { - return if (currencyFrom != null && currencyTo != null) { - val statusFrom = currencyStatusOperations.getCurrencyStatusSync( - userWalletId = userWalletId, - cryptoCurrencyId = currencyFrom.id, - ).getOrNull() - val statusTo = currencyStatusOperations.getCurrencyStatusSync( - userWalletId = userWalletId, - cryptoCurrencyId = currencyTo.id, - ).getOrNull() + /** + * Send with swap specific currency status creation + * We support sending to any available to swap and supported network + * It is possible that currency not added to wallet so we ignore network status + */ + private suspend fun createSendWithSwapCryptoCurrencyStatus(cryptoCurrency: CryptoCurrency?): CryptoCurrencyStatus? { + val rawCurrencyId = cryptoCurrency?.id?.rawCurrencyId ?: return null - if (statusFrom != null && statusTo != null) { - SwapPairModel( - from = statusFrom, - to = statusTo, - providers = emptyList(), - ) - } else { - null - } - } else { - null + val quote = singleQuoteStatusSupplier.getSyncOrNull( + params = SingleQuoteStatusProducer.Params(rawCurrencyId = rawCurrencyId), + )?.right() + + if (quote == null) { + singleQuoteStatusFetcher.invoke( + params = SingleQuoteStatusFetcher.Params( + rawCurrencyId = rawCurrencyId, + appCurrencyId = null, + ), + ) } + + return currencyStatusProxyCreator.createCurrencyStatus( + currency = cryptoCurrency, + maybeQuoteStatus = quote ?: singleQuoteStatusSupplier.getSyncOrNull( + params = SingleQuoteStatusProducer.Params(rawCurrencyId = rawCurrencyId), + ).right(), + maybeNetworkStatus = NetworkStatus( + network = cryptoCurrency.network, + value = NetworkStatus.MissedDerivation, // Caution!!! Do not change this status + ).right(), + maybeYieldBalance = null, + ).getOrNull() } private fun parseTxDetails(txDetailsJson: String): TxDetails? { diff --git a/data/swap/src/main/java/com/tangem/data/swap/di/SwapDataModule.kt b/data/swap/src/main/java/com/tangem/data/swap/di/SwapDataModule.kt index 635a89c736..b7df9273ac 100644 --- a/data/swap/src/main/java/com/tangem/data/swap/di/SwapDataModule.kt +++ b/data/swap/src/main/java/com/tangem/data/swap/di/SwapDataModule.kt @@ -12,10 +12,13 @@ import com.tangem.datasource.crypto.DataSignatureVerifier import com.tangem.datasource.di.NetworkMoshi import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.express.ExpressRepository +import com.tangem.domain.quotes.single.SingleQuoteStatusFetcher +import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier +import com.tangem.domain.staking.repositories.StakingRepository import com.tangem.domain.swap.SwapErrorResolver import com.tangem.domain.swap.SwapRepositoryV2 import com.tangem.domain.swap.SwapTransactionRepository -import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations +import com.tangem.domain.tokens.utils.CurrencyStatusProxyCreator import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides @@ -43,8 +46,10 @@ internal object SwapDataModule { expressRepository: ExpressRepository, coroutineDispatcher: CoroutineDispatcherProvider, appPreferencesStore: AppPreferencesStore, - currencyStatusOperations: BaseCurrencyStatusOperations, dataSignatureVerifier: DataSignatureVerifier, + singleQuoteStatusSupplier: SingleQuoteStatusSupplier, + singleQuoteStatusFetcher: SingleQuoteStatusFetcher, + stakingRepository: StakingRepository, @NetworkMoshi moshi: Moshi, ): SwapRepositoryV2 { return DefaultSwapRepositoryV2( @@ -52,9 +57,11 @@ internal object SwapDataModule { expressRepository = expressRepository, coroutineDispatcher = coroutineDispatcher, appPreferencesStore = appPreferencesStore, - currencyStatusOperations = currencyStatusOperations, dataSignatureVerifier = dataSignatureVerifier, moshi = moshi, + singleQuoteStatusSupplier = singleQuoteStatusSupplier, + singleQuoteStatusFetcher = singleQuoteStatusFetcher, + currencyStatusProxyCreator = CurrencyStatusProxyCreator(stakingRepository), ) } diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/SwapRepositoryV2.kt b/domain/swap/src/main/java/com/tangem/domain/swap/SwapRepositoryV2.kt index 406597d0d7..d3a0b037c7 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/SwapRepositoryV2.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/SwapRepositoryV2.kt @@ -4,12 +4,12 @@ import com.tangem.domain.express.models.ExpressProvider import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.express.models.ExpressRateType import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.models.SwapDataModel import com.tangem.domain.swap.models.SwapPairModel import com.tangem.domain.swap.models.SwapQuoteModel import com.tangem.domain.swap.models.SwapStatusModel import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet import java.math.BigDecimal /** @@ -21,10 +21,10 @@ interface SwapRepositoryV2 { /** * Express swap pairs, both direct and reversed * - * @param userWallet selected user wallet - * @param initialCurrency currency being swapped (either to or from) - * @param cryptoCurrencyStatusList list of currencies might be swapped - * @param filterProviderTypes filters only specified provider types, if empty returns providers as is + * @param userWallet selected user wallet + * @param initialCurrency currency being swapped (either to or from) + * @param cryptoCurrencyStatusList list of currencies might be swapped + * @param filterProviderTypes filters only specified provider types, if empty returns providers as is */ suspend fun getPairs( userWallet: UserWallet, @@ -33,22 +33,27 @@ interface SwapRepositoryV2 { filterProviderTypes: List, ): List - /** Express getPairs request variant without providers request */ - suspend fun getPairsOnly( + /** + * Express getPairs request variant for all pairs of crypto currency supported by Tangem Wallet + * Therefore return list may and will include currencies not added to user wallet. + * Used in [Send With Swap] + */ + suspend fun getSupportedPairs( userWallet: UserWallet, initialCurrency: CryptoCurrency, cryptoCurrencyList: List, + filterProviderTypes: List, ): List /** * Returns swap quotes on selected pair * - * @param userWallet selected user wallet - * @param fromCryptoCurrency currency being swapped from - * @param toCryptoCurrency currency being swapped to - * @param fromAmount swap amount - * @param provider selected express provider - * @param rateType rate type + * @param userWallet selected user wallet + * @param fromCryptoCurrency currency being swapped from + * @param toCryptoCurrency currency being swapped to + * @param fromAmount swap amount + * @param provider selected express provider + * @param rateType rate type */ suspend fun getSwapQuote( userWallet: UserWallet, @@ -62,20 +67,20 @@ interface SwapRepositoryV2 { /** * Returns swap data [SwapDataModel] ready to sign and send on selected quote * - * @param userWallet selected user wallet - * @param fromCryptoCurrencyStatus currency status being swapped from - * @param toCryptoCurrencyStatus currency status being swapped to - * @param fromAmount swap amount - * @param toAddress destination address (optional, if null send to self) - * @param expressProvider selected swap provider - * @param rateType selected provider rate type + * @param userWallet selected user wallet + * @param fromCryptoCurrencyStatus currency status being swapped from + * @param toCryptoCurrency currency being swapped to + * @param fromAmount swap amount + * @param toAddress destination address + * @param expressProvider selected swap provider + * @param rateType selected provider rate type */ suspend fun getSwapData( userWallet: UserWallet, fromCryptoCurrencyStatus: CryptoCurrencyStatus, - toCryptoCurrencyStatus: CryptoCurrencyStatus, + toCryptoCurrency: CryptoCurrency, fromAmount: String, - toAddress: String?, + toAddress: String, expressProvider: ExpressProvider, rateType: ExpressRateType, ): SwapDataModel @@ -83,12 +88,12 @@ interface SwapRepositoryV2 { /** * Send ExpressApi info that swap transaction occurred * - * @param userWallet selected user wallet - * @param fromCryptoCurrencyStatus currency status being swapped from - * @param toAddress swap destination address - * @param txId transaction id in ExpressApi - * @param txHash transaction hash in blockchain - * @param txExtraId extra transaction id in ExpressApi + * @param userWallet selected user wallet + * @param fromCryptoCurrencyStatus currency status being swapped from + * @param toAddress swap destination address + * @param txId transaction id in ExpressApi + * @param txHash transaction hash in blockchain + * @param txExtraId extra transaction id in ExpressApi */ suspend fun swapTransactionSent( userWallet: UserWallet, @@ -102,8 +107,8 @@ interface SwapRepositoryV2 { /** * Returns status [SwapStatusModel] on active swap * - * @param userWallet selected user wallet - * @param txId transaction id in ExpressApi + * @param userWallet selected user wallet + * @param txId transaction id in ExpressApi */ suspend fun getExchangeStatus(userWallet: UserWallet, txId: String): SwapStatusModel } \ No newline at end of file diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt index 0f33c9743d..db527b65a1 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapSupportedPairsUseCase.kt @@ -1,7 +1,9 @@ package com.tangem.domain.swap.usecase import arrow.core.Either +import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.SwapErrorResolver import com.tangem.domain.swap.SwapRepositoryV2 import com.tangem.domain.swap.models.SwapCryptoCurrency @@ -9,7 +11,6 @@ import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.domain.swap.models.SwapCurrenciesGroup import com.tangem.domain.swap.models.SwapPairModel import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet /** * Returns pais @@ -23,11 +24,13 @@ class GetSwapSupportedPairsUseCase( userWallet: UserWallet, initialCurrency: CryptoCurrency, cryptoCurrencyList: List, + filterProviderTypes: List, ) = Either.catch { - val pairs = swapRepositoryV2.getPairsOnly( + val pairs = swapRepositoryV2.getSupportedPairs( userWallet = userWallet, initialCurrency = initialCurrency, cryptoCurrencyList = cryptoCurrencyList, + filterProviderTypes = filterProviderTypes, ) val filteredOutInitial = cryptoCurrencyList.filterNot { it.id == initialCurrency.id } @@ -74,7 +77,7 @@ class GetSwapSupportedPairsUseCase( SwapCryptoCurrency( CryptoCurrencyStatus( currency = currency, - value = CryptoCurrencyStatus.Loading, // todo select token unavailable + value = CryptoCurrencyStatus.Loading, ), emptyList(), ) diff --git a/features/manage-tokens/impl/build.gradle.kts b/features/manage-tokens/impl/build.gradle.kts index 84a0eb5e9a..3fcac8e481 100644 --- a/features/manage-tokens/impl/build.gradle.kts +++ b/features/manage-tokens/impl/build.gradle.kts @@ -31,6 +31,7 @@ dependencies { implementation(projects.domain.tokens) implementation(projects.domain.tokens.models) implementation(projects.domain.wallets.models) + implementation(projects.domain.swap.models) /* AndroidX */ implementation(deps.androidx.activity.compose) diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/converter/SwapAmountFieldConverter.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/converter/SwapAmountFieldConverter.kt index a8dc7d5453..8745ee371d 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/converter/SwapAmountFieldConverter.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/converter/SwapAmountFieldConverter.kt @@ -10,9 +10,9 @@ import com.tangem.core.ui.extensions.* import com.tangem.core.ui.format.bigdecimal.crypto import com.tangem.core.ui.format.bigdecimal.format import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.models.SwapDirection import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet import com.tangem.features.swap.v2.impl.R import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountFieldUM import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountType diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/SwapChooseTokenNetworkModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/SwapChooseTokenNetworkModel.kt index 40bd268b58..98b18cc39d 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/SwapChooseTokenNetworkModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/SwapChooseTokenNetworkModel.kt @@ -18,6 +18,7 @@ import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapCho import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.SwapChooseTokenFactory.getErrorMessage import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.transformers.SwapChooseContentStateTransformer import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.transformers.SwapChooseErrorStateTransformer +import com.tangem.features.swap.v2.impl.common.SwapUtils.SEND_WITH_SWAP_PROVIDER_TYPES import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.transformer.update import kotlinx.coroutines.delay @@ -79,6 +80,7 @@ internal class SwapChooseTokenNetworkModel @Inject constructor( userWallet = userWallet, initialCurrency = params.initialCurrency, cryptoCurrencyList = cryptoCurrencyList + params.initialCurrency, + filterProviderTypes = SEND_WITH_SWAP_PROVIDER_TYPES, ).getOrElse { Timber.e(it.toString()) uiState.update( diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapUtils.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapUtils.kt index a7fc9a0236..a8a7a45905 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapUtils.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/common/SwapUtils.kt @@ -6,12 +6,16 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.simple import com.tangem.domain.express.models.ExpressError +import com.tangem.domain.express.models.ExpressProviderType import com.tangem.features.swap.v2.impl.R internal object SwapUtils { const val INCREASE_GAS_LIMIT_FOR_DEX = 112 // 12% const val INCREASE_GAS_LIMIT_FOR_CEX = 105 // 5% + /** List of supported provider types in Send with Swap */ + internal val SEND_WITH_SWAP_PROVIDER_TYPES = listOf(ExpressProviderType.CEX) + fun getExpressErrorMessage(expressError: ExpressError): TextReference { return when (expressError) { is ExpressError.InternalError -> resourceReference( diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt index c3c1dbbe36..986c936162 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/DefaultSendWithSwapComponent.kt @@ -18,7 +18,6 @@ import com.tangem.core.decompose.navigation.inner.InnerRouter import com.tangem.core.ui.decompose.ComposableContentComponent import com.tangem.core.ui.decompose.getEmptyComposableContentComponent import com.tangem.core.ui.extensions.resourceReference -import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.swap.models.R import com.tangem.domain.swap.models.SwapDirection import com.tangem.features.send.v2.api.subcomponents.destination.DestinationRoute @@ -28,6 +27,7 @@ import com.tangem.features.swap.v2.api.SendWithSwapComponent import com.tangem.features.swap.v2.impl.amount.SwapAmountComponent import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams import com.tangem.features.swap.v2.impl.amount.entity.SwapAmountUM +import com.tangem.features.swap.v2.impl.common.SwapUtils.SEND_WITH_SWAP_PROVIDER_TYPES import com.tangem.features.swap.v2.impl.sendviaswap.confirm.SendWithSwapConfirmComponent import com.tangem.features.swap.v2.impl.sendviaswap.model.SendWithSwapModel import com.tangem.features.swap.v2.impl.sendviaswap.success.SendWithSwapSuccessComponent @@ -199,9 +199,4 @@ internal class DefaultSendWithSwapComponent @AssistedInject constructor( params: SendWithSwapComponent.Params, ): DefaultSendWithSwapComponent } - - companion object { - /** List of supported provider types in Send with Swap */ - internal val SEND_WITH_SWAP_PROVIDER_TYPES = listOf(ExpressProviderType.CEX) - } } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt index 810c2b6f16..83b344621f 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/SendWithSwapConfirmComponent.kt @@ -21,10 +21,10 @@ import com.tangem.features.send.v2.api.subcomponents.destination.SendDestination import com.tangem.features.send.v2.api.subcomponents.destination.SendDestinationComponentParams import com.tangem.features.swap.v2.impl.amount.SwapAmountBlockComponent import com.tangem.features.swap.v2.impl.amount.SwapAmountComponentParams +import com.tangem.features.swap.v2.impl.common.SwapUtils.SEND_WITH_SWAP_PROVIDER_TYPES import com.tangem.features.swap.v2.impl.common.entity.ConfirmUM import com.tangem.features.swap.v2.impl.common.entity.SwapQuoteUM import com.tangem.features.swap.v2.impl.notifications.SwapNotificationsComponent -import com.tangem.features.swap.v2.impl.sendviaswap.DefaultSendWithSwapComponent.Companion.SEND_WITH_SWAP_PROVIDER_TYPES import com.tangem.features.swap.v2.impl.sendviaswap.SendWithSwapRoute import com.tangem.features.swap.v2.impl.sendviaswap.confirm.model.SendWithSwapConfirmModel import com.tangem.features.swap.v2.impl.sendviaswap.confirm.ui.SendWithSwapConfirmContent diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt index 912632f57b..d4a416b177 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SendWithSwapConfirmModel.kt @@ -14,7 +14,6 @@ import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.ui.extensions.resourceReference -import com.tangem.domain.express.models.ExpressError import com.tangem.domain.express.models.ExpressProviderType import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.settings.IsSendTapHelpEnabledUseCase @@ -226,7 +225,7 @@ internal class SendWithSwapConfirmModel @Inject constructor( isAmountSubtractAvailable = isAmountSubtractAvailable, onExpressError = { expressError -> swapAlertFactory.getGenericErrorState( - expressError = ExpressError.UnknownError, + expressError = expressError, onFailedTxEmailClick = { modelScope.launch { swapAlertFactory.onFailedTxEmailClick( From 13fd91fc8c5c79bd7c2c060c5e172d729862d15b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 24 Jul 2025 15:17:25 +0500 Subject: [PATCH 2/2] Updated on 2026-08-14 --- .../domain/models/currency/CryptoCurrency.kt | 2 + .../domain/swap/models/SwapCurrencies.kt | 6 +- .../domain/swap/usecase/GetSwapDataUseCase.kt | 9 +- .../swap/usecase/SelectInitialPairUseCase.kt | 6 +- .../DefaultChooseManagedTokensComponent.kt | 6 +- .../SwapChooseTokenNetworkComponent.kt | 3 +- .../SwapChooseTokenNetworkTrigger.kt | 5 +- .../v2/impl/amount/model/SwapAmountModel.kt | 104 +++++++----------- .../DefaultSwapChooseTokenNetworkTrigger.kt | 9 +- .../SwapChooseContentStateTransformer.kt | 34 ++++-- .../confirm/model/SwapTransactionSender.kt | 10 +- 11 files changed, 93 insertions(+), 101 deletions(-) diff --git a/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrency.kt b/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrency.kt index e3ed9d10db..bb3a9b95ee 100644 --- a/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrency.kt +++ b/domain/models/src/main/kotlin/com/tangem/domain/models/currency/CryptoCurrency.kt @@ -216,7 +216,9 @@ sealed class CryptoCurrency { private const val DERIVATION_PATH_DELIMITER = '\u2192' // → private const val ID_PARTS_COUNT = 3 + const val MAIN_NETWORK_TYPE_NAME = "MAIN" + const val MAIN_NETWORK_L2_TYPE_NAME = "MAIN L2" /** * Creates an [ID] from a string [value]. diff --git a/domain/swap/models/src/main/java/com/tangem/domain/swap/models/SwapCurrencies.kt b/domain/swap/models/src/main/java/com/tangem/domain/swap/models/SwapCurrencies.kt index 78630c8eb6..acfaaf4d46 100644 --- a/domain/swap/models/src/main/java/com/tangem/domain/swap/models/SwapCurrencies.kt +++ b/domain/swap/models/src/main/java/com/tangem/domain/swap/models/SwapCurrencies.kt @@ -24,10 +24,10 @@ data class SwapCurrencies( /** * Return swap group depending on [swapDirection] */ -fun SwapCurrencies.getGroupWithReverse(swapDirection: SwapDirection): SwapCurrenciesGroup { +fun SwapCurrencies.getGroupWithDirection(swapDirection: SwapDirection): SwapCurrenciesGroup { return when (swapDirection) { - SwapDirection.Reverse -> fromGroup - SwapDirection.Direct -> toGroup + SwapDirection.Reverse -> toGroup + SwapDirection.Direct -> fromGroup } } diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapDataUseCase.kt b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapDataUseCase.kt index 476ae10eea..6370564cc2 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapDataUseCase.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/GetSwapDataUseCase.kt @@ -4,11 +4,12 @@ import arrow.core.Either import com.tangem.domain.express.models.ExpressError import com.tangem.domain.express.models.ExpressProvider import com.tangem.domain.express.models.ExpressRateType +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.SwapErrorResolver import com.tangem.domain.swap.SwapRepositoryV2 import com.tangem.domain.swap.models.SwapDataModel import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet @Suppress("LongParameterList") class GetSwapDataUseCase( @@ -20,8 +21,8 @@ class GetSwapDataUseCase( userWallet: UserWallet, fromCryptoCurrencyStatus: CryptoCurrencyStatus, fromAmount: String, - toCryptoCurrencyStatus: CryptoCurrencyStatus, - toAddress: String?, + toCryptoCurrency: CryptoCurrency, + toAddress: String, expressProvider: ExpressProvider, rateType: ExpressRateType, ): Either = Either.catch { @@ -29,7 +30,7 @@ class GetSwapDataUseCase( userWallet = userWallet, fromCryptoCurrencyStatus = fromCryptoCurrencyStatus, fromAmount = fromAmount, - toCryptoCurrencyStatus = toCryptoCurrencyStatus, + toCryptoCurrency = toCryptoCurrency, toAddress = toAddress, expressProvider = expressProvider, rateType = rateType, diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/SelectInitialPairUseCase.kt b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/SelectInitialPairUseCase.kt index f945a4f4eb..ed6c8a1d27 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/usecase/SelectInitialPairUseCase.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/usecase/SelectInitialPairUseCase.kt @@ -1,13 +1,13 @@ package com.tangem.domain.swap.usecase import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.SwapTransactionRepository import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.domain.swap.models.SwapCurrenciesGroup import com.tangem.domain.swap.models.SwapDirection -import com.tangem.domain.swap.models.getGroupWithReverse +import com.tangem.domain.swap.models.getGroupWithDirection import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.models.wallet.UserWallet import com.tangem.utils.extensions.orZero /** @@ -31,7 +31,7 @@ class SelectInitialPairUseCase( swapCurrencies: SwapCurrencies, swapDirection: SwapDirection, ): CryptoCurrencyStatus? { - val swapCurrenciesGroup = swapCurrencies.getGroupWithReverse(swapDirection) + val swapCurrenciesGroup = swapCurrencies.getGroupWithDirection(swapDirection) return tryToGetAlreadySelectedCurrency(secondaryCryptoCurrency, swapCurrenciesGroup) ?: tryGetFromCache(userWallet, primaryCryptoCurrency, swapCurrenciesGroup) ?: tryGetWithMaxAmount(swapCurrenciesGroup) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/DefaultChooseManagedTokensComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/DefaultChooseManagedTokensComponent.kt index ecd9dd8f6d..0480397472 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/DefaultChooseManagedTokensComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/choosetoken/DefaultChooseManagedTokensComponent.kt @@ -62,11 +62,11 @@ internal class DefaultChooseManagedTokensComponent @AssistedInject constructor( initialCurrency = config.initialCurrency, token = config.token, onDismiss = model.bottomSheetNavigation::dismiss, - onResult = { + onResult = { swapCurrencies, cryptoCurrency -> componentScope.launch { - swapChooseTokenNetworkTrigger.trigger(it) + swapChooseTokenNetworkTrigger.trigger(swapCurrencies, cryptoCurrency) + router.pop() } - router.pop() }, ), ) diff --git a/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkComponent.kt b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkComponent.kt index 6d6c78d2b2..047c21c44f 100644 --- a/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkComponent.kt +++ b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkComponent.kt @@ -5,6 +5,7 @@ import com.tangem.core.ui.decompose.ComposableBottomSheetComponent import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.swap.models.SwapCurrencies interface SwapChooseTokenNetworkComponent : ComposableBottomSheetComponent { @@ -13,7 +14,7 @@ interface SwapChooseTokenNetworkComponent : ComposableBottomSheetComponent { val initialCurrency: CryptoCurrency, val token: ManagedCryptoCurrency.Token, val onDismiss: () -> Unit, - val onResult: (CryptoCurrency) -> Unit, + val onResult: (SwapCurrencies, CryptoCurrency) -> Unit, ) interface Factory : ComponentFactory diff --git a/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkTrigger.kt b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkTrigger.kt index e001c83b8b..5f9cd14eee 100644 --- a/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkTrigger.kt +++ b/features/swap-v2/api/src/main/java/com/tangem/features/swap/v2/api/choosetoken/SwapChooseTokenNetworkTrigger.kt @@ -1,6 +1,7 @@ package com.tangem.features.swap.v2.api.choosetoken import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.swap.models.SwapCurrencies import kotlinx.coroutines.flow.SharedFlow /** @@ -8,12 +9,12 @@ import kotlinx.coroutines.flow.SharedFlow */ interface SwapChooseTokenNetworkTrigger { - suspend fun trigger(cryptoCurrency: CryptoCurrency) + suspend fun trigger(swapCurrencies: SwapCurrencies, cryptoCurrency: CryptoCurrency) } /** * Listens to swap token selection */ interface SwapChooseTokenNetworkListener { - val swapChooseTokenNetworkResultFlow: SharedFlow + val swapChooseTokenNetworkResultFlow: SharedFlow> } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt index accd9b772c..3a97328278 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/amount/model/SwapAmountModel.kt @@ -17,14 +17,14 @@ import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.express.models.ExpressError import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.domain.swap.models.SwapDirection import com.tangem.domain.swap.models.SwapDirection.Companion.withSwapDirection import com.tangem.domain.swap.models.SwapQuoteModel -import com.tangem.domain.swap.usecase.GetSwapPairsUseCase +import com.tangem.domain.swap.models.getGroupWithDirection import com.tangem.domain.swap.usecase.GetSwapQuoteUseCase import com.tangem.domain.swap.usecase.SelectInitialPairUseCase import com.tangem.domain.tokens.GetMinimumTransactionAmountSyncUseCase -import com.tangem.domain.tokens.GetMultiCryptoCurrencyStatusUseCase import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.transaction.usecase.GetAllowanceUseCase import com.tangem.features.send.v2.api.subcomponents.feeSelector.FeeSelectorReloadTrigger @@ -60,8 +60,6 @@ import com.tangem.utils.transformer.update as transformerUpdate internal class SwapAmountModel @Inject constructor( paramsContainer: ParamsContainer, override val dispatchers: CoroutineDispatcherProvider, - private val getSwapPairsUseCase: GetSwapPairsUseCase, - private val getMultiCryptoCurrencyStatusUseCase: GetMultiCryptoCurrencyStatusUseCase, private val getMinimumTransactionAmountSyncUseCase: GetMinimumTransactionAmountSyncUseCase, private val selectInitialPairUseCase: SelectInitialPairUseCase, private val getSwapQuoteUseCase: GetSwapQuoteUseCase, @@ -304,10 +302,10 @@ internal class SwapAmountModel @Inject constructor( private fun observeChooseSelectToken() { swapChooseTokenNetworkListener.swapChooseTokenNetworkResultFlow - .onEach { currency -> + .onEach { (swapCurrencies, currency) -> uiState.update { amountUM -> if (amountUM is SwapAmountUM.Content) { - initPairs(currency) + initPairs(swapCurrencies, currency) amountUM.copy( isPrimaryButtonEnabled = false, secondaryAmount = SwapAmountFieldUM.Loading( @@ -322,65 +320,42 @@ internal class SwapAmountModel @Inject constructor( .launchIn(modelScope) } - private fun initPairs(secondaryCryptoCurrency: CryptoCurrency?) { + private fun initPairs(swapCurrencies: SwapCurrencies, secondaryCryptoCurrency: CryptoCurrency?) { modelScope.launch { - val cryptoCurrencyStatusList = getMultiCryptoCurrencyStatusUseCase - .invokeMultiWalletSync(userWallet.walletId) - .getOrElse { emptyList() } - - val cryptoCurrencyStatusListExceptPrimary = cryptoCurrencyStatusList.filter { - val statusFilter = it.value is CryptoCurrencyStatus.Loaded || it.value is CryptoCurrencyStatus.NoAccount - val notCustomTokenFilter = !it.currency.isCustom - statusFilter && notCustomTokenFilter - } - - getSwapPairsUseCase( + val secondaryStatus = selectInitialPairUseCase( + primaryCryptoCurrency = primaryCryptoCurrency, + secondaryCryptoCurrency = secondaryCryptoCurrency, userWallet = userWallet, - initialCurrency = primaryCryptoCurrency, - cryptoCurrencyStatusList = cryptoCurrencyStatusListExceptPrimary, - filterProviderTypes = params.filterProviderTypes, - ).fold( - ifRight = { swapCurrencies -> - val secondaryStatus = selectInitialPairUseCase( - primaryCryptoCurrency = primaryCryptoCurrency, - secondaryCryptoCurrency = secondaryCryptoCurrency, + swapCurrencies = swapCurrencies, + swapDirection = params.swapDirection, + ) + + val primaryStatus = (uiState.value as? SwapAmountUM.Content)?.primaryCryptoCurrencyStatus + if (secondaryStatus != null && primaryStatus != null) { + initCurrencies(primaryStatus, secondaryStatus) + uiState.transformerUpdate( + SwapAmountSecondaryReadyStateTransformer( userWallet = userWallet, swapCurrencies = swapCurrencies, - swapDirection = params.swapDirection, - ) - - val primaryStatus = (uiState.value as? SwapAmountUM.Content)?.primaryCryptoCurrencyStatus - if (secondaryStatus != null && primaryStatus != null) { - initCurrencies(primaryStatus, secondaryStatus) - uiState.transformerUpdate( - SwapAmountSecondaryReadyStateTransformer( - userWallet = userWallet, - swapCurrencies = swapCurrencies, - primaryCryptoCurrencyStatus = primaryStatus, - secondaryCryptoCurrencyStatus = secondaryStatus, - appCurrency = appCurrency, - swapDirection = swapDirection, - clickIntents = this@SwapAmountModel, - isBalanceHidden = params.isBalanceHidingFlow.value, - ), - ) - loadQuotes() - } else { - Timber.e( - """ - Invalid cryptocurrencies status: - | Primary -> $primaryStatus - | Secondary -> $secondaryStatus - """.trimIndent(), - ) - showErrorAlert(errorMessage = null) - } - }, - ifLeft = { error -> - Timber.e(error) - showErrorAlert(errorMessage = error.message) - }, - ) + primaryCryptoCurrencyStatus = primaryStatus, + secondaryCryptoCurrencyStatus = secondaryStatus, + appCurrency = appCurrency, + swapDirection = swapDirection, + clickIntents = this@SwapAmountModel, + isBalanceHidden = params.isBalanceHidingFlow.value, + ), + ) + loadQuotes() + } else { + Timber.e( + """ + Invalid cryptocurrencies status: + | Primary -> $primaryStatus + | Secondary -> $secondaryStatus + """.trimIndent(), + ) + showErrorAlert(errorMessage = null) + } } } @@ -428,15 +403,12 @@ internal class SwapAmountModel @Inject constructor( val fromAmountValue = fromAmount?.amountTextField?.cryptoAmount?.value ?: return - val swapGroups = when (state.swapDirection) { - SwapDirection.Direct -> state.swapCurrencies.toGroup.available - SwapDirection.Reverse -> state.swapCurrencies.fromGroup.available - } + val swapGroups = state.swapCurrencies.getGroupWithDirection(state.swapDirection) uiState.transformerUpdate(SwapQuoteLoadingStateTransformer) modelScope.launch { - val quotes = swapGroups.filter { + val quotes = swapGroups.available.filter { it.currencyStatus.currency.id == toCryptoCurrency.id }.flatMap { it.providers diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/DefaultSwapChooseTokenNetworkTrigger.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/DefaultSwapChooseTokenNetworkTrigger.kt index 8ff862deb8..601f8942db 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/DefaultSwapChooseTokenNetworkTrigger.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/DefaultSwapChooseTokenNetworkTrigger.kt @@ -1,6 +1,7 @@ package com.tangem.features.swap.v2.impl.choosetoken.fromSupported import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.features.swap.v2.api.choosetoken.SwapChooseTokenNetworkListener import com.tangem.features.swap.v2.api.choosetoken.SwapChooseTokenNetworkTrigger import kotlinx.coroutines.flow.MutableSharedFlow @@ -13,10 +14,10 @@ internal class DefaultSwapChooseTokenNetworkTrigger @Inject constructor() : SwapChooseTokenNetworkTrigger, SwapChooseTokenNetworkListener { - override val swapChooseTokenNetworkResultFlow: SharedFlow - field = MutableSharedFlow() + override val swapChooseTokenNetworkResultFlow: SharedFlow> + field = MutableSharedFlow>() - override suspend fun trigger(cryptoCurrency: CryptoCurrency) { - swapChooseTokenNetworkResultFlow.emit(cryptoCurrency) + override suspend fun trigger(swapCurrencies: SwapCurrencies, cryptoCurrency: CryptoCurrency) { + swapChooseTokenNetworkResultFlow.emit(swapCurrencies to cryptoCurrency) } } \ No newline at end of file diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/transformers/SwapChooseContentStateTransformer.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/transformers/SwapChooseContentStateTransformer.kt index ff4f6ce201..3868504cd6 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/transformers/SwapChooseContentStateTransformer.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/choosetoken/fromSupported/model/transformers/SwapChooseContentStateTransformer.kt @@ -4,36 +4,48 @@ import com.tangem.core.ui.extensions.iconResId import com.tangem.core.ui.extensions.stringReference import com.tangem.domain.express.models.ExpressRateType import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.currency.CryptoCurrency.ID.Companion.MAIN_NETWORK_L2_TYPE_NAME import com.tangem.domain.models.currency.CryptoCurrency.ID.Companion.MAIN_NETWORK_TYPE_NAME +import com.tangem.domain.models.network.Network import com.tangem.domain.swap.models.SwapCurrencies import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseNetworkUM import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkContentUM import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.entity.SwapChooseTokenNetworkUM import com.tangem.features.swap.v2.impl.choosetoken.fromSupported.model.SwapChooseTokenFactory.getErrorMessage +import com.tangem.lib.crypto.BlockchainUtils import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.toPersistentList internal class SwapChooseContentStateTransformer( private val pairs: SwapCurrencies, private val tokenName: String, - private val onNetworkClick: (CryptoCurrency) -> Unit, + private val onNetworkClick: (SwapCurrencies, CryptoCurrency) -> Unit, private val onDismiss: () -> Unit, ) : Transformer { override fun transform(prevState: SwapChooseTokenNetworkUM): SwapChooseTokenNetworkUM { - val swapNetworks = pairs.fromGroup.available.map { - val network = it.currencyStatus.currency.network - val isMain = it.currencyStatus.currency is CryptoCurrency.Coin + val swapNetworks = pairs.fromGroup.available.map { availableCurrency -> + val cryptoCurrency = availableCurrency.currencyStatus.currency + val network = cryptoCurrency.network + + val isMain = cryptoCurrency is CryptoCurrency.Coin + val subtitle = when { + BlockchainUtils.isL2Network(networkId = network.backendId) -> MAIN_NETWORK_L2_TYPE_NAME + isMain -> MAIN_NETWORK_TYPE_NAME + network.standardType !is Network.StandardType.Unspecified -> network.standardType.name + else -> "" + } + SwapChooseNetworkUM( title = stringReference(network.name), - subtitle = if (isMain) { - stringReference(MAIN_NETWORK_TYPE_NAME) - } else { - stringReference(network.standardType.name) - }, + subtitle = stringReference(subtitle), iconResId = network.iconResId, isMainNetwork = isMain, - hasFixedRate = it.providers.any { it.rateTypes.any { it == ExpressRateType.Fixed } }, - onNetworkClick = { onNetworkClick(it.currencyStatus.currency) }, + hasFixedRate = availableCurrency.providers.any { provider -> + provider.rateTypes.any { rateType -> + rateType == ExpressRateType.Fixed + } + }, + onNetworkClick = { onNetworkClick(pairs, availableCurrency.currencyStatus.currency) }, ) }.toPersistentList() diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SwapTransactionSender.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SwapTransactionSender.kt index e5dcb79e12..ace6ba9272 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SwapTransactionSender.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/confirm/model/SwapTransactionSender.kt @@ -5,6 +5,7 @@ import com.tangem.blockchain.common.transaction.Fee import com.tangem.domain.express.models.ExpressError import com.tangem.domain.express.models.ExpressProvider import com.tangem.domain.express.models.ExpressProviderType +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.swap.models.SwapDataModel import com.tangem.domain.swap.models.SwapDataTransactionModel import com.tangem.domain.swap.usecase.GetSwapDataUseCase @@ -14,7 +15,6 @@ import com.tangem.domain.transaction.error.SendTransactionError import com.tangem.domain.transaction.usecase.CreateTransferTransactionUseCase import com.tangem.domain.transaction.usecase.SendTransactionUseCase import com.tangem.domain.utils.convertToSdkAmount -import com.tangem.domain.models.wallet.UserWallet import com.tangem.features.send.v2.api.subcomponents.feeSelector.utils.FeeCalculationUtils import com.tangem.features.swap.v2.impl.common.ConfirmData import dagger.assisted.Assisted @@ -22,6 +22,7 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import timber.log.Timber import java.math.BigDecimal +import java.math.RoundingMode @Suppress("LongParameterList") internal class SwapTransactionSender @AssistedInject constructor( @@ -72,6 +73,7 @@ internal class SwapTransactionSender @AssistedInject constructor( val rateType = confirmData.rateType ?: return val amountValue = confirmData.enteredAmount ?: return val feeValue = confirmData.fee?.amount?.value ?: return + val destination = confirmData.enteredDestination ?: return val fromAmount = FeeCalculationUtils.checkAndCalculateSubtractedAmount( isAmountSubtractAvailable = isAmountSubtractAvailable, @@ -85,8 +87,8 @@ internal class SwapTransactionSender @AssistedInject constructor( userWallet = userWallet, fromCryptoCurrencyStatus = fromStatus, fromAmount = fromAmount.toStringWithRightOffset(fromStatus.currency.decimals), - toCryptoCurrencyStatus = toStatus, - toAddress = confirmData.enteredDestination, + toCryptoCurrency = toStatus.currency, + toAddress = destination, expressProvider = provider, rateType = rateType, ).getOrElse { onExpressError(it); return } @@ -163,7 +165,7 @@ internal class SwapTransactionSender @AssistedInject constructor( } private fun BigDecimal.toStringWithRightOffset(decimals: Int): String { - return movePointRight(decimals).toPlainString() + return setScale(decimals, RoundingMode.HALF_DOWN).movePointRight(decimals).toPlainString() } @AssistedFactory