diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/ExpressApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/ExpressApi.kt deleted file mode 100644 index 0ed82c76d9..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/ExpressApi.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.tangem.datasource.api.express - -import com.tangem.datasource.api.common.response.ApiResponse -import com.tangem.datasource.api.express.models.request.AssetsRequestBody -import com.tangem.datasource.api.express.models.request.PairsRequestBody -import com.tangem.datasource.api.express.models.response.* -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query -import java.math.BigDecimal - -/** - * Interface of Tangem Express API (new swap mechanism) - */ -@Suppress("LongParameterList") -interface ExpressApi { - - @POST("assets") - suspend fun getAssets(@Body body: AssetsRequestBody): ApiResponse> - - @POST("pairs") - suspend fun getPairs(@Body body: PairsRequestBody): ApiResponse> - - @GET("providers") - suspend fun getProviders(): ApiResponse> - - @GET("exchange-quote") - suspend fun getExchangeQuote( - @Query("fromContractAddress") fromContractAddress: String, - @Query("fromNetwork") fromNetwork: String, - @Query("toContractAddress") toContractAddress: String, - @Query("toNetwork") toNetwork: String, - @Query("fromAmount") fromAmount: BigDecimal, - @Query("providerId") providerId: Int, - @Query("rateType") rateType: RateType, - ): ApiResponse - - @GET("exchange-data") - suspend fun getExchangeData( - @Query("fromContractAddress") fromContractAddress: String, - @Query("fromNetwork") fromNetwork: String, - @Query("toContractAddress") toContractAddress: String, - @Query("toNetwork") toNetwork: String, - @Query("fromAmount") fromAmount: BigDecimal, - @Query("providerId") providerId: Int, - @Query("rateType") rateType: RateType, - @Query("toAddress") toAddress: String, - ): ApiResponse - - @GET("exchange-result") - suspend fun getExchangeResults(@Query("txId") txId: String): ApiResponse -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt index 627e70bdd0..0c1fb16cf8 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/TangemExpressApi.kt @@ -31,9 +31,9 @@ interface TangemExpressApi { @Query("fromNetwork") fromNetwork: String, @Query("toContractAddress") toContractAddress: String, @Query("toNetwork") toNetwork: String, - @Query("fromAmount") fromAmount: BigDecimal, + @Query("fromAmount") fromAmount: String, @Query("providerId") providerId: Int, - @Query("rateType") rateType: RateType, + @Query("rateType") rateType: String, ): ApiResponse @GET("exchange-data") diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeQuoteResponse.kt b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeQuoteResponse.kt index 214b4ac2d5..de2368e418 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeQuoteResponse.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/express/models/response/ExchangeQuoteResponse.kt @@ -4,9 +4,23 @@ import com.squareup.moshi.Json import java.math.BigDecimal data class ExchangeQuoteResponse( + + @Json(name = "fromAmount") + val fromAmount: BigDecimal, + + @Json(name = "fromDecimals") + val fromDecimals: Int, + @Json(name = "toAmount") val toAmount: BigDecimal, + @Json(name = "toDecimals") + val toDecimals: Int, + @Json(name = "allowanceContract") val allowanceContract: String?, + + @Json(name = "minAmount") + val minAmount: BigDecimal, + ) \ No newline at end of file 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 9eb5bedf15..ff7b2277ed 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 @@ -20,13 +20,16 @@ import com.tangem.domain.walletmanager.WalletManagersFacade import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.converters.* import com.tangem.feature.swap.domain.SwapRepository +import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.data.AggregatedSwapDataModel import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.swap.domain.models.mapErrors import com.tangem.utils.coroutines.CoroutineDispatcherProvider import kotlinx.coroutines.async import kotlinx.coroutines.withContext +import retrofit2.http.Query import java.math.BigDecimal +import java.util.Locale import javax.inject.Inject import com.tangem.datasource.api.express.models.request.LeastTokenInfo as NetworkLeastTokenInfo @@ -127,21 +130,33 @@ internal class SwapRepositoryImpl @Inject constructor( } override suspend fun findBestQuote( - networkId: String, - fromTokenAddress: String, - toTokenAddress: String, - amount: String, + fromContractAddress: String, + fromNetwork: String, + toContractAddress: String, + toNetwork: String, + fromAmount: String, + providerId: Int, + rateType: RateType, ): AggregatedSwapDataModel { return withContext(coroutineDispatcher.io) { try { - val response = oneInchErrorsHandler.handleOneInchResponse( - getOneInchApi(networkId).quote( - fromTokenAddress = fromTokenAddress, - toTokenAddress = toTokenAddress, - amount = amount, - ), + val response = tangemExpressApi.getExchangeQuote( + fromContractAddress = fromContractAddress, + fromNetwork = fromNetwork, + toContractAddress = toContractAddress, + toNetwork = toNetwork, + fromAmount = fromAmount, + providerId = providerId, + rateType = rateType.name.lowercase() + ).getOrThrow() + AggregatedSwapDataModel( + dataModel = QuoteModel( + SwapAmount( + value = response.toAmount, + decimals = response.toDecimals + ) + ) ) - AggregatedSwapDataModel(dataModel = quotesConverter.convert(response)) } catch (ex: OneIncResponseException) { AggregatedSwapDataModel(null, mapErrors(ex.data.description)) } @@ -263,7 +278,7 @@ internal class SwapRepositoryImpl @Inject constructor( fromNetwork: String, toContractAddress: String, toNetwork: String, - fromAmount: BigDecimal, + fromAmount: String, providerId: Int, rateType: RateType ): ExchangeQuote { @@ -274,7 +289,7 @@ internal class SwapRepositoryImpl @Inject constructor( toNetwork, fromAmount, providerId, - rateTypeConverter.convertBack(rateType) + rateType.name.lowercase() ).getOrThrow() return ExchangeQuote( 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 2757583249..4db2ed600b 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 @@ -66,6 +66,7 @@ interface SwapInteractor { networkId: String, fromToken: CryptoCurrency, toToken: CryptoCurrency, + providers: List, amountToSwap: String, selectedFee: FeeType = FeeType.NORMAL, ): SwapState 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 738424d73c..aaa47663ff 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 @@ -274,6 +274,7 @@ internal class SwapInteractorImpl @Inject constructor( networkId: String, fromToken: CryptoCurrency, toToken: CryptoCurrency, + providers: List, amountToSwap: String, selectedFee: FeeType, ): SwapState { @@ -311,6 +312,7 @@ internal class SwapInteractorImpl @Inject constructor( toToken = toToken, isAllowedToSpend = isAllowedToSpend, isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough, + providers = providers ) } } @@ -518,14 +520,23 @@ internal class SwapInteractorImpl @Inject constructor( amount: SwapAmount, fromToken: CryptoCurrency, toToken: CryptoCurrency, + providers: List, isAllowedToSpend: Boolean, isBalanceWithoutFeeEnough: Boolean, ): SwapState { repository.findBestQuote( - networkId = networkId, - fromTokenAddress = fromTokenAddress, - toTokenAddress = toTokenAddress, - amount = amount.toStringWithRightOffset(), + fromContractAddress = fromToken.getContractAddress(), + fromNetwork = fromToken.network.backendId, + toContractAddress = toToken.getContractAddress(), + toNetwork = toToken.network.backendId, + fromAmount = amount.toStringWithRightOffset(), + providerId = providers[0].providerId, + rateType = RateType.FLOAT + + // networkId = networkId, + // fromTokenAddress = fromTokenAddress, + // toTokenAddress = toTokenAddress, + // amount = amount.toStringWithRightOffset(), ).let { quotes -> val quoteDataModel = quotes.dataModel if (quoteDataModel != null) { @@ -668,16 +679,16 @@ internal class SwapInteractorImpl @Inject constructor( tokenWalletBalance = toTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") } ?: ZERO_BALANCE, tokenFiatBalance = toTokenAmount.value.toFiatString( - rateValue = rates[toToken.id.value]?.toBigDecimal() ?: BigDecimal.ZERO, + rateValue = rates[toToken.network.backendId]?.toBigDecimal() ?: BigDecimal.ZERO, fiatCurrencyName = appCurrency.symbol, formatWithSpaces = true, ), ), priceImpact = calculatePriceImpact( fromTokenAmount = fromTokenAmount.value, - fromRate = rates[fromToken.id.value] ?: 0.0, + fromRate = rates[fromToken.network.backendId] ?: 0.0, toTokenAmount = toTokenAmount.value, - toRate = rates[toToken.id.value] ?: 0.0, + toRate = rates[toToken.network.backendId] ?: 0.0, ), networkCurrency = userWalletManager.getNetworkCurrency(networkId), swapDataModel = swapStateData, @@ -819,7 +830,7 @@ internal class SwapInteractorImpl @Inject constructor( private fun getTokenAddress(currency: CryptoCurrency): String { return when (currency) { is CryptoCurrency.Coin -> { - DEFAULT_BLOCKCHAIN_INCH_ADDRESS + "0" } is CryptoCurrency.Token -> { currency.contractAddress 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 8942e75161..2e0a8cbf0f 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 @@ -15,10 +15,13 @@ interface SwapRepository { suspend fun getExchangeableTokens(networkId: String): List suspend fun findBestQuote( - networkId: String, - fromTokenAddress: String, - toTokenAddress: String, - amount: String, + fromContractAddress: String, + fromNetwork: String, + toContractAddress: String, + toNetwork: String, + fromAmount: String, + providerId: Int, + rateType: RateType, ): AggregatedSwapDataModel /** @@ -67,7 +70,7 @@ interface SwapRepository { fromNetwork: String, toContractAddress: String, toNetwork: String, - fromAmount: BigDecimal, + fromAmount: String, providerId: Int, rateType: RateType, ) : ExchangeQuote 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 28809bc066..14610d708f 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 @@ -9,6 +9,7 @@ import java.math.BigDecimal sealed interface SwapState { data class QuotesLoadedState( + //add map < Provider ID, Swap state data> val fromTokenInfo: TokenSwapInfo, val toTokenInfo: TokenSwapInfo, val priceImpact: Float, 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 99919c05a3..8af439d54f 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 @@ -13,6 +13,8 @@ import com.tangem.feature.swap.analytics.SwapEvents import com.tangem.feature.swap.domain.BlockchainInteractor import com.tangem.feature.swap.domain.SwapInteractor import com.tangem.feature.swap.domain.models.domain.PermissionOptions +import com.tangem.feature.swap.domain.models.domain.RateType +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 @@ -138,10 +140,12 @@ internal class SwapViewModel @Inject constructor( ) // updateTokensState(dataState = state.foundTokensState) + val toToken = state.toGroup.available.first() startLoadingQuotes( fromToken = initialCryptoCurrency, - toToken = state.toGroup.available.first().currencyStatus.currency, + toToken = toToken.currencyStatus.currency, amount = lastAmount.value, + toProvidersList = toToken.providers ) }.onFailure { Timber.tag(loggingTag).e(it) @@ -179,7 +183,12 @@ internal class SwapViewModel @Inject constructor( ) } - private fun startLoadingQuotes(fromToken: CryptoCurrency, toToken: CryptoCurrency, amount: String) { + private fun startLoadingQuotes( + fromToken: CryptoCurrency, + toToken: CryptoCurrency, + amount: String, + toProvidersList: List = listOf(SwapProvider(1, listOf(RateType.FLOAT))), + ) { singleTaskScheduler.cancelTask() uiState = stateBuilder.createQuotesLoadingState(uiState, fromToken, toToken, initialCryptoCurrency.id.value) singleTaskScheduler.scheduleTask( @@ -188,6 +197,7 @@ internal class SwapViewModel @Inject constructor( fromToken = fromToken, toToken = toToken, amount = amount, + toProvidersList = toProvidersList ), ) } @@ -205,6 +215,7 @@ internal class SwapViewModel @Inject constructor( fromToken: CryptoCurrency, toToken: CryptoCurrency, amount: String, + toProvidersList: List, ): PeriodicTask { return PeriodicTask( UPDATE_DELAY, @@ -220,6 +231,7 @@ internal class SwapViewModel @Inject constructor( networkId = dataState.networkId, fromToken = fromToken, toToken = toToken, + providers = toProvidersList, amountToSwap = amount, selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL, )