Updated on 2026-08-14

This commit is contained in:
Tangem 2026-05-14 12:37:27 +03:00
parent ce948a71ae
commit ad9def0d21
27 changed files with 6 additions and 291 deletions

View file

@ -129,12 +129,6 @@ internal object OnrampDomainModule {
return OnrampSaveTransactionUseCase(onrampTransactionRepository, onrampErrorResolver)
}
@Provides
@Singleton
fun provideOnrampSepaAvailableUseCase(onrampRepository: OnrampRepository): OnrampSepaAvailableUseCase {
return OnrampSepaAvailableUseCase(onrampRepository)
}
@Provides
@Singleton
fun provideOnrampUpdateTransactionStatusUseCase(

View file

@ -209,7 +209,6 @@ internal class ChildFactory @Inject constructor(
userWalletId = route.userWalletId,
cryptoCurrency = route.currency,
source = route.source,
shouldLaunchSepa = route.shouldLaunchSepa,
),
componentFactory = onrampComponentFactory,
)

View file

@ -290,7 +290,6 @@ sealed class AppRoute(val path: String) : Route {
val source: OnrampSource,
val userWalletId: UserWalletId,
val currency: CryptoCurrency,
val shouldLaunchSepa: Boolean = false,
) : AppRoute(path = "/onramp/${userWalletId.stringValue}/${currency.symbol}"), RouteBundleParams {
override fun getBundle(): Bundle = bundle(serializer())
}

View file

@ -11,10 +11,8 @@ import com.tangem.datasource.local.onramp.paymentmethods.DefaultOnrampPaymentMet
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
import com.tangem.datasource.local.onramp.quotes.DefaultOnrampQuotesStore
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
import com.tangem.datasource.local.onramp.sepa.DefaultOnrampCurrentCountryByIPStore
import com.tangem.datasource.local.onramp.sepa.DefaultOnrampSepaAvailabilityStore
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
import com.tangem.datasource.local.onramp.country.DefaultOnrampCurrentCountryByIPStore
import com.tangem.datasource.local.onramp.country.OnrampCurrentCountryByIPStore
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -55,12 +53,6 @@ internal object OnrampStoreModule {
return DefaultOnrampCurrenciesStore(dataStore = RuntimeDataStore())
}
@Provides
@Singleton
fun provideOnrampSepaAvailableStore(): OnrampSepaAvailabilityStore {
return DefaultOnrampSepaAvailabilityStore(dataStore = RuntimeDataStore())
}
@Provides
@Singleton
fun provideOnrampCurrentCountryByIPStore(): OnrampCurrentCountryByIPStore {

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.local.onramp.sepa
package com.tangem.datasource.local.onramp.country
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator

View file

@ -1,4 +1,4 @@
package com.tangem.datasource.local.onramp.sepa
package com.tangem.datasource.local.onramp.country
import com.tangem.domain.onramp.model.OnrampCountry

View file

@ -1,20 +0,0 @@
package com.tangem.datasource.local.onramp.sepa
import com.tangem.datasource.local.datastore.core.StringKeyDataStore
import com.tangem.datasource.local.datastore.core.StringKeyDataStoreDecorator
internal class DefaultOnrampSepaAvailabilityStore(
val dataStore: StringKeyDataStore<Boolean>,
) : OnrampSepaAvailabilityStore, StringKeyDataStoreDecorator<OnrampSepaAvailabilityStoreKey, Boolean>(
wrappedDataStore = dataStore,
) {
override fun provideStringKey(key: OnrampSepaAvailabilityStoreKey) = with(key) {
buildString {
append(userWallet.walletId.toString())
append("_")
append(country.code)
append("_")
append(cryptoCurrency.id.value)
}
}
}

View file

@ -1,10 +0,0 @@
package com.tangem.datasource.local.onramp.sepa
import kotlinx.coroutines.flow.Flow
interface OnrampSepaAvailabilityStore {
suspend fun getSyncOrNull(key: OnrampSepaAvailabilityStoreKey): Boolean?
fun get(key: OnrampSepaAvailabilityStoreKey): Flow<Boolean>
suspend fun store(key: OnrampSepaAvailabilityStoreKey, value: Boolean)
suspend fun clear()
}

View file

@ -1,11 +0,0 @@
package com.tangem.datasource.local.onramp.sepa
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.model.OnrampCountry
data class OnrampSepaAvailabilityStoreKey(
val userWallet: UserWallet,
val country: OnrampCountry,
val cryptoCurrency: CryptoCurrency,
)

View file

@ -11,9 +11,6 @@ import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStoreFile
import com.tangem.datasource.local.preferences.PreferencesDataStore.INSTANCE
import com.tangem.datasource.local.preferences.PreferencesKeys.APP_LOGS_KEY
import com.tangem.datasource.local.preferences.PreferencesKeys.IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY
import com.tangem.datasource.local.preferences.PreferencesKeys.IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY
import com.tangem.datasource.local.preferences.PreferencesKeys.SHOULD_SHOW_RING_PROMO_KEY
import com.tangem.datasource.local.preferences.utils.CleanupKeyMigration
import com.tangem.datasource.local.preferences.utils.SharedPreferencesKeyMigration
import com.tangem.datasource.local.preferences.utils.SwapCurrencyIdMigration
@ -83,9 +80,6 @@ internal object PreferencesDataStore {
),
SwapCurrencyIdMigration(),
CleanupKeyMigration(key = APP_LOGS_KEY),
CleanupKeyMigration(key = IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY),
CleanupKeyMigration(key = IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY),
CleanupKeyMigration(key = SHOULD_SHOW_RING_PROMO_KEY),
)
}
}

View file

@ -87,23 +87,10 @@ object PreferencesKeys {
val UNSUBMITTED_TRANSACTIONS_KEY by lazy { stringPreferencesKey(name = "unsubmittedTransactions") }
@Deprecated("Remove after CleanupKeyMigration")
val IS_WALLET_SWAP_PROMO_OKX_SHOW_KEY by lazy {
booleanPreferencesKey(name = "isWalletSwapPromoOkxShown")
}
@Deprecated("Remove after CleanupKeyMigration")
val IS_TOKEN_SWAP_PROMO_OKX_SHOW_KEY by lazy {
booleanPreferencesKey(name = "isTokenSwapPromoOkxShown")
}
val apiConfigsEnvironmentKey by lazy { stringPreferencesKey(name = "apiConfigsEnvironment") }
val ADDED_WALLETS_WITH_RING_KEY by lazy { stringSetPreferencesKey(name = "addedWalletsWithRing") }
@Deprecated("Remove after CleanupKeyMigration")
val SHOULD_SHOW_RING_PROMO_KEY by lazy { booleanPreferencesKey(name = "shouldShowRingPromo") }
val ONRAMP_DEFAULT_COUNTRY by lazy { stringPreferencesKey(name = "onrampDefaultCountry") }
val ONRAMP_TRANSACTIONS_STATUSES_KEY by lazy { stringPreferencesKey(name = "onrampTransactionsStatuses") }

View file

@ -28,7 +28,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.datasource.CollectionPreviewParameterProvider
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.R
import com.tangem.core.ui.components.*
import com.tangem.core.ui.components.buttons.common.TangemButtonSize
@ -520,15 +519,5 @@ private class NotificationConfigProvider : CollectionPreviewParameterProvider<No
subtitle = resourceReference(id = R.string.information_generated_with_ai),
iconResId = R.drawable.ic_magic_28,
),
NotificationConfig(
title = resourceReference(R.string.notification_sepa_title),
subtitle = resourceReference(R.string.notification_sepa_text),
iconResId = R.drawable.img_notification_sepa,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.notification_sepa_button),
onClick = { },
),
iconSize = 54.dp,
),
),
)

View file

@ -551,16 +551,6 @@ private class TangemMessageLegacyPreviewProvider : PreviewParameterProvider<Noti
subtitle = resourceReference(id = R.string.information_generated_with_ai),
iconResId = R.drawable.ic_magic_28,
),
NotificationConfig(
title = resourceReference(R.string.notification_sepa_title),
subtitle = resourceReference(R.string.notification_sepa_text),
iconResId = R.drawable.img_notification_sepa,
buttonsState = ButtonsState.SecondaryButtonConfig(
text = resourceReference(R.string.notification_sepa_button),
onClick = { },
),
iconSize = 54.dp,
),
)
}
// endregion

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View file

@ -29,9 +29,7 @@ import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStoreKey
import com.tangem.datasource.local.onramp.country.OnrampCurrentCountryByIPStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObject
@ -67,7 +65,6 @@ internal class DefaultOnrampRepository(
private val dispatchers: CoroutineDispatcherProvider,
private val appPreferencesStore: AppPreferencesStore,
private val paymentMethodsStore: OnrampPaymentMethodsStore,
private val onrampSepaAvailabilityStore: OnrampSepaAvailabilityStore,
private val onrampCurrentCountryByIPStore: OnrampCurrentCountryByIPStore,
private val pairsStore: OnrampPairsStore,
private val quotesStore: OnrampQuotesStore,
@ -281,62 +278,6 @@ internal class DefaultOnrampRepository(
storeOnrampPairs(pairs = onrampPairs.await(), providers = providers.await())
}
override suspend fun hasSepaMethod(
userWallet: UserWallet,
country: OnrampCountry,
cryptoCurrency: CryptoCurrency,
): Boolean {
return withContext(dispatchers.io) {
val key = OnrampSepaAvailabilityStoreKey(
userWallet = userWallet,
country = country,
cryptoCurrency = cryptoCurrency,
)
val isCachedValue = onrampSepaAvailabilityStore.getSyncOrNull(key)
if (isCachedValue != null) {
return@withContext isCachedValue
}
val onrampPairs =
safeApiCall(
call = {
onrampApi.getPairs(
userWalletId = userWallet.walletId.stringValue,
refCode = ExpressUtils.getRefCode(
userWallet = userWallet,
appPreferencesStore = appPreferencesStore,
),
body = OnrampPairsRequest(
fromCurrencyCode = EUR_CURRENCY_CODE,
countryCode = country.code,
to = listOf(
OnrampDestinationDTO(
contractAddress = cryptoCurrency.getContractAddress(),
network = cryptoCurrency.network.rawId,
),
),
),
).bind()
},
onError = { error ->
TangemLogger.w("Unable to fetch onramp pairs", error)
throw error
},
)
val hasSepaMethod = onrampPairs
.flatMap { it.providers }
.flatMap { it.paymentMethods }
.any { it == SEPA_METHOD_ID }
onrampSepaAvailabilityStore.store(key, hasSepaMethod)
hasSepaMethod
}
}
override suspend fun fetchQuotes(userWallet: UserWallet, cryptoCurrency: CryptoCurrency, amount: Amount) =
withContext(dispatchers.io) {
val pairs = requireNotNull(pairsStore.getSyncOrNull(PAIRS_KEY)) {
@ -632,8 +573,5 @@ internal class DefaultOnrampRepository(
const val PROVIDER_THEME_LIGHT = "light"
const val REDIRECT_URL = "https://tangem.com/onramp"
const val SEPA_METHOD_ID = "sepa"
const val EUR_CURRENCY_CODE = "EUR"
}
}

View file

@ -24,8 +24,7 @@ import com.tangem.datasource.local.onramp.currencies.OnrampCurrenciesStore
import com.tangem.datasource.local.onramp.pairs.OnrampPairsStore
import com.tangem.datasource.local.onramp.paymentmethods.OnrampPaymentMethodsStore
import com.tangem.datasource.local.onramp.quotes.OnrampQuotesStore
import com.tangem.datasource.local.onramp.sepa.OnrampCurrentCountryByIPStore
import com.tangem.datasource.local.onramp.sepa.OnrampSepaAvailabilityStore
import com.tangem.datasource.local.onramp.country.OnrampCurrentCountryByIPStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.utils.coroutines.AppCoroutineScope
@ -56,7 +55,6 @@ internal object OnrampDataModule {
currenciesStore: OnrampCurrenciesStore,
walletManagersFacade: WalletManagersFacade,
dataSignatureVerifier: DataSignatureVerifier,
onrampSepaAvailabilityStore: OnrampSepaAvailabilityStore,
onrampCurrentCountryByIPStore: OnrampCurrentCountryByIPStore,
@NetworkMoshi moshi: Moshi,
): OnrampRepository {
@ -66,7 +64,6 @@ internal object OnrampDataModule {
dispatchers = dispatchers,
appPreferencesStore = appPreferencesStore,
paymentMethodsStore = paymentMethodsStore,
onrampSepaAvailabilityStore = onrampSepaAvailabilityStore,
onrampCurrentCountryByIPStore = onrampCurrentCountryByIPStore,
pairsStore = pairsStore,
quotesStore = quotesStore,

View file

@ -1,77 +0,0 @@
package com.tangem.domain.onramp
import arrow.core.Either
import arrow.core.getOrElse
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.onramp.repositories.OnrampRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.onramp.model.OnrampCountry
class OnrampSepaAvailableUseCase(
private val repository: OnrampRepository,
) {
suspend operator fun invoke(
userWallet: UserWallet,
country: OnrampCountry,
cryptoCurrency: CryptoCurrency,
): Boolean {
if (country.code !in SEPA_AVAILABLE_COUNTRY_CODES) {
return false
}
return Either.catch {
repository.hasSepaMethod(
userWallet = userWallet,
country = country,
cryptoCurrency = cryptoCurrency,
)
}.getOrElse { false }
}
companion object {
val SEPA_AVAILABLE_COUNTRY_CODES = listOf(
"AL", // Albania
"AD", // Andorra
"AT", // Austria
"BE", // Belgium
"BG", // Bulgaria
"HR", // Croatia
"CY", // Cyprus
"CZ", // Czech Republic
"DK", // Denmark
"EE", // Estonia
"FI", // Finland
"FR", // France
"DE", // Germany
"GR", // Greece
"HU", // Hungary
"IS", // Iceland
"IE", // Ireland
"IT", // Italy
"LV", // Latvia
"LI", // Liechtenstein
"LT", // Lithuania
"LU", // Luxembourg
"MT", // Malta
"MD", // Moldova
"MC", // Monaco
"ME", // Montenegro
"NL", // Netherlands
"MK", // North Macedonia
"NO", // Norway
"PL", // Poland
"PT", // Portugal
"RO", // Romania
"SM", // San Marino
"RS", // Serbia
"SK", // Slovakia
"SI", // Slovenia
"ES", // Spain
"SE", // Sweden
"CH", // Switzerland
"GB", // United Kingdom
"VA", // Vatican City
)
}
}

View file

@ -15,7 +15,6 @@ interface OnrampRepository {
suspend fun getCountriesSync(): List<OnrampCountry>?
suspend fun getCountryByIp(userWallet: UserWallet, fromCache: Boolean = false): OnrampCountry
suspend fun getStatus(userWallet: UserWallet, txId: String): OnrampStatus
suspend fun hasSepaMethod(userWallet: UserWallet, country: OnrampCountry, cryptoCurrency: CryptoCurrency): Boolean
suspend fun fetchCurrencies(userWallet: UserWallet)
suspend fun fetchCountries(userWallet: UserWallet): List<OnrampCountry>
suspend fun fetchPaymentMethodsIfAbsent(userWallet: UserWallet)

View file

@ -22,7 +22,6 @@ import com.tangem.features.promobanners.api.PromoBannersBlockComponent
import kotlinx.serialization.Serializable
import javax.inject.Inject
@Suppress("LongParameterList")
internal class FeedEntryChildFactory @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
private val portfolioComponentFactory: MarketsPortfolioComponent.Factory,

View file

@ -12,7 +12,6 @@ interface OnrampComponent : ComposableContentComponent {
val userWalletId: UserWalletId,
val cryptoCurrency: CryptoCurrency,
val source: OnrampSource,
val shouldLaunchSepa: Boolean = false,
)
interface Factory : ComponentFactory<Params, OnrampComponent>

View file

@ -12,7 +12,6 @@ internal interface ConfirmResidencyComponent : ComposableBottomSheetComponent {
val userWalletId: UserWalletId,
val cryptoCurrency: CryptoCurrency,
val country: OnrampCountry,
val isLaunchSepa: Boolean,
val onDismiss: () -> Unit,
)

View file

@ -9,14 +9,12 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.domain.onramp.OnrampSaveDefaultCountryUseCase
import com.tangem.domain.onramp.OnrampSaveDefaultCurrencyUseCase
import com.tangem.domain.onramp.analytics.OnrampAnalyticsEvent
import com.tangem.domain.onramp.model.OnrampCountry
import com.tangem.features.onramp.confirmresidency.ConfirmResidencyComponent
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyBottomSheetConfig
import com.tangem.features.onramp.confirmresidency.entity.ConfirmResidencyUM
import com.tangem.features.onramp.impl.R
import com.tangem.features.onramp.utils.model.EUR_CURRENCY
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
@ -28,7 +26,6 @@ internal class ConfirmResidencyModel @Inject constructor(
private val analyticsEventHandler: AnalyticsEventHandler,
private val router: Router,
private val saveDefaultCountryUseCase: OnrampSaveDefaultCountryUseCase,
private val onrampSaveDefaultCurrencyUseCase: OnrampSaveDefaultCurrencyUseCase,
paramsContainer: ParamsContainer,
) : Model() {
@ -57,10 +54,6 @@ internal class ConfirmResidencyModel @Inject constructor(
analyticsEventHandler.send(OnrampAnalyticsEvent.OnResidenceConfirm(country.name))
modelScope.launch {
saveDefaultCountryUseCase.invoke(country)
if (params.isLaunchSepa) {
onrampSaveDefaultCurrencyUseCase.invoke(EUR_CURRENCY)
}
params.onDismiss()
}
},

View file

@ -63,7 +63,6 @@ internal class DefaultOnrampMainComponent @AssistedInject constructor(
userWalletId = params.userWalletId,
cryptoCurrency = params.cryptoCurrency,
country = config.country,
isLaunchSepa = false,
onDismiss = {
model.bottomSheetNavigation.dismiss()
model.handleOnrampAvailable()

View file

@ -1,11 +0,0 @@
package com.tangem.features.onramp.utils.model
import com.tangem.domain.onramp.model.OnrampCurrency
internal val EUR_CURRENCY = OnrampCurrency(
code = "EUR",
name = "Euro",
unit = "",
precision = 2,
image = "https://s3.eu-central-1.amazonaws.com/tangem.api/express/Currencies/EUR.png",
)

View file

@ -26,7 +26,6 @@ dependencies {
implementation(projects.core.analytics.models)
implementation(projects.core.utils)
implementation(projects.core.datasource)
implementation(projects.core.configToggles)
/** Compose */
implementation(deps.compose.foundation)

View file

@ -61,7 +61,6 @@ internal class TokenDetailsNotificationsAnalyticsSender(
is TokenDetailsNotification.MigrationClore,
is TokenDetailsNotification.UsedOutdatedData,
-> null
is TokenDetailsNotification.DynamicAddressesFundsFound -> null // TODO: [REDACTED_TASK_KEY] analytics event
}
}
}

View file

@ -149,9 +149,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
!notificationsRepository.isUserAllowToSubscribeOnPushNotifications(),
)
// Remove in first iteration of yield supply feature
// addYieldSupplyNotifications(flattenCurrencies)
val hasCriticalOrWarning = any { notification ->
notification is WalletNotification.Critical || notification is WalletNotification.Warning
}
@ -283,15 +280,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
.map(CryptoCurrencyStatus::currency)
}
// private fun MutableList<WalletNotification>.addYieldSupplyNotifications(
// flattenCurrencies: Lce<TokenListError, List<CryptoCurrencyStatus>>,
// ) {
// addIf(
// element = WalletNotification.Warning.YeildSupplyApprove,
// condition = flattenCurrencies.hasTokensWithActivatedSupplyWithoutApprove(),
// )
// }
private fun MutableList<WalletNotification>.addWarningNotifications(
cardTypesResolver: CardTypesResolver?,
flattenCurrencies: List<CryptoCurrencyStatus>,
@ -354,15 +342,6 @@ internal class GetMultiWalletWarningsFactory @Inject constructor(
return this.any { it.value is CryptoCurrencyStatus.Unreachable }
}
// Remove in first iteration of yield supply feature
// private fun Lce<TokenListError, List<CryptoCurrencyStatus>>.hasTokensWithActivatedSupplyWithoutApprove(): Boolean {
// val flattenCurrencies = getOrNull(isPartialContentAccepted = false) ?: return false
// val yieldSupplyEnabled = yieldSupplyFeatureToggles.isYieldSupplyFeatureEnabled
// return yieldSupplyEnabled && flattenCurrencies.any {
// it.value.yieldSupplyStatus?.isAllowedToSpend == false
// }
// }
private fun MutableList<WalletNotification>.addAssetsDiscoveryCompletedNotification(
userWallet: UserWallet,
assetsDiscoveryProgress: AssetsDiscoveryProgress,