Updated on 2026-08-14
This commit is contained in:
parent
e9ed80c7a4
commit
cb62ebfd05
42 changed files with 475 additions and 379 deletions
|
|
@ -18,38 +18,56 @@ internal object OnrampDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCurrenciesUseCase(onrampRepository: OnrampRepository): GetOnrampCurrenciesUseCase {
|
||||
return GetOnrampCurrenciesUseCase(onrampRepository)
|
||||
fun provideGetOnrampCurrenciesUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampCurrenciesUseCase {
|
||||
return GetOnrampCurrenciesUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveDefaultCurrencyUseCase(onrampRepository: OnrampRepository): OnrampSaveDefaultCurrencyUseCase {
|
||||
return OnrampSaveDefaultCurrencyUseCase(onrampRepository)
|
||||
fun provideOnrampSaveDefaultCurrencyUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampSaveDefaultCurrencyUseCase {
|
||||
return OnrampSaveDefaultCurrencyUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCountriesUseCase(onrampRepository: OnrampRepository): GetOnrampCountriesUseCase {
|
||||
return GetOnrampCountriesUseCase(onrampRepository)
|
||||
fun provideGetOnrampCountriesUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampCountriesUseCase {
|
||||
return GetOnrampCountriesUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCountryUseCase(onrampRepository: OnrampRepository): GetOnrampCountryUseCase {
|
||||
return GetOnrampCountryUseCase(onrampRepository)
|
||||
fun provideGetOnrampCountryUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampCountryUseCase {
|
||||
return GetOnrampCountryUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveDefaultCountryUseCase(onrampRepository: OnrampRepository): OnrampSaveDefaultCountryUseCase {
|
||||
return OnrampSaveDefaultCountryUseCase(onrampRepository)
|
||||
fun provideOnrampSaveDefaultCountryUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampSaveDefaultCountryUseCase {
|
||||
return OnrampSaveDefaultCountryUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideCheckOnrampAvailabilityUseCase(onrampRepository: OnrampRepository): CheckOnrampAvailabilityUseCase {
|
||||
return CheckOnrampAvailabilityUseCase(onrampRepository)
|
||||
fun provideCheckOnrampAvailabilityUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): CheckOnrampAvailabilityUseCase {
|
||||
return CheckOnrampAvailabilityUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -66,54 +84,65 @@ internal object OnrampDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampCurrencyUseCase(onrampRepository: OnrampRepository): GetOnrampCurrencyUseCase {
|
||||
return GetOnrampCurrencyUseCase(onrampRepository)
|
||||
fun provideGetOnrampCurrencyUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampCurrencyUseCase {
|
||||
return GetOnrampCurrencyUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampTransactionsUseCase(
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampTransactionsUseCase {
|
||||
return GetOnrampTransactionsUseCase(onrampTransactionRepository)
|
||||
return GetOnrampTransactionsUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampTransactionUseCase(
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampTransactionUseCase {
|
||||
return GetOnrampTransactionUseCase(onrampTransactionRepository)
|
||||
return GetOnrampTransactionUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampRemoveTransactionUseCase(
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampRemoveTransactionUseCase {
|
||||
return OnrampRemoveTransactionUseCase(onrampTransactionRepository)
|
||||
return OnrampRemoveTransactionUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveTransactionUseCase(
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampSaveTransactionUseCase {
|
||||
return OnrampSaveTransactionUseCase(onrampTransactionRepository)
|
||||
return OnrampSaveTransactionUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampUpdateTransactionStatusUseCase(
|
||||
onrampTransactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampUpdateTransactionStatusUseCase {
|
||||
return OnrampUpdateTransactionStatusUseCase(onrampTransactionRepository)
|
||||
return OnrampUpdateTransactionStatusUseCase(onrampTransactionRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampPaymentMethodsUseCase(onrampRepository: OnrampRepository): GetOnrampPaymentMethodsUseCase {
|
||||
return GetOnrampPaymentMethodsUseCase(onrampRepository)
|
||||
fun provideGetOnrampPaymentMethodsUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampPaymentMethodsUseCase {
|
||||
return GetOnrampPaymentMethodsUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -124,8 +153,11 @@ internal object OnrampDomainModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampFetchQuotesUseCase(onrampRepository: OnrampRepository): OnrampFetchQuotesUseCase {
|
||||
return OnrampFetchQuotesUseCase(onrampRepository)
|
||||
fun provideOnrampFetchQuotesUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampFetchQuotesUseCase {
|
||||
return OnrampFetchQuotesUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -133,10 +165,12 @@ internal object OnrampDomainModule {
|
|||
fun provideGetOnrampQuotesUseCase(
|
||||
settingsRepository: SettingsRepository,
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampQuotesUseCase {
|
||||
return GetOnrampQuotesUseCase(
|
||||
settingsRepository = settingsRepository,
|
||||
repository = onrampRepository,
|
||||
errorResolver = onrampErrorResolver,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -144,28 +178,36 @@ internal object OnrampDomainModule {
|
|||
@Singleton
|
||||
fun provideGetOnrampSelectedPaymentMethodUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampSelectedPaymentMethodUseCase {
|
||||
return GetOnrampSelectedPaymentMethodUseCase(onrampRepository)
|
||||
return GetOnrampSelectedPaymentMethodUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetOnrampProviderWithQuoteUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampProviderWithQuoteUseCase {
|
||||
return GetOnrampProviderWithQuoteUseCase(onrampRepository)
|
||||
return GetOnrampProviderWithQuoteUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampSaveSelectedPaymentMethod(onrampRepository: OnrampRepository): OnrampSaveSelectedPaymentMethod {
|
||||
return OnrampSaveSelectedPaymentMethod(onrampRepository)
|
||||
fun provideOnrampSaveSelectedPaymentMethod(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampSaveSelectedPaymentMethod {
|
||||
return OnrampSaveSelectedPaymentMethod(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampFetchPairsUseCase(onrampRepository: OnrampRepository): OnrampFetchPairsUseCase {
|
||||
return OnrampFetchPairsUseCase(onrampRepository)
|
||||
fun provideOnrampFetchPairsUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): OnrampFetchPairsUseCase {
|
||||
return OnrampFetchPairsUseCase(onrampRepository, onrampErrorResolver)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
@ -173,7 +215,8 @@ internal object OnrampDomainModule {
|
|||
fun provideGetOnrampRedirectUrlUseCase(
|
||||
onrampRepository: OnrampRepository,
|
||||
transactionRepository: OnrampTransactionRepository,
|
||||
onrampErrorResolver: OnrampErrorResolver,
|
||||
): GetOnrampRedirectUrlUseCase {
|
||||
return GetOnrampRedirectUrlUseCase(onrampRepository, transactionRepository)
|
||||
return GetOnrampRedirectUrlUseCase(onrampRepository, transactionRepository, onrampErrorResolver)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ dependencies {
|
|||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.deepLinks.global)
|
||||
implementation(projects.core.analytics)
|
||||
|
||||
/** Common modules */
|
||||
implementation(projects.data.common)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,43 @@
|
|||
package com.tangem.data.onramp
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.data.onramp.converters.error.OnrampErrorConverter
|
||||
import com.tangem.datasource.api.common.response.ApiResponseError
|
||||
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.model.error.OnrampRedirectError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
|
||||
// TODO: [REDACTED_JIRA]
|
||||
internal class DefaultOnrampErrorResolver : OnrampErrorResolver {
|
||||
internal class DefaultOnrampErrorResolver(
|
||||
private val analyticsEventHandler: AnalyticsEventHandler,
|
||||
private val onrampErrorConverter: OnrampErrorConverter,
|
||||
) : OnrampErrorResolver {
|
||||
|
||||
override fun resolve(throwable: Throwable): OnrampError {
|
||||
return OnrampError.UnknownError
|
||||
val error = when (throwable) {
|
||||
is ApiResponseError.HttpException -> {
|
||||
onrampErrorConverter.convert(throwable.errorBody.orEmpty())
|
||||
}
|
||||
is OnrampRedirectError.WrongRequestId -> OnrampError.RedirectError.WrongRequestId
|
||||
is OnrampRedirectError.VerificationFailed -> OnrampError.RedirectError.VerificationFailed
|
||||
else -> {
|
||||
OnrampError.DomainError(throwable.message)
|
||||
}
|
||||
}
|
||||
|
||||
when (error) {
|
||||
is OnrampError.AmountError.TooBigError -> analyticsEventHandler.send(OnrampAnalyticsEvent.MaxAmountError)
|
||||
is OnrampError.AmountError.TooSmallError -> analyticsEventHandler.send(OnrampAnalyticsEvent.MinAmountError)
|
||||
is OnrampError.DataError -> analyticsEventHandler.send(
|
||||
OnrampAnalyticsEvent.Errors(
|
||||
tokenSymbol = "tokenSymbol",
|
||||
providerName = "providerName",
|
||||
errorCode = error.code,
|
||||
),
|
||||
)
|
||||
else -> { /* no-op */
|
||||
}
|
||||
}
|
||||
return error
|
||||
}
|
||||
}
|
||||
|
|
@ -8,14 +8,14 @@ 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.OnrampQuoteErrorInput
|
||||
import com.tangem.data.onramp.converters.error.OnrampQuotesErrorConverter
|
||||
import com.tangem.data.onramp.converters.error.OnrampErrorConverter
|
||||
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.express.models.response.ExchangeProviderType
|
||||
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
|
||||
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
|
||||
|
|
@ -37,6 +37,8 @@ import com.tangem.datasource.local.preferences.utils.storeObject
|
|||
import com.tangem.domain.apptheme.model.AppThemeMode
|
||||
import com.tangem.domain.onramp.model.*
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.model.error.OnrampRedirectError
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -63,7 +65,6 @@ internal class DefaultOnrampRepository(
|
|||
private val paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||
private val pairsStore: OnrampPairsStore,
|
||||
private val quotesStore: OnrampQuotesStore,
|
||||
private val quotesErrorConverter: OnrampQuotesErrorConverter,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val dataSignatureVerifier: DataSignatureVerifier,
|
||||
moshi: Moshi,
|
||||
|
|
@ -74,6 +75,8 @@ internal class DefaultOnrampRepository(
|
|||
private val statusConverter = StatusConverter()
|
||||
private val paymentMethodsConverter = PaymentMethodConverter()
|
||||
private val onrampDataAdapter = moshi.adapter(OnrampDataJson::class.java)
|
||||
private val onrampErrorAdapter = moshi.adapter(ExpressErrorResponse::class.java)
|
||||
private val onrampErrorConverter = OnrampErrorConverter(onrampErrorAdapter)
|
||||
|
||||
override suspend fun getCurrencies(): List<OnrampCurrency> = withContext(dispatchers.io) {
|
||||
onrampApi.getCurrencies()
|
||||
|
|
@ -194,6 +197,13 @@ internal class DefaultOnrampRepository(
|
|||
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 fromOnrampAmount = OnrampAmount(
|
||||
value = fromAmount
|
||||
.toBigDecimalOrDefault()
|
||||
.movePointLeft(currency.precision),
|
||||
decimals = currency.precision,
|
||||
symbol = amount.currencySymbol,
|
||||
)
|
||||
val quotes: List<OnrampQuote> = pairs.flatMap { pair ->
|
||||
pair.providers.flatMap { provider ->
|
||||
provider.paymentMethods.map { paymentMethod ->
|
||||
|
|
@ -212,13 +222,7 @@ internal class DefaultOnrampRepository(
|
|||
providerId = provider.id,
|
||||
).bind()
|
||||
OnrampQuote.Data(
|
||||
fromAmount = OnrampAmount(
|
||||
value = response.fromAmount
|
||||
.toBigDecimalOrDefault()
|
||||
.movePointLeft(currency.precision),
|
||||
decimals = currency.precision,
|
||||
symbol = amount.currencySymbol,
|
||||
),
|
||||
fromAmount = fromOnrampAmount,
|
||||
toAmount = convertToAmount(response.toAmount, cryptoCurrency),
|
||||
minFromAmount = convertToAmount(response.minFromAmount, cryptoCurrency),
|
||||
maxFromAmount = convertToAmount(response.maxFromAmount, cryptoCurrency),
|
||||
|
|
@ -227,19 +231,12 @@ internal class DefaultOnrampRepository(
|
|||
)
|
||||
},
|
||||
onError = { error ->
|
||||
if (error is ApiResponseError.HttpException) {
|
||||
quotesErrorConverter.convert(
|
||||
OnrampQuoteErrorInput(
|
||||
errorBody = error.errorBody.orEmpty(),
|
||||
amount = amount,
|
||||
paymentMethod = paymentMethod,
|
||||
provider = provider,
|
||||
),
|
||||
)
|
||||
} else {
|
||||
Timber.w(error, "Unable to fetch onramp quotes for ${provider.id}. $error")
|
||||
null
|
||||
}
|
||||
convertQuoteError(
|
||||
error = error,
|
||||
paymentMethod = paymentMethod,
|
||||
provider = provider,
|
||||
fromOnrampAmount = fromOnrampAmount,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -419,19 +416,44 @@ internal class DefaultOnrampRepository(
|
|||
default = AppThemeMode.DEFAULT,
|
||||
)
|
||||
return when (appTheme) {
|
||||
AppThemeMode.FORCE_DARK -> "dark"
|
||||
AppThemeMode.FORCE_DARK -> PROVIDER_THEME_DARK
|
||||
AppThemeMode.FORCE_LIGHT,
|
||||
AppThemeMode.FOLLOW_SYSTEM,
|
||||
-> "light"
|
||||
-> PROVIDER_THEME_LIGHT
|
||||
}
|
||||
}
|
||||
|
||||
private fun List<PaymentMethodDTO>.removeApplePay(): List<PaymentMethodDTO> = filterNot { it.id == "apple-pay" }
|
||||
|
||||
private fun convertQuoteError(
|
||||
error: Throwable,
|
||||
paymentMethod: OnrampPaymentMethod,
|
||||
provider: OnrampProvider,
|
||||
fromOnrampAmount: OnrampAmount,
|
||||
) = if (error is ApiResponseError.HttpException) {
|
||||
val onrampError = onrampErrorConverter.convert(value = error.errorBody.orEmpty())
|
||||
if (onrampError is OnrampError.AmountError) {
|
||||
OnrampQuote.Error(
|
||||
paymentMethod = paymentMethod,
|
||||
provider = provider,
|
||||
fromAmount = fromOnrampAmount,
|
||||
error = onrampError,
|
||||
)
|
||||
} else {
|
||||
Timber.w(error, "Unable to fetch onramp quotes for ${provider.id}. $error")
|
||||
null
|
||||
}
|
||||
} else {
|
||||
Timber.w(error, "Unable to fetch onramp quotes for ${provider.id}. $error")
|
||||
null
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val PAYMENT_METHODS_KEY = "onramp_payment_methods"
|
||||
const val SELECTED_PAYMENT_METHOD_KEY = "onramp_selected_payment_method"
|
||||
const val PAIRS_KEY = "onramp_pairs"
|
||||
const val QUOTES_KEY = "onramp_quotes"
|
||||
const val PROVIDER_THEME_DARK = "dark"
|
||||
const val PROVIDER_THEME_LIGHT = "light"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
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.error.OnrampError
|
||||
import com.tangem.utils.converter.Converter
|
||||
|
||||
internal class OnrampErrorConverter(
|
||||
private val jsonAdapter: JsonAdapter<ExpressErrorResponse>,
|
||||
) : Converter<String, OnrampError> {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
override fun convert(value: String): OnrampError {
|
||||
try {
|
||||
val error = jsonAdapter.fromJson(value)?.error ?: return OnrampError.DomainError(value)
|
||||
return when (error.code) {
|
||||
2250 -> tryParseExchangeTooSmallAmountError(error = error)
|
||||
2251 -> tryParseExchangeTooBigAmountError(error = error)
|
||||
else -> OnrampError.DataError(error.code.toString(), error.description)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return OnrampError.DomainError(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooSmallAmountError(error: ExpressError): OnrampError {
|
||||
val minAmount = error.value?.minAmount ?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
val decimals = error.value?.decimals ?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
val requiredAmount = minAmount.toBigDecimalOrNull()?.movePointLeft(decimals)
|
||||
?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
|
||||
return OnrampError.AmountError.TooSmallError(requiredAmount = requiredAmount)
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooBigAmountError(error: ExpressError): OnrampError {
|
||||
val maxAmount = error.value?.maxAmount ?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
val decimals = error.value?.decimals ?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
val requiredAmount = maxAmount.toBigDecimalOrNull()?.movePointLeft(decimals)
|
||||
?: return OnrampError.DataError(error.code.toString(), error.description)
|
||||
|
||||
return OnrampError.AmountError.TooBigError(requiredAmount = requiredAmount)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.tangem.data.onramp.converters.error
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.OnrampProvider
|
||||
import com.tangem.domain.tokens.model.Amount
|
||||
|
||||
data class OnrampQuoteErrorInput(
|
||||
val errorBody: String,
|
||||
val amount: Amount,
|
||||
val paymentMethod: OnrampPaymentMethod,
|
||||
val provider: OnrampProvider,
|
||||
)
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
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.OnrampAmount
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
internal class OnrampQuotesErrorConverter(
|
||||
private val jsonAdapter: JsonAdapter<ExpressErrorResponse>,
|
||||
) : Converter<OnrampQuoteErrorInput, OnrampQuote.Error?> {
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
override fun convert(value: OnrampQuoteErrorInput): OnrampQuote.Error? {
|
||||
try {
|
||||
val error = jsonAdapter.fromJson(value.errorBody)?.error ?: return null
|
||||
return when (error.code) {
|
||||
2250 -> tryParseExchangeTooSmallAmountError(error = error, input = value)
|
||||
2251 -> tryParseExchangeTooBigAmountError(error = error, input = value)
|
||||
else -> null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooSmallAmountError(
|
||||
error: ExpressError,
|
||||
input: OnrampQuoteErrorInput,
|
||||
): OnrampQuote.Error.AmountTooSmallError? {
|
||||
val minAmount = error.value?.minAmount ?: return null
|
||||
val decimals = error.value?.decimals ?: return null
|
||||
|
||||
return OnrampQuote.Error.AmountTooSmallError(
|
||||
paymentMethod = input.paymentMethod,
|
||||
provider = input.provider,
|
||||
fromAmount = OnrampAmount(
|
||||
symbol = input.amount.currencySymbol,
|
||||
value = input.amount.value.orZero(),
|
||||
decimals = input.amount.decimals,
|
||||
),
|
||||
requiredAmount = createFromAmountWithOffset(
|
||||
amountWithOffset = minAmount,
|
||||
decimals = decimals,
|
||||
symbol = input.amount.currencySymbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun tryParseExchangeTooBigAmountError(
|
||||
error: ExpressError,
|
||||
input: OnrampQuoteErrorInput,
|
||||
): OnrampQuote.Error.AmountTooBigError? {
|
||||
val maxAmount = error.value?.maxAmount ?: return null
|
||||
val decimals = error.value?.decimals ?: return null
|
||||
|
||||
return OnrampQuote.Error.AmountTooBigError(
|
||||
paymentMethod = input.paymentMethod,
|
||||
provider = input.provider,
|
||||
fromAmount = OnrampAmount(
|
||||
symbol = input.amount.currencySymbol,
|
||||
value = input.amount.value.orZero(),
|
||||
decimals = input.amount.decimals,
|
||||
),
|
||||
requiredAmount = createFromAmountWithOffset(
|
||||
amountWithOffset = maxAmount,
|
||||
decimals = decimals,
|
||||
symbol = input.amount.currencySymbol,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun createFromAmountWithOffset(amountWithOffset: String, decimals: Int, symbol: String): OnrampAmount {
|
||||
return OnrampAmount(
|
||||
value = requireNotNull(
|
||||
amountWithOffset.toBigDecimalOrNull()?.movePointLeft(decimals),
|
||||
) { "wrong amount format, use only digits" },
|
||||
decimals = decimals,
|
||||
symbol = symbol,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
package com.tangem.data.onramp.di
|
||||
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
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.data.onramp.converters.error.OnrampErrorConverter
|
||||
import com.tangem.datasource.api.express.TangemExpressApi
|
||||
import com.tangem.datasource.api.express.models.response.ExpressErrorResponse
|
||||
import com.tangem.datasource.api.onramp.OnrampApi
|
||||
|
|
@ -39,7 +40,6 @@ internal object OnrampDataModule {
|
|||
paymentMethodsStore: OnrampPaymentMethodsStore,
|
||||
pairsStore: OnrampPairsStore,
|
||||
quotesStore: OnrampQuotesStore,
|
||||
quotesErrorConverter: OnrampQuotesErrorConverter,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
dataSignatureVerifier: DataSignatureVerifier,
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
|
|
@ -52,7 +52,6 @@ internal object OnrampDataModule {
|
|||
paymentMethodsStore = paymentMethodsStore,
|
||||
pairsStore = pairsStore,
|
||||
quotesStore = quotesStore,
|
||||
quotesErrorConverter = quotesErrorConverter,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
dataSignatureVerifier = dataSignatureVerifier,
|
||||
moshi = moshi,
|
||||
|
|
@ -73,14 +72,14 @@ internal object OnrampDataModule {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOnrampErrorResolver(): OnrampErrorResolver {
|
||||
return DefaultOnrampErrorResolver()
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideErrorsConverter(@NetworkMoshi moshi: Moshi): OnrampQuotesErrorConverter {
|
||||
fun provideOnrampErrorResolver(
|
||||
@NetworkMoshi moshi: Moshi,
|
||||
analyticsEventHandler: AnalyticsEventHandler,
|
||||
): OnrampErrorResolver {
|
||||
val jsonAdapter = moshi.adapter(ExpressErrorResponse::class.java)
|
||||
return OnrampQuotesErrorConverter(jsonAdapter)
|
||||
return DefaultOnrampErrorResolver(
|
||||
analyticsEventHandler,
|
||||
OnrampErrorConverter(jsonAdapter),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
sealed class OnrampError {
|
||||
data object UnknownError : OnrampError()
|
||||
}
|
||||
|
|
@ -21,20 +21,9 @@ sealed interface OnrampProviderWithQuote {
|
|||
val availablePaymentMethods: List<OnrampPaymentMethod>,
|
||||
) : Unavailable
|
||||
|
||||
data class AvailableFrom(
|
||||
data class Error(
|
||||
override val provider: OnrampProvider,
|
||||
val paymentMethod: OnrampPaymentMethod,
|
||||
val quoteError: OnrampQuote.Error,
|
||||
val fromAmount: OnrampAmount,
|
||||
val requiredAmount: OnrampAmount,
|
||||
) : Unavailable
|
||||
|
||||
data class AvailableUpTo(
|
||||
override val provider: OnrampProvider,
|
||||
val paymentMethod: OnrampPaymentMethod,
|
||||
val quoteError: OnrampQuote.Error,
|
||||
val fromAmount: OnrampAmount,
|
||||
val requiredAmount: OnrampAmount,
|
||||
) : Unavailable
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
|
||||
sealed class OnrampQuote {
|
||||
|
||||
abstract val paymentMethod: OnrampPaymentMethod
|
||||
|
|
@ -14,20 +16,10 @@ sealed class OnrampQuote {
|
|||
val maxFromAmount: OnrampAmount,
|
||||
) : OnrampQuote()
|
||||
|
||||
sealed class Error : OnrampQuote() {
|
||||
|
||||
data class AmountTooSmallError(
|
||||
override val paymentMethod: OnrampPaymentMethod,
|
||||
override val provider: OnrampProvider,
|
||||
val fromAmount: OnrampAmount,
|
||||
val requiredAmount: OnrampAmount,
|
||||
) : Error()
|
||||
|
||||
data class AmountTooBigError(
|
||||
override val paymentMethod: OnrampPaymentMethod,
|
||||
override val provider: OnrampProvider,
|
||||
val fromAmount: OnrampAmount,
|
||||
val requiredAmount: OnrampAmount,
|
||||
) : Error()
|
||||
}
|
||||
data class Error(
|
||||
override val paymentMethod: OnrampPaymentMethod,
|
||||
override val provider: OnrampProvider,
|
||||
val fromAmount: OnrampAmount,
|
||||
val error: OnrampError.AmountError,
|
||||
) : OnrampQuote()
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.tangem.domain.onramp.model.error
|
||||
|
||||
import java.math.BigDecimal
|
||||
|
||||
sealed class OnrampError {
|
||||
|
||||
sealed class AmountError : OnrampError() {
|
||||
abstract val requiredAmount: BigDecimal
|
||||
data class TooSmallError(
|
||||
override val requiredAmount: BigDecimal,
|
||||
) : AmountError()
|
||||
|
||||
data class TooBigError(
|
||||
override val requiredAmount: BigDecimal,
|
||||
) : AmountError()
|
||||
}
|
||||
|
||||
sealed class RedirectError : OnrampError() {
|
||||
data object VerificationFailed : RedirectError()
|
||||
data object WrongRequestId : RedirectError()
|
||||
}
|
||||
|
||||
data class DataError(
|
||||
val code: String,
|
||||
val description: String?,
|
||||
) : OnrampError()
|
||||
|
||||
data class DomainError(val error: String?) : OnrampError()
|
||||
}
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
package com.tangem.domain.onramp.model
|
||||
package com.tangem.domain.onramp.model.error
|
||||
|
||||
sealed class OnrampRedirectError : Throwable() {
|
||||
|
||||
data class DataError(override val cause: Throwable?) : OnrampRedirectError()
|
||||
|
||||
data object VerificationFailed : OnrampRedirectError()
|
||||
|
||||
data object WrongRequestId : OnrampRedirectError()
|
||||
|
|
@ -3,11 +3,16 @@ package com.tangem.domain.onramp
|
|||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampAvailability
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class CheckOnrampAvailabilityUseCase(private val repository: OnrampRepository) {
|
||||
class CheckOnrampAvailabilityUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, OnrampAvailability> {
|
||||
suspend operator fun invoke(): Either<OnrampError, OnrampAvailability> {
|
||||
return Either.catch {
|
||||
repository.fetchPaymentMethodsIfAbsent()
|
||||
val savedCountry = repository.getDefaultCountrySync()
|
||||
|
|
@ -17,7 +22,7 @@ class CheckOnrampAvailabilityUseCase(private val repository: OnrampRepository) {
|
|||
val detectedCountry = repository.getCountryByIp()
|
||||
OnrampAvailability.ConfirmResidency(detectedCountry)
|
||||
}
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
||||
private suspend fun proceedWithSavedCountry(savedCountry: OnrampCountry): OnrampAvailability {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,16 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampCountriesUseCase(private val onrampRepository: OnrampRepository) {
|
||||
class GetOnrampCountriesUseCase(
|
||||
private val onrampRepository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, List<OnrampCountry>> {
|
||||
return Either.catch { onrampRepository.getCountries() }
|
||||
suspend operator fun invoke(): Either<OnrampError, List<OnrampCountry>> {
|
||||
return Either.catch { onrampRepository.getCountries() }.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,20 +4,28 @@ import arrow.core.Either
|
|||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetOnrampCountryUseCase(private val repository: OnrampRepository) {
|
||||
class GetOnrampCountryUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<Either<Throwable, OnrampCountry?>> {
|
||||
operator fun invoke(): Flow<Either<OnrampError, OnrampCountry?>> {
|
||||
return repository.getDefaultCountry()
|
||||
.map<OnrampCountry?, Either<Throwable, OnrampCountry?>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
.map<OnrampCountry?, Either<OnrampError, OnrampCountry?>> { it.right() }
|
||||
.catch {
|
||||
emit(errorResolver.resolve(it).left())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun invokeSync(): Either<Throwable, OnrampCountry> {
|
||||
suspend fun invokeSync(): Either<OnrampError, OnrampCountry> {
|
||||
return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp() }
|
||||
.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,19 +2,22 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCurrencies
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampCurrenciesUseCase(
|
||||
private val onrampRepository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, OnrampCurrencies> {
|
||||
suspend operator fun invoke(): Either<OnrampError, OnrampCurrencies> {
|
||||
return Either.catch {
|
||||
val currenciesList = onrampRepository.getCurrencies()
|
||||
val (populars, others) = currenciesList.toSet()
|
||||
.partition { popularFiatCodes.contains(it.code.uppercase()) }
|
||||
OnrampCurrencies(populars = populars, others = others)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -4,16 +4,23 @@ import arrow.core.Either
|
|||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetOnrampCurrencyUseCase(private val repository: OnrampRepository) {
|
||||
class GetOnrampCurrencyUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<Either<Throwable, OnrampCurrency?>> {
|
||||
operator fun invoke(): Flow<Either<OnrampError, OnrampCurrency?>> {
|
||||
return repository.getDefaultCurrency()
|
||||
.map<OnrampCurrency?, Either<Throwable, OnrampCurrency?>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
.map<OnrampCurrency?, Either<OnrampError, OnrampCurrency?>> { it.right() }
|
||||
.catch {
|
||||
emit(errorResolver.resolve(it).left())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,11 +2,17 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampPaymentMethodsUseCase(private val repository: OnrampRepository) {
|
||||
class GetOnrampPaymentMethodsUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): Either<Throwable, Set<OnrampPaymentMethod>> {
|
||||
suspend operator fun invoke(): Either<OnrampError, Set<OnrampPaymentMethod>> {
|
||||
return Either.catch { repository.getAvailablePaymentMethods() }
|
||||
.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,11 +6,18 @@ import com.tangem.domain.onramp.model.OnrampProvider
|
|||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote.Unavailable
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class GetOnrampProviderWithQuoteUseCase(private val repository: OnrampRepository) {
|
||||
class GetOnrampProviderWithQuoteUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(paymentMethod: OnrampPaymentMethod): Either<Throwable, List<OnrampProviderWithQuote>> {
|
||||
suspend operator fun invoke(
|
||||
paymentMethod: OnrampPaymentMethod,
|
||||
): Either<OnrampError, List<OnrampProviderWithQuote>> {
|
||||
return Either.catch {
|
||||
val quotes: List<OnrampQuote> = requireNotNull(repository.getQuotesSync()) { "Quotes must not be null" }
|
||||
quotes
|
||||
|
|
@ -18,7 +25,7 @@ class GetOnrampProviderWithQuoteUseCase(private val repository: OnrampRepository
|
|||
.mapNotNull { (provider, quotes) ->
|
||||
quotes.quoteWithProvider(provider = provider, selectedPaymentMethod = paymentMethod)
|
||||
}
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
||||
private fun List<OnrampQuote>.quoteWithProvider(
|
||||
|
|
@ -27,46 +34,29 @@ class GetOnrampProviderWithQuoteUseCase(private val repository: OnrampRepository
|
|||
): OnrampProviderWithQuote? {
|
||||
val quoteData = this.filterIsInstance<OnrampQuote.Data>()
|
||||
val matchedPaymentMethodQuote = quoteData.firstOrNull { it.paymentMethod == selectedPaymentMethod }
|
||||
|
||||
if (matchedPaymentMethodQuote != null) {
|
||||
return OnrampProviderWithQuote.Data(
|
||||
provider = matchedPaymentMethodQuote.provider,
|
||||
paymentMethod = matchedPaymentMethodQuote.paymentMethod,
|
||||
toAmount = matchedPaymentMethodQuote.toAmount,
|
||||
fromAmount = matchedPaymentMethodQuote.fromAmount,
|
||||
)
|
||||
}
|
||||
|
||||
val paymentMethodNotSupported = quoteData.filterNot { it.paymentMethod == selectedPaymentMethod }
|
||||
if (paymentMethodNotSupported.isNotEmpty()) {
|
||||
return Unavailable.NotSupportedPaymentMethod(
|
||||
provider = provider,
|
||||
availablePaymentMethods = paymentMethodNotSupported.map(OnrampQuote.Data::paymentMethod),
|
||||
)
|
||||
}
|
||||
|
||||
val amountError = this
|
||||
.filterIsInstance<OnrampQuote.Error>()
|
||||
.firstOrNull { it.paymentMethod == selectedPaymentMethod }
|
||||
|
||||
val amountError =
|
||||
filterIsInstance<OnrampQuote.Error>().firstOrNull { it.paymentMethod == selectedPaymentMethod }
|
||||
return when {
|
||||
matchedPaymentMethodQuote != null -> {
|
||||
OnrampProviderWithQuote.Data(
|
||||
provider = matchedPaymentMethodQuote.provider,
|
||||
paymentMethod = matchedPaymentMethodQuote.paymentMethod,
|
||||
toAmount = matchedPaymentMethodQuote.toAmount,
|
||||
fromAmount = matchedPaymentMethodQuote.fromAmount,
|
||||
)
|
||||
}
|
||||
paymentMethodNotSupported.isNotEmpty() -> {
|
||||
Unavailable.NotSupportedPaymentMethod(
|
||||
provider = provider,
|
||||
availablePaymentMethods = paymentMethodNotSupported.map(OnrampQuote.Data::paymentMethod),
|
||||
)
|
||||
}
|
||||
amountError != null -> {
|
||||
when (amountError) {
|
||||
is OnrampQuote.Error.AmountTooBigError -> Unavailable.AvailableUpTo(
|
||||
provider = amountError.provider,
|
||||
paymentMethod = amountError.paymentMethod,
|
||||
quoteError = amountError,
|
||||
fromAmount = amountError.fromAmount,
|
||||
requiredAmount = amountError.requiredAmount,
|
||||
)
|
||||
is OnrampQuote.Error.AmountTooSmallError -> Unavailable.AvailableFrom(
|
||||
provider = amountError.provider,
|
||||
paymentMethod = amountError.paymentMethod,
|
||||
quoteError = amountError,
|
||||
fromAmount = amountError.fromAmount,
|
||||
requiredAmount = amountError.requiredAmount,
|
||||
)
|
||||
}
|
||||
Unavailable.Error(
|
||||
amountError.provider,
|
||||
amountError,
|
||||
)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import arrow.core.left
|
|||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.onramp.model.PaymentMethodType
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.settings.repositories.SettingsRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -14,11 +16,12 @@ import kotlinx.coroutines.flow.map
|
|||
class GetOnrampQuotesUseCase(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(): Flow<Either<Throwable, List<OnrampQuote>>> {
|
||||
operator fun invoke(): Flow<Either<OnrampError, List<OnrampQuote>>> {
|
||||
return repository.getQuotes()
|
||||
.map<List<OnrampQuote>, Either<Throwable, List<OnrampQuote>>> { quotes ->
|
||||
.map<List<OnrampQuote>, Either<OnrampError, List<OnrampQuote>>> { quotes ->
|
||||
val isGooglePayAvailable = settingsRepository.isGooglePayAvailability()
|
||||
|
||||
quotes.groupBy { it.paymentMethod.type }
|
||||
|
|
@ -29,7 +32,9 @@ class GetOnrampQuotesUseCase(
|
|||
.flatten()
|
||||
.right()
|
||||
}
|
||||
.catch { emit(it.left()) }
|
||||
.catch {
|
||||
emit(errorResolver.resolve(it).left())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,8 +49,13 @@ class GetOnrampQuotesUseCase(
|
|||
is OnrampQuote.Data -> it.toAmount.value
|
||||
|
||||
// negative difference to sort both when data and unavailable is present
|
||||
is OnrampQuote.Error.AmountTooSmallError -> it.fromAmount.value - it.requiredAmount.value
|
||||
is OnrampQuote.Error.AmountTooBigError -> it.requiredAmount.value - it.fromAmount.value
|
||||
is OnrampQuote.Error -> {
|
||||
when (val error = it.error) {
|
||||
is OnrampError.AmountError.TooSmallError -> it.fromAmount.value - error.requiredAmount
|
||||
is OnrampError.AmountError.TooBigError -> error.requiredAmount - it.fromAmount.value
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.OnrampRedirectError
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
|
@ -11,13 +12,14 @@ import com.tangem.domain.wallets.models.UserWalletId
|
|||
class GetOnrampRedirectUrlUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val transactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
quote: OnrampProviderWithQuote.Data,
|
||||
cryptoCurrency: CryptoCurrency,
|
||||
): Either<OnrampRedirectError, String> {
|
||||
): Either<OnrampError, String> {
|
||||
return Either.catch {
|
||||
val transaction = repository.getOnrampData(
|
||||
userWalletId = userWalletId,
|
||||
|
|
@ -26,8 +28,6 @@ class GetOnrampRedirectUrlUseCase(
|
|||
)
|
||||
transactionRepository.storeTransaction(transaction)
|
||||
transaction.redirectUrl
|
||||
}.mapLeft { throwable ->
|
||||
if (throwable is OnrampRedirectError) throwable else OnrampRedirectError.DataError(throwable)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,15 +5,22 @@ import arrow.core.left
|
|||
import arrow.core.right
|
||||
import com.tangem.domain.core.utils.EitherFlow
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class GetOnrampSelectedPaymentMethodUseCase(private val repository: OnrampRepository) {
|
||||
class GetOnrampSelectedPaymentMethodUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(): EitherFlow<Throwable, OnrampPaymentMethod> {
|
||||
operator fun invoke(): EitherFlow<OnrampError, OnrampPaymentMethod> {
|
||||
return repository.getSelectedPaymentMethod()
|
||||
.map<OnrampPaymentMethod, Either<Throwable, OnrampPaymentMethod>> { it.right() }
|
||||
.catch { emit(it.left()) }
|
||||
.map<OnrampPaymentMethod, Either<OnrampError, OnrampPaymentMethod>> { it.right() }
|
||||
.catch {
|
||||
emit(errorResolver.resolve(it).left())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
|
|
@ -14,8 +14,6 @@ class GetOnrampStatusUseCase(
|
|||
suspend operator fun invoke(externalTxId: String): Either<OnrampError, OnrampStatus> {
|
||||
return Either.catch {
|
||||
onrampRepository.getStatus(externalTxId)
|
||||
}.mapLeft {
|
||||
errorResolver.resolve(it)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
|
||||
class GetOnrampTransactionUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(externalTxId: String): Either<OnrampError, OnrampTransaction> {
|
||||
|
|
@ -14,8 +16,6 @@ class GetOnrampTransactionUseCase(
|
|||
requireNotNull(
|
||||
onrampTransactionRepository.getTransactionById(externalTxId),
|
||||
)
|
||||
}.mapLeft {
|
||||
OnrampError.UnknownError
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -3,18 +3,19 @@ package com.tangem.domain.onramp
|
|||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEmpty
|
||||
|
||||
class GetOnrampTransactionsUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
operator fun invoke(
|
||||
|
|
@ -25,7 +26,6 @@ class GetOnrampTransactionsUseCase(
|
|||
userWalletId = userWalletId,
|
||||
cryptoCurrencyId = cryptoCurrencyId,
|
||||
).map { it.right() }
|
||||
.catch { OnrampError.UnknownError.left() }
|
||||
.onEmpty { OnrampError.UnknownError.left() }
|
||||
.catch { errorResolver.resolve(it).left() }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,21 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
|
||||
class OnrampFetchPairsUseCase(private val repository: OnrampRepository) {
|
||||
class OnrampFetchPairsUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(cryptoCurrency: CryptoCurrency): Either<Throwable, Unit> {
|
||||
suspend operator fun invoke(cryptoCurrency: CryptoCurrency): Either<OnrampError, Unit> {
|
||||
return Either.catch {
|
||||
val country = requireNotNull(repository.getDefaultCountrySync()) { "Country must not be null" }
|
||||
val currency = requireNotNull(repository.getDefaultCurrencySync()) { "Currency must not be null" }
|
||||
repository.fetchPairs(currency = currency, country = country, cryptoCurrency = cryptoCurrency)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,20 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
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) {
|
||||
class OnrampFetchQuotesUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(amount: Amount, cryptoCurrency: CryptoCurrency) {
|
||||
suspend operator fun invoke(amount: Amount, cryptoCurrency: CryptoCurrency) = Either.catch {
|
||||
repository.fetchQuotes(
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
amount = amount,
|
||||
)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
|
@ -2,20 +2,20 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
|
||||
class OnrampRemoveTransactionUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(externalTxId: String?): Either<OnrampError, Unit> {
|
||||
if (externalTxId == null) return OnrampError.UnknownError.left()
|
||||
if (externalTxId == null) return OnrampError.DomainError("Transaction id not provided").left()
|
||||
|
||||
return Either.catch {
|
||||
onrampTransactionRepository.removeTransaction(externalTxId)
|
||||
}.mapLeft {
|
||||
OnrampError.UnknownError
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,17 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class OnrampSaveDefaultCountryUseCase(private val repository: OnrampRepository) {
|
||||
class OnrampSaveDefaultCountryUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(country: OnrampCountry) {
|
||||
suspend operator fun invoke(country: OnrampCountry) = Either.catch {
|
||||
repository.saveDefaultCurrency(country.defaultCurrency)
|
||||
repository.saveDefaultCountry(country)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class OnrampSaveDefaultCurrencyUseCase(private val repository: OnrampRepository) {
|
||||
class OnrampSaveDefaultCurrencyUseCase(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(currency: OnrampCurrency) {
|
||||
suspend operator fun invoke(currency: OnrampCurrency) = Either.catch {
|
||||
repository.saveDefaultCurrency(currency)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
|
@ -2,11 +2,17 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampRepository
|
||||
|
||||
class OnrampSaveSelectedPaymentMethod(private val repository: OnrampRepository) {
|
||||
class OnrampSaveSelectedPaymentMethod(
|
||||
private val repository: OnrampRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(paymentMethod: OnrampPaymentMethod): Either<Throwable, Unit> {
|
||||
suspend operator fun invoke(paymentMethod: OnrampPaymentMethod): Either<OnrampError, Unit> {
|
||||
return Either.catch { repository.saveSelectedPaymentMethod(paymentMethod) }
|
||||
.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,18 @@
|
|||
package com.tangem.domain.onramp
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.cache.OnrampTransaction
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
|
||||
class OnrampSaveTransactionUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(transaction: OnrampTransaction): Either<OnrampError, Unit> {
|
||||
return Either.catch { onrampTransactionRepository.storeTransaction(transaction) }
|
||||
.mapLeft { OnrampError.UnknownError }
|
||||
.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
}
|
||||
|
|
@ -2,13 +2,15 @@ package com.tangem.domain.onramp
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampStatus
|
||||
import com.tangem.domain.onramp.repositories.OnrampErrorResolver
|
||||
import com.tangem.domain.onramp.repositories.OnrampTransactionRepository
|
||||
|
||||
class OnrampUpdateTransactionStatusUseCase(
|
||||
private val onrampTransactionRepository: OnrampTransactionRepository,
|
||||
private val errorResolver: OnrampErrorResolver,
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(externalTxId: String, status: OnrampStatus.Status) = Either.catch {
|
||||
onrampTransactionRepository.updateTransactionStatus(externalTxId = externalTxId, status = status)
|
||||
}
|
||||
}.mapLeft(errorResolver::resolve)
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.domain.onramp.repositories
|
||||
|
||||
import com.tangem.domain.onramp.model.OnrampError
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
|
||||
interface OnrampErrorResolver {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.OnrampQuote
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.domain.tokens.model.AmountType
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.main.entity.*
|
||||
|
|
@ -162,35 +163,23 @@ internal class OnrampAmountStateFactory(
|
|||
private fun OnrampQuote.Error.toSecondaryFieldUiModel(
|
||||
amountState: OnrampAmountBlockUM,
|
||||
): OnrampAmountSecondaryFieldUM.Error {
|
||||
return when (this) {
|
||||
is OnrampQuote.Error.AmountTooBigError -> {
|
||||
val amount = requiredAmount.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 = requiredAmount.value.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
R.string.onramp_min_amount_restriction,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
val amount = error.requiredAmount.format {
|
||||
fiat(
|
||||
fiatCurrencyCode = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
fiatCurrencySymbol = amountState.amountFieldModel.fiatAmount.currencySymbol,
|
||||
)
|
||||
}
|
||||
|
||||
val errorTextRes = when (error) {
|
||||
is OnrampError.AmountError.TooBigError -> R.string.onramp_max_amount_restriction
|
||||
is OnrampError.AmountError.TooSmallError -> R.string.onramp_min_amount_restriction
|
||||
}
|
||||
|
||||
return OnrampAmountSecondaryFieldUM.Error(
|
||||
resourceReference(
|
||||
errorTextRes,
|
||||
wrappedList(amount),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +113,7 @@ internal class OnrampMainComponentModel @Inject constructor(
|
|||
modelScope.launch {
|
||||
checkOnrampAvailabilityUseCase.invoke()
|
||||
.onRight(::handleOnrampAvailability)
|
||||
.onLeft { Timber.e(it) }
|
||||
.onLeft { Timber.e(it.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,15 +20,12 @@ import com.tangem.domain.onramp.OnrampSaveSelectedPaymentMethod
|
|||
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
|
||||
import com.tangem.domain.onramp.model.OnrampPaymentMethod
|
||||
import com.tangem.domain.onramp.model.OnrampProviderWithQuote
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.paymentmethod.entity.PaymentMethodUM
|
||||
import com.tangem.features.onramp.providers.SelectProviderComponent
|
||||
import com.tangem.features.onramp.providers.entity.ProviderListBottomSheetConfig
|
||||
import com.tangem.features.onramp.providers.entity.ProviderListItemUM
|
||||
import com.tangem.features.onramp.providers.entity.ProviderListPaymentMethodUM
|
||||
import com.tangem.features.onramp.providers.entity.ProviderListUM
|
||||
import com.tangem.utils.StringsSigns.MINUS
|
||||
import com.tangem.features.onramp.providers.entity.*
|
||||
import com.tangem.utils.StringsSigns.MINUS
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
|
@ -79,7 +76,7 @@ internal class SelectProviderModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
.onLeft { Timber.e(it) }
|
||||
.onLeft { Timber.e(it.toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -171,40 +168,25 @@ internal class SelectProviderModel @Inject constructor(
|
|||
},
|
||||
)
|
||||
}
|
||||
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> {
|
||||
val amount = quote.requiredAmount.value.format {
|
||||
crypto(symbol = quote.requiredAmount.symbol, decimals = quote.requiredAmount.decimals)
|
||||
is OnrampProviderWithQuote.Unavailable.Error -> {
|
||||
val quoteError = quote.quoteError
|
||||
val amount = quoteError.error.requiredAmount.format {
|
||||
crypto(symbol = quoteError.fromAmount.symbol, decimals = quoteError.fromAmount.decimals)
|
||||
}
|
||||
val errorSubtitleRes = when (quoteError.error) {
|
||||
is OnrampError.AmountError.TooBigError -> R.string.express_provider_max_amount
|
||||
is OnrampError.AmountError.TooSmallError -> R.string.express_provider_min_amount
|
||||
}
|
||||
|
||||
ProviderListItemUM.AvailableWithError(
|
||||
providerId = quote.provider.id,
|
||||
imageUrl = quote.provider.info.imageLarge,
|
||||
name = quote.provider.info.name,
|
||||
subtitle = resourceReference(R.string.express_provider_min_amount, wrappedList(amount)),
|
||||
subtitle = resourceReference(errorSubtitleRes, wrappedList(amount)),
|
||||
onClick = {
|
||||
onProviderSelected(
|
||||
result = SelectProviderResult.ProviderWithError(
|
||||
paymentMethod = quote.paymentMethod,
|
||||
provider = quote.provider,
|
||||
quoteError = quote.quoteError,
|
||||
),
|
||||
isBestRate = bestProvider == quote,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> {
|
||||
val amount = quote.requiredAmount.value.format {
|
||||
crypto(symbol = quote.requiredAmount.symbol, decimals = quote.requiredAmount.decimals)
|
||||
}
|
||||
ProviderListItemUM.AvailableWithError(
|
||||
providerId = quote.provider.id,
|
||||
imageUrl = quote.provider.info.imageLarge,
|
||||
name = quote.provider.info.name,
|
||||
subtitle = resourceReference(R.string.express_provider_max_amount, wrappedList(amount)),
|
||||
onClick = {
|
||||
onProviderSelected(
|
||||
result = SelectProviderResult.ProviderWithError(
|
||||
paymentMethod = quote.paymentMethod,
|
||||
paymentMethod = quoteError.paymentMethod,
|
||||
provider = quote.provider,
|
||||
quoteError = quote.quoteError,
|
||||
),
|
||||
|
|
@ -250,8 +232,13 @@ internal class SelectProviderModel @Inject constructor(
|
|||
is OnrampProviderWithQuote.Data -> it.toAmount.value
|
||||
|
||||
// negative difference to sort both when data and unavailable is present
|
||||
is OnrampProviderWithQuote.Unavailable.AvailableFrom -> it.fromAmount.value - it.requiredAmount.value
|
||||
is OnrampProviderWithQuote.Unavailable.AvailableUpTo -> it.requiredAmount.value - it.fromAmount.value
|
||||
is OnrampProviderWithQuote.Unavailable.Error -> {
|
||||
when (val error = it.quoteError.error) {
|
||||
is OnrampError.AmountError.TooSmallError -> it.quoteError.fromAmount.value - error.requiredAmount
|
||||
is OnrampError.AmountError.TooBigError -> error.requiredAmount - it.quoteError.fromAmount.value
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
is OnrampProviderWithQuote.Unavailable.NotSupportedPaymentMethod -> null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.tangem.core.ui.extensions.stringReference
|
|||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.message.ContentMessage
|
||||
import com.tangem.domain.onramp.GetOnrampRedirectUrlUseCase
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.features.onramp.impl.R
|
||||
import com.tangem.features.onramp.redirect.OnrampRedirectComponent
|
||||
import com.tangem.features.onramp.redirect.entity.OnrampRedirectTopBarUM
|
||||
|
|
@ -76,8 +77,8 @@ internal class OnrampRedirectModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleError(throwable: Throwable) {
|
||||
Timber.e(throwable)
|
||||
private fun handleError(error: OnrampError) {
|
||||
Timber.e(error.toString())
|
||||
|
||||
val contentMessage = ContentMessage { onDismiss ->
|
||||
BasicDialog(
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ package com.tangem.features.onramp.selectcountry.entity.transformer
|
|||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryItemState
|
||||
import com.tangem.features.onramp.selectcountry.entity.CountryListUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class UpdateCountryItemsTransformer(
|
||||
private val maybeCountries: Either<Throwable, List<OnrampCountry>>,
|
||||
private val maybeCountries: Either<OnrampError, List<OnrampCountry>>,
|
||||
private val defaultCountry: OnrampCountry?,
|
||||
private val query: String,
|
||||
private val onRetry: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import arrow.core.Either
|
|||
import com.tangem.core.ui.extensions.stringReference
|
||||
import com.tangem.domain.onramp.model.OnrampCurrencies
|
||||
import com.tangem.domain.onramp.model.OnrampCurrency
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.features.onramp.selectcurrency.entity.CurrenciesListUM
|
||||
import com.tangem.features.onramp.selectcurrency.entity.CurrenciesSection
|
||||
import com.tangem.features.onramp.selectcurrency.entity.CurrencyItemState
|
||||
|
|
@ -11,7 +12,7 @@ import com.tangem.utils.transformer.Transformer
|
|||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
internal class UpdateCurrencyItemsTransformer(
|
||||
private val maybeCurrencies: Either<Throwable, OnrampCurrencies>,
|
||||
private val maybeCurrencies: Either<OnrampError, OnrampCurrencies>,
|
||||
private val query: String,
|
||||
private val onRetry: () -> Unit,
|
||||
private val onCurrencyClick: (OnrampCurrency) -> Unit,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.tangem.core.decompose.model.ParamsContainer
|
|||
import com.tangem.domain.onramp.GetOnrampCountryUseCase
|
||||
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
|
||||
import com.tangem.domain.onramp.model.OnrampCountry
|
||||
import com.tangem.domain.onramp.model.error.OnrampError
|
||||
import com.tangem.features.onramp.settings.OnrampSettingsComponent
|
||||
import com.tangem.features.onramp.settings.entity.OnrampSettingsConfig
|
||||
import com.tangem.features.onramp.settings.entity.OnrampSettingsItemUM
|
||||
|
|
@ -44,7 +45,7 @@ internal class OnrampSettingsModel @Inject constructor(
|
|||
.launchIn(modelScope)
|
||||
}
|
||||
|
||||
private fun updateResidenceState(maybeCountry: Either<Throwable, OnrampCountry?>) {
|
||||
private fun updateResidenceState(maybeCountry: Either<OnrampError, OnrampCountry?>) {
|
||||
maybeCountry.onRight { country ->
|
||||
_state.update { state ->
|
||||
state.copy(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue