From 343cf1ed2065df4561c1aac52de91f893d337188 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 Feb 2026 15:31:18 +0400 Subject: [PATCH 1/7] Updated on 2026-08-14 --- .../tangem/core/analytics/models/AnalyticsParam.kt | 12 +++++++++++- features/swap/impl/build.gradle.kts | 1 + .../com/tangem/feature/swap/analytics/SwapEvents.kt | 3 +++ .../java/com/tangem/feature/swap/model/SwapModel.kt | 5 ++++- .../feature/wallet/child/wallet/model/WalletModel.kt | 3 +++ .../wallet/analytics/WalletScreenAnalyticsEvent.kt | 7 +++---- .../supply/api/analytics/YieldSupplyAnalytics.kt | 5 +++++ features/yield-supply/impl/build.gradle.kts | 1 + .../model/YieldSupplyStartEarningModel.kt | 3 +++ .../stopearning/model/YieldSupplyStopEarningModel.kt | 5 ++++- 10 files changed, 38 insertions(+), 7 deletions(-) diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index cff2fe1375..ff196b2f0e 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -1,5 +1,8 @@ package com.tangem.core.analytics.models +import com.tangem.core.analytics.models.AnalyticsParam.Key.REFERRAL +import com.tangem.core.analytics.models.AnalyticsParam.Key.REFERRAL_ID + sealed class AnalyticsParam { sealed class CardBalanceState(val value: String) { @@ -268,5 +271,12 @@ sealed class AnalyticsParam { const val ENS = "ENS" const val ENS_ADDRESS = "ENS Address" const val ACCOUNT_DERIVATION_FROM = "Account Derivation (from)" + const val REFERRAL = "Referral" + const val REFERRAL_ID = "Referral_ID" } -} \ No newline at end of file +} + +fun getReferralParams(referralId: String?): List> = listOf( + REFERRAL to (!referralId.isNullOrBlank()).toString().replaceFirstChar(Char::titlecase), + REFERRAL_ID to (referralId ?: "None"), +) \ No newline at end of file diff --git a/features/swap/impl/build.gradle.kts b/features/swap/impl/build.gradle.kts index 9be6f2453e..69dd4663a7 100644 --- a/features/swap/impl/build.gradle.kts +++ b/features/swap/impl/build.gradle.kts @@ -16,6 +16,7 @@ dependencies { implementation(projects.core.analytics) implementation(projects.core.analytics.models) implementation(projects.core.configToggles) + implementation(projects.core.datasource) implementation(projects.core.navigation) implementation(projects.core.utils) implementation(projects.core.ui) diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapEvents.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapEvents.kt index fe69da29ce..b091a1fbfd 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapEvents.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/analytics/SwapEvents.kt @@ -8,6 +8,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.PROVIDER import com.tangem.core.analytics.models.AnalyticsParam.Key.RECEIVE_TOKEN import com.tangem.core.analytics.models.AnalyticsParam.Key.SEND_TOKEN import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.getReferralParams import com.tangem.feature.swap.domain.models.domain.SwapProvider import com.tangem.feature.swap.domain.models.ui.FeeType @@ -86,6 +87,7 @@ sealed class SwapEvents( val receiveToken: String, val fromDerivationIndex: Int?, val toDerivationIndex: Int?, + val referralId: String?, ) : SwapEvents( event = "Swap in Progress Screen Opened", params = mapOf( @@ -96,6 +98,7 @@ sealed class SwapEvents( "Send Blockchain" to sendBlockchain, "Receive Blockchain" to receiveBlockchain, "Account Derivation From or To (optional)" to "$fromDerivationIndex, $toDerivationIndex", + *getReferralParams(referralId).toTypedArray(), ), ), AppsFlyerIncludedEvent diff --git a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt index 65dba91ee9..96763be19f 100644 --- a/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt +++ b/features/swap/impl/src/main/java/com/tangem/feature/swap/model/SwapModel.kt @@ -20,6 +20,7 @@ import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.utils.InputNumberFormatter +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.status.model.AccountCryptoCurrencyStatus import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase @@ -118,6 +119,7 @@ internal class SwapModel @Inject constructor( private val accountsFeatureToggles: AccountsFeatureToggles, private val getTangemPayCurrencyStatusUseCase: GetTangemPayCurrencyStatusUseCase, private val tangemPayWithdrawUseCase: TangemPayWithdrawUseCase, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -888,7 +890,7 @@ internal class SwapModel @Inject constructor( } } - private fun sendSuccessEvent() { + private suspend fun sendSuccessEvent() { val provider = dataState.selectedProvider ?: return val fee = dataState.selectedFee?.feeType ?: return val fromCurrency = dataState.fromCryptoCurrency?.currency ?: return @@ -906,6 +908,7 @@ internal class SwapModel @Inject constructor( receiveToken = toCurrency.symbol, fromDerivationIndex = fromDerivationIndex, toDerivationIndex = toDerivationIndex, + referralId = appsFlyerStore.get()?.refcode, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt index dc160b2505..eedc7314e9 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/WalletModel.kt @@ -10,6 +10,7 @@ import com.tangem.core.analytics.models.event.MainScreenAnalyticsEvent import com.tangem.core.analytics.utils.TrackingContextProxy import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles import com.tangem.domain.account.supplier.SingleAccountListSupplier import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase @@ -105,6 +106,7 @@ internal class WalletModel @Inject constructor( private val isAccountsModeEnabledUseCase: IsAccountsModeEnabledUseCase, private val feedFeatureToggle: FeedFeatureToggle, private val bindRefcodeWithWalletUseCase: BindRefcodeWithWalletUseCase, + private val appsFlyerStore: AppsFlyerStore, val screenLifecycleProvider: ScreenLifecycleProvider, val innerWalletRouter: InnerWalletRouter, ) : Model() { @@ -235,6 +237,7 @@ internal class WalletModel @Inject constructor( accountsCount = accountsCount, theme = theme.value, isImported = selectedWallet.isImported(), + referralId = appsFlyerStore.get()?.refcode, ), ) } diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt index e766bf4333..f92476350d 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/analytics/WalletScreenAnalyticsEvent.kt @@ -1,9 +1,6 @@ package com.tangem.feature.wallet.presentation.wallet.analytics -import com.tangem.core.analytics.models.AnalyticsEvent -import com.tangem.core.analytics.models.AnalyticsParam -import com.tangem.core.analytics.models.AppsFlyerIncludedEvent -import com.tangem.core.analytics.models.OneTimeAnalyticsEvent +import com.tangem.core.analytics.models.* import com.tangem.domain.models.wallet.UserWalletId sealed class WalletScreenAnalyticsEvent { @@ -59,6 +56,7 @@ sealed class WalletScreenAnalyticsEvent { private val accountsCount: Int?, val theme: String, val isImported: Boolean, + val referralId: String?, ) : MainScreen( event = "Screen opened", params = buildMap { @@ -71,6 +69,7 @@ sealed class WalletScreenAnalyticsEvent { "Seedless" } put("Wallet Type", seedPhrase) + putAll(getReferralParams(referralId)) }, ), AppsFlyerIncludedEvent diff --git a/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt b/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt index 02f6ba56aa..629181b412 100644 --- a/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt +++ b/features/yield-supply/api/src/main/java/com/tangem/features/yield/supply/api/analytics/YieldSupplyAnalytics.kt @@ -6,6 +6,7 @@ import com.tangem.core.analytics.models.AnalyticsParam.Key.BLOCKCHAIN import com.tangem.core.analytics.models.AnalyticsParam.Key.ERROR_DESCRIPTION import com.tangem.core.analytics.models.AnalyticsParam.Key.TOKEN_PARAM import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.getReferralParams sealed class YieldSupplyAnalytics( event: String, @@ -103,22 +104,26 @@ sealed class YieldSupplyAnalytics( data class FundsEarned( val token: String, val blockchain: String, + val referralId: String?, ) : YieldSupplyAnalytics( event = "Funds Earned", params = mapOf( TOKEN_PARAM to token, BLOCKCHAIN to blockchain, + *getReferralParams(referralId).toTypedArray(), ), ), AppsFlyerIncludedEvent data class FundsWithdrawn( val token: String, val blockchain: String, + val referralId: String?, ) : YieldSupplyAnalytics( event = "Funds Withdrawn", params = mapOf( TOKEN_PARAM to token, BLOCKCHAIN to blockchain, + *getReferralParams(referralId).toTypedArray(), ), ), AppsFlyerIncludedEvent diff --git a/features/yield-supply/impl/build.gradle.kts b/features/yield-supply/impl/build.gradle.kts index e79c976bd4..f1b9082389 100644 --- a/features/yield-supply/impl/build.gradle.kts +++ b/features/yield-supply/impl/build.gradle.kts @@ -18,6 +18,7 @@ dependencies { /** Core */ implementation(projects.core.configToggles) + implementation(projects.core.datasource) implementation(projects.core.decompose) implementation(projects.core.ui) implementation(projects.core.navigation) diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt index 6a2d3d2597..52fe5d3df6 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/startearning/model/YieldSupplyStartEarningModel.kt @@ -11,6 +11,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrencyStatus @@ -65,6 +66,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( private val yieldSupplyGetMaxFeeUseCase: YieldSupplyGetMaxFeeUseCase, private val yieldSupplyGetCurrentFeeUseCase: YieldSupplyGetCurrentFeeUseCase, private val yieldSupplyRepository: YieldSupplyRepository, + private val appsFlyerStore: AppsFlyerStore, ) : Model(), YieldSupplyNotificationsComponent.ModelCallback { private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require() @@ -267,6 +269,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor( YieldSupplyAnalytics.FundsEarned( blockchain = cryptoCurrency.network.name, token = cryptoCurrency.symbol, + referralId = appsFlyerStore.get()?.refcode, ), ) yieldSupplyFeeUM.transactionDataList.forEach { diff --git a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt index f327d6c82a..0a54db1fee 100644 --- a/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt +++ b/features/yield-supply/impl/src/main/java/com/tangem/features/yield/supply/impl/subcomponents/stopearning/model/YieldSupplyStopEarningModel.kt @@ -11,6 +11,7 @@ import com.tangem.core.navigation.url.UrlOpener import com.tangem.core.ui.components.currency.icon.converter.CryptoCurrencyToIconStateConverter import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.wrappedList +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.models.currency.CryptoCurrency @@ -61,6 +62,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( private val yieldSupplyAlertFactory: YieldSupplyAlertFactory, private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase, private val yieldSupplyRepository: YieldSupplyRepository, + private val appsFlyerStore: AppsFlyerStore, ) : Model(), YieldSupplyNotificationsComponent.ModelCallback { private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require() @@ -160,7 +162,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( yieldSupplyAlertFactory.onFailedTxEmailClick( userWallet = params.userWallet, cryptoCurrency = cryptoCurrency, - errorMessage = error.toString(), + errorMessage = errorMessage, ) } }, @@ -184,6 +186,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor( YieldSupplyAnalytics.FundsWithdrawn( token = cryptoCurrency.symbol, blockchain = cryptoCurrency.network.name, + referralId = appsFlyerStore.get()?.refcode, ), ) val event = AnalyticsParam.TxSentFrom.Earning( From bbc40d7ddf319621c0dc3f3a219bf67f75655cc8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 30 Jan 2026 13:59:48 +0400 Subject: [PATCH 2/7] Updated on 2026-08-14 --- .../tangem/tap/di/TangemSdkManagerModule.kt | 16 ++++++ .../sdk/impl/DefaultTangemSdkManager.kt | 52 +++++++++++++++++-- core/res/src/main/res/values-de/strings.xml | 24 +++++++++ core/res/src/main/res/values-es/strings.xml | 4 +- core/res/src/main/res/values-fr/strings.xml | 12 +++++ core/res/src/main/res/values-ja/strings.xml | 29 ++++++++--- core/res/src/main/res/values-ru/strings.xml | 7 ++- .../src/main/res/values-uk-rUA/strings.xml | 2 + core/res/src/main/res/values/strings.xml | 8 ++- .../feedback/models/FeedbackEmailType.kt | 4 ++ .../feedback/SendFeedbackEmailUseCase.kt | 1 + .../utils/EmailMessageBodyResolver.kt | 1 + .../utils/EmailMessageTitleResolver.kt | 1 + .../feedback/utils/EmailSubjectResolver.kt | 1 + 14 files changed, 147 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/di/TangemSdkManagerModule.kt b/app/src/main/java/com/tangem/tap/di/TangemSdkManagerModule.kt index 0487d0fad7..38e66db21b 100644 --- a/app/src/main/java/com/tangem/tap/di/TangemSdkManagerModule.kt +++ b/app/src/main/java/com/tangem/tap/di/TangemSdkManagerModule.kt @@ -1,8 +1,13 @@ package com.tangem.tap.di import android.content.Context +import com.tangem.core.analytics.api.AnalyticsExceptionHandler +import com.tangem.core.decompose.di.GlobalUiMessageSender +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.navigation.finisher.AppFinisher import com.tangem.domain.card.BuildConfig import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles import com.tangem.sdk.api.TangemSdkManager import com.tangem.tap.domain.sdk.impl.DefaultTangemSdkManager @@ -10,6 +15,7 @@ import com.tangem.tap.domain.sdk.impl.MockTangemSdkManager import com.tangem.tap.domain.tasks.visa.TangemPayGenerateAddressAndSignChallengeTask import com.tangem.tap.domain.tasks.visa.VisaCardActivationTask import com.tangem.tap.domain.visa.VisaCardScanHandler +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -30,6 +36,11 @@ internal class TangemSdkManagerModule { visaCardActivationTaskFactory: VisaCardActivationTask.Factory, tangemPayChallengeTaskFactory: TangemPayGenerateAddressAndSignChallengeTask.Factory, onboardingV2FeatureToggles: OnboardingV2FeatureToggles, + @GlobalUiMessageSender uiMessageSender: UiMessageSender, + appFinisher: AppFinisher, + sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, + analyticsExceptionHandler: AnalyticsExceptionHandler, + dispatchers: CoroutineDispatcherProvider, ): TangemSdkManager { return if (BuildConfig.MOCK_DATA_SOURCE) { MockTangemSdkManager(resources = context.resources) @@ -41,6 +52,11 @@ internal class TangemSdkManagerModule { visaCardActivationTaskFactory = visaCardActivationTaskFactory, tangemPayChallengeTaskFactory = tangemPayChallengeTaskFactory, onboardingV2FeatureToggles = onboardingV2FeatureToggles, + uiMessageSender = uiMessageSender, + appFinisher = appFinisher, + sendFeedbackEmailUseCase = sendFeedbackEmailUseCase, + analyticsExceptionHandler = analyticsExceptionHandler, + dispatchers = dispatchers, ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt index ef82b7c01f..20046a427d 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt @@ -18,12 +18,21 @@ import com.tangem.common.extensions.hexToBytes import com.tangem.common.services.secure.SecureStorage import com.tangem.common.usersCode.UserCodeRepository import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.api.AnalyticsExceptionHandler +import com.tangem.core.analytics.models.ExceptionAnalyticsEvent +import com.tangem.core.decompose.ui.UiMessageSender +import com.tangem.core.navigation.finisher.AppFinisher import com.tangem.core.res.getStringSafe +import com.tangem.core.ui.extensions.resourceReference +import com.tangem.core.ui.message.DialogMessage +import com.tangem.core.ui.message.EventMessageAction import com.tangem.crypto.bip39.DefaultMnemonic import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.card.repository.CardSdkConfigRepository +import com.tangem.domain.feedback.SendFeedbackEmailUseCase +import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.wallet.UserWalletId @@ -57,13 +66,14 @@ import com.tangem.tap.domain.twins.CreateFirstTwinWalletTask import com.tangem.tap.domain.twins.CreateSecondTwinWalletTask import com.tangem.tap.domain.twins.FinalizeTwinTask import com.tangem.tap.domain.visa.VisaCardScanHandler +import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.wallet.R import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlin.coroutines.resume -@Suppress("TooManyFunctions", "LargeClass") +@Suppress("TooManyFunctions", "LargeClass", "LongParameterList") internal class DefaultTangemSdkManager( private val cardSdkConfigRepository: CardSdkConfigRepository, private val resources: Resources, @@ -71,6 +81,11 @@ internal class DefaultTangemSdkManager( private val visaCardActivationTaskFactory: VisaCardActivationTask.Factory, private val tangemPayChallengeTaskFactory: TangemPayGenerateAddressAndSignChallengeTask.Factory, private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles, + private val uiMessageSender: UiMessageSender, + private val appFinisher: AppFinisher, + private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, + private val analyticsExceptionHandler: AnalyticsExceptionHandler, + dispatchers: CoroutineDispatcherProvider, ) : TangemSdkManager { private val awaitInitializationMutex = Mutex() @@ -99,6 +114,8 @@ internal class DefaultTangemSdkManager( override val userCodeRequestPolicy: UserCodeRequestPolicy get() = tangemSdk.config.userCodeRequestPolicy + private val coroutineScope = CoroutineScope(SupervisorJob() + dispatchers.io) + override suspend fun checkNeedEnrollBiometrics(awaitInitialization: Boolean): Boolean { return try { needEnrollBiometrics @@ -413,9 +430,16 @@ internal class DefaultTangemSdkManager( break } else { if (attemps++ >= MAX_INITIALIZE_ATTEMPTS) { - error("Can't initialize authentication manager after $MAX_INITIALIZE_ATTEMPTS attempts") + analyticsExceptionHandler.sendException( + ExceptionAnalyticsEvent( + exception = IllegalStateException( + "Can't initialize authentication manager after $MAX_INITIALIZE_ATTEMPTS attempts", + ), + ), + ) + showAlert() } else { - delay(timeMillis = 200) + delay(timeMillis = 400) } } } while (true) @@ -424,6 +448,28 @@ internal class DefaultTangemSdkManager( } } + private fun showAlert() { + uiMessageSender.send( + message = DialogMessage( + message = resourceReference(id = R.string.alert_authentication_error_message), + title = resourceReference(id = R.string.alert_authentication_error_title), + isDismissable = false, + dismissOnFirstAction = false, + firstActionBuilder = { + EventMessageAction( + title = resourceReference(R.string.alert_button_request_support), + onClick = { + coroutineScope.launch { + sendFeedbackEmailUseCase(FeedbackEmailType.BiometricsAuthenticationFailed) + } + }, + ) + }, + secondActionBuilder = { cancelAction(onClick = appFinisher::finish) }, + ), + ) + } + // region Twin-specific override suspend fun createFirstTwinWallet( diff --git a/core/res/src/main/res/values-de/strings.xml b/core/res/src/main/res/values-de/strings.xml index 4175f06e1c..ab28c8f601 100644 --- a/core/res/src/main/res/values-de/strings.xml +++ b/core/res/src/main/res/values-de/strings.xml @@ -86,6 +86,8 @@ Sende nur %1$s ( %2$s ) vom %3$s -Netzwerk an diese Adresse. Die Verwendung anderer Token und Netzwerke kann zum Verlust von Geldern führen. Standard Altbestand + Bei der biometrischen Authentifizierung ist ein Fehler aufgetreten. Bitte setzen Sie die Biometrie auf Ihrem Gerät zurück oder kontaktieren Sie den Support. + Authentifizierungsfehler So scannt man Hilfe anfordern Erneut versuchen @@ -299,6 +301,7 @@ Zum Token Verstanden Ausblenden + Halten bis %s Stunde Importieren In Arbeit @@ -374,6 +377,7 @@ Tauschen Tangem Tangem Wallet + Tippen und halten Allgemeine Geschäftsbedingungen Nutzungsbedingungen An @@ -463,6 +467,11 @@ Das Senden von Vermögenswerten in anderen Netzwerken führt zu dauerhaftem Verlust. %s Netzwerk Sende Geld nur mit + Beste Gelegenheiten + Alle Netzwerke + Alle Arten + Meist verwendet + Verdienen Hallo Support-Team, ich habe einen Fehler mit dem Code %s festgestellt. WalletConnect-Fehler Du hast eine Karte oder Ring aus einer anderen Wallet verwendet. Tippe auf die Karte oder Ring, die dieser Wallet zugeordnet ist. @@ -613,6 +622,7 @@ Zuerst die Sicherung abschließen Unvollständig Andere Methoden + Bewahre Deine Wiederherstellungsphrase an einem sicheren Ort auf und halte diese geheim, um Dein Guthaben zu schützen. Richte außerdem einen 8 stelligen Zugangscode für zusätzliche Sicherheit ein. Speicher Deinen Wiederherstellungssatz an einem sicheren Ort und halte diesen stets geheim, um Dein Geld zu schützen. Wiederherstellungs-Phrase Um Deine Wallet mit einem Zugangscode zu sichern, schließe den Sicherungsvorgang ab. @@ -1463,6 +1473,9 @@ Einfrieren Ihre Karte ist eingefroren. Hilfe erhalten + Grund: %s + %s · %s + MCC %s Andere Nicht nutzbar auf gerooteten Geräten Abgeschlossen @@ -1834,7 +1847,18 @@ OK, habe ich verstanden! Echt toll! Aktualisieren + Migration starten + Kopie + Um weiterhin Zugriff auf Deine Gelder zu haben, beginne die Migration gemäß den offiziellen Clore-Richtlinien. + Die Nachrichtensignatur wird für dieses Netzwerk nicht unterstützt. + Nachricht konnte nicht signiert werden. Bitte versuche es erneut. Laut der offiziellen Dokumentation von Clore werden alle Münzen, die vor dem 21. Dezember erhalten wurden, in Clore (ERC-20 Token) migriert; Münzen, die nach diesem Datum erhalten wurden, nicht. Eine Lösung für den Transfer ist in Arbeit — bleibt dran. + Nachricht + Claim-Portal öffnen + Um Deine Clore-Token weiterhin nutzen zu können, musst Du die Token-Migration gemäß den Informationen im Claim Portal durchführen. + Clore-Netzwerkmigration + signieren + Unterschrift Migration des Clore-Netzwerks Du befindest sich derzeit im Demo-Modus Demo-Modus aktiv diff --git a/core/res/src/main/res/values-es/strings.xml b/core/res/src/main/res/values-es/strings.xml index c3b8bb8a6a..4e0238e409 100644 --- a/core/res/src/main/res/values-es/strings.xml +++ b/core/res/src/main/res/values-es/strings.xml @@ -86,6 +86,8 @@ Envíe solo %1$s (%2$s) desde redes como %3$s a esta dirección. Usar otros tokens y redes puede resultar en la pérdida de fondos. Por defecto Legacy + Algo salió mal con la biometría. Por favor, intente restablecer la biometría en su dispositivo o contacte con soporte. + Error de inicio de sesión Cómo escanear Solicitar soporte Inténtelo de nuevo @@ -836,7 +838,7 @@ Hace %d minutos Resumen rápido - Noticias relacionadas + Noticias Tokens relacionados Fuentes Manténgase informado diff --git a/core/res/src/main/res/values-fr/strings.xml b/core/res/src/main/res/values-fr/strings.xml index d88cdd4e57..7eda943c3f 100644 --- a/core/res/src/main/res/values-fr/strings.xml +++ b/core/res/src/main/res/values-fr/strings.xml @@ -86,6 +86,8 @@ Envoyez uniquement %1$s (%2$s) depuis les réseaux %3$s à cette adresse. L\'utilisation d\'autres jetons et réseaux peut entraîner une perte de fonds. Défaut Héritage + Quelque chose s’est mal passé avec la biométrie. Veuillez réinitialiser la biométrie sur votre appareil ou contacter le support. + Erreur d’authentification Comment scanner Demander de l\'aide Réessayez @@ -1845,7 +1847,17 @@ Ok, compris! Vraiment cool ! Rafraîchir + Lancer la migration + Copier + La signature des messages n\'est pas prise en charge pour ce réseau. + Impossible de signer le message. Veuillez réessayer. Selon la documentation officielle de Clore, toutes les pièces reçues avant le 21 décembre seront migrées vers Clore (token ERC-20) ; les pièces reçues après cette date ne le seront pas. Une solution de transfert arrive — restez à l\'écoute. + Message + Ouvrir le portail des réclamations + Pour continuer à utiliser vos jetons Clore, vous devez effectuer la migration des jetons conformément aux informations fournies sur le portail de réclamation. + Migration du réseau Clore + Signer + Signature Migration du réseau Clore Vous êtes actuellement en mode démo Mode démo actif diff --git a/core/res/src/main/res/values-ja/strings.xml b/core/res/src/main/res/values-ja/strings.xml index 770eb98276..c773a24141 100644 --- a/core/res/src/main/res/values-ja/strings.xml +++ b/core/res/src/main/res/values-ja/strings.xml @@ -86,6 +86,8 @@ このアドレスには%3$s ネットワークから%1$s (%2$s) のみを送信してください。他のトークンやネットワークを使用すると、資金を失う可能性があります。 デフォルト レガシー + デバイスの生体認証をリセットするか、サポートにお問い合わせください + 認証エラー スキャン方法 サポートをリクエストする もう一度やり直してください @@ -523,7 +525,7 @@ プロバイダー ベストレート FCA警告リスト - 最適な選択 + お得なレート FCA警告リストに掲載されたプロバイダー 最大 %s まで使用可能 %s 以上で利用可能 @@ -724,7 +726,7 @@ データなし マーケット動向 クイックアクション - マーケットから探す + トークンを探す 結果 時価総額10万ドル以下のトークンを見る トークンを表示 @@ -741,8 +743,8 @@ 経験豊富な買い手 時価総額 並べ替え - 上昇率上位 - 下落率上位 + 値上がり + 値下がり トレンド 利息モード ステーキングは暗号資産で報酬を受け取る最も簡単な方法です。 %s @@ -770,7 +772,7 @@ 取引所 経験豊富な買い手 少なくとも100の発信取引を持つネット・バイヤー - 経験豊富な買い手 + アクティブ投資家数 完全希薄化後評価額 現在流通していないものも含め、存在する可能性のあるすべてのコインが流通している場合の暗号資産の理論上の合計価値 完全希薄化後評価額 @@ -895,7 +897,7 @@ 事前申し込み受付中。他にない特別なカードを、いち早く体験しよう。 Tangem Visaカード 利用規約 - 100ドル以上を入金し、30日間保持すると、10ドルを受け取れます。 + $100以上を入金して30日間保有すると、$10を受け取れます Yield Mode キャンペーンに参加しよう! すべてのデバイスを保護するには、単一のアクセスコードを設定してください。 保護する @@ -1011,7 +1013,7 @@ 買付金額は%s以下にしてください 買付金額は少なくとも%sである必要があります この通貨で利用可能なプロバイダーはありません - 最速 + 最短処理 支払う 支払方法 最大 %s まで使用可能 @@ -1598,7 +1600,7 @@ このトークンは、2月%2$s-%3$s の間、%1$s のサービス手数料で別のトークンと交換できます。 Changellyでスワップ、手数料%s 今すぐスワップ - ホットな暗号資産🔥 + 市場トレンド🔥 買付できません 売却できません %sからのスワップは利用できません @@ -1825,7 +1827,18 @@ はい、わかりました! すごくクールだ! リフレッシュ + 移行を開始 + コピー + 資金へのアクセスを維持するため、Cloreの公式ガイドラインに従って移行を開始してください。 + このネットワークではメッセージ署名はサポートされていません + メッセージに署名できません。もう一度お試しください。 Cloreの公式ドキュメントによると、12月21日以前に受け取ったすべてのコインは Clore(ERC-20トークン)へ移行されますが、同日以降に受け取ったコインは移行されません。送金(移行)ソリューションは現在準備中です。続報をお待ちください。 + メッセージ + Claim Portalを開く + Cloreトークンを引き続き使用するには、Claim Portalの案内に従ってトークン移行を完了する必要があります。 + Cloreネットワーク移行 + 署名する + 署名 Cloreネットワークの移行 現在デモモードです デモモードが有効になっています diff --git a/core/res/src/main/res/values-ru/strings.xml b/core/res/src/main/res/values-ru/strings.xml index b0e42bdf47..cc50a2188a 100644 --- a/core/res/src/main/res/values-ru/strings.xml +++ b/core/res/src/main/res/values-ru/strings.xml @@ -86,6 +86,8 @@ Отправляйте только %1$s (%2$s) в сети %3$s на этот адрес. Использование другой сети может привести к утрате средств. По умолчанию Устаревший + Произошла ошибка при работе с биометрией. Пожалуйста, попробуйте обновить биометрию на вашем устройстве или обратитесь в службу поддержки. + Ошибка аутентификации Как сканировать Обратиться в поддержку Попробовать снова @@ -476,6 +478,9 @@ Отправка средств в другой сети может повлечь потерю средств. %s сеть Отправляйте средства, используя только + Все сети + Все типы + Часто используемые Привет, команда поддержки, у меня возникла ошибка с кодом: %s Ошибка WalletConnect Вы использовали карту или кольцо от другого кошелька. Приложите карту или кольцо, связанную с этим кошельком. @@ -850,7 +855,7 @@ %dмин назад Резюме - Связанные новости + Новости Связанные токены Связанные новости Будьте в курсе diff --git a/core/res/src/main/res/values-uk-rUA/strings.xml b/core/res/src/main/res/values-uk-rUA/strings.xml index 67360c1ce3..4bb916c300 100644 --- a/core/res/src/main/res/values-uk-rUA/strings.xml +++ b/core/res/src/main/res/values-uk-rUA/strings.xml @@ -86,6 +86,8 @@ Надсилайте тільки %1$s (%2$s) в мережі %3$s на цю адресу. Використання іншої мережі може призвести до втрати коштів. За замовчуванням Застарілий + Сталася помилка під час роботи з біометрією. Будь ласка, спробуйте оновити біометрію на вашому пристрої або зверніться до служби підтримки. + Помилка автентифікації Як сканувати Звернутися в підтримку Спробуйте ще раз diff --git a/core/res/src/main/res/values/strings.xml b/core/res/src/main/res/values/strings.xml index ed8c132108..8916a5a857 100644 --- a/core/res/src/main/res/values/strings.xml +++ b/core/res/src/main/res/values/strings.xml @@ -86,7 +86,7 @@ Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds. Default Legacy - Try to reset biometrics on your device or contact support + Something went wrong with biometrics. Please try resetting biometrics on your device or contact support. Authentication error How to scan Request support @@ -468,9 +468,13 @@ %s network Send funds using only Best opportunities + Clear filter All networks All types + Filter by + Networks Mostly used + No results Earn Hi support team, I\'ve encountered an error with code: %s WalletConnect error @@ -839,7 +843,7 @@ %d minutes ago Quick recap - Related News + News Related tokens Related news Stay in the loop diff --git a/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt b/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt index 520f49e395..e52c876c09 100644 --- a/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt +++ b/domain/feedback/models/src/main/kotlin/com/tangem/domain/feedback/models/FeedbackEmailType.kt @@ -56,6 +56,10 @@ sealed interface FeedbackEmailType { override val walletMetaInfo: WalletMetaInfo? = null } + data object BiometricsAuthenticationFailed : FeedbackEmailType { + override val walletMetaInfo: WalletMetaInfo? = null + } + sealed class Visa : FeedbackEmailType { data class DirectUserRequest(override val walletMetaInfo: WalletMetaInfo) : Visa() diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt index 07e0eb137e..3289cba524 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/SendFeedbackEmailUseCase.kt @@ -92,6 +92,7 @@ class SendFeedbackEmailUseCase( is FeedbackEmailType.CurrencyDescriptionError, is FeedbackEmailType.PreActivatedWallet, is FeedbackEmailType.CardAttestationFailed, + is FeedbackEmailType.BiometricsAuthenticationFailed, is FeedbackEmailType.Visa.Dispute, is FeedbackEmailType.Visa.DisputeV2, is FeedbackEmailType.Visa.FeatureIsBeta, diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt index 1e4ca44bd2..4533c06c96 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageBodyResolver.kt @@ -30,6 +30,7 @@ internal class EmailMessageBodyResolver( is FeedbackEmailType.PreActivatedWallet -> addUserRequestBody(type.walletMetaInfo) is FeedbackEmailType.ScanningProblem, is FeedbackEmailType.CardAttestationFailed, + is FeedbackEmailType.BiometricsAuthenticationFailed, -> addPhoneInfoBody() is FeedbackEmailType.Visa.Activation -> addUserRequestBody(type.walletMetaInfo) is FeedbackEmailType.Visa.DirectUserRequest -> addUserRequestBody(type.walletMetaInfo) diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt index 36940c948e..852e933644 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailMessageTitleResolver.kt @@ -34,6 +34,7 @@ internal class EmailMessageTitleResolver(private val resources: Resources) { is FeedbackEmailType.TransactionSendingProblem, is FeedbackEmailType.StakingProblem, is FeedbackEmailType.SwapProblem, + is FeedbackEmailType.BiometricsAuthenticationFailed, -> R.string.feedback_preface_tx_failed } diff --git a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt index 4b1e4f9799..39f92cf852 100644 --- a/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt +++ b/domain/feedback/src/main/java/com/tangem/domain/feedback/utils/EmailSubjectResolver.kt @@ -38,6 +38,7 @@ internal class EmailSubjectResolver(private val resources: Resources) { resources.getStringSafe(R.string.feedback_token_description_error) } FeedbackEmailType.CardAttestationFailed -> "Card attestation failed" + FeedbackEmailType.BiometricsAuthenticationFailed -> "Biometrics authentication failed" is FeedbackEmailType.Visa.Activation -> "[Visa] [Activation] {auto-filled subject}" is FeedbackEmailType.Visa.DirectUserRequest -> "[Visa] {auto-filled subject}" is FeedbackEmailType.Visa.FailedIssueCard -> "[Visa] {auto-filled subject}" From 2bba23e1a9fa085213e83d85f60eb4b2296e169f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 Feb 2026 15:19:27 +0300 Subject: [PATCH 3/7] Updated on 2026-08-14 --- .../wallets/usecase/GetSavedWalletsCountUseCase.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetSavedWalletsCountUseCase.kt b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetSavedWalletsCountUseCase.kt index 2784698845..eb6257bd8c 100644 --- a/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetSavedWalletsCountUseCase.kt +++ b/domain/wallets/src/main/java/com/tangem/domain/wallets/usecase/GetSavedWalletsCountUseCase.kt @@ -5,9 +5,12 @@ import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.asLockable import com.tangem.domain.wallets.legacy.isLockedSync +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map class GetSavedWalletsCountUseCase( @@ -16,9 +19,14 @@ class GetSavedWalletsCountUseCase( private val useNewRepository: Boolean, ) { + @OptIn(ExperimentalCoroutinesApi::class) operator fun invoke(): Flow> { if (useNewRepository) { - return userWalletsListRepository.userWallets.map { requireNotNull(it) } + return flowOf(Unit) + .flatMapLatest { + userWalletsListRepository.load() + userWalletsListRepository.userWallets.map { wallets -> requireNotNull(wallets) } + } } return userWalletsListManager.savedWalletsCount From 295d82db8de7b26c5bd5a94502e9c6bfee42ea44 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 Feb 2026 15:23:30 +0300 Subject: [PATCH 4/7] Updated on 2026-08-14 --- app/src/main/assets/tangem-app-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 098662beb5..a5d1a89425 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 098662beb5b0123b11f5ee4873d4bd667ac93c73 +Subproject commit a5d1a89425a95bc9c90c7a6fed3c578b0d324994 From 92b2c145853085246f0e297dde85483d2100c212 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 3 Feb 2026 18:03:32 +0400 Subject: [PATCH 5/7] Updated on 2026-08-14 --- .../java/com/tangem/core/analytics/models/AnalyticsParam.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index ff196b2f0e..287b8a9170 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -278,5 +278,5 @@ sealed class AnalyticsParam { fun getReferralParams(referralId: String?): List> = listOf( REFERRAL to (!referralId.isNullOrBlank()).toString().replaceFirstChar(Char::titlecase), - REFERRAL_ID to (referralId ?: "None"), + REFERRAL_ID to (referralId ?: "Empty"), ) \ No newline at end of file From 45688033c699115c41bf721dbb2fa4e09c729638 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 4 Feb 2026 07:54:30 +0300 Subject: [PATCH 6/7] Updated on 2026-08-14 --- .../models/event/OnboardingAnalyticsEvent.kt | 3 +++ .../domain/card/analytics/IntroductionProcess.kt | 10 +++++++++- features/create-wallet-start/impl/build.gradle.kts | 1 + .../createwalletstart/CreateWalletStartModel.kt | 12 +++++++++--- .../im/port/model/AddExistingWalletImportModel.kt | 3 +++ .../createmobilewallet/CreateMobileWalletModel.kt | 3 +++ .../v2/common/analytics/OnboardingEvent.kt | 4 ++++ .../model/MultiWalletCreateWalletModel.kt | 5 ++++- .../seedphrase/model/MultiWalletSeedPhraseModel.kt | 3 +++ .../create/model/OnboardingNoteCreateWalletModel.kt | 3 +++ .../v2/twin/impl/model/OnboardingTwinModel.kt | 3 +++ 11 files changed, 45 insertions(+), 5 deletions(-) diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt index e449459d0e..6743eccfea 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/event/OnboardingAnalyticsEvent.kt @@ -3,6 +3,7 @@ package com.tangem.core.analytics.models.event import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.getReferralParams sealed class OnboardingAnalyticsEvent( category: String, @@ -55,6 +56,7 @@ sealed class OnboardingAnalyticsEvent( creationType: WalletCreationType = WalletCreationType.NewSeed, seedPhraseLength: Int? = null, passPhraseState: AnalyticsParam.EmptyFull, + referralId: String?, ) : CreateWallet( event = "Wallet Created Successfully", params = buildMap { @@ -64,6 +66,7 @@ sealed class OnboardingAnalyticsEvent( if (seedPhraseLength != null) { put("Seed Phrase Length", seedPhraseLength.toString()) } + putAll(getReferralParams(referralId)) }, ), AppsFlyerIncludedEvent diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt index b7151afd3d..98114357c7 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/analytics/IntroductionProcess.kt @@ -2,6 +2,7 @@ package com.tangem.domain.card.analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam +import com.tangem.core.analytics.models.getReferralParams sealed class IntroductionProcess( event: String, @@ -13,7 +14,14 @@ sealed class IntroductionProcess( class ButtonBuyCards : IntroductionProcess("Button - Buy Cards") class ButtonScanCardLegacy : IntroductionProcess("Button - Scan Card") - class CreateWalletIntroScreenOpened : IntroductionProcess("Create Wallet Intro Screen Opened") + class CreateWalletIntroScreenOpened( + referralId: String?, + ) : IntroductionProcess( + event = "Create Wallet Intro Screen Opened", + params = buildMap { + putAll(getReferralParams(referralId)) + }, + ) class ButtonScanCard( val source: AnalyticsParam.ScreensSources, diff --git a/features/create-wallet-start/impl/build.gradle.kts b/features/create-wallet-start/impl/build.gradle.kts index 987ab1a58b..1578c1916f 100644 --- a/features/create-wallet-start/impl/build.gradle.kts +++ b/features/create-wallet-start/impl/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation(projects.domain.wallets) implementation(projects.domain.models) implementation(projects.domain.hotWallet) + implementation(projects.domain.wallets.models) /** Core modules */ implementation(projects.core.configToggles) diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index 0760ef5917..9596dcee32 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -20,6 +20,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.dialog.Dialogs.hotWalletCreationNotSupportedDialog +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.card.ScanCardProcessor import com.tangem.domain.card.analytics.IntroductionProcess import com.tangem.domain.card.repository.CardSdkConfigRepository @@ -65,6 +66,7 @@ internal class CreateWalletStartModel @Inject constructor( private val trackingContextProxy: TrackingContextProxy, private val analyticsEventHandler: AnalyticsEventHandler, private val hotWalletFeatureToggles: HotWalletFeatureToggles, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -133,9 +135,13 @@ internal class CreateWalletStartModel @Inject constructor( ) init { - analyticsEventHandler.send( - event = IntroductionProcess.CreateWalletIntroScreenOpened(), - ) + modelScope.launch { + analyticsEventHandler.send( + event = IntroductionProcess.CreateWalletIntroScreenOpened( + referralId = appsFlyerStore.get()?.refcode, + ), + ) + } } private fun onScanClick() { diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/im/port/model/AddExistingWalletImportModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/im/port/model/AddExistingWalletImportModel.kt index 4245e9f79d..6b0489cab4 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/im/port/model/AddExistingWalletImportModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/addexistingwallet/im/port/model/AddExistingWalletImportModel.kt @@ -14,6 +14,7 @@ import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.crypto.bip39.Mnemonic +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.common.wallets.error.SaveWalletError import com.tangem.domain.wallets.builder.HotUserWalletBuilder import com.tangem.domain.wallets.usecase.SaveWalletUseCase @@ -41,6 +42,7 @@ internal class AddExistingWalletImportModel @Inject constructor( private val saveUserWalletUseCase: SaveWalletUseCase, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val analyticsEventHandler: AnalyticsEventHandler, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params: AddExistingWalletImportComponent.Params = paramsContainer.require() @@ -122,6 +124,7 @@ internal class AddExistingWalletImportModel @Inject constructor( } else { AnalyticsParam.EmptyFull.Full }, + referralId = appsFlyerStore.get()?.refcode, ), ) params.callbacks.onWalletImported(userWallet.walletId) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt index d268abddb8..dad097a1fb 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createmobilewallet/CreateMobileWalletModel.kt @@ -11,6 +11,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.message.dialog.Dialogs.hotWalletCreationNotSupportedDialog +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.hotwallet.IsHotWalletCreationSupported import com.tangem.domain.wallets.builder.HotUserWalletBuilder import com.tangem.domain.wallets.usecase.SaveWalletUseCase @@ -44,6 +45,7 @@ internal class CreateMobileWalletModel @Inject constructor( private val isHotWalletCreationSupported: IsHotWalletCreationSupported, private val uiMessageSender: UiMessageSender, private val analyticsEventHandler: AnalyticsEventHandler, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params: CreateMobileWalletComponent.Params = paramsContainer.require() @@ -100,6 +102,7 @@ internal class CreateMobileWalletModel @Inject constructor( creationType = OnboardingAnalyticsEvent.CreateWallet.WalletCreationType.NewSeed, seedPhraseLength = SEED_PHRASE_LENGTH, passPhraseState = AnalyticsParam.EmptyFull.Empty, + referralId = appsFlyerStore.get()?.refcode, ), ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt index b8ed2c5101..07da257630 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/common/analytics/OnboardingEvent.kt @@ -3,6 +3,8 @@ package com.tangem.features.onboarding.v2.common.analytics import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.analytics.models.AnalyticsParam import com.tangem.core.analytics.models.AppsFlyerIncludedEvent +import com.tangem.core.analytics.models.getReferralParams +import kotlin.collections.putAll sealed class OnboardingEvent( category: String, @@ -25,6 +27,7 @@ sealed class OnboardingEvent( creationType: WalletCreationType = WalletCreationType.PrivateKey, seedPhraseLength: Int? = null, passPhraseState: AnalyticsParam.EmptyFull, + referralId: String?, ) : CreateWallet( event = "Wallet Created Successfully", params = buildMap { @@ -33,6 +36,7 @@ sealed class OnboardingEvent( if (seedPhraseLength != null) { put("Seed Phrase Length", seedPhraseLength.toString()) } + putAll(getReferralParams(referralId)) }, ), AppsFlyerIncludedEvent diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt index 42d2db0372..d777faa37b 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/createwallet/model/MultiWalletCreateWalletModel.kt @@ -9,13 +9,14 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.extensions.resourceReference +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase import com.tangem.domain.feedback.models.FeedbackEmailType import com.tangem.domain.models.scan.ScanResponse -import com.tangem.domain.wallets.builder.ColdUserWalletBuilder import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.wallets.builder.ColdUserWalletBuilder import com.tangem.domain.wallets.usecase.SaveWalletUseCase import com.tangem.features.onboarding.v2.common.analytics.OnboardingEvent import com.tangem.features.onboarding.v2.impl.R @@ -45,6 +46,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor( private val analyticsHandler: AnalyticsEventHandler, private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, private val saveWalletUseCase: SaveWalletUseCase, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -109,6 +111,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor( analyticsHandler.send( event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully( passPhraseState = AnalyticsParam.EmptyFull.Empty, + referralId = appsFlyerStore.get()?.refcode, ), ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt index 3468f7a11c..fc3e5ad044 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/multiwallet/impl/child/seedphrase/model/MultiWalletSeedPhraseModel.kt @@ -18,6 +18,7 @@ import com.tangem.core.ui.R import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.message.SnackbarMessage import com.tangem.crypto.bip39.Mnemonic +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.feedback.GetWalletMetaInfoUseCase import com.tangem.domain.feedback.SendFeedbackEmailUseCase @@ -64,6 +65,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor( private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, @GlobalUiMessageSender private val uiMessageSender: UiMessageSender, private val analyticsEventHandler: AnalyticsEventHandler, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -248,6 +250,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor( } else { AnalyticsParam.EmptyFull.Full }, + referralId = appsFlyerStore.get()?.refcode, ), ) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/create/model/OnboardingNoteCreateWalletModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/create/model/OnboardingNoteCreateWalletModel.kt index b286fead4f..f083fdec7e 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/create/model/OnboardingNoteCreateWalletModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/note/impl/child/create/model/OnboardingNoteCreateWalletModel.kt @@ -7,6 +7,7 @@ import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.ui.components.artwork.ArtworkUM +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.domain.card.repository.CardRepository import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.builder.ColdUserWalletBuilder @@ -33,6 +34,7 @@ internal class OnboardingNoteCreateWalletModel @Inject constructor( private val coldUserWalletBuilderFactory: ColdUserWalletBuilder.Factory, private val saveWalletUseCase: SaveWalletUseCase, private val analyticsEventHandler: AnalyticsEventHandler, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -68,6 +70,7 @@ internal class OnboardingNoteCreateWalletModel @Inject constructor( analyticsEventHandler.send( event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully( passPhraseState = AnalyticsParam.EmptyFull.Empty, + referralId = appsFlyerStore.get()?.refcode, ), ) createWalletAndNavigateBackWithDone(scanResponse.copy(card = result.data.card)) diff --git a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/twin/impl/model/OnboardingTwinModel.kt b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/twin/impl/model/OnboardingTwinModel.kt index 79c8741734..2dbc11a45c 100644 --- a/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/twin/impl/model/OnboardingTwinModel.kt +++ b/features/onboarding-v2/impl/src/main/kotlin/com/tangem/features/onboarding/v2/twin/impl/model/OnboardingTwinModel.kt @@ -15,6 +15,7 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.toWrappedList +import com.tangem.datasource.local.appsflyer.AppsFlyerStore import com.tangem.datasource.local.config.issuers.IssuersConfigStorage import com.tangem.domain.card.common.TwinCardNumber import com.tangem.domain.card.common.getTwinCardNumber @@ -63,6 +64,7 @@ internal class OnboardingTwinModel @Inject constructor( private val cardRepository: CardRepository, private val uiMessageSender: UiMessageSender, private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase, + private val appsFlyerStore: AppsFlyerStore, ) : Model() { private val params = paramsContainer.require() @@ -174,6 +176,7 @@ internal class OnboardingTwinModel @Inject constructor( analyticsEventHandler.send( event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully( passPhraseState = AnalyticsParam.EmptyFull.Empty, + referralId = appsFlyerStore.get()?.refcode, ), ) From 1bfe32c03b0930378a98633260fbf95d75da3e7d Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 6 Feb 2026 09:14:47 +0000 Subject: [PATCH 7/7] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index d7281ac75f..2318c92aa6 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.32-1404" +tangemBlockchainSdk = "releases-5.33-1413" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.32-574" +tangemCardSdk = "releases-5.33-576" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^