diff --git a/app/src/main/java/com/tangem/tap/TapApplication.kt b/app/src/main/java/com/tangem/tap/TapApplication.kt index b02a66920f..d88cedb4c2 100644 --- a/app/src/main/java/com/tangem/tap/TapApplication.kt +++ b/app/src/main/java/com/tangem/tap/TapApplication.kt @@ -22,6 +22,7 @@ import com.tangem.datasource.config.ConfigManager import com.tangem.datasource.config.FeaturesLocalLoader import com.tangem.datasource.config.models.Config import com.tangem.datasource.connection.NetworkConnectionManager +import com.tangem.datasource.local.token.UserTokensStore import com.tangem.domain.appcurrency.repository.AppCurrencyRepository import com.tangem.domain.apptheme.repository.AppThemeModeRepository import com.tangem.domain.balancehiding.repositories.BalanceHidingRepository @@ -50,7 +51,9 @@ import com.tangem.tap.common.redux.appReducer import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.shop.TangemShopService import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager +import com.tangem.tap.domain.tasks.product.DerivationsFinder import com.tangem.tap.domain.tokens.UserTokensRepository +import com.tangem.tap.domain.tokens.UserTokensStorageService import com.tangem.tap.domain.totalBalance.TotalFiatBalanceCalculator import com.tangem.tap.domain.totalBalance.di.provideDefaultImplementation import com.tangem.tap.domain.walletCurrencies.WalletCurrenciesManager @@ -67,6 +70,7 @@ import com.tangem.tap.features.details.DarkThemeFeatureToggle import com.tangem.tap.features.details.featuretoggles.DetailsFeatureToggles import com.tangem.tap.proxy.AppStateHolder import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.utils.coroutines.AppCoroutineDispatcherProvider import com.tangem.wallet.BuildConfig import dagger.hilt.android.HiltAndroidApp import kotlinx.coroutines.runBlocking @@ -82,7 +86,8 @@ lateinit var activityResultCaller: ActivityResultCaller lateinit var preferencesStorage: PreferencesDataSource lateinit var walletConnectRepository: WalletConnectRepository lateinit var shopService: TangemShopService -lateinit var userTokensRepository: UserTokensRepository +internal lateinit var userTokensRepository: UserTokensRepository +internal lateinit var derivationsFinder: DerivationsFinder private val walletStoresRepository by lazy { WalletStoresRepository.provideDefaultImplementation() } private val walletManagersRepository by lazy { @@ -123,8 +128,9 @@ val totalFiatBalanceCalculator by lazy { } @HiltAndroidApp -class TapApplication : Application(), ImageLoaderFactory { +internal class TapApplication : Application(), ImageLoaderFactory { + // region Injected @Inject lateinit var appStateHolder: AppStateHolder @@ -188,6 +194,10 @@ class TapApplication : Application(), ImageLoaderFactory { @Inject lateinit var darkThemeFeatureToggle: DarkThemeFeatureToggle + @Inject + lateinit var userTokensStore: UserTokensStore + // endregion Injected + override fun onCreate() { super.onCreate() @@ -247,10 +257,17 @@ class TapApplication : Application(), ImageLoaderFactory { ) } + val userTokensStorageService = UserTokensStorageService.init(context = this) userTokensRepository = UserTokensRepository.init( - context = this, tangemTechService = store.state.domainNetworks.tangemTechService, networkConnectionManager = networkConnectionManager, + storageService = userTokensStorageService, + ) + derivationsFinder = DerivationsFinder( + legacyTokensStore = userTokensStorageService, + newTokensStore = userTokensStore, + walletFeatureToggles = walletFeatureToggles, + dispatchers = AppCoroutineDispatcherProvider(), ) appStateHolder.mainStore = store appStateHolder.userTokensRepository = userTokensRepository diff --git a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt index 5e159ae358..15227361e9 100644 --- a/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt +++ b/app/src/main/java/com/tangem/tap/common/redux/global/GlobalAction.kt @@ -1,9 +1,7 @@ package com.tangem.tap.common.redux.global -import com.tangem.blockchain.common.Blockchain import com.tangem.blockchain.common.WalletManager import com.tangem.common.CompletionResult -import com.tangem.common.core.TangemError import com.tangem.datasource.config.ConfigManager import com.tangem.datasource.config.models.ChatConfig import com.tangem.domain.apptheme.model.AppThemeMode @@ -49,13 +47,6 @@ sealed class GlobalAction : Action { object Stop : Onboarding() } - data class ScanCard( - val additionalBlockchainsToDerive: Collection? = null, - val onSuccess: ((ScanResponse) -> Unit)? = null, - val onFailure: ((TangemError) -> Unit)? = null, - val messageResId: Int? = null, - ) : GlobalAction() - object ScanFailsCounter { data class ChooseBehavior(val result: CompletionResult) : GlobalAction() object Reset : GlobalAction() 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 0f2f76f8d0..e7421cf777 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 @@ -5,10 +5,8 @@ import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.guard import com.tangem.datasource.config.models.Config import com.tangem.domain.common.LogConfig -import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.* import com.tangem.tap.common.entities.FiatCurrency import com.tangem.tap.common.extensions.dispatchDebugErrorNotification import com.tangem.tap.common.extensions.dispatchDialogShow @@ -26,7 +24,11 @@ import com.tangem.tap.network.exchangeServices.ExchangeService import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoEnvironment import com.tangem.tap.network.exchangeServices.mercuryo.MercuryoService import com.tangem.tap.network.exchangeServices.moonpay.MoonPayService +import com.tangem.tap.preferencesStorage import com.tangem.tap.proxy.redux.DaggerGraphState +import com.tangem.tap.scope +import com.tangem.tap.store +import com.tangem.tap.walletCurrenciesManager import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import org.rekotlin.Action @@ -151,28 +153,6 @@ private fun handleAction(action: Action, appState: () -> AppState?, dispatch: Di } scope.launch { exchangeManager.update() } } - is GlobalAction.ScanCard -> { - scope.launch { - tangemSdkManager.changeDisplayedCardIdNumbersCount(null) - val result = tangemSdkManager.scanProduct( - userTokensRepository = userTokensRepository, - additionalBlockchainsToDerive = action.additionalBlockchainsToDerive, - messageRes = action.messageResId, - ) - withMainContext { - store.dispatch(GlobalAction.ScanFailsCounter.ChooseBehavior(result)) - when (result) { - is CompletionResult.Success -> { - tangemSdkManager.changeDisplayedCardIdNumbersCount(result.data) - action.onSuccess?.invoke(result.data) - } - is CompletionResult.Failure -> { - action.onFailure?.invoke(result.error) - } - } - } - } - } is GlobalAction.FetchUserCountry -> { scope.launch { // TODO("After adding DI") get dependencies by DI diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 58073accdf..67e752053c 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -8,7 +8,6 @@ import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository import com.tangem.tap.network.exchangeServices.DefaultRampManager import com.tangem.tap.proxy.AppStateHolder -import com.tangem.tap.userTokensRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -38,7 +37,6 @@ internal object ActivityModule { return ScanCardUseCase( cardSdkConfigRepository = cardSdkConfigRepository, scanCardRepository = DefaultScanCardRepository( - userTokensRepository = userTokensRepository, tangemSdkManager = tangemSdkManager, ), ) 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 6796da1e72..d692f0504a 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -4,7 +4,6 @@ import android.content.res.Resources import androidx.annotation.StringRes import com.tangem.Message import com.tangem.TangemSdk -import com.tangem.blockchain.common.Blockchain import com.tangem.common.* import com.tangem.common.biometric.BiometricManager import com.tangem.common.card.FirmwareVersion @@ -25,12 +24,12 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask import com.tangem.operations.pins.SetUserCodeCommand import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask import com.tangem.tap.common.analytics.events.Basic +import com.tangem.tap.derivationsFinder import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask import com.tangem.tap.domain.tasks.product.CreateProductWalletTask import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask import com.tangem.tap.domain.tasks.product.ScanProductTask -import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.wallet.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.suspendCancellableCoroutine @@ -38,7 +37,10 @@ import kotlinx.coroutines.withContext import kotlin.coroutines.resume @Suppress("TooManyFunctions") -class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigRepository, private val resources: Resources) { +class TangemSdkManager( + private val cardSdkConfigRepository: CardSdkConfigRepository, + private val resources: Resources, +) { private val tangemSdk: TangemSdk get() = cardSdkConfigRepository.sdk @@ -60,9 +62,7 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit get() = tangemSdk.biometricManager suspend fun scanProduct( - userTokensRepository: UserTokensRepository, cardId: String? = null, - additionalBlockchainsToDerive: Collection? = null, messageRes: Int? = null, allowsRequestAccessCodeFromRepository: Boolean = false, ): CompletionResult { @@ -70,8 +70,7 @@ class TangemSdkManager(private val cardSdkConfigRepository: CardSdkConfigReposit return runTaskAsyncReturnOnMain( runnable = ScanProductTask( card = null, - userTokensRepository = userTokensRepository, - additionalBlockchainsToDerive = additionalBlockchainsToDerive, + derivationsFinder = derivationsFinder, allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, ), cardId = cardId, diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index ec38e494bc..14a3027937 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -15,7 +15,10 @@ import com.tangem.domain.common.util.twinsIsTwinned import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.* import com.tangem.tap.common.analytics.paramsInterceptor.CardContextInterceptor -import com.tangem.tap.common.extensions.* +import com.tangem.tap.common.extensions.addContext +import com.tangem.tap.common.extensions.dispatchOnMain +import com.tangem.tap.common.extensions.dispatchWithMain +import com.tangem.tap.common.extensions.setContext import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.features.disclaimer.createDisclaimer import com.tangem.tap.features.disclaimer.redux.DisclaimerAction @@ -34,8 +37,7 @@ internal object LegacyScanProcessor { allowsRequestAccessCodeFromRepository: Boolean = false, ): CompletionResult { return tangemSdkManager.scanProduct( - userTokensRepository, - cardId, + cardId = cardId, allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, ) } @@ -56,10 +58,7 @@ internal object LegacyScanProcessor { tangemSdkManager.changeDisplayedCardIdNumbersCount(null) - val result = tangemSdkManager.scanProduct( - userTokensRepository = userTokensRepository, - cardId = cardId, - ) + val result = tangemSdkManager.scanProduct(cardId) store.dispatchOnMain(GlobalAction.ScanFailsCounter.ChooseBehavior(result)) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt index 2de676ba6c..f74d706775 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt @@ -8,13 +8,8 @@ import com.tangem.domain.card.repository.ScanCardRepository import com.tangem.domain.models.scan.ScanResponse import com.tangem.tap.domain.TangemSdkManager import com.tangem.tap.domain.scanCard.utils.ScanCardExceptionConverter -import com.tangem.tap.domain.tokens.UserTokensRepository internal class DefaultScanCardRepository( - // FIXME: The repository should not depend on another repository. - // But now we need to provide loadBlockchainsToDerive() to ScanProductTask and it's hard to move this method from - // UserTokensRepository. - private val userTokensRepository: UserTokensRepository, private val tangemSdkManager: TangemSdkManager, ) : ScanCardRepository { @@ -27,7 +22,6 @@ internal class DefaultScanCardRepository( when ( val result = tangemSdkManager.scanProduct( cardId = cardId, - userTokensRepository = userTokensRepository, allowsRequestAccessCodeFromRepository = allowRequestAccessCodeFromStorage, ) ) { 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 3c0467b1da..b6536cfd4b 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 @@ -303,7 +303,7 @@ private class CreateWalletTangemWallet( private fun getBlockchains(cardId: String, card: CardDTO): List { return when { - DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains + DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains.toList() card.isTestCard -> listOf(Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet) else -> listOf(Blockchain.Bitcoin, Blockchain.Ethereum) } diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt new file mode 100644 index 0000000000..38a23139b6 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/DerivationsFinder.kt @@ -0,0 +1,159 @@ +package com.tangem.tap.domain.tasks.product + +import com.tangem.blockchain.blockchains.cardano.CardanoUtils +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.derivation.DerivationStyle +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.datasource.local.token.UserTokensStore +import com.tangem.domain.common.DerivationStyleProvider +import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation +import com.tangem.domain.common.extensions.fromNetworkId +import com.tangem.domain.models.scan.CardDTO +import com.tangem.domain.userwallets.UserWalletIdBuilder +import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles +import com.tangem.tap.domain.tokens.UserTokensStorageService +import com.tangem.tap.features.demo.DemoHelper +import com.tangem.tap.features.wallet.models.Currency +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.withContext + +internal data class BlockchainToDerive( + val blockchain: Blockchain, + val derivationPath: DerivationPath?, +) + +// FIXME: May be move to DI, currently unnecessary +internal class DerivationsFinder( + private val legacyTokensStore: UserTokensStorageService, + private val newTokensStore: UserTokensStore, + private val walletFeatureToggles: WalletFeatureToggles, + private val dispatchers: CoroutineDispatcherProvider, +) { + + suspend fun findBlockchainsToDerive( + card: CardDTO, + derivationStyleProvider: DerivationStyleProvider, + ): Set { + if (!card.settings.isHDWalletAllowed || card.wallets.isEmpty()) return emptySet() + val userWalletId = UserWalletIdBuilder.card(card).build() ?: return emptySet() + val derivationStyle = derivationStyleProvider.getDerivationStyle() + + var blockchains = withContext(dispatchers.io) { + if (walletFeatureToggles.isRedesignedScreenEnabled) { + getBlockchainsNew(userWalletId) + } else { + getBlockchainsLegacy(userWalletId) + } + } + + if (blockchains.isEmpty()) { + blockchains = if (DemoHelper.isDemoCardId(card.cardId)) { + getDemoBlockchains(derivationStyle) + } else { + getDefaultBlockchains(derivationStyle) + } + } + + // we should generate second key for cardano + // because cardano address generation for wallet2 requires keys from 2 derivations + // https://developers.cardano.org/docs/get-started/cardano-serialization-lib/generating-keys/ + blockchains.addSecondCardanoDerivationIfPresent() + + if (card.settings.isHDWalletAllowed) { + blockchains.addEthereumBlockchains(derivationStyle) + } + + // pay attention to this + if (!card.useOldStyleDerivation) { + blockchains.removeUnnecessaryBlockchains() + } + + return blockchains + } + + private suspend fun getBlockchainsNew(userWalletId: UserWalletId): MutableSet { + val responseTokens = newTokensStore.getSyncOrNull(userWalletId) + ?.tokens + ?: return hashSetOf() + + return responseTokens.asSequence() + .filter { it.contractAddress == null } + .mapNotNull { coin -> + val blockchain = Blockchain.fromNetworkId(coin.networkId) ?: return@mapNotNull null + val derivationPath = coin.derivationPath?.let(::DerivationPath) + + BlockchainToDerive(blockchain, derivationPath) + } + .toMutableSet() + } + + private fun getBlockchainsLegacy(userWalletId: UserWalletId): MutableSet { + val currencies = legacyTokensStore.getUserTokens(userWalletId.stringValue) + ?.takeIf { it.isNotEmpty() } + ?: return hashSetOf() + + return currencies.asSequence() + .filterIsInstance() + .map { coin -> + val blockchain = coin.blockchain + val derivationPath = coin.derivationPath?.let(::DerivationPath) + + BlockchainToDerive(blockchain, derivationPath) + } + .toMutableSet() + } + + // TODO: Move to user wallet config + private fun getDemoBlockchains(derivationStyle: DerivationStyle?): MutableSet { + return DemoHelper.config.demoBlockchains.mapToBlockchainsWithDerivations(derivationStyle) + } + + // TODO: Move to user wallet config + private fun getDefaultBlockchains(derivationStyle: DerivationStyle?): MutableSet { + val defaultBlockchains = setOf(Blockchain.Bitcoin, Blockchain.Ethereum) + + return defaultBlockchains.mapToBlockchainsWithDerivations(derivationStyle) + } +} + +private fun MutableSet.addEthereumBlockchains(derivationStyle: DerivationStyle?) { + val ethereumBlockchains = setOf(Blockchain.Ethereum, Blockchain.EthereumTestnet) + .mapToBlockchainsWithDerivations(derivationStyle) + + addAll(ethereumBlockchains) +} + +private fun MutableSet.removeUnnecessaryBlockchains() { + val unnecessaryBlockchains = listOf( + Blockchain.BSC, Blockchain.BSCTestnet, + Blockchain.Polygon, Blockchain.PolygonTestnet, + Blockchain.RSK, + Blockchain.Fantom, Blockchain.FantomTestnet, + Blockchain.Avalanche, Blockchain.AvalancheTestnet, + ) + + removeAll { it.blockchain in unnecessaryBlockchains } +} + +private fun MutableSet.addSecondCardanoDerivationIfPresent() { + val cardanoDerivation = this + .firstOrNull { it.blockchain == Blockchain.Cardano } + ?.derivationPath + ?: return + + val secondCardanoBlockchain = BlockchainToDerive( + blockchain = Blockchain.Cardano, + derivationPath = CardanoUtils.extendedDerivationPath(cardanoDerivation), + ) + + add(secondCardanoBlockchain) +} + +private fun Set.mapToBlockchainsWithDerivations( + derivationStyle: DerivationStyle?, +): MutableSet { + return mapTo(hashSetOf()) { blockchain -> + BlockchainToDerive(blockchain, blockchain.derivationPath(derivationStyle)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt index 31a7a1ade4..30b5814a11 100644 --- a/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/tasks/product/ScanProductTask.kt @@ -1,7 +1,5 @@ package com.tangem.tap.domain.tasks.product -import com.tangem.blockchain.blockchains.cardano.CardanoUtils -import com.tangem.blockchain.common.Blockchain import com.tangem.common.CompletionResult import com.tangem.common.card.Card import com.tangem.common.card.FirmwareVersion @@ -15,13 +13,11 @@ import com.tangem.common.tlv.Tlv import com.tangem.common.tlv.TlvDecoder import com.tangem.crypto.CryptoUtils import com.tangem.crypto.hdWallet.DerivationPath -import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.TapWorkarounds.isExcluded import com.tangem.domain.common.TapWorkarounds.isNotSupportedInThatRelease import com.tangem.domain.common.TapWorkarounds.isStart2Coin import com.tangem.domain.common.TapWorkarounds.isTangemTwins -import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation import com.tangem.domain.common.TwinsHelper import com.tangem.domain.common.configs.CardConfig import com.tangem.domain.common.util.derivationStyleProvider @@ -35,16 +31,14 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask import com.tangem.operations.files.ReadFilesTask import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand import com.tangem.tap.domain.TapSdkError -import com.tangem.tap.domain.tokens.UserTokensRepository import com.tangem.tap.preferencesStorage import com.tangem.tap.scope import kotlinx.coroutines.launch import kotlin.collections.set -class ScanProductTask( - val card: Card? = null, - private val userTokensRepository: UserTokensRepository?, - private val additionalBlockchainsToDerive: Collection? = null, +internal class ScanProductTask( + private val card: Card?, + private val derivationsFinder: DerivationsFinder?, override val allowsRequestAccessCodeFromRepository: Boolean = false, ) : CardSessionRunnable { @@ -63,14 +57,14 @@ class ScanProductTask( val commandProcessor = when { cardDto.isTangemTwins -> ScanTwinProcessor() - else -> ScanWalletProcessor(userTokensRepository, additionalBlockchainsToDerive) + else -> ScanWalletProcessor(derivationsFinder) } commandProcessor.proceed(cardDto, session) { processorResult -> when (processorResult) { is CompletionResult.Success -> ScanTask().run(session) { scanTaskResult -> when (scanTaskResult) { is CompletionResult.Success -> { - // it need because processorResult.data.card doesn't contains attestation result + // it needed because processorResult.data.card doesn't contains attestation result // and CardWallet.derivedKeys val processorScanResponseWithNewCard = processorResult.data.copy( card = CardDTO(scanTaskResult.data), @@ -99,8 +93,7 @@ class ScanProductTask( } private class ScanWalletProcessor( - private val userTokensRepository: UserTokensRepository?, - private val additionalBlockchainsToDerive: Collection? = null, + private val derivationsFinder: DerivationsFinder?, ) : ProductCommandProcessor { var primaryCard: PrimaryCard? = null @@ -244,120 +237,15 @@ private class ScanWalletProcessor( } } - private suspend fun getBlockchainsToDerive( - card: CardDTO, - derivationStyleProvider: DerivationStyleProvider, - ): List { - val userTokensRepository = userTokensRepository ?: return emptyList() - val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive( - card, - derivationStyleProvider.getDerivationStyle(), - ) - .toMutableList() - .ifEmpty { getDefaultBlockchains(derivationStyleProvider) } - - if (card.settings.isHDWalletAllowed) { - blockchainsToDerive += getEthereumBlockchains(derivationStyleProvider) - } - - additionalBlockchainsToDerive?.let { - blockchainsToDerive += getAdditionalBlockchainToDerive(derivationStyleProvider, it) - } - - // we should generate second key for cardano - // because cardano address generation for wallet2 requires keys from 2 derivations - // https://developers.cardano.org/docs/get-started/cardano-serialization-lib/generating-keys/ - val secondCardanoNetwork = blockchainsToDerive - .find { it.blockchain == Blockchain.Cardano } - ?.let { getCardanoSecondNetwork(it) } - secondCardanoNetwork?.let { blockchainsToDerive.add(it) } - - // pay attention to this - if (!card.useOldStyleDerivation) { - removeUnnecessaryBlockchains(blockchainsToDerive, derivationStyleProvider) - } - - return blockchainsToDerive.distinct() - } - - private fun getDefaultBlockchains( - derivationStyleProvider: DerivationStyleProvider, - ): MutableList { - return mutableListOf( - BlockchainNetwork( - blockchain = Blockchain.Bitcoin, - derivationStyleProvider = derivationStyleProvider, - ), - BlockchainNetwork( - blockchain = Blockchain.Ethereum, - derivationStyleProvider = derivationStyleProvider, - ), - ) - } - - private fun getEthereumBlockchains(derivationStyleProvider: DerivationStyleProvider): List { - return listOf( - BlockchainNetwork( - blockchain = Blockchain.Ethereum, - derivationStyleProvider = derivationStyleProvider, - ), - BlockchainNetwork( - blockchain = Blockchain.EthereumTestnet, - derivationStyleProvider = derivationStyleProvider, - ), - ) - } - - private fun getAdditionalBlockchainToDerive( - derivationStyleProvider: DerivationStyleProvider, - collection: Collection, - ): List { - return collection.map { - BlockchainNetwork( - blockchain = it, - derivationStyleProvider = derivationStyleProvider, - ) - } - } - - private fun getCardanoSecondNetwork(cardanoBlockchainNetwork: BlockchainNetwork): BlockchainNetwork? { - val cardanoStandardDerivation = cardanoBlockchainNetwork.derivationPath?.let { DerivationPath(it) } - ?: return null - val cardanoPatchedDerivation = CardanoUtils.extendedDerivationPath(cardanoStandardDerivation) - return BlockchainNetwork( - blockchain = Blockchain.Cardano, - derivationPath = cardanoPatchedDerivation.rawPath, - tokens = emptyList(), - ) - } - - private fun removeUnnecessaryBlockchains( - blockchainsToDerive: MutableList, - derivationStyleProvider: DerivationStyleProvider, - ) { - blockchainsToDerive.removeAll( - listOf( - Blockchain.BSC, Blockchain.BSCTestnet, - Blockchain.Polygon, Blockchain.PolygonTestnet, - Blockchain.RSK, - Blockchain.Fantom, Blockchain.FantomTestnet, - Blockchain.Avalanche, Blockchain.AvalancheTestnet, - ).map { - BlockchainNetwork( - blockchain = it, - derivationStyleProvider = derivationStyleProvider, - ) - }, - ) - } - private suspend fun collectDerivations( card: CardDTO, config: CardConfig, derivationStyleProvider: DerivationStyleProvider, ): Map> { - val blockchains = getBlockchainsToDerive(card, derivationStyleProvider) val derivations = mutableMapOf>() + val blockchains = derivationsFinder + ?.findBlockchainsToDerive(card, derivationStyleProvider) + ?: return derivations blockchains.forEach { blockchain -> val curve = config.primaryCurve(blockchain.blockchain) @@ -365,7 +253,7 @@ private class ScanWalletProcessor( if (wallet.chainCode == null) return@forEach val key = wallet.publicKey.toMapKey() - val path = blockchain.derivationPath?.let { DerivationPath(it) } + val path = blockchain.derivationPath if (path != null) { val addedDerivations = derivations[key] if (addedDerivations != null) { @@ -375,6 +263,7 @@ private class ScanWalletProcessor( } } } + return derivations } } diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt index 7026203db3..a2baa9126b 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensRepository.kt @@ -1,13 +1,11 @@ package com.tangem.tap.domain.tokens -import android.content.Context import com.tangem.blockchain.common.derivation.DerivationStyle import com.tangem.common.core.TangemSdkError import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.TangemTechService import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.datasource.connection.NetworkConnectionManager -import com.tangem.datasource.files.AndroidFileReader import com.tangem.domain.common.BlockchainNetwork import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.userwallets.UserWalletIdBuilder @@ -131,12 +129,12 @@ class UserTokensRepository( // TODO("After adding DI") get dependencies by DI fun init( - context: Context, tangemTechService: TangemTechService, networkConnectionManager: NetworkConnectionManager, + storageService: UserTokensStorageService, ): UserTokensRepository { return UserTokensRepository( - storageService = UserTokensStorageService(fileReader = AndroidFileReader(context)), + storageService = storageService, tangemTechApi = tangemTechService.api, dispatchers = AppCoroutineDispatcherProvider(), networkConnectionManager = networkConnectionManager, diff --git a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt index ff90f83942..08fb2c4ce4 100644 --- a/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt +++ b/app/src/main/java/com/tangem/tap/domain/tokens/UserTokensStorageService.kt @@ -1,9 +1,11 @@ package com.tangem.tap.domain.tokens +import android.content.Context import com.squareup.moshi.JsonAdapter import com.tangem.Log import com.tangem.datasource.api.common.MoshiConverter import com.tangem.datasource.api.tangemTech.models.UserTokensResponse +import com.tangem.datasource.files.AndroidFileReader import com.tangem.datasource.files.FileReader import com.tangem.tap.features.wallet.models.Currency @@ -30,5 +32,7 @@ class UserTokensStorageService(private val fileReader: FileReader) { companion object { private const val FILE_NAME_PREFIX_USER_TOKENS = "user_tokens" private fun getFileNameForUserTokens(userId: String): String = "${FILE_NAME_PREFIX_USER_TOKENS}_$userId" + + fun init(context: Context) = UserTokensStorageService(AndroidFileReader(context)) } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt index 1ece7060b3..4e3364feba 100644 --- a/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt +++ b/app/src/main/java/com/tangem/tap/domain/twins/FinalizeTwinTask.kt @@ -23,7 +23,7 @@ class FinalizeTwinTask( PreflightReadTask(PreflightReadMode.FullCardRead).run(session) { readResult -> when (readResult) { is CompletionResult.Success -> - ScanProductTask(readResult.data, null) + ScanProductTask(readResult.data, derivationsFinder = null) .run(session, callback) is CompletionResult.Failure -> callback(CompletionResult.Failure(readResult.error)) diff --git a/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt b/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt index 864ed232f9..304c70af48 100644 --- a/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt +++ b/domain/demo/src/main/java/com/tangem/domain/demo/DemoConfig.kt @@ -9,7 +9,7 @@ import java.math.BigDecimal @Suppress("LargeClass") class DemoConfig { - val demoBlockchains = listOf( + val demoBlockchains = setOf( Blockchain.Bitcoin, Blockchain.Ethereum, Blockchain.Dogecoin,