Updated on 2026-08-14
This commit is contained in:
parent
44231e988d
commit
e72c2c87bc
28 changed files with 426 additions and 105 deletions
|
|
@ -108,4 +108,16 @@ internal object OnrampDomainModule {
|
|||
fun provideClearOnrampCacheUseCase(onrampRepository: OnrampRepository): ClearOnrampCacheUseCase {
|
||||
return ClearOnrampCacheUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampFetchQuotesUseCase(onrampRepository: OnrampRepository): OnrampFetchQuotesUseCase {
|
||||
return OnrampFetchQuotesUseCase(onrampRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampQuotesUseCase(onrampRepository: OnrampRepository): GetOnrampQuotesUseCase {
|
||||
return GetOnrampQuotesUseCase(onrampRepository)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ dependencies {
|
|||
implementation(projects.domain.balanceHiding.models)
|
||||
implementation(projects.domain.txhistory.models)
|
||||
implementation(projects.domain.staking.models)
|
||||
implementation(projects.domain.onramp.models)
|
||||
|
||||
/** Tangem libraries */
|
||||
implementation(deps.tangem.blockchain)
|
||||
|
|
|
|||
|
|
@ -41,4 +41,7 @@ enum class ExchangeProviderType {
|
|||
|
||||
@Json(name = "dex-bridge")
|
||||
DEX_BRIDGE,
|
||||
|
||||
@Json(name = "onramp")
|
||||
ONRAMP,
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.datasource.local.onramp.pairs
|
||||
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
|
||||
import com.tangem.domain.onramp.model.OnrampPair
|
||||
|
||||
internal class DefaultOnrampPairsStore(
|
||||
dataStore: StringKeyDataStore<List<OnrampPairDTO>>,
|
||||
) : OnrampPairsStore, StringKeyDataStoreDecorator<String, List<OnrampPairDTO>>(dataStore) {
|
||||
dataStore: StringKeyDataStore<List<OnrampPair>>,
|
||||
) : OnrampPairsStore, StringKeyDataStoreDecorator<String, List<OnrampPair>>(dataStore) {
|
||||
override fun provideStringKey(key: String): String = key
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.tangem.datasource.local.onramp.pairs
|
||||
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO
|
||||
import com.tangem.domain.onramp.model.OnrampPair
|
||||
|
||||
interface OnrampPairsStore {
|
||||
suspend fun getSyncOrNull(key: String): List<OnrampPairDTO>?
|
||||
suspend fun store(key: String, value: List<OnrampPairDTO>)
|
||||
suspend fun getSyncOrNull(key: String): List<OnrampPair>?
|
||||
suspend fun store(key: String, value: List<OnrampPair>)
|
||||
suspend fun clear()
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.tangem.datasource.local.onramp.quotes
|
||||
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampQuoteResponse
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
|
||||
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
|
||||
internal class DefaultOnrampQuotesStore(
|
||||
dataStore: StringKeyDataStore<List<OnrampQuoteResponse>>,
|
||||
) : OnrampQuotesStore, StringKeyDataStoreDecorator<String, List<OnrampQuoteResponse>>(dataStore) {
|
||||
dataStore: StringKeyDataStore<List<OnrampQuote>>,
|
||||
) : OnrampQuotesStore, StringKeyDataStoreDecorator<String, List<OnrampQuote>>(dataStore) {
|
||||
override fun provideStringKey(key: String): String = key
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.tangem.datasource.local.onramp.quotes
|
||||
|
||||
import com.tangem.datasource.api.onramp.models.response.OnrampQuoteResponse
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface OnrampQuotesStore {
|
||||
suspend fun getSyncOrNull(key: String): List<OnrampQuoteResponse>?
|
||||
suspend fun store(key: String, value: List<OnrampQuoteResponse>)
|
||||
suspend fun getSyncOrNull(key: String): List<OnrampQuote>?
|
||||
fun get(key: String): Flow<List<OnrampQuote>>
|
||||
suspend fun store(key: String, value: List<OnrampQuote>)
|
||||
suspend fun clear()
|
||||
}
|
||||
|
|
@ -1,19 +1,12 @@
|
|||
package com.tangem.data.onramp
|
||||
|
||||
import com.tangem.data.onramp.converters.error.OnrampErrorConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
internal class DefaultOnrampErrorResolver : OnrampErrorResolver {
|
||||
|
||||
private val onrampErrorConverter = OnrampErrorConverter()
|
||||
|
||||
override fun resolve(throwable: Throwable): OnrampError {
|
||||
return if (throwable is ApiResponseError.HttpException) {
|
||||
onrampErrorConverter.convert(throwable.errorBody.orEmpty())
|
||||
} else {
|
||||
OnrampError.UnknownError
|
||||
}
|
||||
return OnrampError.UnknownError
|
||||
}
|
||||
}
|
||||
|
|
@ -5,13 +5,19 @@ import com.tangem.data.onramp.converters.CountryConverter
|
|||
import com.tangem.data.onramp.converters.CurrencyConverter
|
||||
import com.tangem.data.onramp.converters.PaymentMethodConverter
|
||||
import com.tangem.data.onramp.converters.StatusConverter
|
||||
import com.tangem.data.onramp.converters.error.OnrampQuotesErrorConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.express.models.TangemExpressValues
|
||||
import com.tangem.datasource.api.express.models.response.ExchangeProvider
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.api.onramp.models.common.OnrampDestinationDTO
|
||||
import com.tangem.datasource.api.onramp.models.request.OnrampPairsRequest
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCountryDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampCurrencyDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.OnrampPairDTO
|
||||
import com.tangem.datasource.api.onramp.models.response.model.PaymentMethodDTO
|
||||
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
||||
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
||||
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
||||
|
|
@ -20,27 +26,30 @@ import com.tangem.datasource.local.preferences.PreferencesKeys
|
|||
import com.tangem.datasource.local.preferences.utils.getObject
|
||||
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
|
||||
import com.tangem.datasource.local.preferences.utils.storeObject
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.*
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import java.math.BigDecimal
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultOnrampRepository(
|
||||
private val onrampApi: OnrampApi,
|
||||
private val expressApi: TangemExpressApi,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||
private val pairsStore: OnrampPairsStore,
|
||||
private val quotesStore: OnrampQuotesStore,
|
||||
private val quotesErrorConverter: OnrampQuotesErrorConverter,
|
||||
) : OnrampRepository {
|
||||
|
||||
private val currencyConverter = CurrencyConverter()
|
||||
|
|
@ -120,77 +129,98 @@ internal class DefaultOnrampRepository(
|
|||
throw it
|
||||
},
|
||||
)
|
||||
paymentMethodsStore.store(PAYMENT_METHODS_KEY, response)
|
||||
paymentMethodsStore.store(PAYMENT_METHODS_KEY, response.removeApplePay())
|
||||
}
|
||||
|
||||
override suspend fun fetchPairs(currency: OnrampCurrency, country: OnrampCountry, cryptoCurrency: CryptoCurrency) =
|
||||
withContext(dispatchers.io) {
|
||||
val pairs = safeApiCall(
|
||||
call = {
|
||||
onrampApi.getPairs(
|
||||
body = OnrampPairsRequest(
|
||||
fromCurrencyCode = currency.code,
|
||||
countryCode = country.code,
|
||||
to = listOf(
|
||||
OnrampDestinationDTO(
|
||||
contractAddress = cryptoCurrency.getContractAddress(),
|
||||
network = cryptoCurrency.network.backendId,
|
||||
val onrampPairs = async {
|
||||
safeApiCall(
|
||||
call = {
|
||||
onrampApi.getPairs(
|
||||
body = OnrampPairsRequest(
|
||||
fromCurrencyCode = currency.code,
|
||||
countryCode = country.code,
|
||||
to = listOf(
|
||||
OnrampDestinationDTO(
|
||||
contractAddress = cryptoCurrency.getContractAddress(),
|
||||
network = cryptoCurrency.network.backendId,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
).bind()
|
||||
},
|
||||
onError = {
|
||||
Timber.w(it, "Unable to fetch onramp pairs")
|
||||
throw it
|
||||
},
|
||||
)
|
||||
pairsStore.store(PAIRS_KEY, pairs)
|
||||
).bind()
|
||||
},
|
||||
onError = {
|
||||
Timber.w(it, "Unable to fetch onramp pairs")
|
||||
throw it
|
||||
},
|
||||
)
|
||||
}
|
||||
val providers = async {
|
||||
safeApiCall(
|
||||
call = { expressApi.getProviders().bind() },
|
||||
onError = {
|
||||
Timber.w(it, "Unable to fetch express providers")
|
||||
throw it
|
||||
},
|
||||
)
|
||||
}
|
||||
storeOnrampPairs(pairs = onrampPairs.await(), providers = providers.await())
|
||||
}
|
||||
|
||||
override suspend fun fetchQuotes(
|
||||
currency: OnrampCurrency,
|
||||
country: OnrampCountry,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
fromAmount: String,
|
||||
) = withContext(dispatchers.io) {
|
||||
override suspend fun fetchQuotes(cryptoCurrency: CryptoCurrency, amount: Amount) = withContext(dispatchers.io) {
|
||||
val pairs = requireNotNull(pairsStore.getSyncOrNull(PAIRS_KEY)) {
|
||||
"Unable to get pairs. At this point they must not be null."
|
||||
}
|
||||
val quotes = pairs.flatMap { pair ->
|
||||
val amountValue = requireNotNull(amount.value) { "Amount value must not be null" }
|
||||
val fromAmount = amountValue.movePointRight(amount.decimals).toString()
|
||||
val currency = requireNotNull(getDefaultCurrencySync()) { "Default currency must not be null" }
|
||||
val country = requireNotNull(getDefaultCountrySync()) { "Default country must not be null" }
|
||||
val quotes: List<OnrampQuote> = pairs.flatMap { pair ->
|
||||
pair.providers.flatMap { provider ->
|
||||
provider.paymentMethods.map { paymentMethod ->
|
||||
async {
|
||||
safeApiCall(
|
||||
call = {
|
||||
onrampApi.getQuote(
|
||||
val response = onrampApi.getQuote(
|
||||
fromCurrencyCode = currency.code,
|
||||
toContractAddress = cryptoCurrency.getContractAddress(),
|
||||
toNetwork = cryptoCurrency.network.backendId,
|
||||
paymentMethod = paymentMethod,
|
||||
paymentMethod = paymentMethod.id,
|
||||
countryCode = country.code,
|
||||
fromAmount = fromAmount,
|
||||
toDecimals = cryptoCurrency.decimals,
|
||||
providerId = provider.providerId,
|
||||
providerId = provider.id,
|
||||
).bind()
|
||||
},
|
||||
onError = {
|
||||
Timber.w(
|
||||
it,
|
||||
"Unable to fetch onramp quotes for ${provider.providerId} -> $paymentMethod",
|
||||
OnrampQuote.Content(
|
||||
fromAmount = convertToBigDecimal(response.fromAmount),
|
||||
toAmount = convertToBigDecimal(response.toAmount),
|
||||
minFromAmount = convertToBigDecimal(response.minFromAmount),
|
||||
maxFromAmount = convertToBigDecimal(response.maxFromAmount),
|
||||
paymentMethodId = response.paymentMethod,
|
||||
providerId = response.providerId,
|
||||
)
|
||||
null
|
||||
},
|
||||
onError = { error ->
|
||||
if (error is ApiResponseError.HttpException) {
|
||||
quotesErrorConverter.convert(error.errorBody.orEmpty() to amount)
|
||||
} else {
|
||||
Timber.w(error, "Unable to fetch onramp quotes for ${provider.id}. $error")
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
.filterNotNull()
|
||||
}.awaitAll().filterNotNull()
|
||||
quotesStore.store(QUOTES_KEY, quotes)
|
||||
}
|
||||
|
||||
override fun getQuotes(): Flow<List<OnrampQuote>> {
|
||||
return quotesStore.get(QUOTES_KEY)
|
||||
}
|
||||
|
||||
override suspend fun getPaymentMethods(): List<OnrampPaymentMethod> {
|
||||
val paymentMethods = requireNotNull(paymentMethodsStore.getSyncOrNull(PAYMENT_METHODS_KEY)) {
|
||||
"Onramp payment methods is absent in storage"
|
||||
|
|
@ -198,17 +228,43 @@ internal class DefaultOnrampRepository(
|
|||
return paymentMethodsConverter.convertList(paymentMethods)
|
||||
}
|
||||
|
||||
override suspend fun clearCache() {
|
||||
override suspend fun clearCache() = withContext(NonCancellable) {
|
||||
paymentMethodsStore.clear()
|
||||
pairsStore.clear()
|
||||
quotesStore.clear()
|
||||
}
|
||||
|
||||
private suspend fun storeOnrampPairs(pairs: List<OnrampPairDTO>, providers: List<ExchangeProvider>) {
|
||||
val onrampPaymentMethods = getPaymentMethods()
|
||||
val onrampPairs = pairs.map { pair ->
|
||||
val onrampProviders = pair.providers.mapNotNull { onrampProviderDTO ->
|
||||
val providerInfo = providers.find { provider ->
|
||||
provider.id == onrampProviderDTO.providerId
|
||||
} ?: return@mapNotNull null
|
||||
|
||||
OnrampProvider(
|
||||
id = onrampProviderDTO.providerId,
|
||||
info = OnrampProviderInfo(name = providerInfo.name, imageLarge = providerInfo.imageLargeUrl),
|
||||
paymentMethods = onrampPaymentMethods.filter { paymentMethod ->
|
||||
onrampProviderDTO.paymentMethods.any { paymentMethod.id == it }
|
||||
},
|
||||
)
|
||||
}
|
||||
OnrampPair(onrampProviders)
|
||||
}
|
||||
pairsStore.store(PAIRS_KEY, onrampPairs)
|
||||
}
|
||||
|
||||
private fun CryptoCurrency.getContractAddress(): String = when (this) {
|
||||
is CryptoCurrency.Coin -> TangemExpressValues.EMPTY_CONTRACT_ADDRESS_VALUE
|
||||
is CryptoCurrency.Token -> this.contractAddress
|
||||
}
|
||||
|
||||
private fun convertToBigDecimal(value: String): BigDecimal =
|
||||
requireNotNull(value.toBigDecimalOrNull()) { "Can not parse $value to BigDecimal" }
|
||||
|
||||
private fun List<PaymentMethodDTO>.removeApplePay(): List<PaymentMethodDTO> = filterNot { it.id == "apple-pay" }
|
||||
|
||||
private companion object {
|
||||
const val PAYMENT_METHODS_KEY = "onramp_payment_methods"
|
||||
const val PAIRS_KEY = "onramp_pairs"
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
package com.tangem.data.onramp.converters.error
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class OnrampErrorConverter : Converter<String, OnrampError> {
|
||||
|
||||
override fun convert(value: String): OnrampError {
|
||||
return OnrampError.UnknownError
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.data.onramp.converters.error
|
||||
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.tangem.datasource.api.express.models.response.ExpressError
|
||||
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class OnrampQuotesErrorConverter(
|
||||
private val jsonAdapter: JsonAdapter<ExpressErrorResponse>,
|
||||
) : Converter<Pair<String, Amount>, OnrampQuote.Error?> {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
override fun convert(value: Pair<String, Amount>): OnrampQuote.Error? {
|
||||
val (errorResponse, amount) = value
|
||||
try {
|
||||
val error = jsonAdapter.fromJson(errorResponse)?.error ?: return null
|
||||
return when (error.code) {
|
||||
2250 -> tryParseExchangeTooSmallAmountError(error = error, amount = amount)
|
||||
2251 -> tryParseExchangeTooBigAmountError(error = error, amount = amount)
|
||||
else -> null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooSmallAmountError(
|
||||
error: ExpressError,
|
||||
amount: Amount,
|
||||
): OnrampQuote.Error.AmountTooSmallError? {
|
||||
val minAmount = error.value?.minAmount ?: return null
|
||||
val decimals = error.value?.decimals ?: return null
|
||||
|
||||
return OnrampQuote.Error.AmountTooSmallError(
|
||||
amount = createFromAmountWithOffset(
|
||||
amountWithOffset = minAmount,
|
||||
decimals = decimals,
|
||||
symbol = amount.currencySymbol,
|
||||
type = amount.type,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooBigAmountError(
|
||||
error: ExpressError,
|
||||
amount: Amount,
|
||||
): OnrampQuote.Error.AmountTooBigError? {
|
||||
val maxAmount = error.value?.maxAmount ?: return null
|
||||
val decimals = error.value?.decimals ?: return null
|
||||
|
||||
return OnrampQuote.Error.AmountTooBigError(
|
||||
amount = createFromAmountWithOffset(
|
||||
amountWithOffset = maxAmount,
|
||||
decimals = decimals,
|
||||
symbol = amount.currencySymbol,
|
||||
type = amount.type,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createFromAmountWithOffset(
|
||||
amountWithOffset: String,
|
||||
decimals: Int,
|
||||
symbol: String,
|
||||
type: AmountType,
|
||||
): Amount {
|
||||
return Amount(
|
||||
value = requireNotNull(
|
||||
amountWithOffset.toBigDecimalOrNull()?.movePointLeft(decimals),
|
||||
) { "wrong amount format, use only digits" },
|
||||
decimals = decimals,
|
||||
currencySymbol = symbol,
|
||||
type = type,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
package com.tangem.data.onramp.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.data.onramp.DefaultOnrampErrorResolver
|
||||
import com.tangem.data.onramp.DefaultOnrampRepository
|
||||
import com.tangem.data.onramp.DefaultOnrampTransactionRepository
|
||||
import com.tangem.data.onramp.converters.error.OnrampQuotesErrorConverter
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
import com.tangem.datasource.di.NetworkMoshi
|
||||
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
|
||||
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
|
||||
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
|
||||
|
|
@ -26,19 +31,23 @@ internal object OnrampDataModule {
|
|||
@Singleton
|
||||
fun provideOnrampRepository(
|
||||
onrampApi: OnrampApi,
|
||||
expressApi: TangemExpressApi,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||
pairsStore: OnrampPairsStore,
|
||||
quotesStore: OnrampQuotesStore,
|
||||
quotesErrorConverter: OnrampQuotesErrorConverter,
|
||||
): OnrampRepository {
|
||||
return DefaultOnrampRepository(
|
||||
onrampApi = onrampApi,
|
||||
expressApi = expressApi,
|
||||
dispatchers = dispatchers,
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
paymentMethodsStore = paymentMethodsStore,
|
||||
pairsStore = pairsStore,
|
||||
quotesStore = quotesStore,
|
||||
quotesErrorConverter = quotesErrorConverter,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -59,4 +68,11 @@ internal object OnrampDataModule {
|
|||
fun provideOnrampErrorResolver(): OnrampErrorResolver {
|
||||
return DefaultOnrampErrorResolver()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideErrorsConverter(@NetworkMoshi moshi: Moshi): OnrampQuotesErrorConverter {
|
||||
val jsonAdapter = moshi.adapter(ExpressErrorResponse::class.java)
|
||||
return OnrampQuotesErrorConverter(jsonAdapter)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
data class OnrampPair(val providers: List<OnrampProvider>)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
data class OnrampProvider(
|
||||
val id: String,
|
||||
val info: OnrampProviderInfo,
|
||||
val paymentMethods: List<OnrampPaymentMethod>,
|
||||
)
|
||||
|
||||
data class OnrampProviderInfo(val name: String, val imageLarge: String)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class OnrampQuote {
|
||||
|
||||
data class Content(
|
||||
val fromAmount: BigDecimal,
|
||||
val toAmount: BigDecimal,
|
||||
val minFromAmount: BigDecimal,
|
||||
val maxFromAmount: BigDecimal,
|
||||
val paymentMethodId: String,
|
||||
val providerId: String,
|
||||
) : OnrampQuote()
|
||||
|
||||
sealed class Error : OnrampQuote() {
|
||||
|
||||
data class AmountTooSmallError(val amount: Amount) : Error()
|
||||
|
||||
data class AmountTooBigError(val amount: Amount) : Error()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetOnrampQuotesUseCase(private val repository: OnrampRepository) {
|
||||
|
||||
operator fun invoke(): Flow<Either<Throwable, List<OnrampQuote>>> {
|
||||
return repository.getQuotes()
|
||||
.map<List<OnrampQuote>, Either<Throwable, List<OnrampQuote>>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
class OnrampFetchQuotesUseCase(private val repository: OnrampRepository) {
|
||||
|
||||
suspend operator fun invoke(amount: Amount, cryptoCurrency: CryptoCurrency) {
|
||||
repository.fetchQuotes(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
amount = amount,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.domain.onramp.repositories
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.*
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -15,12 +13,7 @@ interface OnrampRepository {
|
|||
suspend fun getStatus(txId: String): OnrampStatus
|
||||
suspend fun fetchPaymentMethodsIfAbsent()
|
||||
suspend fun fetchPairs(currency: OnrampCurrency, country: OnrampCountry, cryptoCurrency: CryptoCurrency)
|
||||
suspend fun fetchQuotes(
|
||||
currency: OnrampCurrency,
|
||||
country: OnrampCountry,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
fromAmount: String,
|
||||
)
|
||||
suspend fun fetchQuotes(cryptoCurrency: CryptoCurrency, amount: Amount)
|
||||
|
||||
// cache
|
||||
suspend fun saveDefaultCurrency(currency: OnrampCurrency)
|
||||
|
|
@ -30,5 +23,6 @@ interface OnrampRepository {
|
|||
suspend fun getDefaultCountrySync(): OnrampCountry?
|
||||
fun getDefaultCountry(): Flow<OnrampCountry?>
|
||||
suspend fun getPaymentMethods(): List<OnrampPaymentMethod>
|
||||
fun getQuotes(): Flow<List<OnrampQuote>>
|
||||
suspend fun clearCache()
|
||||
}
|
||||
|
|
@ -72,7 +72,7 @@ internal class OnrampStateFactory(
|
|||
isValuePasted = false,
|
||||
onValuePastedTriggerDismiss = {},
|
||||
),
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Content(TextReference.EMPTY),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.features.onramp.main.entity.factory.amount
|
|||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import com.tangem.core.ui.extensions.TextReference
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountSecondaryFieldUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.utils.Provider
|
||||
|
|
@ -56,7 +57,7 @@ internal class OnrampAmountFieldChangeConverter(
|
|||
return copy(
|
||||
amountBlockState = amountBlockState.copy(
|
||||
amountFieldModel = amountFieldModel,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading,
|
||||
secondaryFieldModel = OnrampAmountSecondaryFieldUM.Content(TextReference.EMPTY),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
package com.tangem.features.onramp.main.entity.factory.amount
|
||||
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.format.bigdecimal.crypto
|
||||
import com.tangem.core.ui.format.bigdecimal.fiat
|
||||
import com.tangem.core.ui.format.bigdecimal.format
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountBlockUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampAmountSecondaryFieldUM
|
||||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.utils.Provider
|
||||
|
||||
|
|
@ -35,4 +45,69 @@ internal class OnrampAmountStateFactory(private val currentStateProvider: Provid
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
fun getAmountSecondaryLoadingState(): OnrampMainComponentUM {
|
||||
val currentState = currentStateProvider()
|
||||
if (currentState !is OnrampMainComponentUM.Content) return currentState
|
||||
|
||||
val amountState = currentState.amountBlockState
|
||||
|
||||
return currentState.copy(
|
||||
amountBlockState = amountState.copy(secondaryFieldModel = OnrampAmountSecondaryFieldUM.Loading),
|
||||
)
|
||||
}
|
||||
|
||||
fun getAmountSecondaryUpdatedState(quote: OnrampQuote): OnrampMainComponentUM {
|
||||
val currentState = currentStateProvider()
|
||||
if (currentState !is OnrampMainComponentUM.Content) return currentState
|
||||
|
||||
val amountState = currentState.amountBlockState
|
||||
return currentState.copy(
|
||||
amountBlockState = amountState.copy(
|
||||
secondaryFieldModel = quote.toUiModel(amountState),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun OnrampQuote.toUiModel(amountState: OnrampAmountBlockUM): OnrampAmountSecondaryFieldUM {
|
||||
return when (this) {
|
||||
is OnrampQuote.Content -> {
|
||||
val amount = toAmount.format {
|
||||
crypto(
|
||||
symbol = amountState.amountFieldModel.cryptoAmount.currencySymbol,
|
||||
decimals = amountState.amountFieldModel.cryptoAmount.decimals,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Content(stringReference(amount))
|
||||
}
|
||||
is OnrampQuote.Error.AmountTooBigError -> {
|
||||
val amount = this.amount.value.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
R.string.onramp_max_amount_restriction,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
is OnrampQuote.Error.AmountTooSmallError -> {
|
||||
val amount = this.amount.value.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
R.string.onramp_min_amount_restriction,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,7 @@ import com.arkivanov.decompose.router.slot.activate
|
|||
import com.tangem.core.decompose.model.Model
|
||||
import com.tangem.core.decompose.model.ParamsContainer
|
||||
import com.tangem.core.decompose.navigation.Router
|
||||
import com.tangem.domain.onramp.CheckOnrampAvailabilityUseCase
|
||||
import com.tangem.domain.onramp.ClearOnrampCacheUseCase
|
||||
import com.tangem.domain.onramp.GetOnrampCurrencyUseCase
|
||||
import com.tangem.domain.onramp.*
|
||||
import com.tangem.domain.onramp.model.OnrampAvailability
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.features.onramp.main.OnrampMainComponent
|
||||
|
|
@ -16,6 +14,7 @@ import com.tangem.features.onramp.main.entity.OnrampMainBottomSheetConfig
|
|||
import com.tangem.features.onramp.main.entity.OnrampMainComponentUM
|
||||
import com.tangem.features.onramp.main.entity.factory.OnrampStateFactory
|
||||
import com.tangem.features.onramp.main.entity.factory.amount.OnrampAmountStateFactory
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.utils.Provider
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -23,12 +22,16 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class OnrampMainComponentModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val router: Router,
|
||||
private val checkOnrampAvailabilityUseCase: CheckOnrampAvailabilityUseCase,
|
||||
private val getOnrampCurrencyUseCase: GetOnrampCurrencyUseCase,
|
||||
private val clearOnrampCacheUseCase: ClearOnrampCacheUseCase,
|
||||
private val fetchQuotesUseCase: OnrampFetchQuotesUseCase,
|
||||
private val getOnrampQuotesUseCase: GetOnrampQuotesUseCase,
|
||||
private val amountInputManager: InputManager,
|
||||
paramsContainer: ParamsContainer,
|
||||
) : Model(), OnrampIntents {
|
||||
|
||||
|
|
@ -51,6 +54,7 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
|
||||
init {
|
||||
checkResidenceCountry()
|
||||
subscribeToAmountChanges()
|
||||
}
|
||||
|
||||
private fun checkResidenceCountry() {
|
||||
|
|
@ -73,6 +77,7 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
private fun handleOnrampAvailable(currency: OnrampCurrency) {
|
||||
_state.update { stateFactory.getReadyState(currency) }
|
||||
subscribeToCurrencyUpdates()
|
||||
subscribeToQuotesUpdate()
|
||||
}
|
||||
|
||||
private fun subscribeToCurrencyUpdates() {
|
||||
|
|
@ -86,8 +91,31 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun subscribeToAmountChanges() = modelScope.launch {
|
||||
amountInputManager.query
|
||||
.filter(String::isNotEmpty)
|
||||
.collectLatest { _ ->
|
||||
val content = state.value as? OnrampMainComponentUM.Content ?: return@collectLatest
|
||||
_state.update { amountStateFactory.getAmountSecondaryLoadingState() }
|
||||
fetchQuotesUseCase.invoke(
|
||||
amount = content.amountBlockState.amountFieldModel.fiatAmount,
|
||||
cryptoCurrency = params.cryptoCurrency,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun subscribeToQuotesUpdate() {
|
||||
getOnrampQuotesUseCase.invoke()
|
||||
.onEach { maybeQuotes ->
|
||||
val quote = maybeQuotes.getOrNull()?.firstOrNull() ?: return@onEach
|
||||
_state.update { amountStateFactory.getAmountSecondaryUpdatedState(quote) }
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
override fun onAmountValueChanged(value: String) {
|
||||
_state.update { amountStateFactory.getOnAmountValueChange(value) }
|
||||
modelScope.launch { amountInputManager.update(value) }
|
||||
}
|
||||
|
||||
override fun openSettings() {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import com.tangem.features.onramp.selectcountry.entity.CountryListUM
|
|||
import com.tangem.features.onramp.selectcountry.entity.CountryListUMController
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsLoadingTransformer
|
||||
import com.tangem.features.onramp.selectcountry.entity.transformer.UpdateCountryItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -30,7 +30,7 @@ import javax.inject.Inject
|
|||
@ComponentScoped
|
||||
internal class OnrampSelectCountryModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getOnrampCountriesUseCase: GetOnrampCountriesUseCase,
|
||||
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
|
||||
private val getOnrampCountryUseCase: GetOnrampCountryUseCase,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import com.tangem.features.onramp.selectcurrency.entity.CurrencyItemState
|
|||
import com.tangem.features.onramp.selectcurrency.entity.CurrencyListController
|
||||
import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsLoadingTransformer
|
||||
import com.tangem.features.onramp.selectcurrency.entity.transformer.UpdateCurrencyItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -31,7 +31,7 @@ import javax.inject.Inject
|
|||
@ComponentScoped
|
||||
internal class OnrampSelectCurrencyModel @Inject constructor(
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getOnrampCurrenciesUseCase: GetOnrampCurrenciesUseCase,
|
||||
private val saveDefaultCurrencyUseCase: OnrampSaveDefaultCurrencyUseCase,
|
||||
paramsContainer: ParamsContainer,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import com.tangem.features.onramp.swap.availablepairs.entity.transformers.SetLoa
|
|||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -37,7 +37,7 @@ internal class AvailableSwapPairsModel @Inject constructor(
|
|||
getTokenListUseCase: GetTokenListUseCase,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getAvailablePairsUseCase: GetAvailablePairsUseCase,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.tangem.features.onramp.tokenlist.OnrampTokenListComponent
|
|||
import com.tangem.features.onramp.tokenlist.entity.TokenListUM
|
||||
import com.tangem.features.onramp.tokenlist.entity.TokenListUMController
|
||||
import com.tangem.features.onramp.tokenlist.entity.transformer.UpdateTokenItemsTransformer
|
||||
import com.tangem.features.onramp.utils.SearchManager
|
||||
import com.tangem.features.onramp.utils.InputManager
|
||||
import com.tangem.features.onramp.utils.UpdateSearchBarActiveStateTransformer
|
||||
import com.tangem.features.onramp.utils.UpdateSearchQueryTransformer
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -33,7 +33,7 @@ internal class OnrampTokenListModel @Inject constructor(
|
|||
paramsContainer: ParamsContainer,
|
||||
override val dispatchers: CoroutineDispatcherProvider,
|
||||
private val tokenListUMController: TokenListUMController,
|
||||
private val searchManager: SearchManager,
|
||||
private val searchManager: InputManager,
|
||||
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getTokenListUseCase: GetTokenListUseCase,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import javax.inject.Inject
|
|||
*
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
internal class SearchManager @Inject constructor() {
|
||||
internal class InputManager @Inject constructor() {
|
||||
|
||||
val query: Flow<String>
|
||||
get() = _query
|
||||
|
|
@ -32,16 +32,17 @@ class SwapPairInfoConverter : Converter<SwapPairsWithProviders, PairsWithProvide
|
|||
}
|
||||
return PairsWithProviders(
|
||||
pairs = pairs,
|
||||
allProviders = value.providers.map { convertLeastProvider(it) },
|
||||
allProviders = value.providers.mapNotNull { convertLeastProvider(it) },
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertLeastProvider(exchangeProvider: ExchangeProvider): SwapProvider {
|
||||
private fun convertLeastProvider(exchangeProvider: ExchangeProvider): SwapProvider? {
|
||||
val type = convertExchangeType(exchangeProvider.type) ?: return null
|
||||
return SwapProvider(
|
||||
providerId = exchangeProvider.id,
|
||||
rateTypes = emptyList(),
|
||||
name = exchangeProvider.name,
|
||||
type = convertExchangeType(exchangeProvider.type),
|
||||
type = type,
|
||||
imageLarge = exchangeProvider.imageLargeUrl,
|
||||
termsOfUse = exchangeProvider.termsOfUse,
|
||||
privacyPolicy = exchangeProvider.privacyPolicy,
|
||||
|
|
@ -55,11 +56,12 @@ class SwapPairInfoConverter : Converter<SwapPairsWithProviders, PairsWithProvide
|
|||
providerAdditional: Map<String, ExchangeProvider>,
|
||||
): SwapPairProviderDomain? {
|
||||
val additionalProvider = providerAdditional[swapPairProvider.providerId] ?: return null
|
||||
val type = convertExchangeType(additionalProvider.type) ?: return null
|
||||
return SwapPairProviderDomain(
|
||||
providerId = swapPairProvider.providerId,
|
||||
rateTypes = swapPairProvider.rateTypes.map { rateTypeConverter.convert(it) },
|
||||
name = additionalProvider.name,
|
||||
type = convertExchangeType(additionalProvider.type),
|
||||
type = type,
|
||||
imageLarge = additionalProvider.imageLargeUrl,
|
||||
termsOfUse = additionalProvider.termsOfUse,
|
||||
privacyPolicy = additionalProvider.privacyPolicy,
|
||||
|
|
@ -68,11 +70,12 @@ class SwapPairInfoConverter : Converter<SwapPairsWithProviders, PairsWithProvide
|
|||
)
|
||||
}
|
||||
|
||||
private fun convertExchangeType(type: ExchangeProviderType): ExchangeProviderTypeDomain {
|
||||
private fun convertExchangeType(type: ExchangeProviderType): ExchangeProviderTypeDomain? {
|
||||
return when (type) {
|
||||
ExchangeProviderType.DEX -> ExchangeProviderTypeDomain.DEX
|
||||
ExchangeProviderType.CEX -> ExchangeProviderTypeDomain.CEX
|
||||
ExchangeProviderType.DEX_BRIDGE -> ExchangeProviderTypeDomain.DEX_BRIDGE
|
||||
ExchangeProviderType.ONRAMP -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue