Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-06 16:33:54 +07:00
commit eec7f2ffc0
35 changed files with 234 additions and 25 deletions

View file

@ -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,
)
}
}

View file

@ -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(

View file

@ -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
const val IS_NOT_HTTP_ERROR = "Is not http error"
sealed class AnalyticsParam {
@ -287,5 +290,12 @@ sealed class AnalyticsParam {
const val ACCOUNT_DERIVATION_TO = "Account Derivation (to)"
const val FEE_TOKEN = "Fee Token"
const val ACCOUNT_DERIVATION = "Account Derivation"
const val REFERRAL = "Referral"
const val REFERRAL_ID = "Referral_ID"
}
}
}
fun getReferralParams(referralId: String?): List<Pair<String, String>> = listOf(
REFERRAL to (!referralId.isNullOrBlank()).toString().replaceFirstChar(Char::titlecase),
REFERRAL_ID to (referralId ?: "Empty"),
)

View file

@ -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

View file

@ -86,6 +86,8 @@
<string name="address_qr_code_message_format">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.</string>
<string name="address_type_default">Standard</string>
<string name="address_type_legacy">Altbestand</string>
<string name="alert_authentication_error_message">Bei der biometrischen Authentifizierung ist ein Fehler aufgetreten. Bitte setzen Sie die Biometrie auf Ihrem Gerät zurück oder kontaktieren Sie den Support.</string>
<string name="alert_authentication_error_title">Authentifizierungsfehler</string>
<string name="alert_button_how_to_scan">So scannt man</string>
<string name="alert_button_request_support">Hilfe anfordern</string>
<string name="alert_button_try_again">Erneut versuchen</string>
@ -299,6 +301,7 @@
<string name="common_go_to_token">Zum Token</string>
<string name="common_got_it">Verstanden</string>
<string name="common_hide">Ausblenden</string>
<string name="common_hold_to">Halten bis %s</string>
<string name="common_hour">Stunde</string>
<string name="common_import">Importieren</string>
<string name="common_in_progress">In Arbeit</string>
@ -374,6 +377,7 @@
<string name="common_swap">Tauschen</string>
<string name="common_tangem">Tangem</string>
<string name="common_tangem_wallet">Tangem Wallet</string>
<string name="common_tap_and_hold_hint">Tippen und halten</string>
<string name="common_terms_and_conditions">Allgemeine Geschäftsbedingungen</string>
<string name="common_terms_of_use">Nutzungsbedingungen</string>
<string name="common_to">An</string>
@ -463,6 +467,11 @@
<string name="domain_receive_assets_onboarding_description">Das Senden von Vermögenswerten in anderen Netzwerken führt zu dauerhaftem Verlust.</string>
<string name="domain_receive_assets_onboarding_network_name">%s Netzwerk</string>
<string name="domain_receive_assets_onboarding_title">Sende Geld nur mit</string>
<string name="earn_best_opportunities">Beste Gelegenheiten</string>
<string name="earn_filter_all_networks">Alle Netzwerke</string>
<string name="earn_filter_all_types">Alle Arten</string>
<string name="earn_mostly_used">Meist verwendet</string>
<string name="earn_title">Verdienen</string>
<string name="email_preface_wc_error">Hallo Support-Team, ich habe einen Fehler mit dem Code %s festgestellt.</string>
<string name="email_subject_wc_error">WalletConnect-Fehler</string>
<string name="error_wrong_wallet_tapped">Du hast eine Karte oder Ring aus einer anderen Wallet verwendet. Tippe auf die Karte oder Ring, die dieser Wallet zugeordnet ist.</string>
@ -613,6 +622,7 @@
<string name="hw_backup_need_title">Zuerst die Sicherung abschließen</string>
<string name="hw_backup_no_backup">Unvollständig</string>
<string name="hw_backup_section_other_title">Andere Methoden</string>
<string name="hw_backup_seed_code_description">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.</string>
<string name="hw_backup_seed_description">Speicher Deinen Wiederherstellungssatz an einem sicheren Ort und halte diesen stets geheim, um Dein Geld zu schützen.</string>
<string name="hw_backup_seed_title">Wiederherstellungs-Phrase</string>
<string name="hw_backup_to_secure_description">Um Deine Wallet mit einem Zugangscode zu sichern, schließe den Sicherungsvorgang ab.</string>
@ -1463,6 +1473,9 @@
<string name="tangem_pay_freeze_card_freeze">Einfrieren</string>
<string name="tangem_pay_freeze_card_success">Ihre Karte ist eingefroren.</string>
<string name="tangem_pay_get_help">Hilfe erhalten</string>
<string name="tangem_pay_history_item_spend_mc_declined_reason">Grund: %s</string>
<string name="tangem_pay_history_item_spend_mc_title_format" formatted="false">%s · %s</string>
<string name="tangem_pay_history_item_spend_mcc">MCC %s</string>
<string name="tangem_pay_other">Andere</string>
<string name="tangem_pay_rooted_device_subtitle">Nicht nutzbar auf gerooteten Geräten</string>
<string name="tangem_pay_status_completed">Abgeschlossen</string>
@ -1834,7 +1847,18 @@
<string name="warning_button_ok">OK, habe ich verstanden!</string>
<string name="warning_button_really_cool">Echt toll!</string>
<string name="warning_button_refresh">Aktualisieren</string>
<string name="warning_clore_migration_button">Migration starten</string>
<string name="warning_clore_migration_copy_button">Kopie</string>
<string name="warning_clore_migration_description">Um weiterhin Zugriff auf Deine Gelder zu haben, beginne die Migration gemäß den offiziellen Clore-Richtlinien.</string>
<string name="warning_clore_migration_error_signing_not_supported">Die Nachrichtensignatur wird für dieses Netzwerk nicht unterstützt.</string>
<string name="warning_clore_migration_error_wallet_manager_not_found">Nachricht konnte nicht signiert werden. Bitte versuche es erneut.</string>
<string name="warning_clore_migration_message">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.</string>
<string name="warning_clore_migration_message_label">Nachricht</string>
<string name="warning_clore_migration_open_portal_button">Claim-Portal öffnen</string>
<string name="warning_clore_migration_sheet_description">Um Deine Clore-Token weiterhin nutzen zu können, musst Du die Token-Migration gemäß den Informationen im Claim Portal durchführen.</string>
<string name="warning_clore_migration_sheet_title">Clore-Netzwerkmigration</string>
<string name="warning_clore_migration_sign_button">signieren</string>
<string name="warning_clore_migration_signature_label">Unterschrift</string>
<string name="warning_clore_migration_title">Migration des Clore-Netzwerks</string>
<string name="warning_demo_mode_message">Du befindest sich derzeit im Demo-Modus</string>
<string name="warning_demo_mode_title">Demo-Modus aktiv</string>

View file

@ -86,6 +86,8 @@
<string name="address_qr_code_message_format">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.</string>
<string name="address_type_default">Por defecto</string>
<string name="address_type_legacy">Legacy</string>
<string name="alert_authentication_error_message">Algo salió mal con la biometría. Por favor, intente restablecer la biometría en su dispositivo o contacte con soporte.</string>
<string name="alert_authentication_error_title">Error de inicio de sesión</string>
<string name="alert_button_how_to_scan">Cómo escanear</string>
<string name="alert_button_request_support">Solicitar soporte</string>
<string name="alert_button_try_again">Inténtelo de nuevo</string>

View file

@ -86,6 +86,8 @@
<string name="address_qr_code_message_format">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.</string>
<string name="address_type_default">Défaut</string>
<string name="address_type_legacy">Héritage</string>
<string name="alert_authentication_error_message">Quelque chose sest mal passé avec la biométrie. Veuillez réinitialiser la biométrie sur votre appareil ou contacter le support.</string>
<string name="alert_authentication_error_title">Erreur dauthentification</string>
<string name="alert_button_how_to_scan">Comment scanner</string>
<string name="alert_button_request_support">Demander de l\'aide</string>
<string name="alert_button_try_again">Réessayez</string>
@ -1845,7 +1847,17 @@
<string name="warning_button_ok">Ok, compris!</string>
<string name="warning_button_really_cool">Vraiment cool !</string>
<string name="warning_button_refresh">Rafraîchir</string>
<string name="warning_clore_migration_button">Lancer la migration</string>
<string name="warning_clore_migration_copy_button">Copier</string>
<string name="warning_clore_migration_error_signing_not_supported">La signature des messages n\'est pas prise en charge pour ce réseau.</string>
<string name="warning_clore_migration_error_wallet_manager_not_found">Impossible de signer le message. Veuillez réessayer.</string>
<string name="warning_clore_migration_message">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.</string>
<string name="warning_clore_migration_message_label">Message</string>
<string name="warning_clore_migration_open_portal_button">Ouvrir le portail des réclamations</string>
<string name="warning_clore_migration_sheet_description">Pour continuer à utiliser vos jetons Clore, vous devez effectuer la migration des jetons conformément aux informations fournies sur le portail de réclamation.</string>
<string name="warning_clore_migration_sheet_title">Migration du réseau Clore</string>
<string name="warning_clore_migration_sign_button">Signer</string>
<string name="warning_clore_migration_signature_label">Signature</string>
<string name="warning_clore_migration_title">Migration du réseau Clore</string>
<string name="warning_demo_mode_message">Vous êtes actuellement en mode démo</string>
<string name="warning_demo_mode_title">Mode démo actif</string>

View file

@ -86,6 +86,8 @@
<string name="address_qr_code_message_format">このアドレスには%3$s ネットワークから%1$s (%2$s) のみを送信してください。他のトークンやネットワークを使用すると、資金を失う可能性があります。</string>
<string name="address_type_default">デフォルト</string>
<string name="address_type_legacy">レガシー</string>
<string name="alert_authentication_error_message">デバイスの生体認証をリセットするか、サポートにお問い合わせください</string>
<string name="alert_authentication_error_title">認証エラー</string>
<string name="alert_button_how_to_scan">スキャン方法</string>
<string name="alert_button_request_support">サポートをリクエストする</string>
<string name="alert_button_try_again">もう一度やり直してください</string>
@ -523,7 +525,7 @@
<string name="express_provider">プロバイダー</string>
<string name="express_provider_best_rate">ベストレート</string>
<string name="express_provider_fca_warning_list">FCA警告リスト</string>
<string name="express_provider_great_rate">最適な選択</string>
<string name="express_provider_great_rate">お得なレート</string>
<string name="express_provider_in_fca_warning_list">FCA警告リストに掲載されたプロバイダー</string>
<string name="express_provider_max_amount">最大 %s まで使用可能</string>
<string name="express_provider_min_amount">%s 以上で利用可能</string>
@ -724,7 +726,7 @@
<string name="markets_loading_no_data_title">データなし</string>
<string name="markets_pulse_common_title">マーケット動向</string>
<string name="markets_quick_actions">クイックアクション</string>
<string name="markets_search_header_title">マーケットから探す</string>
<string name="markets_search_header_title">トークンを探す</string>
<string name="markets_search_result_title">結果</string>
<string name="markets_search_see_tokens_under_100k">時価総額10万ドル以下のトークンを見る</string>
<string name="markets_search_show_tokens">トークンを表示</string>
@ -741,8 +743,8 @@
<string name="markets_sort_by_experienced_buyers_title">経験豊富な買い手</string>
<string name="markets_sort_by_rating_title">時価総額</string>
<string name="markets_sort_by_title">並べ替え</string>
<string name="markets_sort_by_top_gainers_title">上昇率上位</string>
<string name="markets_sort_by_top_losers_title">下落率上位</string>
<string name="markets_sort_by_top_gainers_title">値上がり</string>
<string name="markets_sort_by_top_losers_title">値下がり</string>
<string name="markets_sort_by_trending_title">トレンド</string>
<string name="markets_sort_by_yield_mode_title">利息モード</string>
<string name="markets_staking_banner_description_placeholder">ステーキングは暗号資産で報酬を受け取る最も簡単な方法です。 %s</string>
@ -770,7 +772,7 @@
<string name="markets_token_details_exchanges_title">取引所</string>
<string name="markets_token_details_experienced_buyers">経験豊富な買い手</string>
<string name="markets_token_details_experienced_buyers_description">少なくとも100の発信取引を持つネット・バイヤー</string>
<string name="markets_token_details_experienced_buyers_full">経験豊富な買い手</string>
<string name="markets_token_details_experienced_buyers_full">アクティブ投資家数</string>
<string name="markets_token_details_fully_diluted_valuation">完全希薄化後評価額</string>
<string name="markets_token_details_fully_diluted_valuation_description">現在流通していないものも含め、存在する可能性のあるすべてのコインが流通している場合の暗号資産の理論上の合計価値</string>
<string name="markets_token_details_fully_diluted_valuation_full">完全希薄化後評価額</string>
@ -895,7 +897,7 @@
<string name="notification_visa_waitlist_promo_text">事前申し込み受付中。他にない特別なカードを、いち早く体験しよう。</string>
<string name="notification_visa_waitlist_promo_title">Tangem Visaカード</string>
<string name="notification_yield_promo_button">利用規約</string>
<string name="notification_yield_promo_text">100ドル以上を入金し、30日間保持すると、10ドルを受け取れます。</string>
<string name="notification_yield_promo_text">$100以上を入金して30日間保有すると、$10を受け取れます</string>
<string name="notification_yield_promo_title">Yield Mode キャンペーンに参加しよう!</string>
<string name="onboarding_access_code_feature_1_description">すべてのデバイスを保護するには、単一のアクセスコードを設定してください。</string>
<string name="onboarding_access_code_feature_1_title">保護する</string>
@ -1011,7 +1013,7 @@
<string name="onramp_max_amount_restriction">買付金額は%s以下にしてください</string>
<string name="onramp_min_amount_restriction">買付金額は少なくとも%sである必要があります</string>
<string name="onramp_no_available_providers">この通貨で利用可能なプロバイダーはありません</string>
<string name="onramp_offer_type_fastet"></string>
<string name="onramp_offer_type_fastet">短処理</string>
<string name="onramp_pay_with">支払う</string>
<string name="onramp_payment_method_subtitle">支払方法</string>
<string name="onramp_provider_max_amount">最大 %s まで使用可能</string>
@ -1598,7 +1600,7 @@
<string name="token_swap_changelly_promotion_message">このトークンは、2月%2$s-%3$s の間、%1$s のサービス手数料で別のトークンと交換できます。</string>
<string name="token_swap_changelly_promotion_title">Changellyでスワップ、手数料%s</string>
<string name="token_swap_promotion_button">今すぐスワップ</string>
<string name="tokens_list_hot_crypto_header">ホットな暗号資産🔥</string>
<string name="tokens_list_hot_crypto_header">市場トレンド🔥</string>
<string name="tokens_list_unavailable_to_purchase_header">買付できません</string>
<string name="tokens_list_unavailable_to_sell_header">売却できません</string>
<string name="tokens_list_unavailable_to_swap_header">%sからのスワップは利用できません</string>
@ -1825,7 +1827,18 @@
<string name="warning_button_ok">はい、わかりました!</string>
<string name="warning_button_really_cool">すごくクールだ!</string>
<string name="warning_button_refresh">リフレッシュ</string>
<string name="warning_clore_migration_button">移行を開始</string>
<string name="warning_clore_migration_copy_button">コピー</string>
<string name="warning_clore_migration_description">資金へのアクセスを維持するため、Cloreの公式ガイドラインに従って移行を開始してください。</string>
<string name="warning_clore_migration_error_signing_not_supported">このネットワークではメッセージ署名はサポートされていません</string>
<string name="warning_clore_migration_error_wallet_manager_not_found">メッセージに署名できません。もう一度お試しください。</string>
<string name="warning_clore_migration_message">Cloreの公式ドキュメントによると、12月21日以前に受け取ったすべてのコインは CloreERC-20トークンへ移行されますが、同日以降に受け取ったコインは移行されません。送金移行ソリューションは現在準備中です。続報をお待ちください。</string>
<string name="warning_clore_migration_message_label">メッセージ</string>
<string name="warning_clore_migration_open_portal_button">Claim Portalを開く</string>
<string name="warning_clore_migration_sheet_description">Cloreトークンを引き続き使用するには、Claim Portalの案内に従ってトークン移行を完了する必要があります。</string>
<string name="warning_clore_migration_sheet_title">Cloreネットワーク移行</string>
<string name="warning_clore_migration_sign_button">署名する</string>
<string name="warning_clore_migration_signature_label">署名</string>
<string name="warning_clore_migration_title">Cloreネットワークの移行</string>
<string name="warning_demo_mode_message">現在デモモードです</string>
<string name="warning_demo_mode_title">デモモードが有効になっています</string>

View file

@ -86,6 +86,8 @@
<string name="address_qr_code_message_format">Отправляйте только %1$s (%2$s) в сети %3$s на этот адрес. Использование другой сети может привести к утрате средств.</string>
<string name="address_type_default">По умолчанию</string>
<string name="address_type_legacy">Устаревший</string>
<string name="alert_authentication_error_message">Произошла ошибка при работе с биометрией. Пожалуйста, попробуйте обновить биометрию на вашем устройстве или обратитесь в службу поддержки.</string>
<string name="alert_authentication_error_title">Ошибка аутентификации</string>
<string name="alert_button_how_to_scan">Как сканировать</string>
<string name="alert_button_request_support">Обратиться в поддержку</string>
<string name="alert_button_try_again">Попробовать снова</string>
@ -476,6 +478,9 @@
<string name="domain_receive_assets_onboarding_description">Отправка средств в другой сети может повлечь потерю средств.</string>
<string name="domain_receive_assets_onboarding_network_name">%s сеть</string>
<string name="domain_receive_assets_onboarding_title">Отправляйте средства, используя только</string>
<string name="earn_filter_all_networks">Все сети</string>
<string name="earn_filter_all_types">Все типы</string>
<string name="earn_mostly_used">Часто используемые</string>
<string name="email_preface_wc_error">Привет, команда поддержки, у меня возникла ошибка с кодом: %s</string>
<string name="email_subject_wc_error">Ошибка WalletConnect</string>
<string name="error_wrong_wallet_tapped">Вы использовали карту или кольцо от другого кошелька. Приложите карту или кольцо, связанную с этим кошельком.</string>

View file

@ -86,7 +86,7 @@
<string name="address_qr_code_message_format">Send only %1$s (%2$s) from %3$s network to this address. Using other tokens and networks may result in loss of funds.</string>
<string name="address_type_default">Default</string>
<string name="address_type_legacy">Legacy</string>
<string name="alert_authentication_error_message">Try to reset biometrics on your device or contact support</string>
<string name="alert_authentication_error_message">Something went wrong with biometrics. Please try resetting biometrics on your device or contact support.</string>
<string name="alert_authentication_error_title">Authentication error</string>
<string name="alert_button_how_to_scan">How to scan</string>
<string name="alert_button_request_support">Request support</string>
@ -468,9 +468,13 @@
<string name="domain_receive_assets_onboarding_network_name">%s network</string>
<string name="domain_receive_assets_onboarding_title">Send funds using only</string>
<string name="earn_best_opportunities">Best opportunities</string>
<string name="earn_clear_filter">Clear filter</string>
<string name="earn_filter_all_networks">All networks</string>
<string name="earn_filter_all_types">All types</string>
<string name="earn_filter_by">Filter by</string>
<string name="earn_filter_networks">Networks</string>
<string name="earn_mostly_used">Mostly used</string>
<string name="earn_no_results">No results</string>
<string name="earn_title">Earn</string>
<string name="email_preface_wc_error">Hi support team, I\'ve encountered an error with code: %s</string>
<string name="email_subject_wc_error">WalletConnect error</string>

View file

@ -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,

View file

@ -59,6 +59,10 @@ sealed interface FeedbackEmailType {
override val walletMetaInfo: WalletMetaInfo? = null
}
data object BiometricsAuthenticationFailed : FeedbackEmailType {
override val walletMetaInfo: WalletMetaInfo? = null
}
sealed class Visa : FeedbackEmailType {
abstract val customerId: String

View file

@ -93,6 +93,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,

View file

@ -31,6 +31,7 @@ class EmailMessageBodyResolver(
is FeedbackEmailType.BackupProblem -> 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)

View file

@ -36,6 +36,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
}

View file

@ -39,6 +39,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}"

View file

@ -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<List<UserWallet>> {
if (useNewRepository) {
return userWalletsListRepository.userWallets.map { requireNotNull(it) }
return flowOf(Unit)
.flatMapLatest {
userWalletsListRepository.load()
userWalletsListRepository.userWallets.map { wallets -> requireNotNull(wallets) }
}
}
return userWalletsListManager.savedWalletsCount

View file

@ -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)

View file

@ -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<CreateWalletStartComponent.Params>()
@ -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() {

View file

@ -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)

View file

@ -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,
),
)

View file

@ -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

View file

@ -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<MultiWalletChildParams>()
@ -109,6 +111,7 @@ internal class MultiWalletCreateWalletModel @Inject constructor(
analyticsHandler.send(
event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,
),
)

View file

@ -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<MultiWalletChildParams>()
@ -248,6 +250,7 @@ internal class MultiWalletSeedPhraseModel @Inject constructor(
} else {
AnalyticsParam.EmptyFull.Full
},
referralId = appsFlyerStore.get()?.refcode,
),
)

View file

@ -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<OnboardingNoteCreateWalletComponent.Params>()
@ -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))

View file

@ -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<OnboardingTwinComponent.Params>()
@ -174,6 +176,7 @@ internal class OnboardingTwinModel @Inject constructor(
analyticsEventHandler.send(
event = OnboardingEvent.CreateWallet.WalletCreatedSuccessfully(
passPhraseState = AnalyticsParam.EmptyFull.Empty,
referralId = appsFlyerStore.get()?.refcode,
),
)

View file

@ -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)

View file

@ -13,6 +13,7 @@ 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.AnalyticsParam.Key.TOKEN_PARAM
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
@ -98,6 +99,7 @@ sealed class SwapEvents(
val feeToken: String,
val fromDerivationIndex: Int?,
val toDerivationIndex: Int?,
val referralId: String?,
) : SwapEvents(
event = "Swap in Progress Screen Opened",
params = buildMap {
@ -110,6 +112,7 @@ sealed class SwapEvents(
if (fromDerivationIndex != null) put(ACCOUNT_DERIVATION_FROM, fromDerivationIndex.toString())
if (toDerivationIndex != null) put(ACCOUNT_DERIVATION_TO, toDerivationIndex.toString())
put(FEE_TOKEN, feeToken)
putAll(getReferralParams(referralId))
},
), AppsFlyerIncludedEvent

View file

@ -26,6 +26,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
@ -158,6 +159,7 @@ internal class SwapModel @Inject constructor(
private val excludedBlockchains: ExcludedBlockchains,
private val getUserWalletsUseCase: GetWalletsUseCase,
private val getTangemPayCustomerIdUseCase: GetTangemPayCustomerIdUseCase,
private val appsFlyerStore: AppsFlyerStore,
) : Model() {
private val params = paramsContainer.require<SwapComponent.Params>()
@ -1108,7 +1110,7 @@ internal class SwapModel @Inject constructor(
}
}
private fun sendSuccessEvent() {
private suspend fun sendSuccessEvent() {
val provider = dataState.selectedProvider ?: return
val fee = (getSelectedFee() as? TxFee.Legacy)?.feeType ?: FeeType.NORMAL
val fromCurrency = dataState.fromCryptoCurrency?.currency ?: return
@ -1127,6 +1129,7 @@ internal class SwapModel @Inject constructor(
feeToken = getFeeToken().symbol,
fromDerivationIndex = fromDerivationIndex,
toDerivationIndex = toDerivationIndex,
referralId = appsFlyerStore.get()?.refcode,
),
)
}

View file

@ -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
@ -104,6 +105,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() {
@ -234,6 +236,7 @@ internal class WalletModel @Inject constructor(
accountsCount = accountsCount,
theme = theme.value,
isImported = selectedWallet.isImported(),
referralId = appsFlyerStore.get()?.refcode,
),
)
}

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
@ -67,6 +68,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
private val yieldSupplyGetCurrentFeeUseCase: YieldSupplyGetCurrentFeeUseCase,
private val yieldSupplyRepository: YieldSupplyRepository,
private val yieldSupplyPendingTracker: YieldSupplyPendingTracker,
private val appsFlyerStore: AppsFlyerStore,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStartEarningComponent.Params = paramsContainer.require()
@ -274,6 +276,7 @@ internal class YieldSupplyStartEarningModel @Inject constructor(
YieldSupplyAnalytics.FundsEarned(
blockchain = cryptoCurrency.network.name,
token = cryptoCurrency.symbol,
referralId = appsFlyerStore.get()?.refcode,
),
)
yieldSupplyFeeUM.transactionDataList.forEach {

View file

@ -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
@ -64,6 +65,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
private val yieldSupplyDeactivateUseCase: YieldSupplyDeactivateUseCase,
private val yieldSupplyRepository: YieldSupplyRepository,
private val yieldSupplyPendingTracker: YieldSupplyPendingTracker,
private val appsFlyerStore: AppsFlyerStore,
) : Model(), YieldSupplyNotificationsComponent.ModelCallback {
private val params: YieldSupplyStopEarningComponent.Params = paramsContainer.require()
@ -164,7 +166,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
yieldSupplyAlertFactory.onFailedTxEmailClick(
userWallet = params.userWallet,
cryptoCurrency = cryptoCurrency,
errorMessage = error.toString(),
errorMessage = errorMessage,
)
}
},
@ -188,6 +190,7 @@ internal class YieldSupplyStopEarningModel @Inject constructor(
YieldSupplyAnalytics.FundsWithdrawn(
token = cryptoCurrency.symbol,
blockchain = cryptoCurrency.network.name,
referralId = appsFlyerStore.get()?.refcode,
),
)
val event = AnalyticsParam.TxSentFrom.Earning(