Updated on 2026-08-14

This commit is contained in:
Tangem 2025-01-21 13:32:44 +03:00
parent 780686645b
commit 5b841dbac5
13 changed files with 235 additions and 54 deletions

View file

@ -8,6 +8,8 @@ import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.filter.OneTimeEventFilter
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
@ -134,4 +136,7 @@ interface ApplicationEntryPoint {
fun getSettingsManager(): SettingsManager
fun getBlockchainExceptionHandler(): BlockchainExceptionHandler
@GlobalUiMessageSender
fun getUiMessageSender(): UiMessageSender
}

View file

@ -21,6 +21,7 @@ import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.Basic.TransactionSent.WalletForm
import com.tangem.core.configtoggle.blockchain.ExcludedBlockchainsManager
import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.datasource.api.common.MoshiConverter
@ -210,6 +211,10 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
private val blockchainExceptionHandler: BlockchainExceptionHandler
get() = entryPoint.getBlockchainExceptionHandler()
private val uiMessageSender: UiMessageSender
get() = entryPoint.getUiMessageSender()
// endregion
override fun onCreate() {
@ -308,6 +313,7 @@ abstract class TangemApplication : Application(), ImageLoaderFactory {
appPreferencesStore = appPreferencesStore,
clipboardManager = clipboardManager,
settingsManager = settingsManager,
uiMessageSender = uiMessageSender,
),
),
)

View file

@ -11,13 +11,13 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.AnalyticsEvent
import com.tangem.core.analytics.models.AnalyticsParam
import com.tangem.core.analytics.models.Basic
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.toWrappedList
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.message.dialog.Dialogs
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull
@ -28,7 +28,6 @@ import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.redux.AppDialog
@ -168,36 +167,25 @@ internal class LegacyScanProcessor @Inject constructor(
crossinline onCancel: () -> Unit,
) {
if (error is TangemSdkError.CardVerificationFailed) {
analyticsEventHandler.send(event = Onboarding.OfflineAttestationFailed)
analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
val resource = error.localizedDescriptionRes()
val resId = resource.resId ?: R.string.common_unknown_error
val resArgs = resource.args.map { it.value }
uiMessageSender.send(
message = DialogMessage(
message = resourceReference(id = resId, resArgs.toWrappedList()),
title = resourceReference(id = R.string.security_alert_title),
isDismissable = false,
firstActionBuilder = {
EventMessageAction(
title = resourceReference(id = R.string.alert_button_request_support),
onClick = {
mainScope.launch {
onCancel()
message = Dialogs.cardVerificationFailed(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = {
mainScope.launch {
onCancel()
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
type = FeedbackEmailType.CardAttestationFailed,
)
}
},
)
},
secondActionBuilder = {
cancelAction {
mainScope.launch { onCancel() }
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
type = FeedbackEmailType.CardAttestationFailed,
)
}
},
onCancelClick = { onCancel() },
),
)
} else {

View file

@ -4,7 +4,9 @@ import com.tangem.common.CompletionResult
import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.CompletionCallback
import com.tangem.domain.common.TwinsHelper
import com.tangem.operations.attestation.AttestationTask
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.operations.wallet.PurgeWalletCommand
@ -13,7 +15,7 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu
override val allowsRequestAccessCodeFromRepository: Boolean = false
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
override fun run(session: CardSession, callback: CompletionCallback<CreateWalletResponse>) {
val card = session.environment.card
val publicKey = card?.wallets?.firstOrNull()?.publicKey
if (publicKey != null) {
@ -29,13 +31,40 @@ class CreateFirstTwinWalletTask(private val firstCardId: String) : CardSessionRu
when (response) {
is CompletionResult.Success -> {
session.environment.card = session.environment.card?.setWallets(emptyList())
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { callback(it) }
createWallet(session, callback)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(response.error))
}
}
} else {
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { callback(it) }
createWallet(session, callback)
}
}
private fun createWallet(session: CardSession, callback: CompletionCallback<CreateWalletResponse>) {
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { createWalletResponse ->
when (createWalletResponse) {
is CompletionResult.Success -> {
runAttestation(session) { attestationResponse ->
when (attestationResponse) {
is CompletionResult.Success -> callback(createWalletResponse)
is CompletionResult.Failure -> callback(CompletionResult.Failure(attestationResponse.error))
}
}
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(createWalletResponse.error))
}
}
}
companion object {
internal fun runAttestation(session: CardSession, callback: CompletionCallback<*>) {
val mode = session.environment.config.attestationMode
val secureStorage = session.environment.secureStorage
val attestationTask = AttestationTask(mode, secureStorage)
attestationTask.run(session, callback)
}
}
}

View file

@ -6,11 +6,13 @@ import com.tangem.common.KeyPair
import com.tangem.common.card.EllipticCurve
import com.tangem.common.core.CardSession
import com.tangem.common.core.CardSessionRunnable
import com.tangem.common.core.CompletionCallback
import com.tangem.common.extensions.hexToBytes
import com.tangem.domain.common.TwinsHelper
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.operations.wallet.PurgeWalletCommand
import com.tangem.tap.domain.twins.CreateFirstTwinWalletTask.Companion.runAttestation
class CreateSecondTwinWalletTask(
private val firstPublicKey: String,
@ -59,12 +61,10 @@ class CreateSecondTwinWalletTask(
CreateWalletTask(EllipticCurve.Secp256k1).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
session.environment.card = session.environment.card?.updateWallet(result.data.wallet)
WriteProtectedIssuerDataTask(firstPublicKey.hexToBytes(), issuerKeys).run(session) { writeResult ->
when (writeResult) {
is CompletionResult.Success -> callback(result)
is CompletionResult.Failure -> callback(CompletionResult.Failure(writeResult.error))
runAttestation(session) { attestationResponse ->
when (attestationResponse) {
is CompletionResult.Success -> writeProtectedIssuerData(session, result, callback)
is CompletionResult.Failure -> callback(CompletionResult.Failure(attestationResponse.error))
}
}
}
@ -72,4 +72,19 @@ class CreateSecondTwinWalletTask(
}
}
}
private fun writeProtectedIssuerData(
session: CardSession,
result: CompletionResult.Success<CreateWalletResponse>,
callback: CompletionCallback<CreateWalletResponse>,
) {
session.environment.card = session.environment.card?.updateWallet(result.data.wallet)
WriteProtectedIssuerDataTask(firstPublicKey.hexToBytes(), issuerKeys).run(session) { writeResult ->
when (writeResult) {
is CompletionResult.Success -> callback(result)
is CompletionResult.Failure -> callback(CompletionResult.Failure(writeResult.error))
}
}
}
}

View file

@ -1,7 +1,6 @@
package com.tangem.tap.domain.twins
import com.tangem.Message
import com.tangem.blockchain.extensions.Result
import com.tangem.common.CompletionResult
import com.tangem.common.KeyPair
import com.tangem.common.extensions.hexToBytes
@ -57,7 +56,7 @@ class TwinCardsManager(card: CardDTO) {
return response
}
suspend fun complete(message: Message): Result<ScanResponse> {
suspend fun complete(message: Message): CompletionResult<ScanResponse> {
val response = tangemSdkManager.finalizeTwin(
secondCardPublicKey = secondCardPublicKey!!.hexToBytes(),
issuerKeyPair = getIssuerKeys(),
@ -65,10 +64,7 @@ class TwinCardsManager(card: CardDTO) {
initialMessage = message,
)
return when (response) {
is CompletionResult.Success -> Result.Success(response.data)
is CompletionResult.Failure -> Result.fromTangemSdkError(response.error)
}
return response
}
private suspend fun getIssuerKeys(): KeyPair {

View file

@ -1,17 +1,25 @@
package com.tangem.tap.features.onboarding.products.twins.redux
import com.tangem.blockchain.extensions.Result
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemError
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.guard
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.utils.popTo
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.toWrappedList
import com.tangem.core.ui.message.dialog.Dialogs
import com.tangem.domain.common.extensions.makePrimaryWalletManager
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.domain.wallets.legacy.asLockable
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.entities.ProgressState
import com.tangem.tap.common.extensions.*
@ -185,8 +193,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateSecondWallet))
}
}
is CompletionResult.Failure -> {
}
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
}
}
}
@ -208,8 +215,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateThirdWallet))
}
}
is CompletionResult.Failure -> {
}
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
}
}
}
@ -218,7 +224,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
scope.launch {
when (val result = manager.complete(action.message)) {
is Result.Success -> {
is CompletionResult.Success -> {
Analytics.send(Onboarding.Twins.SetupFinished())
updateScanResponse(result.data)
@ -234,8 +240,7 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
}
}
}
is Result.Failure -> {
}
is CompletionResult.Failure -> showCardVerificationFailedDialog(result.error)
}
}
}
@ -349,6 +354,29 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
}
}
private fun showCardVerificationFailedDialog(error: TangemError) {
if (error is TangemSdkError.CardVerificationFailed) {
Analytics.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
val resource = error.localizedDescriptionRes()
val resId = resource.resId ?: R.string.common_unknown_error
val resArgs = resource.args.map { it.value }
store.inject(DaggerGraphState::uiMessageSender).send(
message = Dialogs.cardVerificationFailed(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = {
mainScope.launch {
store.inject(DaggerGraphState::sendFeedbackEmailUseCase).invoke(
type = FeedbackEmailType.CardAttestationFailed,
)
}
},
),
)
}
}
private fun getPopBackScreen(): KClass<out AppRoute> {
val userWalletsListManager = store.inject(DaggerGraphState::generalUserWalletsListManager)

View file

@ -12,9 +12,14 @@ import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.common.services.Result
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.toWrappedList
import com.tangem.core.ui.message.dialog.Dialogs
import com.tangem.domain.common.extensions.withIOContext
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.feedback.models.FeedbackEmailType
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX
@ -30,6 +35,7 @@ import com.tangem.feature.wallet.presentation.wallet.domain.BackupValidator
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.operations.backup.BackupService
import com.tangem.sdk.api.CreateProductWalletTaskResponse
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
@ -469,6 +475,25 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
val crashlytics = FirebaseCrashlytics.getInstance()
when (val error = result.error) {
is TangemSdkError.CardVerificationFailed -> {
Analytics.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
val resource = error.localizedDescriptionRes()
val resId = resource.resId ?: com.tangem.core.ui.R.string.common_unknown_error
val resArgs = resource.args.map { it.value }
store.inject(DaggerGraphState::uiMessageSender).send(
message = Dialogs.cardVerificationFailed(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = {
mainScope.launch {
store.inject(DaggerGraphState::sendFeedbackEmailUseCase)
.invoke(type = FeedbackEmailType.CardAttestationFailed)
}
},
),
)
}
is TangemSdkError.BackupFailedNotEmptyWallets -> {
store.dispatchOnMain(
GlobalAction.ShowDialog(

View file

@ -4,6 +4,7 @@ import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.blockchainsdk.signer.TransactionSignerFactory
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.common.routing.AppRouter
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.navigation.settings.SettingsManager
import com.tangem.core.navigation.share.ShareManager
import com.tangem.core.navigation.url.UrlOpener
@ -79,4 +80,5 @@ data class DaggerGraphState(
val appPreferencesStore: AppPreferencesStore? = null,
val clipboardManager: ClipboardManager? = null,
val settingsManager: SettingsManager? = null,
val uiMessageSender: UiMessageSender? = null,
) : StateType

View file

@ -0,0 +1,18 @@
package com.tangem.core.analytics.models.event
import com.tangem.core.analytics.models.AnalyticsEvent
sealed class OnboardingAnalyticsEvent(
category: String,
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(category, event, params) {
sealed class Onboarding(
event: String,
params: Map<String, String> = mapOf(),
) : OnboardingAnalyticsEvent(category = "Onboarding", event = event, params = params) {
data object OfflineAttestationFailed : Onboarding(event = "Offline Attestation Failed")
}
}

View file

@ -0,0 +1,39 @@
package com.tangem.core.ui.message.dialog
import com.tangem.core.ui.R
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.EventMessageAction
/**
[REDACTED_AUTHOR]
*/
object Dialogs {
/**
* Card verification failed dialog
*
* @param errorDescription sdk error description
* @param onRequestSupport lambda be invoked when request support action is clicked
* @param onCancelClick lambda be invoked when cancel action is clicked
*/
fun cardVerificationFailed(
errorDescription: TextReference,
onRequestSupport: () -> Unit,
onCancelClick: () -> Unit = {},
): DialogMessage {
return DialogMessage(
message = errorDescription,
title = resourceReference(id = R.string.security_alert_title),
isDismissable = false,
firstActionBuilder = {
EventMessageAction(
title = resourceReference(id = R.string.alert_button_request_support),
onClick = onRequestSupport,
)
},
secondActionBuilder = { cancelAction(onClick = onCancelClick) },
)
}
}

View file

@ -5,11 +5,17 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.event.OnboardingAnalyticsEvent
import com.tangem.core.decompose.di.ComponentScoped
import com.tangem.core.decompose.model.Model
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.core.ui.message.dialog.Dialogs
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.ProductType
import com.tangem.features.onboarding.v2.impl.R
import com.tangem.features.onboarding.v2.multiwallet.impl.analytics.OnboardingEvent
@ -21,6 +27,7 @@ import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.resetB
import com.tangem.features.onboarding.v2.multiwallet.impl.child.backup.ui.state.MultiWalletBackupUM
import com.tangem.sdk.api.BackupServiceHolder
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.sdk.extensions.localizedDescriptionRes
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@ -31,13 +38,16 @@ import javax.inject.Inject
@Stable
@ComponentScoped
@Suppress("LongParameterList")
class MultiWalletBackupModel @Inject constructor(
paramsContainer: ParamsContainer,
override val dispatchers: CoroutineDispatcherProvider,
private val backupServiceHolder: BackupServiceHolder,
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val tangemSdkManager: TangemSdkManager,
private val analyticsHandler: AnalyticsEventHandler,
private val analyticsEventHandler: AnalyticsEventHandler,
private val uiMessageSender: UiMessageSender,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
) : Model() {
@Suppress("UnusedPrivateMember")
@ -65,10 +75,10 @@ class MultiWalletBackupModel @Inject constructor(
init {
// for wallet 1 this event is sent in Wallet1ChooseOptionModel
if (scanResponse.productType == ProductType.Wallet2 || scanResponse.productType == ProductType.Ring) {
analyticsHandler.send(OnboardingEvent.Backup.ScreenOpened)
analyticsEventHandler.send(OnboardingEvent.Backup.ScreenOpened)
}
analyticsHandler.send(OnboardingEvent.Backup.Started)
analyticsEventHandler.send(OnboardingEvent.Backup.Started)
}
private fun getInitState(): MultiWalletBackupUM {
@ -153,7 +163,7 @@ class MultiWalletBackupModel @Inject constructor(
modelScope.launch { eventFlow.emit(MultiWalletBackupComponent.Event.Done) }
analyticsHandler.send(OnboardingEvent.Backup.Finished(cardsCount = state.value.numberOfBackupCards + 1))
analyticsEventHandler.send(OnboardingEvent.Backup.Finished(cardsCount = state.value.numberOfBackupCards + 1))
}
private fun showOnlyOneBackupWarningDialog() {
@ -203,6 +213,7 @@ class MultiWalletBackupModel @Inject constructor(
}
is CompletionResult.Failure -> {
when (val error = result.error) {
is TangemSdkError.CardVerificationFailed -> showCardVerificationFailedDialog(error)
is TangemSdkError.BackupFailedNotEmptyWallets -> {
_uiState.update { st ->
st.copy(
@ -212,7 +223,7 @@ class MultiWalletBackupModel @Inject constructor(
_uiState.update { it.copy(dialog = null) }
},
onDismissClick = {
analyticsHandler.send(OnboardingEvent.Backup.ResetCancelEvent)
analyticsEventHandler.send(OnboardingEvent.Backup.ResetCancelEvent)
},
),
)
@ -234,8 +245,27 @@ class MultiWalletBackupModel @Inject constructor(
}
}
private fun showCardVerificationFailedDialog(error: TangemSdkError.CardVerificationFailed) {
analyticsEventHandler.send(event = OnboardingAnalyticsEvent.Onboarding.OfflineAttestationFailed)
val resource = error.localizedDescriptionRes()
val resId = resource.resId ?: com.tangem.core.ui.R.string.common_unknown_error
val resArgs = resource.args.map { it.value }
uiMessageSender.send(
message = Dialogs.cardVerificationFailed(
errorDescription = resourceReference(id = resId, resArgs.toWrappedList()),
onRequestSupport = {
modelScope.launch {
sendFeedbackEmailUseCase(type = FeedbackEmailType.CardAttestationFailed)
}
},
),
)
}
private fun resetBackupCard(cardId: String) {
analyticsHandler.send(OnboardingEvent.Backup.ResetPerformEvent)
analyticsEventHandler.send(OnboardingEvent.Backup.ResetPerformEvent)
modelScope.launch {
tangemSdkManager.resetToFactorySettings(

View file

@ -90,7 +90,7 @@ markdownComposeView = "0.5.4"
# region Tangem
tangemBlockchainSdk = "release-app_5.20-908"
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
tangemCardSdk = "release-app_5.20-422"
tangemCardSdk = "release-app_5.20-423"
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^
tangemVico = "2.0.0-alpha.25-tangem17"
#tangemVico = "0.0.1" # Keep it! - used for local builds ^