Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-24 15:16:52 +05:00
parent ae79b95521
commit 94b459d7c2
13 changed files with 131 additions and 85 deletions

View file

@ -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<CryptoCurrency>,
filterProviderTypes: List<ExpressProviderType>,
): List<SwapPairModel> = 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? {

View file

@ -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),
)
}