Updated on 2026-08-14

This commit is contained in:
Tangem 2023-06-30 09:26:53 +08:00
parent 65ff4a4b49
commit 9112d2bab8
55 changed files with 492 additions and 389 deletions

View file

@ -20,7 +20,9 @@ import com.tangem.datasource.config.FeaturesLocalLoader
import com.tangem.datasource.config.models.Config
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.domain.DomainLayer
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.LogConfig
import com.tangem.domain.common.Provider
import com.tangem.feature.learn2earn.domain.api.Learn2earnInteractor
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
import com.tangem.tap.common.analytics.AnalyticsFactory
@ -82,6 +84,7 @@ private val walletManagersRepository by lazy {
?.blockchainSdkConfig
?: BlockchainSdkConfig(),
),
cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) },
)
}
private val walletAmountsRepository by lazy {
@ -96,6 +99,7 @@ val walletStoresManager by lazy {
walletManagersRepository = walletManagersRepository,
walletAmountsRepository = walletAmountsRepository,
appCurrencyProvider = { store.state.globalState.appCurrency },
cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) },
)
}
val walletCurrenciesManager by lazy {
@ -105,6 +109,7 @@ val walletCurrenciesManager by lazy {
walletManagersRepository = walletManagersRepository,
walletAmountsRepository = walletAmountsRepository,
appCurrencyProvider = { store.state.globalState.appCurrency },
cardTypeResolverProvider = Provider { store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver) },
)
}
val totalFiatBalanceCalculator by lazy {
@ -147,6 +152,9 @@ class TapApplication : Application(), ImageLoaderFactory {
@Inject
lateinit var learn2earnInteractor: Learn2earnInteractor
@Inject
lateinit var cardTypeResolver: CardTypeResolver
override fun onCreate() {
super.onCreate()
@ -163,6 +171,7 @@ class TapApplication : Application(), ImageLoaderFactory {
walletFeatureToggles = walletFeatureToggles,
walletConnectRepository = walletConnect2Repository,
walletConnectSessionsRepository = walletConnectSessionsRepository,
cardTypeResolver = cardTypeResolver,
),
),
)
@ -219,6 +228,7 @@ class TapApplication : Application(), ImageLoaderFactory {
},
walletStoresManagerProvider = { walletStoresManager },
topupWalletStorage = preferencesStorage.toppedUpWalletStorage,
cardTypeResolver = cardTypeResolver,
)
store.dispatch(GlobalAction.SetTopUpController(topUpController))
}

View file

@ -2,15 +2,15 @@ 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.card.CardTypeResolver
import com.tangem.tap.common.analytics.events.AnalyticsParam
/**
[REDACTED_AUTHOR]
*/
class ParamCardCurrencyConverter : Converter<CardTypesResolver, AnalyticsParam.CardCurrency?> {
class ParamCardCurrencyConverter : Converter<CardTypeResolver, AnalyticsParam.CardCurrency?> {
override fun convert(value: CardTypesResolver): AnalyticsParam.CardCurrency? {
override fun convert(value: CardTypeResolver): AnalyticsParam.CardCurrency? {
if (value.isMultiwalletAllowed()) return AnalyticsParam.CardCurrency.MultiCurrency
val type = when {

View file

@ -1,15 +1,15 @@
package com.tangem.tap.common.analytics.converters
import com.tangem.common.Converter
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.tap.common.analytics.events.Basic
/**
[REDACTED_AUTHOR]
*/
class TopUpEventConverter : Converter<CardTypesResolver, Basic.ToppedUp?> {
class TopUpEventConverter : Converter<CardTypeResolver, Basic.ToppedUp?> {
override fun convert(value: CardTypesResolver): Basic.ToppedUp? {
override fun convert(value: CardTypeResolver): Basic.ToppedUp? {
val paramCardCurrency = ParamCardCurrencyConverter().convert(value) ?: return null
return Basic.ToppedUp(paramCardCurrency)

View file

@ -2,7 +2,7 @@ package com.tangem.tap.common.analytics.paramsInterceptor
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.core.analytics.api.ParamsInterceptor
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
@ -16,6 +16,7 @@ import com.tangem.tap.features.demo.DemoHelper
*/
class CardContextInterceptor(
private val scanResponse: ScanResponse?,
private val cardTypeResolver: CardTypeResolver,
) : ParamsInterceptor {
override fun id(): String = CardContextInterceptor.id()
@ -35,7 +36,7 @@ class CardContextInterceptor(
params[AnalyticsParam.PRODUCT_TYPE] = getProductType(scanResponse)
params[AnalyticsParam.FIRMWARE] = card.firmwareVersion.stringValue
ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver)?.let {
ParamCardCurrencyConverter().convert(cardTypeResolver)?.let {
params[AnalyticsParam.CURRENCY] = it.value
}
}

View file

@ -2,17 +2,19 @@ package com.tangem.tap.common.analytics.paramsInterceptor
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.core.analytics.api.ParamsInterceptor
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.models.scan.ScanResponse
/**
[REDACTED_AUTHOR]
*/
class LinkedCardContextInterceptor(
private val scanResponse: ScanResponse,
scanResponse: ScanResponse,
cardTypeResolver: CardTypeResolver,
val parent: LinkedCardContextInterceptor? = null,
) : ParamsInterceptor {
private val contextInterceptor = CardContextInterceptor(scanResponse)
private val contextInterceptor = CardContextInterceptor(scanResponse, cardTypeResolver)
override fun id(): String = LinkedCardContextInterceptor.id()

View file

@ -5,9 +5,8 @@ import com.tangem.common.extensions.isZero
import com.tangem.core.analytics.Analytics
import com.tangem.data.source.preferences.model.DataSourceTopupInfo
import com.tangem.data.source.preferences.storage.ToppedUpWalletStorage
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.util.UserWalletId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.converters.TopUpEventConverter
import com.tangem.tap.common.analytics.events.AnalyticsParam
@ -32,6 +31,7 @@ class TopUpController(
var scanResponseProvider: (() -> ScanResponse?)? = null,
var walletStoresManagerProvider: (() -> WalletStoresManager)? = null,
private val topupWalletStorage: ToppedUpWalletStorage,
private val cardTypeResolver: CardTypeResolver,
) : WalletCurrenciesManager.Listener {
private var hadMissedDerivations: Boolean = false
@ -100,7 +100,7 @@ class TopUpController(
}
val cardBalanceState = BalanceCalculator(walletDataModels).calculate().toCardBalanceState()
send(userWalletId, cardBalanceState, scanResponse.cardTypesResolver)
send(userWalletId, cardBalanceState, cardTypeResolver)
}
}
@ -120,14 +120,14 @@ class TopUpController(
fun send(scanResponse: ScanResponse, cardBalanceState: AnalyticsParam.CardBalanceState) {
UserWalletIdBuilder.scanResponse(scanResponse).build()?.let {
send(it, cardBalanceState, scanResponse.cardTypesResolver)
send(it, cardBalanceState, cardTypeResolver)
}
}
fun send(
userWalletId: UserWalletId,
cardBalanceState: AnalyticsParam.CardBalanceState,
cardTypesResolver: CardTypesResolver,
cardTypeResolver: CardTypeResolver,
) {
val topupInfo = topupWalletStorage.restore(userWalletId.stringValue).guard {
val topupInfo = DataSourceTopupInfo(
@ -152,7 +152,7 @@ class TopUpController(
if (cardBalanceState.isToppedUp()) {
topupWalletStorage.save(topupInfo.copy(cardBalanceState = DataSourceTopupInfo.CardBalanceState.Full))
TopUpEventConverter().convert(cardTypesResolver)?.let {
TopUpEventConverter().convert(cardTypeResolver)?.let {
Analytics.send(it)
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.tap.common.extensions
import com.tangem.core.analytics.Analytics
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor
@ -11,8 +12,8 @@ import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterc
/**
* Sets the new context
*/
fun Analytics.setContext(scanResponse: ScanResponse) {
addParamsInterceptor(LinkedCardContextInterceptor(scanResponse))
fun Analytics.setContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) {
addParamsInterceptor(LinkedCardContextInterceptor(scanResponse, cardTypeResolver))
}
/**
@ -25,9 +26,13 @@ fun Analytics.eraseContext() {
/**
* Adds a new context and keeps a previous context as the parent of the new one
*/
fun Analytics.addContext(scanResponse: ScanResponse) {
fun Analytics.addContext(scanResponse: ScanResponse, cardTypeResolver: CardTypeResolver) {
val currentContext = removeParamsInterceptor(LinkedCardContextInterceptor.id()) as? LinkedCardContextInterceptor
val newContext = LinkedCardContextInterceptor(scanResponse, parent = currentContext)
val newContext = LinkedCardContextInterceptor(
scanResponse = scanResponse,
cardTypeResolver = cardTypeResolver,
parent = currentContext,
)
addParamsInterceptor(newContext)
}

View file

@ -3,6 +3,7 @@ package com.tangem.tap.di
import android.content.Context
import androidx.fragment.app.FragmentActivity
import com.tangem.TangemSdk
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.sdk.extensions.initWithBiometrics
import com.tangem.tap.domain.TangemSdkManager
@ -27,8 +28,12 @@ internal object ActivityModule {
@Provides
@ActivityScoped
fun provideTangemSdkManager(@ActivityContext context: Context, tangemSdk: TangemSdk): TangemSdkManager {
return TangemSdkManager(tangemSdk, context)
fun provideTangemSdkManager(
@ActivityContext context: Context,
tangemSdk: TangemSdk,
cardTypeResolver: CardTypeResolver,
): TangemSdkManager {
return TangemSdkManager(tangemSdk, context, cardTypeResolver)
}
@Provides

View file

@ -14,7 +14,7 @@ import com.tangem.common.usersCode.UserCodeRepository
import com.tangem.core.analytics.Analytics
import com.tangem.crypto.bip39.DefaultMnemonic
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.ScanTask
@ -38,7 +38,11 @@ import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
@Suppress("TooManyFunctions")
class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Context) {
class TangemSdkManager(
private val tangemSdk: TangemSdk,
private val context: Context,
private val cardTypeResolver: CardTypeResolver,
) {
private val userCodeRepository by lazy {
UserCodeRepository(
@ -78,7 +82,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
suspend fun createProductWallet(scanResponse: ScanResponse): CompletionResult<CreateProductWalletTaskResponse> {
return runTaskAsync(
CreateProductWalletTask(scanResponse.cardTypesResolver),
CreateProductWalletTask(cardTypeResolver),
scanResponse.card.cardId,
Message(context.getString(R.string.initial_message_create_wallet_body)),
)
@ -90,7 +94,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
): CompletionResult<CreateProductWalletTaskResponse> {
return when (val seedResult = DefaultMnemonic(mnemonic, tangemSdk.wordlist).generateSeed()) {
is CompletionResult.Success -> runTaskAsync(
CreateProductWalletTask(scanResponse.cardTypesResolver, seedResult.data),
CreateProductWalletTask(cardTypeResolver, seedResult.data),
scanResponse.card.cardId,
Message(context.getString(R.string.initial_message_create_wallet_body)),
)
@ -228,7 +232,7 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) {
tangemSdk.config.cardIdDisplayFormat = when {
scanResponse == null -> CardIdDisplayFormat.Full
scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
cardTypeResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
else -> CardIdDisplayFormat.Full
}
}

View file

@ -9,8 +9,6 @@ import com.tangem.common.doOnSuccess
import com.tangem.core.analytics.Analytics
import com.tangem.datasource.config.ConfigManager
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.attestation.Attestation
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.Basic
@ -25,6 +23,7 @@ import com.tangem.tap.features.disclaimer.createDisclaimer
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.CoroutineScope
@ -58,7 +57,10 @@ class TapWalletManager(
}
private suspend fun loadUserWalletData(userWallet: UserWallet, refresh: Boolean, sendAnalyticsEvent: Boolean) {
Analytics.setContext(userWallet.scanResponse)
Analytics.setContext(
scanResponse = userWallet.scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
if (sendAnalyticsEvent) {
Analytics.send(Basic.WalletOpened())
}
@ -68,7 +70,7 @@ class TapWalletManager(
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
store.state.globalState.feedbackManager?.infoHolder?.setCardInfo(scanResponse)
updateConfigManager(scanResponse)
updateConfigManager()
withMainContext {
// Order is important
store.dispatch(DisclaimerAction.SetDisclaimer(card.createDisclaimer()))
@ -135,10 +137,11 @@ class TapWalletManager(
}
}
fun updateConfigManager(data: ScanResponse) {
fun updateConfigManager() {
val configManager = store.state.globalState.configManager
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (data.cardTypesResolver.isStart2Coin()) {
if (cardTypeResolver.isStart2Coin()) {
configManager?.turnOff(ConfigManager.IS_TOP_UP_ENABLED)
} else {
configManager?.resetToDefault(ConfigManager.IS_TOP_UP_ENABLED)

View file

@ -1,24 +1,19 @@
package com.tangem.tap.domain.extensions
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.common.*
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toMapKey
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.models.Currency
fun WalletManagerFactory.makeWalletManagerForApp(
scanResponse: ScanResponse,
cardTypeResolver: CardTypeResolver,
blockchain: Blockchain,
derivationParams: DerivationParams?,
): WalletManager? {
@ -34,7 +29,7 @@ fun WalletManagerFactory.makeWalletManagerForApp(
val seedKey = wallet.extendedPublicKey
return when {
scanResponse.cardTypesResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
cardTypeResolver.isTangemTwins() && scanResponse.secondTwinPublicKey != null -> {
makeTwinWalletManager(
walletPublicKey = wallet.publicKey,
pairPublicKey = scanResponse.secondTwinPublicKey!!.hexToBytes(),
@ -68,17 +63,6 @@ fun WalletManagerFactory.makeWalletManagerForApp(
}
}
fun WalletManagerFactory.makeWalletManagerForApp(
scanResponse: ScanResponse,
blockchainNetwork: BlockchainNetwork,
): WalletManager? {
return makeWalletManagerForApp(
scanResponse,
blockchain = blockchainNetwork.blockchain,
derivationParams = getDerivationParams(blockchainNetwork.derivationPath, scanResponse.card),
)
}
private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? {
return derivationPath?.let {
DerivationParams.Custom(
@ -93,32 +77,19 @@ private fun getDerivationParams(derivationPath: String?, card: CardDTO): Derivat
}
}
fun WalletManagerFactory.makeWalletManagerForApp(scanResponse: ScanResponse, currency: Currency): WalletManager? {
return makeWalletManagerForApp(
scanResponse,
blockchain = currency.blockchain,
derivationParams = getDerivationParams(currency.derivationPath, scanResponse.card),
)
}
fun WalletManagerFactory.makeWalletManagersForApp(
fun WalletManagerFactory.makePrimaryWalletManager(
scanResponse: ScanResponse,
blockchains: List<Currency>,
): List<WalletManager> {
return blockchains
.filter { it.isBlockchain() }
.mapNotNull { this.makeWalletManagerForApp(scanResponse, it) }
}
fun WalletManagerFactory.makePrimaryWalletManager(scanResponse: ScanResponse): WalletManager? {
cardTypeResolver: CardTypeResolver,
): WalletManager? {
val blockchain = if (scanResponse.card.isTestCard) {
scanResponse.cardTypesResolver.getBlockchain().getTestnetVersion() ?: return null
cardTypeResolver.getBlockchain().getTestnetVersion() ?: return null
} else {
scanResponse.cardTypesResolver.getBlockchain()
cardTypeResolver.getBlockchain()
}
val derivationParams = getDerivationParams(null, scanResponse.card)
return makeWalletManagerForApp(
scanResponse = scanResponse,
cardTypeResolver = cardTypeResolver,
blockchain = blockchain,
derivationParams = derivationParams,
)

View file

@ -1,15 +1,16 @@
package com.tangem.tap.domain.model.builders
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.domain.userWalletList.GetCardImageUseCase
class UserWalletBuilder(
private val scanResponse: ScanResponse,
private val cardTypeResolver: CardTypeResolver,
private val getCardImageUseCase: GetCardImageUseCase = GetCardImageUseCase(),
) {
private var backupCardsIds: Set<String> = emptySet()
@ -46,7 +47,7 @@ class UserWalletBuilder(
artworkUrl = getCardImageUseCase.invoke(card.cardId, card.cardPublicKey),
cardsInWallet = backupCardsIds.plus(card.cardId),
scanResponse = this,
isMultiCurrency = cardTypesResolver.isMultiwalletAllowed(),
isMultiCurrency = cardTypeResolver.isMultiwalletAllowed(),
)
}
}

View file

@ -1,14 +1,10 @@
package com.tangem.tap.domain.model.builders
import com.tangem.blockchain.blockchains.polkadot.ExistentialDepositProvider
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.*
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.domain.model.WalletDataModel
import com.tangem.tap.domain.model.WalletStoreModel
@ -29,19 +25,25 @@ interface WalletStoreBuilder {
companion object {
operator fun invoke(
userWallet: UserWallet,
cardTypeResolver: CardTypeResolver,
blockchainNetwork: BlockchainNetwork,
): BlockchainNetworkWalletStoreBuilder {
return BlockchainNetworkWalletStoreBuilderImpl(userWallet, blockchainNetwork)
return BlockchainNetworkWalletStoreBuilderImpl(userWallet, cardTypeResolver, blockchainNetwork)
}
operator fun invoke(userWallet: UserWallet, walletManager: WalletManager): WalletMangerWalletStoreBuilder {
return WalletMangerWalletStoreBuilderImpl(userWallet, walletManager)
operator fun invoke(
userWallet: UserWallet,
cardTypeResolver: CardTypeResolver,
walletManager: WalletManager,
): WalletMangerWalletStoreBuilder {
return WalletMangerWalletStoreBuilderImpl(userWallet, cardTypeResolver, walletManager)
}
}
}
private class BlockchainNetworkWalletStoreBuilderImpl(
private val userWallet: UserWallet,
private val cardTypeResolver: CardTypeResolver,
private val blockchainNetwork: BlockchainNetwork,
) : WalletStoreBuilder.BlockchainNetworkWalletStoreBuilder {
private var walletManager: WalletManager? = null
@ -56,7 +58,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl(
val tokensWalletsData = blockchainNetwork.getTokensWalletsData(
walletManager = walletManager,
cardDerivationStyle = cardDerivationStyle,
primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(),
primaryToken = cardTypeResolver.getPrimaryToken(),
)
return WalletStoreModel(
@ -73,6 +75,7 @@ private class BlockchainNetworkWalletStoreBuilderImpl(
private class WalletMangerWalletStoreBuilderImpl(
private val userWallet: UserWallet,
private val cardTypeResolver: CardTypeResolver,
private val walletManager: WalletManager,
) : WalletStoreBuilder.WalletMangerWalletStoreBuilder {
@ -81,7 +84,7 @@ private class WalletMangerWalletStoreBuilderImpl(
val blockchainWalletData = wallet.blockchain.toBlockchainWalletData(walletManager)
val tokenWalletsData = wallet.getTokens().firstOrNull()?.toTokenWalletData(
walletManager = walletManager,
primaryToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken(),
primaryToken = cardTypeResolver.getPrimaryToken(),
)
return WalletStoreModel(

View file

@ -7,6 +7,7 @@ import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.models.scan.ScanResponse
@ -22,6 +23,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerCallback
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -71,7 +73,11 @@ internal object LegacyScanProcessor {
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
onScanStateChange(false)
sendAnalytics(analyticsEvent, scanResponse)
sendAnalytics(
analyticsEvent = analyticsEvent,
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
showDisclaimerIfNeed(
scanResponse = scanResponse,
@ -89,10 +95,14 @@ internal object LegacyScanProcessor {
}
}
private fun sendAnalytics(analyticsEvent: AnalyticsEvent?, scanResponse: ScanResponse) {
private fun sendAnalytics(
analyticsEvent: AnalyticsEvent?,
scanResponse: ScanResponse,
cardTypeResolver: CardTypeResolver,
) {
analyticsEvent?.let {
// this workaround needed to send CardWasScannedEvent without adding a context
val interceptor = CardContextInterceptor(scanResponse)
val interceptor = CardContextInterceptor(scanResponse, cardTypeResolver)
val params = it.params.toMutableMap()
interceptor.intercept(params)
it.params = params.toMap()
@ -146,18 +156,25 @@ internal object LegacyScanProcessor {
) {
val globalState = store.state.globalState
val tapWalletManager = globalState.tapWalletManager
tapWalletManager.updateConfigManager(scanResponse)
tapWalletManager.updateConfigManager()
store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(scanResponse))
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
Analytics.addContext(scanResponse)
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (OnboardingHelper.isOnboardingCase(scanResponse, cardTypeResolver)) {
Analytics.addContext(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
onWalletNotCreated()
store.dispatchOnMain(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = true))
val appScreen = OnboardingHelper.whereToNavigate(scanResponse)
navigateTo(appScreen) { onProgressStateChange(it) }
} else {
Analytics.setContext(scanResponse)
Analytics.setContext(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
if (scanResponse.twinsIsTwinned() && !preferencesStorage.wasTwinsOnboardingShown()) {
onWalletNotCreated()
store.dispatchOnMain(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly(scanResponse)))

View file

@ -49,7 +49,12 @@ internal object UseCaseScanProcessor {
val chains = buildList {
add(ScanningFinishedChain { onScanStateChange(false) })
if (analyticsEvent != null) {
add(AnalyticsChain(analyticsEvent))
add(
AnalyticsChain(
event = analyticsEvent,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
),
)
}
add(DisclaimerChain(store, disclaimerWillShow))
add(CheckForOnboardingChain(store, store.state.globalState.tapWalletManager, preferencesStorage))

View file

@ -4,6 +4,7 @@ import arrow.core.Either
import arrow.core.right
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.AnalyticsEvent
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.card.ScanCardException
import com.tangem.domain.core.chain.Chain
import com.tangem.domain.models.scan.ScanResponse
@ -19,12 +20,16 @@ import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor
*/
class AnalyticsChain(
private val event: AnalyticsEvent,
private val cardTypeResolver: CardTypeResolver,
) : Chain<ScanCardException.ChainException, ScanResponse> {
override suspend fun invoke(
previousChainResult: ScanResponse,
): Either<ScanCardException.ChainException, ScanResponse> {
val interceptor = CardContextInterceptor(previousChainResult)
val interceptor = CardContextInterceptor(
scanResponse = previousChainResult,
cardTypeResolver = cardTypeResolver,
)
val params = event.params.toMutableMap()
interceptor.intercept(params)
event.params = params.toMap()

View file

@ -20,6 +20,7 @@ import com.tangem.tap.domain.TapWalletManager
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import org.rekotlin.Store
@ -44,18 +45,25 @@ class CheckForOnboardingChain(
override suspend fun invoke(
previousChainResult: ScanResponse,
): Either<ScanCardException.ChainException, ScanResponse> {
tapWalletManager.updateConfigManager(previousChainResult)
tapWalletManager.updateConfigManager()
store.dispatchOnMain(TwinCardsAction.IfTwinsPrepareState(previousChainResult))
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
return when {
OnboardingHelper.isOnboardingCase(previousChainResult) -> {
Analytics.addContext(previousChainResult)
OnboardingHelper.isOnboardingCase(previousChainResult, cardTypeResolver) -> {
Analytics.addContext(
scanResponse = previousChainResult,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
store.dispatchOnMain(GlobalAction.Onboarding.Start(previousChainResult, canSkipBackup = true))
val appScreen = OnboardingHelper.whereToNavigate(previousChainResult)
ScanChainException.OnboardingNeeded(appScreen).left()
}
else -> {
Analytics.setContext(previousChainResult)
Analytics.setContext(
scanResponse = previousChainResult,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
// If twins was twinned previously but twins welcome not shown
if (previousChainResult.twinsIsTwinned() && !preferencesStore.wasTwinsOnboardingShown()) {
store.dispatchOnMain(

View file

@ -12,7 +12,7 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.map
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.models.scan.CardDTO
@ -55,7 +55,7 @@ private data class CreateWalletResponse(
}
class CreateProductWalletTask(
private val cardTypesResolver: CardTypesResolver,
private val cardTypeResolver: CardTypeResolver,
private val seed: ByteArray? = null,
) : CardSessionRunnable<CreateProductWalletTaskResponse> {
@ -72,8 +72,8 @@ class CreateProductWalletTask(
val cardDto = CardDTO(card)
val commandProcessor = when {
cardTypesResolver.isTangemNote() -> CreateWalletTangemNote(cardTypesResolver)
cardTypesResolver.isTangemTwins() ->
cardTypeResolver.isTangemNote() -> CreateWalletTangemNote(cardTypeResolver)
cardTypeResolver.isTangemTwins() ->
throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
else -> CreateWalletTangemWallet(seed)
@ -97,7 +97,7 @@ class CreateProductWalletTask(
}
}
private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesResolver) :
private class CreateWalletTangemNote(private val cardTypeResolver: CardTypeResolver) :
ProductCommandProcessor<CreateWalletResponse> {
override fun proceed(
card: CardDTO,
@ -109,7 +109,7 @@ private class CreateWalletTangemNote(private val cardTypesResolver: CardTypesRes
return
}
val curvesSupportedByBlockchain = cardTypesResolver.getBlockchain().getSupportedCurves().toSet()
val curvesSupportedByBlockchain = cardTypeResolver.getBlockchain().getSupportedCurves().toSet()
if (curvesSupportedByBlockchain.isEmpty()) {
callback(CompletionResult.Failure(TangemSdkError.CardError()))
return

View file

@ -1,5 +1,7 @@
package com.tangem.tap.domain.walletCurrencies.di
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager
@ -8,12 +10,14 @@ import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
@Suppress("LongParameterList")
fun WalletCurrenciesManager.Companion.provideDefaultImplementation(
userTokensRepository: UserTokensRepository,
walletStoresRepository: WalletStoresRepository,
walletAmountsRepository: WalletAmountsRepository,
walletManagersRepository: WalletManagersRepository,
appCurrencyProvider: () -> FiatCurrency,
cardTypeResolverProvider: Provider<CardTypeResolver>,
): WalletCurrenciesManager {
return DefaultWalletCurrenciesManager(
userTokensRepository = userTokensRepository,
@ -21,5 +25,6 @@ fun WalletCurrenciesManager.Companion.provideDefaultImplementation(
walletAmountsRepository = walletAmountsRepository,
walletManagersRepository = walletManagersRepository,
appCurrencyProvider = appCurrencyProvider,
cardTypeResolverProvider = cardTypeResolverProvider,
)
}

View file

@ -2,6 +2,8 @@ package com.tangem.tap.domain.walletCurrencies.implementation
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.common.*
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.util.UserWalletId
import com.tangem.domain.models.scan.CardDTO
@ -26,6 +28,7 @@ internal class DefaultWalletCurrenciesManager(
private val walletAmountsRepository: WalletAmountsRepository,
private val walletManagersRepository: WalletManagersRepository,
private val appCurrencyProvider: () -> FiatCurrency,
private val cardTypeResolverProvider: Provider<CardTypeResolver>,
) : WalletCurrenciesManager {
private val listeners = mutableListOf<WalletCurrenciesManager.Listener>()
@ -227,7 +230,11 @@ internal class DefaultWalletCurrenciesManager(
.flatMap { walletManager ->
walletStoresRepository.storeOrUpdate(
userWalletId = userWallet.walletId,
walletStore = WalletStoreBuilder(userWallet, blockchainNetwork)
walletStore = WalletStoreBuilder(
userWallet = userWallet,
cardTypeResolver = cardTypeResolverProvider.invoke(),
blockchainNetwork = blockchainNetwork,
)
.walletManager(walletManager)
.build(),
)

View file

@ -1,24 +1,23 @@
package com.tangem.tap.domain.walletStores.di
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.domain.walletStores.implementation.DummyWalletStoresManager
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.walletStores.WalletStoresManager
import com.tangem.tap.domain.walletStores.implementation.DefaultWalletStoresManager
import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
fun WalletStoresManager.Companion.provideDummyImplementation(): WalletStoresManager {
return DummyWalletStoresManager()
}
@Suppress("LongParameterList")
fun WalletStoresManager.Companion.provideDefaultImplementation(
userTokensRepository: UserTokensRepository,
walletStoresRepository: WalletStoresRepository,
walletAmountsRepository: WalletAmountsRepository,
walletManagersRepository: WalletManagersRepository,
appCurrencyProvider: () -> FiatCurrency,
cardTypeResolverProvider: Provider<CardTypeResolver>,
): WalletStoresManager {
return DefaultWalletStoresManager(
userTokensRepository = userTokensRepository,
@ -26,5 +25,6 @@ fun WalletStoresManager.Companion.provideDefaultImplementation(
walletAmountsRepository = walletAmountsRepository,
walletManagersRepository = walletManagersRepository,
appCurrencyProvider = appCurrencyProvider,
cardTypeResolverProvider = cardTypeResolverProvider,
)
}

View file

@ -2,12 +2,9 @@ package com.tangem.tap.domain.walletStores.implementation
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.CompletionResult
import com.tangem.common.doOnSuccess
import com.tangem.common.flatMap
import com.tangem.common.flatMapOnFailure
import com.tangem.common.fold
import com.tangem.common.map
import com.tangem.common.*
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.domain.common.util.UserWalletId
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.domain.model.UserWallet
@ -35,6 +32,7 @@ internal class DefaultWalletStoresManager(
private val walletAmountsRepository: WalletAmountsRepository,
private val walletManagersRepository: WalletManagersRepository,
private val appCurrencyProvider: () -> FiatCurrency,
private val cardTypeResolverProvider: Provider<CardTypeResolver>,
) : WalletStoresManager {
private val state = MutableStateFlow(State())
@ -151,7 +149,11 @@ internal class DefaultWalletStoresManager(
{ walletManager ->
walletStoresRepository.storeOrUpdate(
userWalletId = userWalletId,
walletStore = WalletStoreBuilder(userWallet, blockchainNetwork)
walletStore = WalletStoreBuilder(
userWallet = userWallet,
cardTypeResolver = cardTypeResolverProvider.invoke(),
blockchainNetwork = blockchainNetwork,
)
.walletManager(walletManager)
.build(),
)
@ -185,7 +187,11 @@ internal class DefaultWalletStoresManager(
val userWalletId = userWallet.walletId
walletStoresRepository.storeOrUpdate(
userWalletId = userWalletId,
walletStore = WalletStoreBuilder(userWallet, walletManager)
walletStore = WalletStoreBuilder(
userWallet = userWallet,
cardTypeResolver = cardTypeResolverProvider.invoke(),
walletManager = walletManager,
)
.build(),
)
}

View file

@ -2,6 +2,8 @@ package com.tangem.tap.domain.walletStores.repository.di
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.datasource.api.tangemTech.TangemTechService
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.tap.domain.walletStores.repository.WalletAmountsRepository
import com.tangem.tap.domain.walletStores.repository.WalletManagersRepository
import com.tangem.tap.domain.walletStores.repository.WalletStoresRepository
@ -16,8 +18,9 @@ fun WalletStoresRepository.Companion.provideDefaultImplementation(): WalletStore
fun WalletManagersRepository.Companion.provideDefaultImplementation(
walletManagerFactory: WalletManagerFactory,
cardTypeResolverProvider: Provider<CardTypeResolver>,
): WalletManagersRepository {
return DefaultWalletManagersRepository(walletManagerFactory)
return DefaultWalletManagersRepository(walletManagerFactory, cardTypeResolverProvider)
}
fun WalletAmountsRepository.Companion.provideDefaultImplementation(

View file

@ -1,22 +1,17 @@
package com.tangem.tap.domain.walletStores.repository.implementation
import com.tangem.blockchain.common.Amount
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.blockchain.common.*
import com.tangem.common.CompletionResult
import com.tangem.common.catching
import com.tangem.common.doOnSuccess
import com.tangem.common.mapFailure
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.UserWalletId
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
@ -30,6 +25,7 @@ import timber.log.Timber
internal class DefaultWalletManagersRepository(
private val walletManagerFactory: WalletManagerFactory,
private val cardTypeResolverProvider: Provider<CardTypeResolver>,
) : WalletManagersRepository {
private val walletManagersStorage = WalletManagerStorage
@ -56,10 +52,7 @@ internal class DefaultWalletManagersRepository(
derivationPath = blockchainNetwork?.derivationPath,
)
foundWalletManager?.updateTokens(
scanResponse = userWallet.scanResponse,
blockchainNetwork = blockchainNetwork,
)
foundWalletManager?.updateTokens(blockchainNetwork = blockchainNetwork)
?: makeAndStore(userWallet, blockchainNetwork)
}
@ -69,7 +62,7 @@ internal class DefaultWalletManagersRepository(
): CompletionResult<WalletManager> {
val scanResponse = userWallet.scanResponse
val blockchain = blockchainNetwork?.blockchain
?: scanResponse.cardTypesResolver.getBlockchain().let { blockchain ->
?: cardTypeResolverProvider.invoke().getBlockchain().let { blockchain ->
if (scanResponse.card.isTestCard) blockchain.getTestnetVersion() else blockchain
}
val derivationParams = getDerivationParams(
@ -80,6 +73,7 @@ internal class DefaultWalletManagersRepository(
val walletManager = blockchain?.let {
walletManagerFactory.makeWalletManagerForApp(
scanResponse = userWallet.scanResponse,
cardTypeResolver = cardTypeResolverProvider.invoke(),
blockchain = blockchain,
derivationParams = derivationParams,
)
@ -98,10 +92,7 @@ internal class DefaultWalletManagersRepository(
CompletionResult.Failure(error)
}
walletManager != null -> {
walletManager.updateTokens(
scanResponse = scanResponse,
blockchainNetwork = blockchainNetwork,
)
walletManager.updateTokens(blockchainNetwork = blockchainNetwork)
.doOnSuccess { store(userWallet.walletId, it) }
}
else -> {
@ -161,13 +152,10 @@ internal class DefaultWalletManagersRepository(
}
}
private fun WalletManager.updateTokens(
scanResponse: ScanResponse,
blockchainNetwork: BlockchainNetwork?,
): CompletionResult<WalletManager> {
private fun WalletManager.updateTokens(blockchainNetwork: BlockchainNetwork?): CompletionResult<WalletManager> {
val walletManager = this
return catching {
val tokens = blockchainNetwork?.tokens ?: listOfNotNull(scanResponse.cardTypesResolver.getPrimaryToken())
val tokens = blockchainNetwork?.tokens ?: listOfNotNull(cardTypeResolverProvider.invoke().getPrimaryToken())
if (tokens != walletManager.cardTokens) {
// TODO: remove ability to manipulate with walletManager.cardTokens

View file

@ -1,13 +1,14 @@
package com.tangem.tap.features.demo
import com.tangem.common.extensions.guard
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.common.demo.DemoConfig
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteAction
import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import kotlinx.coroutines.launch
@ -28,9 +29,14 @@ internal class DemoOnboardingNoteMiddleware : DemoMiddleware {
noteState.walletManager
} else {
val wmFactory = globalState.tapWalletManager.walletManagerFactory
val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard {
return false
}
val walletManager = wmFactory
.makePrimaryWalletManager(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.guard {
return false
}
store.dispatch(OnboardingNoteAction.SetWalletManager(walletManager))
walletManager
}

View file

@ -2,7 +2,6 @@ package com.tangem.tap.features.details.redux
import com.tangem.blockchain.common.Wallet
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.entities.FiatCurrency
import org.rekotlin.Action
@ -26,7 +25,7 @@ sealed class DetailsAction : Action {
object ScanCard : DetailsAction()
data class PrepareCardSettingsData(val card: CardDTO, val cardTypesResolver: CardTypesResolver) : DetailsAction()
data class PrepareCardSettingsData(val card: CardDTO) : DetailsAction()
object ResetCardSettingsData : DetailsAction()
sealed class AccessCodeRecovery : DetailsAction() {

View file

@ -8,7 +8,6 @@ import com.tangem.common.extensions.guard
import com.tangem.common.flatMap
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
@ -33,13 +32,8 @@ import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.walletStoresManager
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
@ -92,10 +86,7 @@ class DetailsMiddleware {
if (isSameWallet) {
store.dispatchOnMain(
DetailsAction.PrepareCardSettingsData(
scanResponse.card,
scanResponse.cardTypesResolver,
),
DetailsAction.PrepareCardSettingsData(card = scanResponse.card),
)
} else {
store.dispatchDialogShow(
@ -328,7 +319,12 @@ class DetailsMiddleware {
enableAccessCodesSaving: Boolean,
): CompletionResult<Unit> {
val userWallet = userWalletsListManager.selectedUserWalletSync
?: scanResponse?.let { UserWalletBuilder(it).build() }
?: scanResponse?.let {
UserWalletBuilder(
scanResponse = it,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
).build()
}
?: return CompletionResult.Failure(
error = TangemSdkError.ExceptionError(IllegalStateException("scanResponse is null")),
)

View file

@ -1,15 +1,15 @@
package com.tangem.tap.features.details.redux
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.extensions.signedHashesCount
import com.tangem.tap.preferencesStorage
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import org.rekotlin.Action
import java.util.*
import java.util.EnumSet
object DetailsReducer {
fun reduce(action: Action, state: AppState): DetailsState = internalReduce(action, state)
@ -23,11 +23,7 @@ private fun internalReduce(action: Action, state: AppState): DetailsState {
handlePrepareScreen(action)
}
is DetailsAction.PrepareCardSettingsData -> {
handlePrepareCardSettingsScreen(
card = action.card,
cardTypesResolver = action.cardTypesResolver,
state = detailsState,
)
handlePrepareCardSettingsScreen(card = action.card, state = detailsState)
}
is DetailsAction.ResetCardSettingsData -> detailsState.copy(cardSettingsState = null)
is DetailsAction.ResetToFactory -> {
@ -60,17 +56,14 @@ private fun handlePrepareScreen(action: DetailsAction.PrepareScreen): DetailsSta
)
}
private fun handlePrepareCardSettingsScreen(
card: CardDTO,
cardTypesResolver: CardTypesResolver,
state: DetailsState,
): DetailsState {
private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): DetailsState {
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
val cardSettingsState = CardSettingsState(
cardInfo = card.toCardInfo(cardTypesResolver),
manageSecurityState = prepareSecurityOptions(card, cardTypesResolver),
cardInfo = card.toCardInfo(cardTypeResolver),
manageSecurityState = prepareSecurityOptions(card, cardTypeResolver),
card = card,
resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypesResolver),
accessCodeRecovery = if (cardTypesResolver.isWallet2()) {
resetCardAllowed = isResetToFactoryAllowedByCard(card, cardTypeResolver),
accessCodeRecovery = if (cardTypeResolver.isWallet2()) {
val enabled = card.userSettings?.isUserCodeRecoveryAllowed ?: false
AccessCodeRecoveryState(
enabledOnCard = enabled,
@ -83,7 +76,7 @@ private fun handlePrepareCardSettingsScreen(
return state.copy(cardSettingsState = cardSettingsState)
}
private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesResolver): ManageSecurityState {
private fun prepareSecurityOptions(card: CardDTO, cardTypeResolver: CardTypeResolver): ManageSecurityState {
val securityOption = when {
card.isAccessCodeSet -> {
SecurityOption.AccessCode
@ -98,14 +91,15 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesRe
}
}
val allowedSecurityOptions = when {
cardTypesResolver.isStart2Coin() || cardTypesResolver.isTangemNote() -> {
cardTypeResolver.isStart2Coin() || cardTypeResolver.isTangemNote() -> {
EnumSet.of(SecurityOption.LongTap)
}
card.settings.isBackupAllowed -> {
EnumSet.of(securityOption)
}
else ->
prepareAllowedSecurityOptions(cardTypesResolver = cardTypesResolver, currentSecurityOption = securityOption)
else -> {
prepareAllowedSecurityOptions(cardTypeResolver = cardTypeResolver, currentSecurityOption = securityOption)
}
}
return ManageSecurityState(
currentOption = securityOption,
@ -114,9 +108,9 @@ private fun prepareSecurityOptions(card: CardDTO, cardTypesResolver: CardTypesRe
)
}
private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypesResolver: CardTypesResolver): Boolean {
private fun isResetToFactoryAllowedByCard(card: CardDTO, cardTypeResolver: CardTypeResolver): Boolean {
val hasPermanentWallet = card.wallets.any { it.settings.isPermanent }
val isNotAllowed = hasPermanentWallet || cardTypesResolver.isStart2Coin()
val isNotAllowed = hasPermanentWallet || cardTypeResolver.isStart2Coin()
return !isNotAllowed
}
@ -140,12 +134,10 @@ private fun handleSecurityAction(action: DetailsAction.ManageSecurity, state: De
// 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?.cardTypesResolver?.let {
prepareAllowedSecurityOptions(
cardTypesResolver = it,
currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption,
)
} ?: EnumSet.of(SecurityOption.LongTap),
allowedOptions = prepareAllowedSecurityOptions(
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
currentSecurityOption = state.cardSettingsState.manageSecurityState.selectedOption,
),
)
state.copy(
cardSettingsState = state.cardSettingsState?.copy(
@ -229,12 +221,12 @@ private fun handleAccessCodeRecoveryAction(
}
private fun prepareAllowedSecurityOptions(
cardTypesResolver: CardTypesResolver,
cardTypeResolver: CardTypeResolver,
currentSecurityOption: SecurityOption?,
): EnumSet<SecurityOption> {
val allowedSecurityOptions = EnumSet.of(SecurityOption.LongTap)
if (cardTypesResolver.isTangemTwins()) {
if (cardTypeResolver.isTangemTwins()) {
allowedSecurityOptions.add(SecurityOption.PassCode)
}
if (currentSecurityOption == SecurityOption.AccessCode) {
@ -246,9 +238,8 @@ private fun prepareAllowedSecurityOptions(
return allowedSecurityOptions
}
@Suppress("MagicNumber")
private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo {
val cardId = this.cardId.chunked(4).joinToString(separator = " ")
private fun CardDTO.toCardInfo(cardTypeResolver: CardTypeResolver): CardInfo {
val cardId = this.cardId.chunked(size = 4).joinToString(separator = " ")
val issuer = this.issuer.name
val signedHashes = this.signedHashesCount()
@ -256,7 +247,7 @@ private fun CardDTO.toCardInfo(cardTypesResolver: CardTypesResolver): CardInfo {
cardId = cardId,
issuer = issuer,
signedHashes = signedHashes,
isTwin = cardTypesResolver.isTangemTwins(),
isTwin = cardTypeResolver.isTangemTwins(),
hasBackup = backupStatus?.isActive == true,
)
}

View file

@ -8,7 +8,6 @@ import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.extensions.dispatchOnMain
@ -404,7 +403,8 @@ class WalletConnectMiddleware {
private fun handleScanResponse(scanResponse: ScanResponse, session: WalletConnectSession, blockchain: Blockchain) {
val card = scanResponse.card
if (!scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (!cardTypeResolver.isMultiwalletAllowed()) {
store.dispatchOnMain(WalletConnectAction.UnsupportedCard)
return
}

View file

@ -3,7 +3,6 @@ package com.tangem.tap.features.details.ui.details
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.common.analytics.events.Settings
import com.tangem.tap.common.feedback.FeedbackEmail
import com.tangem.tap.common.feedback.SupportInfo
@ -16,6 +15,7 @@ import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
import com.tangem.tap.features.home.LocaleRegionProvider
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.wallet.BuildConfig
import org.rekotlin.Store
@ -26,11 +26,11 @@ class DetailsViewModel(private val store: Store<AppState>) {
@Suppress("ComplexMethod")
fun updateState(state: DetailsState): DetailsScreenState {
val cardTypesResolver = state.scanResponse?.cardTypesResolver
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
val settings = SettingsElement.values().mapNotNull {
when (it) {
SettingsElement.WalletConnect -> {
if (cardTypesResolver?.isMultiwalletAllowed() == true) it else null
if (cardTypeResolver.isMultiwalletAllowed()) it else null
}
SettingsElement.SendFeedback -> it
SettingsElement.LinkMoreCards -> if (state.createBackupAllowed) it else null
@ -38,8 +38,8 @@ class DetailsViewModel(private val store: Store<AppState>) {
if (state.privacyPolicyUrl != null) it else null
}
SettingsElement.AppSettings -> if (state.appSettingsState.isBiometricsAvailable) it else null
SettingsElement.AppCurrency -> if (cardTypesResolver?.isMultiwalletAllowed() != true) it else null
SettingsElement.ReferralProgram -> if (cardTypesResolver?.isTangemWallet() == true) it else null
SettingsElement.AppCurrency -> if (!cardTypeResolver.isMultiwalletAllowed()) it else null
SettingsElement.ReferralProgram -> if (cardTypeResolver.isTangemWallet()) it else null
SettingsElement.TesterMenu -> if (BuildConfig.TESTER_MENU_ENABLED) it else null
else -> it
}

View file

@ -27,6 +27,7 @@ import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
import com.tangem.tap.features.home.redux.HomeMiddleware.BUY_WALLET_URL
import com.tangem.tap.features.send.redux.states.ButtonState
import com.tangem.tap.features.signin.redux.SignInAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
@ -101,10 +102,15 @@ private fun readCard(analyticsEvent: AnalyticsEvent?) = scope.launch {
}
private fun proceedWithScanResponse(scanResponse: ScanResponse) = scope.launch {
val userWallet = UserWalletBuilder(scanResponse).build().guard {
Timber.e("User wallet not created")
return@launch
}
val userWallet = UserWalletBuilder(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.build()
.guard {
Timber.e("User wallet not created")
return@launch
}
userWalletsListManager.save(userWallet)
.doOnFailure { error ->

View file

@ -4,10 +4,11 @@ import com.tangem.common.doOnFailure
import com.tangem.common.doOnSuccess
import com.tangem.common.extensions.guard
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.util.twinsIsTwinned
import com.tangem.domain.models.scan.ProductType
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.*
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.onUserWalletSelected
import com.tangem.tap.common.extensions.removeContext
@ -16,11 +17,7 @@ import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.model.builders.UserWalletBuilder
import com.tangem.tap.features.saveWallet.redux.SaveWalletAction
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import timber.log.Timber
@ -29,11 +26,11 @@ import timber.log.Timber
[REDACTED_AUTHOR]
*/
object OnboardingHelper {
fun isOnboardingCase(response: ScanResponse): Boolean {
fun isOnboardingCase(response: ScanResponse, cardTypeResolver: CardTypeResolver): Boolean {
val cardInfoStorage = preferencesStorage.usedCardsPrefStorage
val cardId = response.card.cardId
return when {
response.cardTypesResolver.isTangemTwins() -> {
cardTypeResolver.isTangemTwins() -> {
if (!response.twinsIsTwinned()) {
true
} else {
@ -41,7 +38,7 @@ object OnboardingHelper {
}
}
response.cardTypesResolver.isWallet2() -> {
cardTypeResolver.isWallet2() -> {
val emptyWallets = response.card.wallets.isEmpty()
val activationInProgress = cardInfoStorage.isActivationInProgress(cardId)
val backupNotActive = response.card.backupStatus?.isActive != true
@ -73,7 +70,10 @@ object OnboardingHelper {
accessCode: String? = null,
backupCardsIds: List<String>? = null,
) {
Analytics.setContext(scanResponse)
Analytics.setContext(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
when {
// When should save user wallets, then save card without navigate to save wallet screen
preferencesStorage.shouldSaveUserWallets -> scope.launch {
@ -119,7 +119,10 @@ object OnboardingHelper {
}
private suspend fun proceedWithScanResponse(scanResponse: ScanResponse, backupCardsIds: List<String>?) {
val userWallet = UserWalletBuilder(scanResponse)
val userWallet = UserWalletBuilder(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.backupCardsIds(backupCardsIds?.toSet())
.build()
.guard {

View file

@ -7,13 +7,7 @@ import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.extensions.dispatchDebugErrorNotification
import com.tangem.tap.common.extensions.dispatchDialogShow
import com.tangem.tap.common.extensions.dispatchErrorNotification
import com.tangem.tap.common.extensions.dispatchOnMain
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.extensions.getAddressData
import com.tangem.tap.common.extensions.getTopUpUrl
import com.tangem.tap.common.extensions.*
import com.tangem.tap.common.postUi
import com.tangem.tap.common.redux.AppDialog
import com.tangem.tap.common.redux.AppState
@ -29,6 +23,7 @@ import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
@ -123,7 +118,10 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
noteState.walletManager
} else {
val wmFactory = globalState.tapWalletManager.walletManagerFactory
val walletManager = wmFactory.makePrimaryWalletManager(scanResponse).guard {
val walletManager = wmFactory.makePrimaryWalletManager(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
).guard {
val message = "Loading cancelled. Cause: wallet manager didn't created"
val customError = TapError.CustomError(message)
store.dispatchErrorNotification(customError)

View file

@ -3,9 +3,8 @@ package com.tangem.tap.features.onboarding.products.otherCards.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.Onboarding
import com.tangem.tap.common.postUi
import com.tangem.tap.common.redux.AppState
@ -13,10 +12,7 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.wallet.models.toCurrencies
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userTokensRepository
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
@ -90,9 +86,10 @@ private fun handleOtherCardsAction(action: Action) {
onboardingManager.activationStarted(updatedCard.cardId)
store.state.globalState.topUpController?.registerEmptyWallet(updatedResponse)
val primaryBlockchain = updatedResponse.cardTypesResolver.getBlockchain()
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
val primaryBlockchain = cardTypeResolver.getBlockchain()
val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) {
val primaryToken = updatedResponse.cardTypesResolver.getPrimaryToken()
val primaryToken = cardTypeResolver.getPrimaryToken()
val blockchainNetwork =
BlockchainNetwork(
blockchain = primaryBlockchain,

View file

@ -29,6 +29,7 @@ import com.tangem.tap.features.wallet.models.Currency
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
@ -221,7 +222,10 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
twinCardsState.walletManager
} else {
val wmFactory = globalState.tapWalletManager.walletManagerFactory
val walletManager = wmFactory.makePrimaryWalletManager(getScanResponse()).guard {
val walletManager = wmFactory.makePrimaryWalletManager(
scanResponse = getScanResponse(),
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
).guard {
val message = "Loading cancelled. Cause: wallet manager didn't created"
val customError = TapError.CustomError(message)
store.dispatchErrorNotification(customError)

View file

@ -1,8 +1,9 @@
package com.tangem.tap.features.onboarding.products.twins.redux
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.getTwinCardNumber
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import org.rekotlin.Action
object TwinCardsReducer {
@ -17,7 +18,8 @@ private fun internalReduce(action: Action, state: AppState): TwinCardsState {
when (action) {
is TwinCardsAction.IfTwinsPrepareState -> {
state = if (action.scanResponse.cardTypesResolver.isTangemTwins()) {
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
state = if (cardTypeResolver.isTangemTwins()) {
val cardNumber = action.scanResponse.card.getTwinCardNumber() ?: return state
TwinCardsState(

View file

@ -7,7 +7,6 @@ import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ifNotNull
import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.feature.onboarding.data.model.CreateWalletResponse
@ -30,9 +29,9 @@ import com.tangem.tap.features.onboarding.OnboardingDialog
import com.tangem.tap.features.onboarding.OnboardingHelper
import com.tangem.tap.features.wallet.models.toCurrencies
import com.tangem.tap.features.wallet.redux.Artwork
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.DispatchFunction
import org.rekotlin.Middleware
object OnboardingWalletMiddleware {
@ -43,8 +42,8 @@ private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state
{ next ->
{ action ->
when (action) {
is OnboardingWallet2Action -> handleWallet2Action(action, state)
else -> handleWalletAction(action, state, dispatch)
is OnboardingWallet2Action -> handleWallet2Action(action)
else -> handleWalletAction(action)
}
next(action)
}
@ -52,7 +51,7 @@ private val onboardingWalletMiddleware: Middleware<AppState> = { dispatch, state
}
@Suppress("LongMethod", "ComplexMethod")
private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch: DispatchFunction) {
private fun handleWalletAction(action: Action) {
if (action !is OnboardingWalletAction) return
val globalState = store.state.globalState
@ -178,7 +177,7 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch:
}
@Suppress("LongMethod", "ComplexMethod")
private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> AppState?) {
private fun handleWallet2Action(action: OnboardingWallet2Action) {
val globalState = store.state.globalState
val onboardingManager = globalState.onboardingState.onboardingManager
@ -186,7 +185,8 @@ private fun handleWallet2Action(action: OnboardingWallet2Action, state: () -> Ap
when (action) {
is OnboardingWallet2Action.Init -> {
if (scanResponse?.cardTypesResolver?.isWallet2() == true) {
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (cardTypeResolver.isWallet2()) {
store.dispatch(OnboardingWallet2Action.SetDependencies(action.maxProgress))
}
}

View file

@ -7,6 +7,7 @@ import com.tangem.common.doOnSuccess
import com.tangem.common.extensions.guard
import com.tangem.common.flatMap
import com.tangem.core.analytics.Analytics
import com.tangem.tap.*
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.MainScreen
import com.tangem.tap.common.analytics.events.Onboarding
@ -21,12 +22,7 @@ import com.tangem.tap.domain.userWalletList.UserWalletsListManager
import com.tangem.tap.domain.userWalletList.di.provideBiometricImplementation
import com.tangem.tap.domain.userWalletList.isLockable
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.foregroundActivityObserver
import com.tangem.tap.preferencesStorage
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.tangemSdkManager
import com.tangem.tap.userWalletsListManager
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
@ -96,7 +92,10 @@ internal class SaveWalletMiddleware {
scope.launch {
val userWallet = userWalletsListManager.selectedUserWalletSync
?: UserWalletBuilder(scanResponse)
?: UserWalletBuilder(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.backupCardsIds(state.backupInfo?.backupCardsIds)
.build()
?: return@launch

View file

@ -4,7 +4,6 @@ import android.graphics.Bitmap
import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.WalletManager
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.toggleWidget.WidgetState
@ -50,9 +49,6 @@ data class WalletState(
store.state.twinCardsState
}
val isTangemTwins: Boolean
get() = store.state.globalState.scanResponse?.cardTypesResolver?.isTangemTwins() == true
val isExchangeServiceFeatureOn: Boolean
get() = store.state.globalState.exchangeManager.featureIsSwitchedOn()

View file

@ -19,6 +19,7 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.redux.WalletState
import com.tangem.tap.features.wallet.redux.models.WalletDialog
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.scope
import com.tangem.tap.store
import com.tangem.tap.userWalletsListManager
@ -82,7 +83,10 @@ class MultiWalletMiddleware {
return
}
val scanResponse = selectedUserWallet.scanResponse
Analytics.addContext(scanResponse)
Analytics.addContext(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
store.dispatch(GlobalAction.Onboarding.Start(scanResponse, canSkipBackup = false))
store.dispatch(NavigationAction.NavigateTo(AppScreen.OnboardingWallet))
}

View file

@ -5,7 +5,6 @@ import com.tangem.blockchain.common.SignatureCountValidator
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.tap.common.extensions.dispatchOnMain
@ -107,9 +106,10 @@ class WarningsMiddleware {
}
private fun checkIfWarningNeeded(scanResponse: ScanResponse): WarningMessage? {
if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.isDemoCard()) return null
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (cardTypeResolver.isTangemTwins() || scanResponse.isDemoCard()) return null
if (scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
if (cardTypeResolver.isMultiwalletAllowed()) {
val isBackupForbidden = with(scanResponse.card.settings) { !(isBackupAllowed || isHDWalletAllowed) }
return if (scanResponse.card.hasSignedHashes() && isBackupForbidden) {
WarningMessagesManager.signedHashesMultiWalletWarning
@ -139,9 +139,8 @@ class WarningsMiddleware {
val card = scanResponse?.card
if (card == null || preferencesStorage.usedCardsPrefStorage.wasScanned(card.cardId)) return
if (scanResponse.cardTypesResolver.isTangemTwins() || scanResponse.cardTypesResolver.isMultiwalletAllowed()) {
return
}
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (cardTypeResolver.isTangemTwins() || cardTypeResolver.isMultiwalletAllowed()) return
val validator = store.state.walletState.walletManagers.firstOrNull()
as? SignatureCountValidator

View file

@ -5,7 +5,6 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.events.MainScreen
@ -14,6 +13,7 @@ import com.tangem.tap.domain.model.TotalFiatBalance
import com.tangem.tap.domain.userWalletList.UserWalletsListManager
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.features.wallet.ui.analytics.WalletAnalyticsEventsMapper
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import com.tangem.tap.walletStoresManager
import dagger.hilt.android.lifecycle.HiltViewModel
@ -54,8 +54,9 @@ internal class WalletViewModel @Inject constructor(
override fun onCreate(owner: LifecycleOwner) {
launch()
val scanResponse = store.state.globalState.scanResponse
val cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver)
if (scanResponse != null) {
val currency = ParamCardCurrencyConverter().convert(scanResponse.cardTypesResolver)
val currency = ParamCardCurrencyConverter().convert(cardTypeResolver)
val signInType = store.state.signInState.type
if (currency != null && signInType != null) {
analyticsEventHandler.send(

View file

@ -22,6 +22,7 @@ import com.tangem.tap.domain.model.builders.UserWalletBuilder
import com.tangem.tap.domain.model.builders.UserWalletIdBuilder
import com.tangem.tap.domain.scanCard.ScanCardProcessor
import com.tangem.tap.domain.userWalletList.unlockIfLockable
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.firstOrNull
@ -162,7 +163,11 @@ internal class WalletSelectorMiddleware {
}
private suspend fun saveUserWalletAndPopBackToWalletScreen(scanResponse: ScanResponse): CompletionResult<Unit> {
val userWallet = UserWalletBuilder(scanResponse).build()
val userWallet = UserWalletBuilder(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.build()
?: return CompletionResult.Failure(TangemSdkError.WalletIsNotCreated())
return userWalletsListManager.save(userWallet)

View file

@ -1,10 +1,11 @@
package com.tangem.tap.features.walletSelector.redux
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.model.TotalFiatBalance
import com.tangem.tap.domain.model.UserWallet
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import org.rekotlin.Action
internal object WalletSelectorReducer {
@ -99,7 +100,10 @@ internal object WalletSelectorReducer {
)
} else {
UserWalletModel.Type.SingleCurrency(
blockchainName = scanResponse.cardTypesResolver.getBlockchain().fullName,
blockchainName = store.state.daggerGraphState
.get(DaggerGraphState::cardTypeResolver)
.getBlockchain()
.fullName,
)
}
}

View file

@ -20,6 +20,7 @@ import com.tangem.tap.domain.scanCard.ScanCardProcessor
import com.tangem.tap.domain.userWalletList.unlockIfLockable
import com.tangem.tap.features.intentHandler.handlers.WalletConnectLinkIntentHandler
import com.tangem.tap.features.signin.redux.SignInAction
import com.tangem.tap.proxy.redux.DaggerGraphState
import kotlinx.coroutines.launch
import org.rekotlin.Middleware
import timber.log.Timber
@ -79,7 +80,12 @@ internal class WelcomeMiddleware {
private fun proceedWithCard(state: WelcomeState) = scope.launch {
scanCardInternal { scanResponse ->
val userWallet = UserWalletBuilder(scanResponse).build() ?: return@scanCardInternal
val userWallet = UserWalletBuilder(
scanResponse = scanResponse,
cardTypeResolver = store.state.daggerGraphState.get(DaggerGraphState::cardTypeResolver),
)
.build()
?: return@scanCardInternal
userWalletsListManager.save(userWallet, canOverride = true)
.doOnFailure { error ->

View file

@ -0,0 +1,100 @@
package com.tangem.tap.legacy.card
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.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
internal class LegacyCardTypeResolver(
private val cardProvider: Provider<CardDTO>,
private val productTypeProvider: Provider<ProductType>,
private val walletDataProvider: Provider<WalletData?>,
) : CardTypeResolver {
private val card: CardDTO get() = cardProvider.invoke()
private val productType: ProductType get() = productTypeProvider.invoke()
private val walletData: WalletData? get() = walletDataProvider.invoke()
override fun isTangemNote(): Boolean = productType == ProductType.Note
override fun isTangemWallet(): Boolean {
return with(card.settings) {
isBackupAllowed && isHDWalletAllowed && card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable
}
}
override fun isWallet2(): Boolean {
return with(card) {
firmwareVersion >= FirmwareVersion.KeysImportAvailable && settings.isKeysImportAllowed
}
}
override fun isTangemTwins(): Boolean = productType == ProductType.Twins
override fun isStart2Coin(): Boolean = card.isStart2Coin
override fun isMultiwalletAllowed(): Boolean {
return (multiWalletAvailable() || card.wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1) &&
!isTangemTwins() && !card.isStart2Coin && !isTangemNote()
}
private fun multiWalletAvailable() = card.firmwareVersion >= FirmwareVersion.MultiWalletAvailable
override fun getBlockchain(): Blockchain {
if (productType == ProductType.Start2Coin) {
return if (card.isTestCard) Blockchain.BitcoinTestnet else Blockchain.Bitcoin
}
val blockchainName = walletData?.blockchain
?: return if (productType == ProductType.Note) {
TANGEM_NOTE_BATCHES[card.batchId] ?: Blockchain.Unknown
} else {
Blockchain.Unknown
}
return Blockchain.fromBlockchainName(blockchainName)
}
override fun getPrimaryToken(): Token? {
val cardToken = walletData?.token ?: return null
return Token(
name = cardToken.name,
symbol = cardToken.symbol,
contractAddress = cardToken.contractAddress,
decimals = cardToken.decimals,
)
}
private fun Blockchain.Companion.fromBlockchainName(name: String): Blockchain {
// workaround for BSC (BNB) notes cards
return when (name) {
"BINANCE" -> Blockchain.BSC
"BINANCE/test" -> Blockchain.BSCTestnet
else -> Blockchain.fromId(name)
}
}
private companion object {
val TANGEM_NOTE_BATCHES = mapOf(
"AB01" to Blockchain.Bitcoin,
"AB02" to Blockchain.Ethereum,
"AB03" to Blockchain.CardanoShelley,
"AB04" to Blockchain.Dogecoin,
"AB05" to Blockchain.BSC,
"AB06" to Blockchain.XRP,
"AB07" to Blockchain.Bitcoin,
"AB08" to Blockchain.Ethereum,
"AB09" to Blockchain.Bitcoin, // new batches for 3.34
"AB10" to Blockchain.Ethereum,
"AB11" to Blockchain.Bitcoin,
"AB12" to Blockchain.Ethereum,
)
}
}

View file

@ -0,0 +1,34 @@
package com.tangem.tap.legacy.card.di
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.common.Provider
import com.tangem.tap.legacy.card.LegacyCardTypeResolver
import com.tangem.tap.proxy.AppStateHolder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
internal object LegacyCardModule {
@Provides
@Singleton
fun providesCardTypeResolver(reduxStateHolder: AppStateHolder): CardTypeResolver {
return LegacyCardTypeResolver(
cardProvider = Provider {
requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.card)
},
productTypeProvider = Provider {
requireNotNull(
value = reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse?.productType,
)
},
walletDataProvider = Provider {
requireNotNull(reduxStateHolder.userWalletsListManager?.selectedUserWalletSync?.scanResponse).walletData
},
)
}
}

View file

@ -29,9 +29,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.coroutines.suspendCoroutine
class DerivationManagerImpl(
private val appStateHolder: AppStateHolder,
) : DerivationManager {
class DerivationManagerImpl(private val appStateHolder: AppStateHolder) : DerivationManager {
override suspend fun deriveMissingBlockchains(currency: Currency) = suspendCoroutine { continuation ->
val blockchain = Blockchain.fromNetworkId(currency.networkId)

View file

@ -46,9 +46,7 @@ class ProxyModule {
@Provides
@Singleton
fun provideDerivationManager(appStateHolder: AppStateHolder): DerivationManager {
return DerivationManagerImpl(
appStateHolder = appStateHolder,
)
return DerivationManagerImpl(appStateHolder = appStateHolder)
}
// regions FeatureConsumers

View file

@ -2,6 +2,7 @@ package com.tangem.tap.proxy.redux
import com.tangem.datasource.asset.AssetReader
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.domain.card.CardTypeResolver
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.features.tester.api.TesterRouter
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
@ -23,6 +24,7 @@ data class DaggerGraphState(
val walletConnectRepository: WalletConnectRepository? = null,
val walletConnectSessionsRepository: WalletConnectSessionsRepository? = null,
val walletConnectInteractor: WalletConnectInteractor? = null,
val cardTypeResolver: CardTypeResolver? = null,
) : StateType {
inline fun <reified T> get(getDependency: DaggerGraphState.() -> T?): T {