From 96195bfbffe17b43c6f5542682fe7bb609036886 Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 13 Jan 2023 12:39:16 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../converters/BasicEventConverter.kt | 14 +-- .../converters/ParamCardCurrencyConverter.kt | 14 +-- .../common/redux/global/GlobalMiddleware.kt | 2 +- .../com/tangem/tap/domain/TangemSdkManager.kt | 6 +- .../com/tangem/tap/domain/TapWalletManager.kt | 23 ++-- .../com/tangem/tap/domain/extensions/Card.kt | 18 +--- .../domain/extensions/WalletManagerFactory.kt | 8 +- .../model/builders/UserWalletBuilder.kt | 22 +--- .../tap/domain/scanCard/ScanCardProcessor.kt | 6 +- .../tasks/product/CreateProductWalletTask.kt | 29 ++--- .../domain/tasks/product/ScanProductTask.kt | 102 ++++++++++++++++-- .../DefaultWalletManagersRepository.kt | 4 +- .../features/details/redux/DetailsAction.kt | 3 +- .../details/redux/DetailsMiddleware.kt | 7 +- .../features/details/redux/DetailsReducer.kt | 46 ++++---- .../features/details/redux/DetailsState.kt | 3 - .../walletconnect/WalletConnectMiddleware.kt | 3 +- .../details/ui/details/DetailsViewModel.kt | 11 +- .../features/onboarding/OnboardingHelper.kt | 2 +- .../redux/OnboardingOtherCardsMiddleware.kt | 4 +- .../products/twins/redux/TwinCardsReducer.kt | 2 +- .../redux/OnboardingWalletMiddleware.kt | 4 +- .../wallet/redux/OnboardingWalletReducer.kt | 43 ++++---- .../saltPay/redux/OnboardingSaltPayState.kt | 2 +- .../tap/features/wallet/redux/WalletState.kt | 2 +- .../redux/middlewares/WarningsMiddleware.kt | 9 +- .../wallet/redux/reducers/WalletReducer.kt | 2 - .../tap/features/wallet/ui/WalletFragment.kt | 2 +- .../redux/WalletSelectorReducer.kt | 2 +- buildSrc/src/main/java/Versions.kt | 5 +- .../java/com/tangem/domain/common/CardDTO.kt | 3 + .../tangem/domain/common/CardTypesResolver.kt | 19 ++++ .../com/tangem/domain/common/ScanResponse.kt | 44 ++------ .../domain/common/TangemCardTypesResolver.kt | 69 ++++++++++++ .../tangem/domain/common/TapWorkarounds.kt | 4 + 35 files changed, 332 insertions(+), 207 deletions(-) create mode 100644 domain/src/main/java/com/tangem/domain/common/CardTypesResolver.kt create mode 100644 domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt index 21a9dbbaf6..264c3a5567 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/BasicEventConverter.kt @@ -2,11 +2,11 @@ package com.tangem.tap.common.analytics.converters import com.tangem.common.Converter import com.tangem.common.extensions.isZero +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.filters.BasicTopUpFilter -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.domain.model.builders.UserWalletIdBuilder import com.tangem.tap.features.wallet.redux.ProgressState import com.tangem.tap.features.wallet.redux.WalletData @@ -21,8 +21,8 @@ class BasicSignInEventConverter( ) : Converter { override fun convert(value: WalletState): Basic.SignedIn? { - if (!statesIsReadyToCreateEvent(scanResponse, value)) return null - val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + if (!statesIsReadyToCreateEvent(scanResponse.cardTypesResolver, value)) return null + val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) ?: return null return Basic.SignedIn( state = AnalyticsParam.CardBalanceState.from(value.walletsDataFromStores), @@ -41,8 +41,8 @@ class BasicTopUpEventConverter( ) : Converter { override fun convert(value: WalletState): Basic.ToppedUp? { - if (!statesIsReadyToCreateEvent(scanResponse, value)) return null - val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null + if (!statesIsReadyToCreateEvent(scanResponse.cardTypesResolver, value)) return null + val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver) ?: return null val data = BasicTopUpFilter.Data( walletId = UserWalletIdBuilder.scanResponse(scanResponse).build()?.stringValue ?: "", @@ -63,8 +63,8 @@ private fun AnalyticsParam.CardBalanceState.Companion.from( } } -private fun statesIsReadyToCreateEvent(scanResponse: ScanResponse, state: WalletState): Boolean { - if (scanResponse.card.isMultiwalletAllowed && state.missingDerivations.isNotEmpty()) return false +private fun statesIsReadyToCreateEvent(cardTypesResolver: CardTypesResolver, state: WalletState): Boolean { + if (cardTypesResolver.isMultiwalletAllowed() && state.missingDerivations.isNotEmpty()) return false if (state.walletsDataFromStores.isEmpty()) return false val totalBalanceState = state.totalBalance?.state ?: return false diff --git a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt index e64b751f4f..95ec22a8aa 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/converters/ParamCardCurrencyConverter.kt @@ -2,24 +2,20 @@ package com.tangem.tap.common.analytics.converters import com.tangem.blockchain.common.Blockchain import com.tangem.common.Converter +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.SaltPayWorkaround -import com.tangem.domain.common.ScanResponse -import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain import com.tangem.tap.common.analytics.events.AnalyticsParam -import com.tangem.tap.domain.extensions.isMultiwalletAllowed /** [REDACTED_AUTHOR] */ -class ParamCardCurrencyConverter : Converter { +class ParamCardCurrencyConverter : Converter { - override fun convert(value: ScanResponse): AnalyticsParam.CardCurrency? { - if (value.card.isMultiwalletAllowed) return AnalyticsParam.CardCurrency.MultiCurrency + override fun convert(value: CardTypesResolver): AnalyticsParam.CardCurrency? { + if (value.isMultiwalletAllowed()) return AnalyticsParam.CardCurrency.MultiCurrency val type = when { - value.isTangemNote() -> { - value.card.getTangemNoteBlockchain()?.let { AnalyticsParam.CurrencyType.Blockchain(it) } - } + value.isTangemNote() -> AnalyticsParam.CurrencyType.Blockchain(value.getBlockchain()) value.isTangemTwins() -> AnalyticsParam.CurrencyType.Blockchain(Blockchain.Bitcoin) value.isSaltPay() -> AnalyticsParam.CurrencyType.Token(SaltPayWorkaround.tokenFrom(Blockchain.SaltPay)) value.getPrimaryToken() != null -> AnalyticsParam.CurrencyType.Token(value.getPrimaryToken()!!) diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt index c6c51659e2..ba8ed416cf 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalMiddleware.kt @@ -99,7 +99,7 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di // if config not set -> try to get it based on a scanResponse.productType val unsafeZendeskConfig = action.zendeskConfig ?: when { - scanResponse?.isSaltPay() == true -> config.saltPayConfig?.zendesk + scanResponse?.cardTypesResolver?.isSaltPay() == true -> config.saltPayConfig?.zendesk else -> config.zendesk } diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 09a23afbf3..288d399817 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -85,7 +85,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co scanResponse: ScanResponse, ): CompletionResult { return runTaskAsync( - CreateProductWalletTask(scanResponse.productType), + CreateProductWalletTask(scanResponse.cardTypesResolver), scanResponse.card.cardId, Message(context.getString(R.string.initial_message_create_wallet_body)), ) @@ -215,8 +215,8 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) { tangemSdk.config.cardIdDisplayFormat = when { scanResponse == null -> CardIdDisplayFormat.Full - scanResponse.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) - scanResponse.isSaltPay() -> CardIdDisplayFormat.None + scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4) + scanResponse.cardTypesResolver.isSaltPay() -> CardIdDisplayFormat.None else -> CardIdDisplayFormat.Full } } diff --git a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt index 12ee35a3a9..1f535fa3c6 100644 --- a/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TapWalletManager.kt @@ -11,7 +11,6 @@ import com.tangem.common.doOnSuccess import com.tangem.common.services.Result import com.tangem.domain.common.CardDTO import com.tangem.domain.common.ScanResponse -import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.ThrottlerWithValues import com.tangem.domain.common.extensions.withMainContext @@ -20,7 +19,6 @@ import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.configurable.config.ConfigManager -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.domain.extensions.makePrimaryWalletManager import com.tangem.tap.domain.extensions.makeWalletManagersForApp import com.tangem.tap.domain.model.UserWallet @@ -161,7 +159,11 @@ class TapWalletManager { store.dispatch(WalletConnectAction.ResetState) store.dispatch(GlobalAction.SaveScanResponse(data)) store.dispatch(WalletAction.SetIfTestnetCard(data.card.isTestCard)) - store.dispatch(WalletAction.MultiWallet.SetIsMultiwalletAllowed(data.card.isMultiwalletAllowed)) + store.dispatch( + WalletAction.MultiWallet.SetIsMultiwalletAllowed( + data.cardTypesResolver.isMultiwalletAllowed(), + ), + ) store.dispatch(WalletConnectAction.RestoreSessions(data)) store.dispatch( WalletAction.MultiWallet.ShowWalletBackupWarning( @@ -175,8 +177,8 @@ class TapWalletManager { fun updateConfigManager(data: ScanResponse) { val configManager = store.state.globalState.configManager - val blockchain = data.getBlockchain() - if (data.card.isStart2Coin) { + val blockchain = data.cardTypesResolver.getBlockchain() + if (data.cardTypesResolver.isStart2Coin()) { configManager?.turnOff(ConfigManager.isSendingToPayIdEnabled) configManager?.turnOff(ConfigManager.isTopUpEnabled) } else if (blockchain == Blockchain.Bitcoin @@ -197,7 +199,7 @@ class TapWalletManager { return } - if (data.card.isMultiwalletAllowed) { + if (data.cardTypesResolver.isMultiwalletAllowed()) { loadMultiWalletData(data) } else { loadSingleWalletData(data) @@ -226,11 +228,11 @@ class TapWalletManager { } private suspend fun loadSingleWalletData(data: ScanResponse) { - val blockchain = data.getBlockchain() + val blockchain = data.cardTypesResolver.getBlockchain() val primaryWalletManager = walletManagerFactory.makePrimaryWalletManager(data) if (blockchain != Blockchain.Unknown && primaryWalletManager != null) { - val primaryToken = data.getPrimaryToken() + val primaryToken = data.cardTypesResolver.getPrimaryToken() dispatchOnMain(WalletAction.MultiWallet.SetPrimaryBlockchain(blockchain)) if (primaryToken != null) { @@ -292,10 +294,11 @@ class TapWalletManager { private fun getActionIfUnknownBlockchainOrEmptyWallet(data: ScanResponse): WalletAction? { return when { // check order is important - data.isTangemTwins() && !data.twinsIsTwinned() -> { + data.cardTypesResolver.isTangemTwins() && !data.twinsIsTwinned() -> { WalletAction.EmptyWallet } - data.getBlockchain() == Blockchain.Unknown && !data.card.isMultiwalletAllowed -> { + data.cardTypesResolver.getBlockchain() == Blockchain.Unknown && + !data.cardTypesResolver.isMultiwalletAllowed() -> { WalletAction.LoadData.Failure(TapError.UnknownBlockchain) } data.isDemoCard() -> { diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt index b321c5f5c3..005f05500c 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/Card.kt @@ -1,16 +1,12 @@ package com.tangem.tap.domain.extensions -import com.tangem.common.card.EllipticCurve import com.tangem.common.card.FirmwareVersion import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.domain.common.CardDTO import com.tangem.domain.common.TapWorkarounds.isSaltPay -import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.TapWorkarounds.isTangemNote import com.tangem.domain.common.TwinCardNumber import com.tangem.domain.common.getTwinCardNumber -import com.tangem.domain.common.isTangemTwin import com.tangem.operations.attestation.CardVerifyAndGetInfo import com.tangem.operations.attestation.OnlineCardVerifier import com.tangem.tap.features.wallet.redux.Artwork @@ -21,22 +17,12 @@ val CardDTO.remainingSignatures: Int? val CardDTO.isWalletDataSupported: Boolean get() = this.firmwareVersion.major >= 4 -val CardDTO.isMultiwalletAllowed: Boolean - get() { - return !isTangemTwin() && !isStart2Coin && !isTangemNote && !isSaltPay && - (firmwareVersion >= FirmwareVersion.MultiWalletAvailable || - wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) - } +val CardDTO.isFirmwareMultiwalletAllowed: Boolean + get() = firmwareVersion >= FirmwareVersion.MultiWalletAvailable && settings.maxWalletsCount > 1 val CardDTO.isHdWalletAllowedByApp: Boolean get() = settings.isHDWalletAllowed && !isSaltPay -val CardDTO.isTangemWallet: Boolean - get() = settings.isBackupAllowed - && settings.isHDWalletAllowed - && firmwareVersion >= FirmwareVersion.MultiWalletAvailable - && !isSaltPay - @Suppress("UnnecessaryParentheses") fun CardDTO.hasSignedHashes(): Boolean { return wallets.any { (it.totalSignedHashes ?: 0) > 0 } diff --git a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt index a41280542c..4959e73705 100644 --- a/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt +++ b/app/src/main/java/com/tangem/tap/domain/extensions/WalletManagerFactory.kt @@ -37,7 +37,7 @@ fun WalletManagerFactory.makeWalletManagerForApp( val seedKey = wallet.extendedPublicKey return when { - scanResponse.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { + scanResponse.cardTypesResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> { makeTwinWalletManager( walletPublicKey = wallet.publicKey, pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(), @@ -119,9 +119,9 @@ fun WalletManagerFactory.makePrimaryWalletManager( scanResponse: ScanResponse, ): WalletManager? { val blockchain = if (scanResponse.card.isTestCard) { - scanResponse.getBlockchain().getTestnetVersion() ?: return null + scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null } else { - scanResponse.getBlockchain() + scanResponse.cardTypesResolver.getBlockchain() } val derivationParams = getDerivationParams(null, scanResponse.card) return makeWalletManagerForApp( @@ -142,7 +142,7 @@ private fun selectWallet(wallets: List): CardDTO.Wallet? { fun WalletManagerFactory.makeSaltPayWalletManager( scanResponse: ScanResponse, ): EthereumWalletManager { - val blockchain = scanResponse.getBlockchain() + val blockchain = scanResponse.cardTypesResolver.getBlockchain() if (blockchain != Blockchain.SaltPay) { error("WalletManager for the SaltPay can be created based only on Blockchain.SaltPay") } diff --git a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt index ab216a2a87..6b7f179e01 100644 --- a/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt +++ b/app/src/main/java/com/tangem/tap/domain/model/builders/UserWalletBuilder.kt @@ -1,7 +1,5 @@ package com.tangem.tap.domain.model.builders -import com.tangem.common.card.EllipticCurve -import com.tangem.common.card.FirmwareVersion import com.tangem.common.extensions.toHexString import com.tangem.common.services.Result import com.tangem.domain.common.CardDTO @@ -37,24 +35,6 @@ class UserWalletBuilder( } } - private val ScanResponse.isMultiCurrency: Boolean - get() = when (productType) { - ProductType.Note -> false - ProductType.Twins -> false - ProductType.SaltPay -> false - ProductType.Start2Coin -> false - ProductType.Wallet -> when { - card.isStart2Coin -> false - card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable -> true - else -> { - val cardWallets = card.wallets - require(cardWallets.isNotEmpty()) { "Card wallets must not be empty" } - - cardWallets.first().curve == EllipticCurve.Secp256k1 - } - } - } - fun backupCardsIds(backupCardsIds: Set?) = this.apply { if (backupCardsIds != null) { this.backupCardsIds = backupCardsIds @@ -72,7 +52,7 @@ class UserWalletBuilder( artworkUrl = loadArtworkUrl(card.cardId, card.cardPublicKey), cardsInWallet = backupCardsIds.plus(card.cardId), scanResponse = this, - isMultiCurrency = isMultiCurrency, + isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(), ) } } diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt index 60cfd3b5f9..f8404f04ab 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/ScanCardProcessor.kt @@ -122,7 +122,7 @@ object ScanCardProcessor { ?.let { it == scanResponse.card.cardId } ?: false - if (scanResponse.isSaltPayWallet() || !isTheSamePrimaryCard) { + if (scanResponse.cardTypesResolver.isSaltPayWallet() || !isTheSamePrimaryCard) { onProgressStateChange(false) showSaltPayTapVisaLogoCardDialog() } else { @@ -186,8 +186,8 @@ object ScanCardProcessor { store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse)) - if (scanResponse.isSaltPay()) { - if (scanResponse.isSaltPayVisa()) { + if (scanResponse.cardTypesResolver.isSaltPay()) { + if (scanResponse.cardTypesResolver.isSaltPayVisa()) { val (manager, config) = OnboardingSaltPayState.initDependency(scanResponse) val result = OnboardingSaltPayHelper.isOnboardingCase(scanResponse, manager) delay(500) diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt index 98ce39259e..c995f306e0 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/CreateProductWalletTask.kt @@ -13,10 +13,9 @@ import com.tangem.common.extensions.toMapKey import com.tangem.common.hdWallet.DerivationPath import com.tangem.common.map import com.tangem.domain.common.CardDTO +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.KeyWalletPublicKey -import com.tangem.domain.common.ProductType import com.tangem.domain.common.TapWorkarounds.derivationStyle -import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.operations.CommandResponse import com.tangem.operations.backup.PrimaryCard @@ -56,7 +55,7 @@ private data class CreateWalletResponse( } class CreateProductWalletTask( - private val type: ProductType, + private val cardTypesResolver: CardTypesResolver, ) : CardSessionRunnable { override val allowsRequestAccessCodeFromRepository: Boolean = false @@ -71,9 +70,10 @@ class CreateProductWalletTask( } val cardDto = CardDTO(card) - val commandProcessor = when (type) { - ProductType.Note -> CreateWalletTangemNote() - ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") + val commandProcessor = when { + cardTypesResolver.isTangemNote() -> CreateWalletTangemNote(cardTypesResolver) + cardTypesResolver.isTangemTwins() -> + throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet") else -> CreateWalletTangemWallet() } commandProcessor.proceed(cardDto, session) { @@ -95,7 +95,8 @@ class CreateProductWalletTask( } } -private class CreateWalletTangemNote : ProductCommandProcessor { +private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesResolver) : + ProductCommandProcessor { override fun proceed( card: CardDTO, session: CardSession, @@ -106,8 +107,8 @@ private class CreateWalletTangemNote : ProductCommandProcessor { callback( CompletionResult.Success( - CreateProductWalletTaskResponse(card = session.environment.card!!) - ) + CreateProductWalletTaskResponse(card = session.environment.card!!), + ), ) } } @@ -209,9 +210,9 @@ private class CreateWalletTangemWallet : ProductCommandProcessor ScanNoteProcessor() cardDto.isTangemTwins -> ScanTwinProcessor() else -> ScanWalletProcessor(userTokensRepository, additionalBlockchainsToDerive) } @@ -126,15 +130,84 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { + + if (card.firmwareVersion.doubleValue >= 4.39) { + if (card.settings.maxWalletsCount == 1) { + readFile(card, session, callback) + return + } + } + createMissingWalletsIfNeeded(card, session, callback) } + private fun readFile( + card: CardDTO, + session: CardSession, + callback: (result: CompletionResult) -> Unit, + ) { + val funToContinue = { createMissingWalletsIfNeeded(card, session, callback) } + + ReadFilesTask(fileName = "blockchainInfo", walletPublicKey = null).run(session) { result -> + + when (result) { + is CompletionResult.Success -> { + val file = result.data.firstOrNull() + val counter = file?.counter + val signature = file?.signature + + val tlv = file?.data?.let { Tlv.deserialize(it) } + val walletData = tlv?.let { WalletDataDeserializer.deserialize(TlvDecoder(tlv)) } + + if (walletData == null || counter == null || signature == null) { + funToContinue() + return@run + } + + val dataToVerify = card.cardId.hexToBytes() + file.data + counter.toByteArray() + val isVerified = CryptoUtils.verify( + publicKey = card.issuer.publicKey, + message = dataToVerify, + signature = signature, + ) + if (!isVerified) { + funToContinue() + return@run + } + + if (walletData.blockchain != "ANY") { + callback( + CompletionResult.Success( + ScanResponse( + card = card, + productType = ProductType.Note, + walletData = walletData, + ), + ), + ) + } else { + funToContinue() + } + } + is CompletionResult.Failure -> { + when (result.error) { + is TangemSdkError.FileNotFound, is TangemSdkError.InsNotSupported -> { + funToContinue() + } + else -> callback(CompletionResult.Failure(result.error)) + } + } + } + + } + } + private fun createMissingWalletsIfNeeded( card: CardDTO, session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - if (card.wallets.isEmpty() || !card.isMultiwalletAllowed) { + if (card.wallets.isEmpty() || !card.isFirmwareMultiwalletAllowed) { startLinkingForBackupIfNeeded(card, session, callback) return } @@ -195,9 +268,8 @@ private class ScanWalletProcessor( session: CardSession, callback: (result: CompletionResult) -> Unit, ) { - val productType = when { - card.isSaltPay -> ProductType.SaltPay - card.isStart2Coin -> ProductType.Start2Coin + val productType = when (card.isSaltPay) { + true -> ProductType.SaltPay else -> ProductType.Wallet } scope.launch { @@ -267,7 +339,12 @@ private class ScanWalletProcessor( } if (additionalBlockchainsToDerive != null) { blockchainsToDerive.addAll( - additionalBlockchainsToDerive.map { BlockchainNetwork(it, card) }, + additionalBlockchainsToDerive.map { + BlockchainNetwork( + blockchain = it, + card = card, + ) + }, ) } if (!card.useOldStyleDerivation) { @@ -278,7 +355,12 @@ private class ScanWalletProcessor( Blockchain.RSK, Blockchain.Fantom, Blockchain.FantomTestnet, Blockchain.Avalanche, Blockchain.AvalancheTestnet, - ).map { BlockchainNetwork(it, card) }, + ).map { + BlockchainNetwork( + blockchain = it, + card = card, + ) + }, ) } return blockchainsToDerive.distinct() diff --git a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt index 788958565a..1758c2fbf9 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletStores/repository/implementation/DefaultWalletManagersRepository.kt @@ -66,7 +66,7 @@ internal class DefaultWalletManagersRepository( ): CompletionResult { val scanResponse = userWallet.scanResponse val blockchain = blockchainNetwork?.blockchain - ?: scanResponse.getBlockchain().let { blockchain -> + ?: scanResponse.cardTypesResolver.getBlockchain().let { blockchain -> if (scanResponse.card.isTestCard) blockchain.getTestnetVersion() else blockchain } val derivationParams = getDerivationParams( @@ -156,7 +156,7 @@ internal class DefaultWalletManagersRepository( ): CompletionResult { val walletManager = this return catching { - val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.getPrimaryToken()) + val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.cardTypesResolver.getPrimaryToken()) if (tokens != cardTokens) { cardTokens.clear() diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt index 5447faf5b0..7fb6399681 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsAction.kt @@ -2,6 +2,7 @@ package com.tangem.tap.features.details.redux import com.tangem.blockchain.common.Wallet import com.tangem.domain.common.CardDTO +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.ScanResponse import com.tangem.tap.common.entities.FiatCurrency import org.rekotlin.Action @@ -27,7 +28,7 @@ sealed class DetailsAction : Action { object ScanCard : DetailsAction() - data class PrepareCardSettingsData(val card: CardDTO) : DetailsAction() + data class PrepareCardSettingsData(val card: CardDTO, val cardTypesResolver: CardTypesResolver) : DetailsAction() object ResetCardSettingsData : DetailsAction() sealed class ManageSecurity : DetailsAction() { diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt index 602bfa3378..38de2a1336 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsMiddleware.kt @@ -82,7 +82,12 @@ class DetailsMiddleware { val isSameWallet = currentUserWalletId == scannedUserWalletId if (isSameWallet) { - store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(scanResponse.card)) + store.dispatchOnMain( + DetailsAction.PrepareCardSettingsData( + scanResponse.card, + scanResponse.cardTypesResolver, + ), + ) } else { store.dispatchDialogShow( AppDialog.SimpleOkDialogRes( diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt index 9b6814f90e..402c9dd26c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsReducer.kt @@ -1,11 +1,8 @@ package com.tangem.tap.features.details.redux import com.tangem.domain.common.CardDTO +import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.TapWorkarounds.isSaltPay -import com.tangem.domain.common.TapWorkarounds.isStart2Coin -import com.tangem.domain.common.TapWorkarounds.isTangemNote -import com.tangem.domain.common.TapWorkarounds.isTangemTwins -import com.tangem.domain.common.isTangemTwin import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.extensions.isWalletDataSupported import com.tangem.tap.domain.extensions.signedHashesCount @@ -27,7 +24,11 @@ private fun internalReduce(action: Action, state: AppState): DetailsState { handlePrepareScreen(action) } is DetailsAction.PrepareCardSettingsData -> { - handlePrepareCardSettingsScreen(action.card, detailsState) + handlePrepareCardSettingsScreen( + card = action.card, + cardTypesResolver = action.cardTypesResolver, + state = detailsState, + ) } is DetailsAction.ResetCardSettingsData -> detailsState.copy(cardSettingsState = null) is DetailsAction.ResetToFactory -> { @@ -59,17 +60,22 @@ private fun handlePrepareScreen( ) } -private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): DetailsState { +private fun handlePrepareCardSettingsScreen( + card: CardDTO, + cardTypesResolver: CardTypesResolver, + state: DetailsState, +): + DetailsState { val cardSettingsState = CardSettingsState( - cardInfo = card.toCardInfo(), - manageSecurityState = prepareSecurityOptions(card), + cardInfo = card.toCardInfo(cardTypesResolver), + manageSecurityState = prepareSecurityOptions(card, cardTypesResolver), card = card, - resetCardAllowed = isResetToFactoryAllowedByCard(card), + resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver), ) return state.copy(cardSettingsState = cardSettingsState) } -private fun prepareSecurityOptions(card: CardDTO): ManageSecurityState { +private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesResolver): ManageSecurityState { val securityOption = when { card.isAccessCodeSet -> { SecurityOption.AccessCode @@ -84,13 +90,14 @@ private fun prepareSecurityOptions(card: CardDTO): ManageSecurityState { } } val allowedSecurityOptions = when { - card.isStart2Coin || card.isTangemNote || card.isSaltPay -> { + cardTypesResolver.isStart2Coin() || cardTypesResolver.isTangemNote() || cardTypesResolver.isSaltPay() -> { EnumSet.of(SecurityOption.LongTap) } card.settings.isBackupAllowed -> { EnumSet.of(securityOption) } - else -> prepareAllowedSecurityOptions(card, securityOption) + else -> + prepareAllowedSecurityOptions(cardTypesResolver = cardTypesResolver, currentSecurityOption = securityOption) } return ManageSecurityState( currentOption = securityOption, @@ -99,10 +106,11 @@ private fun prepareSecurityOptions(card: CardDTO): ManageSecurityState { ) } -private fun isResetToFactoryAllowedByCard(card: CardDTO): Boolean { +private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: CardTypesResolver): Boolean { val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent } val notAllowedByCard = notAllowedByAnyWallet || - card.isWalletDataSupported && !card.isTangemNote && !card.settings.isBackupAllowed || card.isSaltPay + card.isWalletDataSupported && !cardTypesResolver.isTangemNote() && !card.settings.isBackupAllowed || + card.isSaltPay return !notAllowedByCard } @@ -132,7 +140,7 @@ private fun handleSecurityAction( // Setting options to show only LongTap from now on for non-twins val manageSecurityState = state.cardSettingsState?.manageSecurityState?.copy( currentOption = state.cardSettingsState.manageSecurityState.selectedOption, - allowedOptions = state.scanResponse?.card?.let { + allowedOptions = state.scanResponse?.cardTypesResolver?.let { prepareAllowedSecurityOptions( it, state.cardSettingsState.manageSecurityState.selectedOption, ) @@ -168,12 +176,12 @@ private fun handlePrivacyAction( } private fun prepareAllowedSecurityOptions( - card: CardDTO?, + cardTypesResolver: CardTypesResolver, currentSecurityOption: SecurityOption?, ): EnumSet { val allowedSecurityOptions = EnumSet.of(SecurityOption.LongTap) - if (card?.isTangemTwin() == true) { + if (cardTypesResolver.isTangemTwins()) { allowedSecurityOptions.add(SecurityOption.PassCode) } if (currentSecurityOption == SecurityOption.AccessCode) { @@ -186,7 +194,7 @@ private fun prepareAllowedSecurityOptions( } @Suppress("MagicNumber") -private fun CardDTO.toCardInfo(): CardInfo { +private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo { val cardId = this.cardId.chunked(4).joinToString(separator = " ") val issuer = this.issuer.name val signedHashes = this.signedHashesCount() @@ -195,7 +203,7 @@ private fun CardDTO.toCardInfo(): CardInfo { cardId = cardId, issuer = issuer, signedHashes = signedHashes, - isTwin = isTangemTwins, + isTwin = cardTypesResolver.isTangemTwins(), hasBackup = backupStatus?.isActive == true, ) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt index 5eea8a0775..2c1f141a8d 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/DetailsState.kt @@ -29,9 +29,6 @@ data class DetailsState( val twinCardsState: TwinCardsState by ReadOnlyProperty { _, _ -> store.state.twinCardsState } - - val isTangemTwins: Boolean - get() = store.state.globalState.scanResponse?.isTangemTwins() == true } data class CardInfo( diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index 958d119c37..b92891884c 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -14,7 +14,6 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.domain.walletconnect.BnbHelper import com.tangem.tap.domain.walletconnect.WalletConnectManager @@ -290,7 +289,7 @@ class WalletConnectMiddleware { blockchain: Blockchain, ) { val card = scanResponse.card - if (!card.isMultiwalletAllowed) { + if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) { store.dispatchOnMain(WalletConnectAction.UnsupportedCard) return } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt index cf2e38f02b..3d706b6a38 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/details/DetailsViewModel.kt @@ -9,7 +9,6 @@ import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.navigation.AppScreen import com.tangem.tap.common.redux.navigation.NavigationAction -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.features.details.redux.DetailsAction import com.tangem.tap.features.details.redux.DetailsState import com.tangem.tap.features.disclaimer.redux.DisclaimerAction @@ -23,22 +22,24 @@ class DetailsViewModel(private val store: Store) { @Suppress("ComplexMethod") fun updateState(state: DetailsState): DetailsScreenState { + val cardTypesResolver = state.scanResponse?.cardTypesResolver val settings = SettingsElement.values().mapNotNull { when (it) { SettingsElement.WalletConnect -> { - if (state.scanResponse?.card?.isMultiwalletAllowed == true) it else null + if (cardTypesResolver?.isMultiwalletAllowed() == true) it else null } - SettingsElement.SendFeedback -> if (state.scanResponse?.card?.isSaltPay != true) it else null + SettingsElement.SendFeedback -> + if (cardTypesResolver?.isSaltPay() != true) it else null SettingsElement.LinkMoreCards -> { // if (state.createBackupAllowed) it else null // TODO: SaltPay: temporary excluding backup process for Visa cards - if (state.createBackupAllowed && state.scanResponse?.card?.isSaltPay != true) it else null + if (state.createBackupAllowed && cardTypesResolver?.isSaltPay() != true) it else null } SettingsElement.PrivacyPolicy -> { if (state.privacyPolicyUrl != null) it else null } SettingsElement.AppSettings -> if (state.isBiometricsAvailable) it else null - SettingsElement.AppCurrency -> if (state.scanResponse?.card?.isMultiwalletAllowed != true) it else null + SettingsElement.AppCurrency -> if (cardTypesResolver?.isMultiwalletAllowed() != true) it else null // SettingsElement.ReferralProgram -> if (state.scanResponse?.card?.isTangemWallet == true) it else null else -> it } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt index a92129dbd9..5ed844549d 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/OnboardingHelper.kt @@ -22,7 +22,7 @@ object OnboardingHelper { val cardInfoStorage = preferencesStorage.usedCardsPrefStorage val cardId = response.card.cardId return when { - response.isTangemTwins() -> { + response.cardTypesResolver.isTangemTwins() -> { if (!response.twinsIsTwinned()) { true } else { diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt index 98f5ce5df2..8711eaadad 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/otherCards/redux/OnboardingOtherCardsMiddleware.kt @@ -87,9 +87,9 @@ private fun handleOtherCardsAction(action: Action) { onboardingManager.scanResponse = updatedResponse onboardingManager.activationStarted(updatedCard.cardId) - val primaryBlockchain = updatedResponse.getBlockchain() + val primaryBlockchain = updatedResponse.cardTypesResolver.getBlockchain() val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) { - val primaryToken = updatedResponse.getPrimaryToken() + val primaryToken = updatedResponse.cardTypesResolver.getPrimaryToken() val blockchainNetwork = BlockchainNetwork( blockchain = primaryBlockchain, diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt index 878176c323..9902cd2ce5 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/twins/redux/TwinCardsReducer.kt @@ -16,7 +16,7 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState { when (action) { is TwinCardsAction.IfTwinsPrepareState -> { - state = if (action.scanResponse.isTangemTwins()) { + state = if (action.scanResponse.cardTypesResolver.isTangemTwins()) { val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state TwinCardsState( diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt index b4daef5268..9e63233695 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletMiddleware.kt @@ -80,11 +80,11 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: card.wallets.isNotEmpty() && card.backupStatus?.isActive == true -> { when { // check for unfinished backup for saltPay cards. See more - scanResponse.isSaltPay() && backupService.hasIncompletedBackup -> { + scanResponse.cardTypesResolver.isSaltPay() && backupService.hasIncompletedBackup -> { store.dispatch(OnboardingWalletAction.ResumeBackup) } - scanResponse.isSaltPay() -> { + scanResponse.cardTypesResolver.isSaltPay() -> { store.dispatch(OnboardingWalletAction.GetToSaltPayStep) store.dispatch(BackupAction.FinishBackup) } diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt index ffc422f1a3..dec5422ae4 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/redux/OnboardingWalletReducer.kt @@ -35,30 +35,31 @@ private fun internalReduce(action: Action, appState: AppState): OnboardingWallet } private object ReducerForGlobalAction { - fun reduce(action: GlobalAction.Onboarding, state: OnboardingWalletState): OnboardingWalletState { - return when (action) { - is GlobalAction.Onboarding.Start -> { - OnboardingWalletState( - backupState = state.backupState.copy( - maxBackupCards = if (action.scanResponse.isSaltPay()) 1 else 2, - canSkipBackup = if (action.scanResponse.isSaltPay()) false else action.canSkipBackup, - ), - isSaltPay = action.scanResponse.isSaltPay(), - ) + fun reduce(action: GlobalAction.Onboarding, state: OnboardingWalletState): OnboardingWalletState { + return when (action) { + is GlobalAction.Onboarding.Start -> { + OnboardingWalletState( + backupState = state.backupState.copy( + maxBackupCards = if (action.scanResponse.cardTypesResolver.isSaltPay()) 1 else 2, + canSkipBackup = + if (action.scanResponse.cardTypesResolver.isSaltPay()) false else action.canSkipBackup, + ), + isSaltPay = action.scanResponse.cardTypesResolver.isSaltPay(), + ) + } + is GlobalAction.Onboarding.StartForUnfinishedBackup -> { + OnboardingWalletState( + backupState = state.backupState.copy( + maxBackupCards = action.addedBackupCardsCount, + canSkipBackup = false, + ), + isSaltPay = false, + ) + } + else -> state } - is GlobalAction.Onboarding.StartForUnfinishedBackup -> { - OnboardingWalletState( - backupState = state.backupState.copy( - maxBackupCards = action.addedBackupCardsCount, - canSkipBackup = false, - ), - isSaltPay = false, - ) - } - else -> state } } -} private object BackupReducer { @Suppress("ComplexMethod") diff --git a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt index e530450920..d62c679e37 100644 --- a/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt +++ b/app/src/main/java/com/tangem/tap/features/onboarding/products/wallet/saltPay/redux/OnboardingSaltPayState.kt @@ -64,7 +64,7 @@ data class OnboardingSaltPayState( paymentologyService: PaymentologyApiService, kycProvider: KYCProvider, ): SaltPayActivationManager { - if (!scanResponse.isSaltPay()) { + if (!scanResponse.cardTypesResolver.isSaltPay()) { throw IllegalArgumentException("Can't initialize the OnboardingSaltPayMiddleware if card is not SalPay") } val saltPaySingleWallet = scanResponse.card.wallets.firstOrNull().guard { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt index 0e42de22a6..b5fdfafa3c 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/WalletState.kt @@ -63,7 +63,7 @@ data class WalletState( } val isTangemTwins: Boolean - get() = store.state.globalState.scanResponse?.isTangemTwins() == true + get() = store.state.globalState.scanResponse?.cardTypesResolver?.isTangemTwins() == true val isExchangeServiceFeatureOn: Boolean get() = store.state.globalState.exchangeManager.featureIsSwitchedOn() diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt index 4f0307c06f..d9a40e965d 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/WarningsMiddleware.kt @@ -14,7 +14,6 @@ import com.tangem.tap.common.redux.global.GlobalState import com.tangem.tap.domain.configurable.warningMessage.WarningMessage import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager import com.tangem.tap.domain.extensions.hasSignedHashes -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.features.demo.isDemoCard import com.tangem.tap.features.wallet.redux.WalletAction import com.tangem.tap.network.NetworkConnectivity @@ -120,9 +119,9 @@ class WarningsMiddleware { private fun checkIfWarningNeeded( scanResponse: ScanResponse, ): WarningMessage? { - if (scanResponse.isTangemTwins() || scanResponse.isDemoCard()) return null + if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.isDemoCard()) return null - if (scanResponse.card.isMultiwalletAllowed) { + if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) { val isBackupForbidden = with(scanResponse.card.settings) { !(isBackupAllowed || isHDWalletAllowed) } return if (scanResponse.card.hasSignedHashes() && isBackupForbidden) { WarningMessagesManager.signedHashesMultiWalletWarning() @@ -154,7 +153,9 @@ class WarningsMiddleware { val card = scanResponse?.card if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return - if (scanResponse.isTangemTwins() || card.isMultiwalletAllowed) return + if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.cardTypesResolver.isMultiwalletAllowed()) { + return + } val validator = store.state.walletState.walletManagers.firstOrNull() as? SignatureCountValidator diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt index 3b6e95d27c..796f5e1a57 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/reducers/WalletReducer.kt @@ -16,7 +16,6 @@ import com.tangem.tap.common.extensions.toFormattedFiatValue import com.tangem.tap.common.redux.AppState import com.tangem.tap.domain.TapError import com.tangem.tap.domain.extensions.getArtworkUrl -import com.tangem.tap.domain.extensions.isMultiwalletAllowed import com.tangem.tap.domain.getFirstToken import com.tangem.tap.domain.tokens.models.BlockchainNetwork import com.tangem.tap.features.wallet.models.Currency @@ -382,7 +381,6 @@ private fun internalReduce(action: Action, state: AppState, appStateHolder: AppS private fun CardDTO.findCardsCount(): Int? { return (this.backupStatus as? CardDTO.BackupStatus.Active)?.cardCount?.inc() - ?.takeIf { this.isMultiwalletAllowed } } fun createAddressList(wallet: Wallet?, walletAddresses: WalletAddresses? = null): WalletAddresses? { diff --git a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt index 3873d90c69..b1991cf9a9 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/ui/WalletFragment.kt @@ -218,7 +218,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber major.compareTo(other.major) minor != other.minor -> minor.compareTo(other.minor) diff --git a/domain/src/main/java/com/tangem/domain/common/CardTypesResolver.kt b/domain/src/main/java/com/tangem/domain/common/CardTypesResolver.kt new file mode 100644 index 0000000000..a938ae53b0 --- /dev/null +++ b/domain/src/main/java/com/tangem/domain/common/CardTypesResolver.kt @@ -0,0 +1,19 @@ +package com.tangem.domain.common + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token + +interface CardTypesResolver { + fun isTangemNote(): Boolean + fun isTangemWallet(): Boolean + fun isSaltPay(): Boolean + fun isSaltPayVisa(): Boolean + fun isSaltPayWallet(): Boolean + fun isTangemTwins(): Boolean + fun isStart2Coin(): Boolean + + fun isMultiwalletAllowed(): Boolean + + fun getBlockchain(): Blockchain + fun getPrimaryToken(): Token? +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt index c5576f6037..9031c1dd89 100644 --- a/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt +++ b/domain/src/main/java/com/tangem/domain/common/ScanResponse.kt @@ -1,16 +1,11 @@ package com.tangem.domain.common import com.tangem.blockchain.common.Blockchain -import com.tangem.blockchain.common.Token import com.tangem.common.card.EllipticCurve import com.tangem.common.card.WalletData import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.toMapKey import com.tangem.common.hdWallet.DerivationPath -import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain -import com.tangem.domain.common.TapWorkarounds.isSaltPay -import com.tangem.domain.common.TapWorkarounds.isSaltPayVisa -import com.tangem.domain.common.TapWorkarounds.isSaltPayWallet import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.operations.CommandResponse @@ -28,36 +23,13 @@ data class ScanResponse( val derivedKeys: Map = mapOf(), val primaryCard: PrimaryCard? = null, ) : CommandResponse { - fun getBlockchain(): Blockchain { - return when (productType) { - ProductType.Start2Coin -> if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin - ProductType.SaltPay -> Blockchain.SaltPay - ProductType.Note -> card.getTangemNoteBlockchain() ?: Blockchain.Unknown - else -> { - val blockchainName: String = walletData?.blockchain ?: return Blockchain.Unknown - Blockchain.fromId(blockchainName) - } - } - } - fun getPrimaryToken(): Token? { - if (card.isSaltPay) return SaltPayWorkaround.tokenFrom(getBlockchain()) + val cardTypesResolver: CardTypesResolver = TangemCardTypesResolver( + card = card, + productType = productType, + walletData = walletData, + ) - val cardToken = walletData?.token ?: return null - return Token( - cardToken.name, - cardToken.symbol, - cardToken.contractAddress, - cardToken.decimals, - ) - } - - fun isTangemNote(): Boolean = productType == ProductType.Note - fun isTangemWallet(): Boolean = productType == ProductType.Wallet - fun isSaltPay(): Boolean = productType == ProductType.SaltPay - fun isSaltPayVisa(): Boolean = card.isSaltPayVisa - fun isSaltPayWallet(): Boolean = card.isSaltPayWallet - fun isTangemTwins(): Boolean = productType == ProductType.Twins fun twinsIsTwinned(): Boolean = card.isTangemTwins && walletData != null && secondTwinPublicKey != null fun supportsHdWallet(): Boolean = card.settings.isHDWalletAllowed fun supportsBackup(): Boolean = card.settings.isBackupAllowed @@ -88,8 +60,4 @@ data class ScanResponse( } } -enum class ProductType { - Note, Twins, Wallet, SaltPay, Start2Coin -} - -typealias KeyWalletPublicKey = ByteArrayKey \ No newline at end of file +typealias KeyWalletPublicKey = ByteArrayKey diff --git a/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt b/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt new file mode 100644 index 0000000000..dfb2fb262e --- /dev/null +++ b/domain/src/main/java/com/tangem/domain/common/TangemCardTypesResolver.kt @@ -0,0 +1,69 @@ +package com.tangem.domain.common + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.Token +import com.tangem.common.card.EllipticCurve +import com.tangem.common.card.FirmwareVersion +import com.tangem.common.card.WalletData +import com.tangem.common.extensions.guard +import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain +import com.tangem.domain.common.TapWorkarounds.isSaltPay +import com.tangem.domain.common.TapWorkarounds.isSaltPayVisa +import com.tangem.domain.common.TapWorkarounds.isSaltPayWallet +import com.tangem.domain.common.TapWorkarounds.isStart2Coin +import com.tangem.domain.common.TapWorkarounds.isTestCard + +class TangemCardTypesResolver( + private val card: CardDTO, private val productType: ProductType, private val walletData: WalletData?, +) : CardTypesResolver { + + override fun isTangemNote(): Boolean = productType == ProductType.Note + override fun isTangemWallet(): Boolean = card.settings.isBackupAllowed + && card.settings.isHDWalletAllowed + && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable + && !card.isSaltPay + + override fun isSaltPay(): Boolean = productType == ProductType.SaltPay + override fun isSaltPayVisa(): Boolean = card.isSaltPayVisa + override fun isSaltPayWallet(): Boolean = card.isSaltPayWallet + override fun isTangemTwins(): Boolean = productType == ProductType.Twins + override fun isStart2Coin(): Boolean = card.isStart2Coin + + override fun isMultiwalletAllowed(): Boolean = + !isTangemTwins() && !card.isStart2Coin && !isTangemNote() && !isSaltPay() && + (card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable || + card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) + + override fun getBlockchain(): Blockchain { + return when (productType) { + ProductType.Start2Coin -> if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin + ProductType.SaltPay -> Blockchain.SaltPay + else -> { + val blockchainName: String = walletData?.blockchain.guard { + if (productType == ProductType.Note) { + return card.getTangemNoteBlockchain() ?: Blockchain.Unknown + } else { + return Blockchain.Unknown + } + } + Blockchain.fromId(blockchainName) + } + } + } + + override fun getPrimaryToken(): Token? { + if (isSaltPay()) return SaltPayWorkaround.tokenFrom(getBlockchain()) + + val cardToken = walletData?.token ?: return null + return Token( + cardToken.name, + cardToken.symbol, + cardToken.contractAddress, + cardToken.decimals, + ) + } +} + +enum class ProductType { + Note, Twins, Wallet, SaltPay, Start2Coin +} \ No newline at end of file diff --git a/domain/src/main/java/com/tangem/domain/common/TapWorkarounds.kt b/domain/src/main/java/com/tangem/domain/common/TapWorkarounds.kt index cf9c502268..521d74759c 100644 --- a/domain/src/main/java/com/tangem/domain/common/TapWorkarounds.kt +++ b/domain/src/main/java/com/tangem/domain/common/TapWorkarounds.kt @@ -75,6 +75,10 @@ object TapWorkarounds { private val excludedIssuers = listOf("TTM BANK") + @Deprecated( + "Now blockchain is read form files (CardTypesResolver.getBlockchain), " + + "but for previously saved cards this method is still used", + ) fun CardDTO.getTangemNoteBlockchain(): Blockchain? = tangemNoteBatches[batchId] ?: if (isSaltPay) Blockchain.Gnosis else null