Updated on 2026-08-14
This commit is contained in:
commit
64ed64820b
10 changed files with 198 additions and 136 deletions
|
|
@ -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<List<Asset>>
|
||||
|
||||
@POST("pairs")
|
||||
suspend fun getPairs(@Body body: PairsRequestBody): ApiResponse<List<SwapPair>>
|
||||
|
||||
@GET("providers")
|
||||
suspend fun getProviders(): ApiResponse<List<ExchangeProvider>>
|
||||
|
||||
@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<ExchangeQuoteResponse>
|
||||
|
||||
@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<ExchangeDataResponse>
|
||||
|
||||
@GET("exchange-result")
|
||||
suspend fun getExchangeResults(@Query("txId") txId: String): ApiResponse<ExchangeResultsResponse>
|
||||
}
|
||||
|
|
@ -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<ExchangeQuoteResponse>
|
||||
|
||||
@GET("exchange-data")
|
||||
|
|
|
|||
|
|
@ -4,9 +4,23 @@ import com.squareup.moshi.Json
|
|||
import java.math.BigDecimal
|
||||
|
||||
data class ExchangeQuoteResponse(
|
||||
|
||||
@Json(name = "fromAmount")
|
||||
val fromAmount: String,
|
||||
|
||||
@Json(name = "fromDecimals")
|
||||
val fromDecimals: Int,
|
||||
|
||||
@Json(name = "toAmount")
|
||||
val toAmount: BigDecimal,
|
||||
val toAmount: String,
|
||||
|
||||
@Json(name = "toDecimals")
|
||||
val toDecimals: Int,
|
||||
|
||||
@Json(name = "allowanceContract")
|
||||
val allowanceContract: String?,
|
||||
|
||||
@Json(name = "minAmount")
|
||||
val minAmount: BigDecimal,
|
||||
|
||||
)
|
||||
|
|
@ -20,6 +20,7 @@ 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.createFromAmountWithOffset
|
||||
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
|
||||
|
|
@ -127,21 +128,30 @@ 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<QuoteModel> {
|
||||
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(
|
||||
toTokenAmount = createFromAmountWithOffset(response.toAmount, response.toDecimals),
|
||||
),
|
||||
)
|
||||
AggregatedSwapDataModel(dataModel = quotesConverter.convert(response))
|
||||
} catch (ex: OneIncResponseException) {
|
||||
AggregatedSwapDataModel(null, mapErrors(ex.data.description))
|
||||
}
|
||||
|
|
@ -263,7 +273,7 @@ internal class SwapRepositoryImpl @Inject constructor(
|
|||
fromNetwork: String,
|
||||
toContractAddress: String,
|
||||
toNetwork: String,
|
||||
fromAmount: BigDecimal,
|
||||
fromAmount: String,
|
||||
providerId: Int,
|
||||
rateType: RateType,
|
||||
): ExchangeQuote {
|
||||
|
|
@ -274,7 +284,7 @@ internal class SwapRepositoryImpl @Inject constructor(
|
|||
toNetwork,
|
||||
fromAmount,
|
||||
providerId,
|
||||
rateTypeConverter.convertBack(rateType),
|
||||
rateType.name.lowercase(),
|
||||
).getOrThrow()
|
||||
|
||||
return ExchangeQuote(
|
||||
|
|
|
|||
|
|
@ -67,9 +67,10 @@ interface SwapInteractor {
|
|||
networkId: String,
|
||||
fromToken: CryptoCurrency,
|
||||
toToken: CryptoCurrency,
|
||||
providers: List<SwapProvider>,
|
||||
amountToSwap: String,
|
||||
selectedFee: FeeType = FeeType.NORMAL,
|
||||
): SwapState
|
||||
): Map<SwapProvider, SwapState>
|
||||
|
||||
/**
|
||||
* Starts swap transaction, perform sign transaction
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
|
|||
import com.tangem.feature.swap.domain.cache.SwapDataCache
|
||||
import com.tangem.feature.swap.domain.converters.SwapCurrencyConverter
|
||||
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.domain.Currency
|
||||
import com.tangem.feature.swap.domain.models.toStringWithRightOffset
|
||||
|
|
@ -27,6 +28,9 @@ import timber.log.Timber
|
|||
import java.math.BigDecimal
|
||||
import java.math.RoundingMode
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
|
||||
@Suppress("LargeClass", "LongParameterList")
|
||||
internal class SwapInteractorImpl @Inject constructor(
|
||||
|
|
@ -274,13 +278,14 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
networkId: String,
|
||||
fromToken: CryptoCurrency,
|
||||
toToken: CryptoCurrency,
|
||||
providers: List<SwapProvider>,
|
||||
amountToSwap: String,
|
||||
selectedFee: FeeType,
|
||||
): SwapState {
|
||||
): Map<SwapProvider, SwapState> {
|
||||
syncWalletBalanceForTokens(networkId, listOf(fromToken, toToken))
|
||||
val amountDecimal = toBigDecimalOrNull(amountToSwap)
|
||||
if (amountDecimal == null || amountDecimal.signum() == 0) {
|
||||
return createEmptyAmountState(networkId, fromToken, toToken)
|
||||
return providers.associateWith { createEmptyAmountState(networkId, fromToken, toToken) }
|
||||
}
|
||||
val amount = SwapAmount(amountDecimal, getTokenDecimals(fromToken))
|
||||
val fromTokenAddress = getTokenAddress(fromToken)
|
||||
|
|
@ -292,25 +297,27 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
}
|
||||
val isBalanceWithoutFeeEnough = isBalanceEnough(networkId, fromToken, amount, null)
|
||||
return if (isAllowedToSpend && isBalanceWithoutFeeEnough) {
|
||||
loadSwapData(
|
||||
networkId = networkId,
|
||||
fromTokenAddress = fromTokenAddress,
|
||||
toTokenAddress = toTokenAddress,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = amount,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
// TODO
|
||||
providers.associateWith {
|
||||
loadSwapData(
|
||||
networkId = networkId,
|
||||
fromTokenAddress = fromTokenAddress,
|
||||
toTokenAddress = toTokenAddress,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = amount,
|
||||
selectedFee = selectedFee,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
loadQuoteData(
|
||||
networkId = networkId,
|
||||
fromTokenAddress = fromTokenAddress,
|
||||
toTokenAddress = toTokenAddress,
|
||||
amount = amount,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
isAllowedToSpend = isAllowedToSpend,
|
||||
isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough,
|
||||
providers = providers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -513,45 +520,76 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
@Suppress("LongParameterList")
|
||||
private suspend fun loadQuoteData(
|
||||
networkId: String,
|
||||
fromTokenAddress: String,
|
||||
toTokenAddress: String,
|
||||
amount: SwapAmount,
|
||||
fromToken: CryptoCurrency,
|
||||
toToken: CryptoCurrency,
|
||||
providers: List<SwapProvider>,
|
||||
isAllowedToSpend: Boolean,
|
||||
isBalanceWithoutFeeEnough: Boolean,
|
||||
): Map<SwapProvider, SwapState> {
|
||||
return coroutineScope {
|
||||
val quoteRequests = providers.map { provider ->
|
||||
async {
|
||||
provider to repository.findBestQuote(
|
||||
fromContractAddress = fromToken.getContractAddress(),
|
||||
fromNetwork = fromToken.network.backendId,
|
||||
toContractAddress = toToken.getContractAddress(),
|
||||
toNetwork = toToken.network.backendId,
|
||||
fromAmount = amount.toStringWithRightOffset(),
|
||||
providerId = provider.providerId,
|
||||
rateType = RateType.FLOAT,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
quoteRequests.awaitAll().map {
|
||||
it.first to
|
||||
getState(
|
||||
quoteDataModel = it.second,
|
||||
amount = amount,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
networkId = networkId,
|
||||
isAllowedToSpend = isAllowedToSpend,
|
||||
isBalanceWithoutFeeEnough = isBalanceWithoutFeeEnough
|
||||
)
|
||||
}.associate { it.first to it.second }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getState(
|
||||
quoteDataModel: AggregatedSwapDataModel<QuoteModel>,
|
||||
amount: SwapAmount,
|
||||
fromToken: CryptoCurrency,
|
||||
toToken: CryptoCurrency,
|
||||
networkId: String,
|
||||
isAllowedToSpend: Boolean,
|
||||
isBalanceWithoutFeeEnough: Boolean,
|
||||
): SwapState {
|
||||
repository.findBestQuote(
|
||||
networkId = networkId,
|
||||
fromTokenAddress = fromTokenAddress,
|
||||
toTokenAddress = toTokenAddress,
|
||||
amount = amount.toStringWithRightOffset(),
|
||||
).let { quotes ->
|
||||
val quoteDataModel = quotes.dataModel
|
||||
if (quoteDataModel != null) {
|
||||
val swapState = updateBalances(
|
||||
networkId = networkId,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
fromTokenAmount = amount,
|
||||
toTokenAmount = quoteDataModel.toTokenAmount,
|
||||
swapStateData = null,
|
||||
)
|
||||
val quotesState = updatePermissionState(
|
||||
networkId = networkId,
|
||||
fromToken = fromToken,
|
||||
swapAmount = amount,
|
||||
quotesLoadedState = swapState,
|
||||
)
|
||||
return quotesState.copy(
|
||||
preparedSwapConfigState = quotesState.preparedSwapConfigState.copy(
|
||||
isAllowedToSpend = isAllowedToSpend,
|
||||
isBalanceEnough = isBalanceWithoutFeeEnough,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
return SwapState.SwapError(quotes.error)
|
||||
}
|
||||
val quoteModel = quoteDataModel.dataModel
|
||||
if (quoteModel != null) {
|
||||
val swapState = updateBalances(
|
||||
networkId = networkId,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
fromTokenAmount = amount,
|
||||
toTokenAmount = quoteModel.toTokenAmount,
|
||||
swapStateData = null,
|
||||
)
|
||||
val quotesState = updatePermissionState(
|
||||
networkId = networkId,
|
||||
fromToken = fromToken,
|
||||
swapAmount = amount,
|
||||
quotesLoadedState = swapState,
|
||||
)
|
||||
return quotesState.copy(
|
||||
preparedSwapConfigState = quotesState.preparedSwapConfigState.copy(
|
||||
isAllowedToSpend = isAllowedToSpend,
|
||||
isBalanceEnough = isBalanceWithoutFeeEnough,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
return SwapState.SwapError(quoteDataModel.error)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -647,7 +685,10 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
): SwapState.QuotesLoadedState {
|
||||
val appCurrency = userWalletManager.getUserAppCurrency()
|
||||
val nativeToken = userWalletManager.getNativeTokenForNetwork(networkId)
|
||||
val rates = repository.getRates(appCurrency.code, listOf(fromToken.id.value, toToken.id.value, nativeToken.id))
|
||||
val rates = repository.getRates(
|
||||
appCurrency.code,
|
||||
listOf(fromToken.network.backendId, toToken.network.backendId, nativeToken.id),
|
||||
)
|
||||
val fromTokenBalance = cache.getBalanceForToken(networkId, derivationPath, fromToken.symbol)
|
||||
val toTokenBalance = cache.getBalanceForToken(networkId, derivationPath, toToken.symbol)
|
||||
return SwapState.QuotesLoadedState(
|
||||
|
|
@ -657,7 +698,7 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
tokenWalletBalance = fromTokenBalance?.let { amountFormatter.formatSwapAmountToUI(it, "") }
|
||||
?: ZERO_BALANCE,
|
||||
tokenFiatBalance = fromTokenAmount.value.toFiatString(
|
||||
rateValue = rates[fromToken.id.value]?.toBigDecimal() ?: BigDecimal.ZERO,
|
||||
rateValue = rates[fromToken.network.backendId]?.toBigDecimal() ?: BigDecimal.ZERO,
|
||||
fiatCurrencyName = appCurrency.symbol,
|
||||
formatWithSpaces = true,
|
||||
),
|
||||
|
|
@ -668,16 +709,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 +860,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
|
||||
|
|
@ -893,7 +934,6 @@ internal class SwapInteractorImpl @Inject constructor(
|
|||
companion object {
|
||||
private const val DEFAULT_SLIPPAGE = 2
|
||||
private const val ZERO_BALANCE = "0"
|
||||
private const val DEFAULT_BLOCKCHAIN_INCH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
private const val INCREASE_FEE_TO_CHECK_ENOUGH_PERCENT = 1.0 // if need to increase fee when check isEnough
|
||||
|
|
|
|||
|
|
@ -14,11 +14,15 @@ interface SwapRepository {
|
|||
|
||||
suspend fun getExchangeableTokens(networkId: String): List<Currency>
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
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<QuoteModel>
|
||||
|
||||
/**
|
||||
|
|
@ -68,7 +72,7 @@ interface SwapRepository {
|
|||
fromNetwork: String,
|
||||
toContractAddress: String,
|
||||
toNetwork: String,
|
||||
fromAmount: BigDecimal,
|
||||
fromAmount: String,
|
||||
providerId: Int,
|
||||
rateType: RateType,
|
||||
): ExchangeQuote
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.feature.swap.domain.di
|
||||
|
||||
import com.tangem.domain.tokens.GetCardTokensListUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase
|
||||
import com.tangem.domain.tokens.repository.CurrenciesRepository
|
||||
import com.tangem.domain.tokens.repository.NetworksRepository
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package com.tangem.feature.swap.domain.models.domain
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
data class ExchangeQuote(
|
||||
val toAmount: BigDecimal,
|
||||
val toAmount: String,
|
||||
val allowanceContract: String?,
|
||||
)
|
||||
|
|
@ -18,6 +18,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
|
||||
|
|
@ -175,6 +177,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = fromCurrencyStatus.currency,
|
||||
toToken = selectedCurrency.currency,
|
||||
amount = lastAmount.value,
|
||||
toProvidersList = findSwapProviders(fromCurrencyStatus, selectedCurrency)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -192,7 +195,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<SwapProvider>,
|
||||
) {
|
||||
singleTaskScheduler.cancelTask()
|
||||
uiState = stateBuilder.createQuotesLoadingState(uiState, fromToken, toToken, initialCryptoCurrency.id.value)
|
||||
singleTaskScheduler.scheduleTask(
|
||||
|
|
@ -201,6 +209,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
amount = amount,
|
||||
toProvidersList = toProvidersList,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -210,7 +219,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
val toCurrency = dataState.toCryptoCurrency
|
||||
val amount = dataState.amount
|
||||
if (fromCurrency != null && toCurrency != null && amount != null) {
|
||||
startLoadingQuotes(fromCurrency.currency, toCurrency.currency, amount)
|
||||
startLoadingQuotes(
|
||||
fromToken = fromCurrency.currency,
|
||||
toToken = toCurrency.currency,
|
||||
amount = amount,
|
||||
toProvidersList = findSwapProviders(fromCurrency, toCurrency)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,6 +232,7 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromToken: CryptoCurrency,
|
||||
toToken: CryptoCurrency,
|
||||
amount: String,
|
||||
toProvidersList: List<SwapProvider>,
|
||||
): PeriodicTask<SwapState> {
|
||||
return PeriodicTask(
|
||||
UPDATE_DELAY,
|
||||
|
|
@ -233,9 +248,10 @@ internal class SwapViewModel @Inject constructor(
|
|||
networkId = dataState.networkId,
|
||||
fromToken = fromToken,
|
||||
toToken = toToken,
|
||||
providers = toProvidersList,
|
||||
amountToSwap = amount,
|
||||
selectedFee = dataState.selectedFee?.feeType ?: FeeType.NORMAL,
|
||||
)
|
||||
).entries.first().value// TODO
|
||||
}
|
||||
},
|
||||
onSuccess = { swapState ->
|
||||
|
|
@ -418,7 +434,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
fromCryptoCurrency = fromToken,
|
||||
toCryptoCurrency = toToken,
|
||||
)
|
||||
startLoadingQuotes(fromToken.currency, toToken.currency, lastAmount.value)
|
||||
startLoadingQuotes(
|
||||
fromToken = fromToken.currency,
|
||||
toToken = toToken.currency,
|
||||
amount = lastAmount.value,
|
||||
toProvidersList = findSwapProviders(fromToken, toToken)
|
||||
)
|
||||
swapRouter.openScreen(SwapNavScreen.Main)
|
||||
}
|
||||
}
|
||||
|
|
@ -438,7 +459,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
uiState,
|
||||
inputNumberFormatter.formatWithThousands(lastAmount.value, decimals),
|
||||
)
|
||||
startLoadingQuotes(newFromToken.currency, newToToken.currency, lastAmount.value)
|
||||
startLoadingQuotes(
|
||||
fromToken = newFromToken.currency,
|
||||
toToken = newToToken.currency,
|
||||
amount = lastAmount.value,
|
||||
toProvidersList = findSwapProviders(newFromToken, newToToken)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +478,12 @@ internal class SwapViewModel @Inject constructor(
|
|||
uiState =
|
||||
stateBuilder.updateSwapAmount(uiState, inputNumberFormatter.formatWithThousands(cutValue, decimals))
|
||||
amountDebouncer.debounce(viewModelScope, DEBOUNCE_AMOUNT_DELAY) {
|
||||
startLoadingQuotes(fromToken.currency, toToken.currency, lastAmount.value)
|
||||
startLoadingQuotes(
|
||||
fromToken = fromToken.currency,
|
||||
toToken = toToken.currency,
|
||||
amount = lastAmount.value,
|
||||
toProvidersList = findSwapProviders(fromToken, toToken)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -566,6 +597,22 @@ internal class SwapViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun findSwapProviders(fromToken: CryptoCurrencyStatus, toToken: CryptoCurrencyStatus): List<SwapProvider> {
|
||||
val groupToFind = if (isOrderReversed) {
|
||||
dataState.tokensDataState?.fromGroup
|
||||
} else {
|
||||
dataState.tokensDataState?.toGroup
|
||||
} ?: return emptyList()
|
||||
|
||||
val idToFind = if (isOrderReversed) {
|
||||
fromToken.currency.id.value
|
||||
} else {
|
||||
toToken.currency.id.value
|
||||
}
|
||||
|
||||
return groupToFind.available.find { idToFind == it.currencyStatus.currency.id.value }?.providers ?: emptyList()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val loggingTag = "SwapViewModel"
|
||||
private const val INITIAL_AMOUNT = ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue