diff --git a/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt index 36627cbffe..2c7ebb8702 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/OnrampDomainModule.kt @@ -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) } } \ No newline at end of file diff --git a/data/onramp/build.gradle.kts b/data/onramp/build.gradle.kts index 3510507736..8d28d658eb 100644 --- a/data/onramp/build.gradle.kts +++ b/data/onramp/build.gradle.kts @@ -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) diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt index 7a837b1197..8fc5e23cc5 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampErrorResolver.kt @@ -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 } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt index 7227a919f3..05d14b1d18 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/DefaultOnrampRepository.kt @@ -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 = 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 = 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.removeApplePay(): List = 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" } } \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampErrorConverter.kt b/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampErrorConverter.kt new file mode 100644 index 0000000000..895da30c18 --- /dev/null +++ b/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampErrorConverter.kt @@ -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, +) : Converter { + + @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) + } +} \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuoteErrorInput.kt b/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuoteErrorInput.kt deleted file mode 100644 index 218eb846c4..0000000000 --- a/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuoteErrorInput.kt +++ /dev/null @@ -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, -) \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuotesErrorConverter.kt b/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuotesErrorConverter.kt deleted file mode 100644 index f604f71009..0000000000 --- a/data/onramp/src/main/java/com/tangem/data/onramp/converters/error/OnrampQuotesErrorConverter.kt +++ /dev/null @@ -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, -) : Converter { - - @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, - ) - } -} \ No newline at end of file diff --git a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt index fa7f7e5302..072b2dbbdb 100644 --- a/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt +++ b/data/onramp/src/main/java/com/tangem/data/onramp/di/OnrampDataModule.kt @@ -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), + ) } } \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampError.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampError.kt deleted file mode 100644 index 4720b06769..0000000000 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampError.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.tangem.domain.onramp.model - -sealed class OnrampError { - data object UnknownError : OnrampError() -} \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampProviderWithQuote.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampProviderWithQuote.kt index bb8efebbff..f0d51802d6 100644 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampProviderWithQuote.kt +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampProviderWithQuote.kt @@ -21,20 +21,9 @@ sealed interface OnrampProviderWithQuote { val availablePaymentMethods: List, ) : 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 } } \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt index 8a4619bbf8..cc6a4586c1 100644 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampQuote.kt @@ -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() } \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt new file mode 100644 index 0000000000..50b8598b78 --- /dev/null +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampError.kt @@ -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() +} \ No newline at end of file diff --git a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampRedirectError.kt similarity index 57% rename from domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt rename to domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampRedirectError.kt index 119530ef72..4c57e3b2a0 100644 --- a/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/OnrampRedirectError.kt +++ b/domain/onramp/models/src/main/kotlin/com/tangem/domain/onramp/model/error/OnrampRedirectError.kt @@ -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() diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt index 13d75e5688..561f2cf5fd 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/CheckOnrampAvailabilityUseCase.kt @@ -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 { + suspend operator fun invoke(): Either { 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 { diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt index bbf1323710..928db29e59 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountriesUseCase.kt @@ -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> { - return Either.catch { onrampRepository.getCountries() } + suspend operator fun invoke(): Either> { + return Either.catch { onrampRepository.getCountries() }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt index 209324027a..65c945e7b5 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCountryUseCase.kt @@ -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> { + operator fun invoke(): Flow> { return repository.getDefaultCountry() - .map> { it.right() } - .catch { emit(it.left()) } + .map> { it.right() } + .catch { + emit(errorResolver.resolve(it).left()) + } } - suspend fun invokeSync(): Either { + suspend fun invokeSync(): Either { return Either.catch { repository.getDefaultCountrySync() ?: repository.getCountryByIp() } + .mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt index b1206947db..29b1aee914 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrenciesUseCase.kt @@ -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 { + suspend operator fun invoke(): Either { 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 { diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrencyUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrencyUseCase.kt index d2fc5147d1..210a6c3051 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrencyUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampCurrencyUseCase.kt @@ -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> { + operator fun invoke(): Flow> { return repository.getDefaultCurrency() - .map> { it.right() } - .catch { emit(it.left()) } + .map> { it.right() } + .catch { + emit(errorResolver.resolve(it).left()) + } } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt index 31b15f8c92..d709e81bbf 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampPaymentMethodsUseCase.kt @@ -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> { + suspend operator fun invoke(): Either> { return Either.catch { repository.getAvailablePaymentMethods() } + .mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampProviderWithQuoteUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampProviderWithQuoteUseCase.kt index 0773755610..9626d02dd2 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampProviderWithQuoteUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampProviderWithQuoteUseCase.kt @@ -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> { + suspend operator fun invoke( + paymentMethod: OnrampPaymentMethod, + ): Either> { return Either.catch { val quotes: List = 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.quoteWithProvider( @@ -27,46 +34,29 @@ class GetOnrampProviderWithQuoteUseCase(private val repository: OnrampRepository ): OnrampProviderWithQuote? { val quoteData = this.filterIsInstance() 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() - .firstOrNull { it.paymentMethod == selectedPaymentMethod } - + val amountError = + filterIsInstance().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 } diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampQuotesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampQuotesUseCase.kt index 0b0dee9fce..1da7243f67 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampQuotesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampQuotesUseCase.kt @@ -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>> { + operator fun invoke(): Flow>> { return repository.getQuotes() - .map, Either>> { quotes -> + .map, Either>> { 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 + } + } } } } diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt index 8d179444fd..34bb9f5202 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampRedirectUrlUseCase.kt @@ -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 { + ): Either { 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) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampSelectedPaymentMethodUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampSelectedPaymentMethodUseCase.kt index 23daf16d80..0548228e5e 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampSelectedPaymentMethodUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampSelectedPaymentMethodUseCase.kt @@ -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 { + operator fun invoke(): EitherFlow { return repository.getSelectedPaymentMethod() - .map> { it.right() } - .catch { emit(it.left()) } + .map> { it.right() } + .catch { + emit(errorResolver.resolve(it).left()) + } } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt index efc63c9188..a79f332c23 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampStatusUseCase.kt @@ -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 { return Either.catch { onrampRepository.getStatus(externalTxId) - }.mapLeft { - errorResolver.resolve(it) - } + }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionUseCase.kt index c7301172f5..32d3f258db 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionUseCase.kt @@ -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 { @@ -14,8 +16,6 @@ class GetOnrampTransactionUseCase( requireNotNull( onrampTransactionRepository.getTransactionById(externalTxId), ) - }.mapLeft { - OnrampError.UnknownError - } + }.mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionsUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionsUseCase.kt index 4deb1ece79..e7e54f0875 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionsUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/GetOnrampTransactionsUseCase.kt @@ -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() } } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt index 7ad73c3171..1bbaf78853 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchPairsUseCase.kt @@ -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 { + suspend operator fun invoke(cryptoCurrency: CryptoCurrency): Either { 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) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt index 2d360513fa..1842f2a819 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampFetchQuotesUseCase.kt @@ -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) } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampRemoveTransactionUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampRemoveTransactionUseCase.kt index dfc0fc3316..b1d3699272 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampRemoveTransactionUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampRemoveTransactionUseCase.kt @@ -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 { - 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) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt index bff9d1e4bb..9451683177 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCountryUseCase.kt @@ -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) } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt index 6362609fbf..27edb53002 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveDefaultCurrencyUseCase.kt @@ -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) } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveSelectedPaymentMethod.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveSelectedPaymentMethod.kt index 69f40194af..d7200a0b7d 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveSelectedPaymentMethod.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveSelectedPaymentMethod.kt @@ -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 { + suspend operator fun invoke(paymentMethod: OnrampPaymentMethod): Either { return Either.catch { repository.saveSelectedPaymentMethod(paymentMethod) } + .mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveTransactionUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveTransactionUseCase.kt index d939933d9c..716f588daf 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveTransactionUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampSaveTransactionUseCase.kt @@ -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 { return Either.catch { onrampTransactionRepository.storeTransaction(transaction) } - .mapLeft { OnrampError.UnknownError } + .mapLeft(errorResolver::resolve) } } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampUpdateTransactionStatusUseCase.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampUpdateTransactionStatusUseCase.kt index a31c31632e..8e28d63d32 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampUpdateTransactionStatusUseCase.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/OnrampUpdateTransactionStatusUseCase.kt @@ -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) } \ No newline at end of file diff --git a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampErrorResolver.kt b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampErrorResolver.kt index 6a1a1d90af..b18ec46936 100644 --- a/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampErrorResolver.kt +++ b/domain/onramp/src/main/java/com/tangem/domain/onramp/repositories/OnrampErrorResolver.kt @@ -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 { diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt index b196910fff..7c58bb465f 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/entity/factory/amount/OnrampAmountStateFactory.kt @@ -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), + ), + ) } } \ No newline at end of file diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt index 54eb03154f..3d7d00260e 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/main/model/OnrampMainComponentModel.kt @@ -113,7 +113,7 @@ internal class OnrampMainComponentModel @Inject constructor( modelScope.launch { checkOnrampAvailabilityUseCase.invoke() .onRight(::handleOnrampAvailability) - .onLeft { Timber.e(it) } + .onLeft { Timber.e(it.toString()) } } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt index 436a0454c1..45c6d33457 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/providers/model/SelectProviderModel.kt @@ -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 } } diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt index e75051640c..c5657187c0 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/redirect/model/OnrampRedirectModel.kt @@ -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( diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt index 0005ddd810..b171e2c8b6 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcountry/entity/transformer/UpdateCountryItemsTransformer.kt @@ -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>, + private val maybeCountries: Either>, private val defaultCountry: OnrampCountry?, private val query: String, private val onRetry: () -> Unit, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsTransformer.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsTransformer.kt index 8e3782838b..e5e3328194 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsTransformer.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/selectcurrency/entity/transformer/UpdateCurrencyItemsTransformer.kt @@ -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, + private val maybeCurrencies: Either, private val query: String, private val onRetry: () -> Unit, private val onCurrencyClick: (OnrampCurrency) -> Unit, diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt index 17fb7e14db..c62ccff591 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/settings/model/OnrampSettingsModel.kt @@ -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) { + private fun updateResidenceState(maybeCountry: Either) { maybeCountry.onRight { country -> _state.update { state -> state.copy(