Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-25 16:39:35 +03:00
commit bfd903b43c
595 changed files with 12755 additions and 19837 deletions

View file

@ -19,7 +19,7 @@ import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.data.card.TransactionSignerFactory
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
@ -48,7 +48,6 @@ import com.tangem.tap.common.analytics.handlers.appsflyer.AppsFlyerClient
import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@ -58,12 +57,12 @@ import dagger.hilt.components.SingletonComponent
@Suppress("TooManyFunctions")
interface ApplicationEntryPoint {
fun getEnvironmentConfigStorage(): EnvironmentConfigStorage
fun getAppStateHolder(): AppStateHolder
fun getIssuersConfigStorage(): IssuersConfigStorage
fun getEnvironmentConfig(): EnvironmentConfig
fun getFeatureTogglesManager(): FeatureTogglesManager
fun getExcludedBlockchainsManager(): ExcludedBlockchainsManager
@ -120,8 +119,6 @@ interface ApplicationEntryPoint {
fun getOnboardingRepository(): OnboardingRepository
fun getCoroutineDispatcherProvider(): CoroutineDispatcherProvider
fun getExcludedBlockchains(): ExcludedBlockchains
fun getAppLogsStore(): AppLogsStore

View file

@ -44,7 +44,6 @@ import com.tangem.domain.settings.ShouldInitiallyAskPermissionUseCase
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.domain.staking.SendUnsubmittedHashesUseCase
import com.tangem.domain.wallets.usecase.ClearAllHotWalletContextualUnlockUseCase
import com.tangem.features.tangempay.TangemPayFeatureToggles
import com.tangem.features.tester.api.TesterMenuLauncher
import com.tangem.google.GoogleServicesHelper
import com.tangem.operations.backup.BackupService
@ -161,9 +160,6 @@ class MainActivity : AppCompatActivity(), ActivityResultCallbackHolder {
@Inject
internal lateinit var clearAllHotWalletContextualUnlockUseCase: ClearAllHotWalletContextualUnlockUseCase
@Inject
internal lateinit var tangemPayFeatureToggles: TangemPayFeatureToggles
private val viewModel: MainViewModel by viewModels()
private lateinit var appThemeModeFlow: SharedFlow<AppThemeMode>

View file

@ -36,7 +36,6 @@ import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
import com.tangem.datasource.api.common.createNetworkLoggingInterceptor
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
import com.tangem.datasource.local.logs.AppLogsStore
import com.tangem.datasource.local.preferences.AppPreferencesStore
@ -73,23 +72,19 @@ import com.tangem.tap.common.log.TangemAppLoggerInitializer
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.appReducer
import com.tangem.tap.domain.scanCard.CardScanningFeatureToggles
import com.tangem.tap.domain.tasks.product.DerivationsFinder
import com.tangem.tap.proxy.AppStateHolder
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.wallet.BuildConfig
import dagger.hilt.EntryPoints
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.rekotlin.Store
import timber.log.Timber
lateinit var store: Store<AppState>
val foregroundActivityObserver = ForegroundActivityObserver
internal lateinit var derivationsFinder: DerivationsFinder
open class TangemApplication : Application(), ImageLoaderFactory, Configuration.Provider {
@ -100,12 +95,12 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
private val appStateHolder: AppStateHolder
get() = entryPoint.getAppStateHolder()
private val environmentConfigStorage: EnvironmentConfigStorage
get() = entryPoint.getEnvironmentConfigStorage()
private val issuersConfigStorage: IssuersConfigStorage
get() = entryPoint.getIssuersConfigStorage()
private val environmentConfig: EnvironmentConfig
get() = entryPoint.getEnvironmentConfig()
private val featureTogglesManager: FeatureTogglesManager
get() = entryPoint.getFeatureTogglesManager()
@ -190,9 +185,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
private val onboardingRepository: OnboardingRepository
get() = entryPoint.getOnboardingRepository()
private val dispatchers: CoroutineDispatcherProvider
get() = entryPoint.getCoroutineDispatcherProvider()
private val excludedBlockchains: ExcludedBlockchains
get() = entryPoint.getExcludedBlockchains()
@ -312,9 +304,7 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
Timber.i(excludedBlockchainsManager.toString())
}
runBlocking {
initWithConfigDependency(environmentConfig = environmentConfigStorage.initialize())
}
initWithConfigDependency(environmentConfig = environmentConfig)
abTestsManager.init()
@ -348,15 +338,10 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
)
}
derivationsFinder = DerivationsFinder(
userTokensResponseStore = userTokensResponseStore,
dispatchers = dispatchers,
)
appStateHolder.mainStore = store
wcInitializeUseCase.init(
projectId = environmentConfigStorage.getConfigSync().walletConnectProjectId,
projectId = environmentConfig.walletConnectProjectId,
)
}
@ -387,7 +372,6 @@ open class TangemApplication : Application(), ImageLoaderFactory, Configuration.
shareManager = shareManager,
appRouter = appRouter,
transactionSignerFactory = transactionSignerFactory,
environmentConfigStorage = environmentConfigStorage,
onboardingV2FeatureToggles = onboardingV2FeatureToggles,
onboardingRepository = onboardingRepository,
excludedBlockchains = excludedBlockchains,

View file

@ -6,7 +6,6 @@ import com.tangem.tap.common.redux.legacy.LegacyMiddleware
import com.tangem.tap.features.details.redux.DetailsMiddleware
import com.tangem.tap.features.details.redux.DetailsState
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupMiddleware
import com.tangem.tap.features.wallet.redux.middlewares.TradeCryptoMiddleware
import com.tangem.tap.proxy.redux.DaggerGraphMiddleware
import com.tangem.tap.proxy.redux.DaggerGraphState
import org.rekotlin.Middleware
@ -29,7 +28,6 @@ data class AppState(
AccessCodeRequestPolicyMiddleware().middleware,
DaggerGraphMiddleware.daggerGraphMiddleware,
LegacyMiddleware.legacyMiddleware,
TradeCryptoMiddleware.middleware,
)
}
}

View file

@ -0,0 +1,29 @@
package com.tangem.tap.data
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.offramp.repository.OfframpRepository
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
import com.tangem.tap.network.exchangeServices.SellService
/**
* Default implementation of [OfframpRepository]
*
* @property sellService sell service for getting offramp URL
*/
internal class DefaultOfframpRepository(
private val sellService: SellService,
) : OfframpRepository {
override fun getOfframpUrl(
cryptoCurrency: CryptoCurrency,
fiatCurrencyCode: String,
walletAddress: String,
): String? {
return sellService.getUrl(
cryptoCurrency = cryptoCurrency,
fiatCurrencyName = fiatCurrencyCode,
walletAddress = walletAddress,
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
)
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.tap.di
import com.tangem.datasource.api.moonpay.MoonPayApi
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.exchange.RampStateManager
@ -69,14 +69,14 @@ internal object ActivityModule {
@Provides
@Singleton
fun provideExchangeService(
environmentConfigStorage: EnvironmentConfigStorage,
getSelectedWalletUseCase: GetSelectedWalletUseCase,
moonPayApi: MoonPayApi,
environmentConfig: EnvironmentConfig,
): SellService {
return MoonPayService(
api = moonPayApi,
apiKeyProvider = Provider { environmentConfigStorage.getConfigSync().moonPayApiKey },
secretKeyProvider = Provider { environmentConfigStorage.getConfigSync().moonPayApiSecretKey },
apiKey = environmentConfig.moonPayApiKey,
secretKey = environmentConfig.moonPayApiSecretKey,
userWalletProvider = { getSelectedWalletUseCase.sync().getOrNull() },
)
}

View file

@ -12,6 +12,7 @@ import com.tangem.features.onboarding.v2.OnboardingV2FeatureToggles
import com.tangem.sdk.api.TangemSdkManager
import com.tangem.tap.domain.sdk.impl.DefaultTangemSdkManager
import com.tangem.tap.domain.sdk.impl.MockTangemSdkManager
import com.tangem.tap.domain.tasks.product.BlockchainToDeriveFinder
import com.tangem.tap.domain.tasks.visa.TangemPayGenerateAddressAndSignChallengeTask
import com.tangem.tap.domain.tasks.visa.VisaCardActivationTask
import com.tangem.tap.domain.visa.VisaCardScanHandler
@ -40,6 +41,7 @@ internal class TangemSdkManagerModule {
appFinisher: AppFinisher,
sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
analyticsExceptionHandler: AnalyticsExceptionHandler,
blockchainToDeriveFinder: BlockchainToDeriveFinder,
dispatchers: CoroutineDispatcherProvider,
): TangemSdkManager {
return if (BuildConfig.MOCK_DATA_SOURCE) {
@ -56,6 +58,7 @@ internal class TangemSdkManagerModule {
appFinisher = appFinisher,
sendFeedbackEmailUseCase = sendFeedbackEmailUseCase,
analyticsExceptionHandler = analyticsExceptionHandler,
blockchainToDeriveFinder = blockchainToDeriveFinder,
dispatchers = dispatchers,
)
}

View file

@ -1,9 +1,9 @@
package com.tangem.tap.di.domain
import com.tangem.domain.account.supplier.MultiAccountListSupplier
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.earn.repository.EarnRepository
import com.tangem.domain.earn.usecase.*
import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -19,15 +19,15 @@ object EarnDomainModule {
}
@Provides
fun provideManageEarnNetworksUseCase(
fun provideGetEarnNetworksUseCase(
earnRepository: EarnRepository,
multiAccountListSupplier: MultiAccountListSupplier,
userWalletsListRepository: UserWalletsListRepository,
multiNetworkStatusSupplier: MultiNetworkStatusSupplier,
): GetEarnNetworksUseCase {
return GetEarnNetworksUseCase(
earnRepository = earnRepository,
multiAccountListSupplier = multiAccountListSupplier,
userWalletsListRepository = userWalletsListRepository,
multiNetworkStatusSupplier = multiNetworkStatusSupplier,
)
}

View file

@ -1,9 +1,13 @@
package com.tangem.tap.di.domain
import com.tangem.domain.offramp.GetOfframpUrlUseCase
import com.tangem.domain.offramp.repository.OfframpRepository
import com.tangem.domain.onramp.*
import com.tangem.domain.onramp.repositories.*
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.settings.repositories.SettingsRepository
import com.tangem.tap.data.DefaultOfframpRepository
import com.tangem.tap.network.exchangeServices.SellService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@ -275,4 +279,16 @@ internal object OnrampDomainModule {
promoRepository = promoRepository,
)
}
@Provides
@Singleton
fun provideOfframpRepository(sellService: SellService): OfframpRepository {
return DefaultOfframpRepository(sellService)
}
@Provides
@Singleton
fun provideGetOfframpUrlUseCase(offrampRepository: OfframpRepository): GetOfframpUrlUseCase {
return GetOfframpUrlUseCase(offrampRepository)
}
}

View file

@ -7,6 +7,7 @@ import com.tangem.domain.networks.multi.MultiNetworkStatusSupplier
import com.tangem.domain.networks.repository.NetworksRepository
import com.tangem.domain.networks.single.SingleNetworkStatusFetcher
import com.tangem.domain.networks.single.SingleNetworkStatusSupplier
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
import com.tangem.domain.promo.PromoRepository
import com.tangem.domain.quotes.QuotesRepository
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
@ -176,20 +177,6 @@ internal object TokensDomainModule {
return GetCryptoCurrencyUseCase(currenciesRepository, multiWalletCryptoCurrenciesSupplier)
}
@Provides
@Singleton
fun provideToggleTokenListGroupingUseCase(
dispatchers: CoroutineDispatcherProvider,
): ToggleTokenListGroupingUseCase {
return ToggleTokenListGroupingUseCase(dispatchers)
}
@Provides
@Singleton
fun provideToggleTokenListSortingUseCase(dispatchers: CoroutineDispatcherProvider): ToggleTokenListSortingUseCase {
return ToggleTokenListSortingUseCase(dispatchers)
}
@Provides
@Singleton
fun provideApplyTokenListSortingUseCase(
@ -378,6 +365,7 @@ internal object TokensDomainModule {
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
multiStakingBalanceFetcher: MultiStakingBalanceFetcher,
paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
stakingIdFactory: StakingIdFactory,
dispatchers: CoroutineDispatcherProvider,
): WalletBalanceFetcher {
@ -388,6 +376,7 @@ internal object TokensDomainModule {
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
multiStakingBalanceFetcher = multiStakingBalanceFetcher,
paymentAccountStatusFetcher = paymentAccountStatusFetcher,
stakingIdFactory = stakingIdFactory,
dispatchers = dispatchers,
)

View file

@ -53,11 +53,7 @@ import com.tangem.sdk.api.TangemSdkManager
import com.tangem.sdk.api.visa.VisaCardActivationResponse
import com.tangem.sdk.api.visa.VisaCardActivationTaskMode
import com.tangem.tap.common.analytics.events.TangemSdkErrorEvent
import com.tangem.tap.derivationsFinder
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
import com.tangem.tap.domain.tasks.product.ResetBackupCardTask
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.tap.domain.tasks.product.*
import com.tangem.tap.domain.tasks.visa.TangemPayGenerateAddressAndSignChallengeTask
import com.tangem.tap.domain.tasks.visa.TangemPaySignWithdrawalHashTask
import com.tangem.tap.domain.tasks.visa.VisaCardActivationTask
@ -85,6 +81,7 @@ internal class DefaultTangemSdkManager(
private val appFinisher: AppFinisher,
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
private val analyticsExceptionHandler: AnalyticsExceptionHandler,
private val blockchainToDeriveFinder: BlockchainToDeriveFinder,
dispatchers: CoroutineDispatcherProvider,
) : TangemSdkManager {
@ -172,7 +169,7 @@ internal class DefaultTangemSdkManager(
runTaskAsyncReturnOnMain(
runnable = ScanProductTask(
card = null,
derivationsFinder = derivationsFinder,
blockchainToDeriveFinder = blockchainToDeriveFinder,
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
visaCardScanHandler = visaCardScanHandler,
visaCoroutineScope = this,

View file

@ -0,0 +1,74 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.derivation.DerivationStyle
import com.tangem.blockchainsdk.utils.fromNetworkId
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.data.common.account.WalletAccountsFetcher
import com.tangem.data.wallets.derivations.BlockchainToDerive
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.domain.wallets.derivations.derivationStyleProvider
import com.tangem.tap.features.demo.DemoHelper
import javax.inject.Inject
/**
* Finder of blockchains to derive.
* Returns only saved, default or demo blockchains without any additional logic
* (no cardano/ethereum additions or unnecessary blockchain removals).
*/
class BlockchainToDeriveFinder @Inject constructor(
private val walletAccountsFetcher: WalletAccountsFetcher,
) {
suspend fun find(card: CardDTO): Set<BlockchainToDerive> {
if (!card.settings.isHDWalletAllowed || card.wallets.isEmpty()) return emptySet()
val userWalletId = UserWalletIdBuilder.card(card).build() ?: return emptySet()
val derivationStyle = card.derivationStyleProvider.getDerivationStyle()
val blockchains = getBlockchains(userWalletId).ifEmpty {
if (DemoHelper.isDemoCardId(card.cardId)) {
getDemoBlockchains(derivationStyle, card.cardId)
} else {
getDefaultBlockchains(derivationStyle)
}
}
return blockchains
}
private suspend fun getBlockchains(userWalletId: UserWalletId): Set<BlockchainToDerive> {
return walletAccountsFetcher.getSaved(userWalletId)?.accounts.orEmpty()
.flatMap { accountDTO ->
accountDTO.tokens.orEmpty()
.filter { it.contractAddress == null }
}
.mapNotNull { coin ->
val blockchain = Blockchain.fromNetworkId(coin.networkId) ?: return@mapNotNull null
val derivationPath = coin.derivationPath?.let(::DerivationPath) ?: return@mapNotNull null
BlockchainToDerive(blockchain, derivationPath)
}
.toSet()
}
private fun getDemoBlockchains(derivationStyle: DerivationStyle?, cardId: String): Set<BlockchainToDerive> {
return DemoHelper.config.getDemoBlockchains(cardId).mapToBlockchainsWithDerivations(derivationStyle)
}
private fun getDefaultBlockchains(derivationStyle: DerivationStyle?): Set<BlockchainToDerive> {
val defaultBlockchains = setOf(Blockchain.Bitcoin, Blockchain.Ethereum)
return defaultBlockchains.mapToBlockchainsWithDerivations(derivationStyle)
}
private fun Set<Blockchain>.mapToBlockchainsWithDerivations(
derivationStyle: DerivationStyle?,
): Set<BlockchainToDerive> {
return mapNotNullTo(hashSetOf()) { blockchain ->
val derivationPath = blockchain.derivationPath(derivationStyle) ?: return@mapNotNullTo null
BlockchainToDerive(blockchain, derivationPath)
}
}
}

View file

@ -1,131 +0,0 @@
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.blockchainsdk.utils.fromNetworkId
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.domain.wallets.derivations.DerivationStyleProvider
import com.tangem.domain.card.common.TapWorkarounds.hasOldStyleDerivation
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.tap.features.demo.DemoHelper
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 userTokensResponseStore: UserTokensResponseStore,
private val dispatchers: CoroutineDispatcherProvider,
) {
suspend fun findBlockchainsToDerive(
card: CardDTO,
derivationStyleProvider: DerivationStyleProvider,
): Set<BlockchainToDerive> {
if (!card.settings.isHDWalletAllowed || card.wallets.isEmpty()) return emptySet()
val userWalletId = UserWalletIdBuilder.card(card).build() ?: return emptySet()
val derivationStyle = derivationStyleProvider.getDerivationStyle()
val blockchains = withContext(dispatchers.io) {
getBlockchains(userWalletId)
}.ifEmpty {
if (DemoHelper.isDemoCardId(card.cardId)) {
getDemoBlockchains(derivationStyle, card.cardId)
} 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.hasOldStyleDerivation) {
blockchains.removeUnnecessaryBlockchains()
}
return blockchains
}
private suspend fun getBlockchains(userWalletId: UserWalletId): MutableSet<BlockchainToDerive> {
val responseTokens = userTokensResponseStore.getSyncOrNull(userWalletId = 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()
}
// TODO: Move to user wallet config
private fun getDemoBlockchains(derivationStyle: DerivationStyle?, cardId: String): MutableSet<BlockchainToDerive> {
return DemoHelper.config.getDemoBlockchains(cardId).mapToBlockchainsWithDerivations(derivationStyle)
}
// TODO: Move to user wallet config
private fun getDefaultBlockchains(derivationStyle: DerivationStyle?): MutableSet<BlockchainToDerive> {
val defaultBlockchains = setOf(Blockchain.Bitcoin, Blockchain.Ethereum)
return defaultBlockchains.mapToBlockchainsWithDerivations(derivationStyle)
}
}
private fun MutableSet<BlockchainToDerive>.addEthereumBlockchains(derivationStyle: DerivationStyle?) {
val ethereumBlockchains = setOf(Blockchain.Ethereum, Blockchain.EthereumTestnet)
.mapToBlockchainsWithDerivations(derivationStyle)
addAll(ethereumBlockchains)
}
private fun MutableSet<BlockchainToDerive>.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<BlockchainToDerive>.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<Blockchain>.mapToBlockchainsWithDerivations(
derivationStyle: DerivationStyle?,
): MutableSet<BlockchainToDerive> {
return mapTo(hashSetOf()) { blockchain ->
BlockchainToDerive(blockchain, blockchain.derivationPath(derivationStyle))
}
}

View file

@ -13,16 +13,14 @@ 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.wallets.derivations.DerivationStyleProvider
import com.tangem.data.wallets.derivations.MissedDerivationsFinder
import com.tangem.domain.card.common.TapWorkarounds.isExcluded
import com.tangem.domain.card.common.TapWorkarounds.isNotSupportedInThatRelease
import com.tangem.domain.card.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.card.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.card.common.TapWorkarounds.isVisa
import com.tangem.domain.card.common.TwinsHelper
import com.tangem.domain.wallets.derivations.derivationStyleProvider
import com.tangem.domain.card.common.visa.VisaUtilities
import com.tangem.domain.card.configs.CardConfig
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_IDS
import com.tangem.domain.models.scan.CardDTO.Companion.RING_BATCH_PREFIX
@ -45,11 +43,10 @@ import com.tangem.tap.scope
import com.tangem.tap.store
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.collections.set
internal class ScanProductTask(
private val card: Card?,
private val derivationsFinder: DerivationsFinder?,
private val blockchainToDeriveFinder: BlockchainToDeriveFinder?,
private val visaCardScanHandler: VisaCardScanHandler?,
private val visaCoroutineScope: CoroutineScope?,
private val onboardingV2FeatureToggles: OnboardingV2FeatureToggles?,
@ -81,7 +78,7 @@ internal class ScanProductTask(
readVisaCard(
session = session,
cardDto = cardDto,
scanWalletProcessor = ScanWalletProcessor(derivationsFinder),
scanWalletProcessor = ScanWalletProcessor(blockchainToDeriveFinder),
callback = callback,
)
return
@ -89,7 +86,7 @@ internal class ScanProductTask(
val commandProcessor = when {
cardDto.isTangemTwins -> ScanTwinProcessor()
else -> ScanWalletProcessor(derivationsFinder)
else -> ScanWalletProcessor(blockchainToDeriveFinder)
}
commandProcessor.proceed(cardDto, session) { processorResult ->
when (processorResult) {
@ -170,7 +167,7 @@ internal class ScanProductTask(
}
private class ScanWalletProcessor(
private val derivationsFinder: DerivationsFinder?,
private val blockchainToDeriveFinder: BlockchainToDeriveFinder?,
) : ProductCommandProcessor<ScanResponse> {
var primaryCard: PrimaryCard? = null
@ -293,7 +290,6 @@ private class ScanWalletProcessor(
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
val productType = getWalletProductType(card)
val config = CardConfig.createConfig(card)
scope.launch {
val scanResponse = ScanResponse(
card = card,
@ -301,8 +297,7 @@ private class ScanWalletProcessor(
walletData = session.environment.walletData,
primaryCard = primaryCard,
)
val derivations =
collectDerivations(card, config, scanResponse.derivationStyleProvider)
val derivations = collectDerivations(card, scanResponse)
if (derivations.isEmpty() || !card.settings.isHDWalletAllowed) {
callback(CompletionResult.Success(scanResponse))
return@launch
@ -332,32 +327,13 @@ private class ScanWalletProcessor(
private suspend fun collectDerivations(
card: CardDTO,
config: CardConfig,
derivationStyleProvider: DerivationStyleProvider,
scanResponse: ScanResponse,
): Map<ByteArrayKey, List<DerivationPath>> {
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
val blockchains = derivationsFinder
?.findBlockchainsToDerive(card, derivationStyleProvider)
?: return derivations
val blockchains = blockchainToDeriveFinder
?.find(card)
?: return emptyMap()
blockchains.forEach { blockchain ->
val curve = config.primaryCurve(blockchain.blockchain)
val wallet = card.wallets.firstOrNull { it.curve == curve } ?: return@forEach
if (wallet.chainCode == null) return@forEach
val key = wallet.publicKey.toMapKey()
val path = blockchain.derivationPath
if (path != null) {
val addedDerivations = derivations[key]
if (addedDerivations != null) {
derivations[key] = addedDerivations + path
} else {
derivations[key] = listOf(path)
}
}
}
return derivations
return MissedDerivationsFinder(scanResponse).findByBlockchainsToDerive(blockchains)
}
}

View file

@ -4,5 +4,9 @@ import com.tangem.core.configtoggle.feature.FeatureTogglesManager
import com.tangem.domain.tokens.TokensFeatureToggles
internal class DefaultTokensFeatureToggles(
@Suppress("UnusedPrivateMember") private val featureTogglesManager: FeatureTogglesManager,
) : TokensFeatureToggles
private val featureTogglesManager: FeatureTogglesManager,
) : TokensFeatureToggles {
override val isMultiAddressUtxoEnabled: Boolean
get() = featureTogglesManager.isFeatureEnabled("MULTI_ADDRESS_UTXO_ENABLED")
}

View file

@ -28,7 +28,7 @@ class FinalizeTwinTask(
is CompletionResult.Success ->
ScanProductTask(
card = readResult.data,
derivationsFinder = null,
blockchainToDeriveFinder = null,
visaCardScanHandler = null,
visaCoroutineScope = null,
shouldCheckIsAlreadyActivated = false,

View file

@ -88,7 +88,7 @@ internal class DefaultUserWalletsListRepository(
.map { wallets.updateWith(it) }
}
.doOnSuccess { loadedWallets ->
userWallets.update { toUpdate ->
userWallets.update { _ ->
val selectedUserWalletId = selectedUserWalletRepository.get()
selectedUserWallet.value = loadedWallets.firstOrNull { it.walletId == selectedUserWalletId }
?: loadedWallets.firstOrNull()?.also {
@ -240,7 +240,7 @@ internal class DefaultUserWalletsListRepository(
}
}
@Suppress("CyclomaticComplexMethod")
@Suppress("CyclomaticComplexMethod", "LongMethod")
override suspend fun unlock(
userWalletId: UserWalletId,
unlockMethod: UserWalletsListRepository.UnlockMethod,
@ -315,7 +315,13 @@ internal class DefaultUserWalletsListRepository(
sensitiveInformationRepository.getAll(listOf(encryptionKey))
.doOnSuccess { sensitiveInfo ->
updateWallets { it?.updateWith(sensitiveInfo) }
updateWallets { wallets ->
// It is necessary to update derivations because when scanning we obtain the missing keys
wallets?.updateWith(
walletIdToSensitiveInformation = sensitiveInfo,
walletIdToDerivedKeys = mapOf(userWallet.walletId to scanResponse.derivedKeys),
)
}
trackSignInEvent(userWallet, Basic.SignedIn.SignInType.Card)
}
.doOnFailure { error -> raise(UnlockWalletError.UnableToUnlock.RawException(error)) }

View file

@ -1,8 +1,10 @@
package com.tangem.tap.domain.userWalletList.utils
import com.tangem.domain.models.scan.KeyWalletPublicKey
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.models.wallet.isMultiCurrency
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
@ -72,7 +74,10 @@ internal fun List<UserWalletPublicInformation>.toUserWallets(): List<UserWallet>
return this.map { it.toUserWallet() }
}
internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInformation): UserWallet {
internal fun UserWallet.updateWith(
sensitiveInformation: UserWalletSensitiveInformation,
derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap>?,
): UserWallet {
return when (this) {
is UserWallet.Cold -> {
copy(
@ -80,6 +85,7 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
card = scanResponse.card.copy(
wallets = requireNotNull(sensitiveInformation.wallets),
),
derivedKeys = derivedKeys ?: scanResponse.derivedKeys,
// visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
),
)
@ -92,14 +98,20 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
internal fun List<UserWallet>.updateWith(
walletIdToSensitiveInformation: Map<UserWalletId, UserWalletSensitiveInformation>,
walletIdToDerivedKeys: Map<UserWalletId, Map<KeyWalletPublicKey, ExtendedPublicKeysMap>>? = null,
): List<UserWallet> {
return if (walletIdToSensitiveInformation.isEmpty()) {
this
} else {
this.map { wallet ->
walletIdToSensitiveInformation[wallet.walletId]
?.let(wallet::updateWith)
?: wallet
val sensitiveInformation = walletIdToSensitiveInformation[wallet.walletId]
val derivedKeys = walletIdToDerivedKeys?.get(wallet.walletId)
if (sensitiveInformation != null) {
wallet.updateWith(sensitiveInformation, derivedKeys)
} else {
wallet
}
}
}
}

View file

@ -221,7 +221,7 @@ internal class CardSettingsModel @Inject constructor(
val card = scanResponse.card
modelScope.launch {
val hasTangemPay = onboardingRepository.checkCustomerWallet(userWalletId).getOrNull() == true
val hasTangemPay = onboardingRepository.hasTangemPayInWallet(userWalletId).getOrNull() == true
store.dispatchNavigationAction {
push(
route = AppRoute.ResetToFactory(

View file

@ -1,66 +0,0 @@
package com.tangem.tap.features.wallet.redux.middlewares
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.Analytics
import com.tangem.domain.models.network.NetworkAddress
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.tap.common.analytics.events.Token
import com.tangem.tap.common.apptheme.MutableAppThemeModeHolder
import com.tangem.tap.common.extensions.dispatchNavigationAction
import com.tangem.tap.common.extensions.dispatchOpenUrl
import com.tangem.tap.common.extensions.inject
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.proxy.redux.DaggerGraphState
import com.tangem.tap.store
import org.rekotlin.Middleware
@Deprecated("Will be removed soon")
object TradeCryptoMiddleware {
val middleware: Middleware<AppState> = { _, appState ->
{ nextDispatch ->
{ action ->
if (action is TradeCryptoAction) {
handle(appState, action)
}
nextDispatch(action)
}
}
}
private fun handle(state: () -> AppState?, action: TradeCryptoAction) {
if (DemoHelper.tryHandle(state)) return
when (action) {
is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
is TradeCryptoAction.Sell -> proceedSellAction(action)
}
}
private fun proceedSellAction(action: TradeCryptoAction.Sell) {
val networkAddress = action.cryptoCurrencyStatus.value.networkAddress
?.defaultAddress
?.let(NetworkAddress.Address::value)
?: return
val currency = action.cryptoCurrencyStatus.currency
store.inject(DaggerGraphState::appStateHolder).sellService?.getUrl(
cryptoCurrency = currency,
fiatCurrencyName = action.appCurrencyCode,
walletAddress = networkAddress,
isDarkTheme = MutableAppThemeModeHolder.isDarkThemeActive,
)?.let { url ->
store.dispatchOpenUrl(url)
Analytics.send(Token.Withdraw.ScreenOpened())
}
}
private fun openReceiptUrl(transactionId: String) {
store.dispatchNavigationAction(AppRouter::pop)
val sellService = store.inject(DaggerGraphState::appStateHolder).sellService
sellService?.getSellCryptoReceiptUrl(transactionId = transactionId)
?.let(store::dispatchOpenUrl)
}
}

View file

@ -3,7 +3,7 @@ package com.tangem.tap.network.auth
import com.tangem.common.extensions.toHexString
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.config.ApiEnvironment
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.utils.Provider
@ -11,7 +11,7 @@ import com.tangem.utils.ProviderSuspend
internal class DefaultAuthProvider(
private val userWalletsListRepository: UserWalletsListRepository,
private val environmentConfigStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
) : AuthProvider {
override suspend fun getCardPublicKey(): String {
@ -47,11 +47,11 @@ internal class DefaultAuthProvider(
ApiEnvironment.DEV,
ApiEnvironment.DEV_2,
ApiEnvironment.DEV_3,
-> environmentConfigStorage.getConfigSync().tangemApiKeyDev
-> environmentConfig.tangemApiKeyDev
ApiEnvironment.STAGE_2,
ApiEnvironment.STAGE,
-> environmentConfigStorage.getConfigSync().tangemApiKeyStage
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().tangemApiKey
-> environmentConfig.tangemApiKeyStage
ApiEnvironment.PROD -> environmentConfig.tangemApiKey
} ?: error("No tangem tech api config provided")
}
}
@ -60,8 +60,8 @@ internal class DefaultAuthProvider(
return ProviderSuspend {
when (apiEnvironment.invoke()) {
ApiEnvironment.DEV,
-> environmentConfigStorage.getConfigSync().gaslessTxApiKeyDev
ApiEnvironment.PROD -> environmentConfigStorage.getConfigSync().gaslessTxApiKey
-> environmentConfig.gaslessTxApiKeyDev
ApiEnvironment.PROD -> environmentConfig.gaslessTxApiKey
else -> error("No gasless tx api config provided for ${apiEnvironment.invoke()}")
} ?: error("No gasless tx api config provided")
}

View file

@ -1,15 +1,15 @@
package com.tangem.tap.network.auth
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.staking.model.ethpool.P2PEthPoolStakingConfig
import com.tangem.lib.auth.P2PEthPoolAuthProvider
internal class DefaultP2PEthPoolAuthProvider(
private val environmentConfigStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
) : P2PEthPoolAuthProvider {
override fun getApiKey(): String {
val keys = environmentConfigStorage.getConfigSync().p2pApiKey
val keys = environmentConfig.p2pApiKey
?: error("No P2P api keys provided")
return if (P2PEthPoolStakingConfig.USE_TESTNET) keys.hoodi else keys.mainnet

View file

@ -1,13 +1,13 @@
package com.tangem.tap.network.auth
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.lib.auth.StakeKitAuthProvider
internal class DefaultStakeKitAuthProvider(
private val environmentConfigStorage: EnvironmentConfigStorage,
private val environmentConfig: EnvironmentConfig,
) : StakeKitAuthProvider {
override fun getApiKey(): String {
return environmentConfigStorage.getConfigSync().stakeKitApiKey ?: error("No StakeKit api key provided")
return environmentConfig.stakeKitApiKey ?: error("No StakeKit api key provided")
}
}

View file

@ -1,7 +1,7 @@
package com.tangem.tap.network.auth.di
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.environment.EnvironmentConfig
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.lib.auth.ExpressAuthProvider
import com.tangem.lib.auth.P2PEthPoolAuthProvider
@ -22,11 +22,11 @@ internal class AuthModule {
@Singleton
fun provideAuthProvider(
userWalletsListRepository: UserWalletsListRepository,
environmentConfigStorage: EnvironmentConfigStorage,
environmentConfig: EnvironmentConfig,
): AuthProvider {
return DefaultAuthProvider(
userWalletsListRepository = userWalletsListRepository,
environmentConfigStorage = environmentConfigStorage,
environmentConfig = environmentConfig,
)
}
@ -38,14 +38,14 @@ internal class AuthModule {
@Provides
@Singleton
fun provideStakeKitAuthProvider(environmentConfigStorage: EnvironmentConfigStorage): StakeKitAuthProvider {
return DefaultStakeKitAuthProvider(environmentConfigStorage)
fun provideStakeKitAuthProvider(environmentConfig: EnvironmentConfig): StakeKitAuthProvider {
return DefaultStakeKitAuthProvider(environmentConfig)
}
@Provides
@Singleton
fun provideP2PEthPoolAuthProvider(environmentConfigStorage: EnvironmentConfigStorage): P2PEthPoolAuthProvider {
return DefaultP2PEthPoolAuthProvider(environmentConfigStorage)
fun provideP2PEthPoolAuthProvider(environmentConfig: EnvironmentConfig): P2PEthPoolAuthProvider {
return DefaultP2PEthPoolAuthProvider(environmentConfig)
}
@Provides

View file

@ -21,6 +21,4 @@ interface SellService {
walletAddress: String,
isDarkTheme: Boolean,
): String?
fun getSellCryptoReceiptUrl(transactionId: String): String?
}

View file

@ -19,7 +19,6 @@ import com.tangem.tap.domain.model.Currency
import com.tangem.tap.network.exchangeServices.SellService
import com.tangem.tap.network.exchangeServices.SellServiceInitializationStatus
import com.tangem.tap.network.exchangeServices.moonpay.models.MoonPayAvailableCurrency
import com.tangem.utils.Provider
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import timber.log.Timber
@ -28,8 +27,8 @@ import javax.crypto.spec.SecretKeySpec
class MoonPayService(
private val api: MoonPayApi,
private val apiKeyProvider: Provider<String>,
private val secretKeyProvider: Provider<String>,
private val apiKey: String,
private val secretKey: String,
private val userWalletProvider: () -> UserWallet?,
) : SellService {
@ -47,18 +46,18 @@ class MoonPayService(
_initializationStatus.value = lceLoading()
performRequest {
val userStatus = when (val result = performRequest { api.getUserStatus(apiKeyProvider()) }) {
val userStatus = when (val result = performRequest { api.getUserStatus(apiKey) }) {
is Result.Failure -> {
Timber.e("Failed to load user status", result.error)
Timber.e(result.error, "Failed to load user status")
_initializationStatus.value = result.error.lceError()
return@performRequest
}
is Result.Success -> result.data
}
val currencies = when (val result = performRequest { api.getCurrencies(apiKeyProvider()) }) {
val currencies = when (val result = performRequest { api.getCurrencies(apiKey) }) {
is Result.Failure -> {
Timber.e("Failed to load currencies", result.error)
Timber.e(result.error, "Failed to load currencies")
_initializationStatus.value = result.error.lceError()
return@performRequest
}
@ -163,7 +162,7 @@ class MoonPayService(
val uri = Uri.Builder()
.scheme(SCHEME)
.authority(URL_SELL)
.appendQueryParameter("apiKey", apiKeyProvider())
.appendQueryParameter("apiKey", apiKey)
.appendQueryParameter("baseCurrencyCode", moonpayCurrency.currencyCode.uppercase())
.appendQueryParameter("refundWalletAddress", walletAddress)
.appendQueryParameter("redirectURL", "tangem://redirect_sell?currency_id=${cryptoCurrency.id.value}")
@ -177,17 +176,9 @@ class MoonPayService(
return uri.build().toString()
}
override fun getSellCryptoReceiptUrl(transactionId: String): String {
return Uri.Builder()
.scheme(SCHEME)
.authority(URL_SELL)
.appendPath("transaction_receipt")
.appendQueryParameter("transactionId", transactionId).build().toString()
}
private fun createSignature(data: String): String {
val sha256Hmac = Mac.getInstance("HmacSHA256")
val secretKey = SecretKeySpec(secretKeyProvider().toByteArray(), "HmacSHA256")
val secretKey = SecretKeySpec(secretKey.toByteArray(), "HmacSHA256")
sha256Hmac.init(secretKey)
val sha256encoded = sha256Hmac.doFinal("?$data".toByteArray())
return Base64.encodeToString(sha256encoded, Base64.NO_WRAP)

View file

@ -11,7 +11,6 @@ import com.tangem.core.navigation.url.UrlOpener
import com.tangem.core.ui.clipboard.ClipboardManager
import com.tangem.data.card.TransactionSignerFactory
import com.tangem.datasource.connection.NetworkConnectionManager
import com.tangem.datasource.local.config.environment.EnvironmentConfigStorage
import com.tangem.datasource.local.config.issuers.IssuersConfigStorage
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.token.UserTokensResponseStore
@ -63,7 +62,6 @@ data class DaggerGraphState(
val shareManager: ShareManager? = null,
val appRouter: AppRouter? = null,
val transactionSignerFactory: TransactionSignerFactory? = null,
val environmentConfigStorage: EnvironmentConfigStorage? = null,
val onboardingV2FeatureToggles: OnboardingV2FeatureToggles? = null,
val onboardingRepository: OnboardingRepository? = null,
val excludedBlockchains: ExcludedBlockchains? = null,

View file

@ -18,7 +18,6 @@ import com.tangem.features.details.component.DetailsComponent
import com.tangem.features.disclaimer.api.components.DisclaimerComponent
import com.tangem.features.feed.entry.components.FeedEntryComponent
import com.tangem.features.feed.entry.components.FeedEntryRoute
import com.tangem.features.feed.entry.featuretoggle.FeedFeatureToggle
import com.tangem.features.home.api.HomeComponent
import com.tangem.features.hotwallet.*
import com.tangem.features.kyc.KycComponent
@ -26,7 +25,6 @@ import com.tangem.features.managetokens.component.ChooseManagedTokensComponent
import com.tangem.features.managetokens.component.ManageTokensComponent
import com.tangem.features.managetokens.component.ManageTokensMode
import com.tangem.features.managetokens.component.ManageTokensSource
import com.tangem.features.markets.details.MarketsTokenDetailsComponent
import com.tangem.features.markets.tokenlist.MarketsTokenListComponent
import com.tangem.features.nft.component.NFTComponent
import com.tangem.features.onboarding.v2.entry.OnboardingEntryComponent
@ -67,7 +65,6 @@ internal class ChildFactory @Inject constructor(
private val walletHardwareBackupComponentFactory: WalletHardwareBackupComponent.Factory,
private val disclaimerComponentFactory: DisclaimerComponent.Factory,
private val manageTokensComponentFactory: ManageTokensComponent.Factory,
private val marketsTokenDetailsComponentFactory: MarketsTokenDetailsComponent.Factory,
private val marketsTokenListComponentFactory: MarketsTokenListComponent.FactoryScreen,
private val onrampComponentFactory: OnrampComponent.Factory,
private val onrampSuccessComponentFactory: OnrampSuccessComponent.Factory,
@ -117,7 +114,6 @@ internal class ChildFactory @Inject constructor(
private val kycComponentFactory: KycComponent.Factory,
private val yieldSupplyEntryComponentFactory: YieldSupplyEntryComponent.Factory,
private val feedEntryComponentFactory: FeedEntryComponent.Factory,
private val feedFeatureToggle: FeedFeatureToggle,
) {
@Suppress("LongMethod", "CyclomaticComplexMethod")
@ -193,39 +189,21 @@ internal class ChildFactory @Inject constructor(
)
}
is AppRoute.MarketsTokenDetails -> {
if (feedFeatureToggle.isFeedEnabled) {
createComponentChild(
context = context,
params = FeedEntryRoute.MarketTokenDetails(
token = route.token,
appCurrency = route.appCurrency,
shouldShowPortfolio = route.shouldShowPortfolio,
analyticsParams = route.analyticsParams?.let { params ->
FeedEntryRoute.MarketTokenDetails.AnalyticsParams(
blockchain = params.blockchain,
source = params.source,
)
},
),
componentFactory = feedEntryComponentFactory,
)
} else {
createComponentChild(
context = context,
params = MarketsTokenDetailsComponent.Params(
token = route.token,
appCurrency = route.appCurrency,
shouldShowPortfolio = route.shouldShowPortfolio,
analyticsParams = route.analyticsParams?.let { params ->
MarketsTokenDetailsComponent.AnalyticsParams(
blockchain = params.blockchain,
source = params.source,
)
},
),
componentFactory = marketsTokenDetailsComponentFactory,
)
}
createComponentChild(
context = context,
params = FeedEntryRoute.MarketTokenDetails(
token = route.token,
appCurrency = route.appCurrency,
shouldShowPortfolio = route.shouldShowPortfolio,
analyticsParams = route.analyticsParams?.let { params ->
FeedEntryRoute.MarketTokenDetails.AnalyticsParams(
blockchain = params.blockchain,
source = params.source,
)
},
),
componentFactory = feedEntryComponentFactory,
)
}
is AppRoute.Onramp -> {
createComponentChild(

View file

@ -7,7 +7,6 @@ import com.tangem.common.routing.DeepLinkScheme
import com.tangem.data.card.sdk.CardSdkProvider
import com.tangem.feature.referral.api.deeplink.ReferralDeepLinkHandler
import com.tangem.features.feed.entry.deeplink.NewsDetailsDeepLinkHandler
import com.tangem.features.feed.entry.featuretoggle.FeedFeatureToggle
import com.tangem.features.markets.deeplink.MarketsDeepLinkHandler
import com.tangem.features.markets.deeplink.MarketsTokenDetailDeepLinkHandler
import com.tangem.features.onramp.deeplink.BuyDeepLinkHandler
@ -53,7 +52,6 @@ internal class DeepLinkFactory @Inject constructor(
private val promoDeepLink: PromoDeeplinkHandler.Factory,
private val onboardVisaDeepLink: OnboardVisaDeepLinkHandler.Factory,
private val newsDetailsDeepLink: NewsDetailsDeepLinkHandler.Factory,
private val feedFeatureToggle: FeedFeatureToggle,
) {
private val permittedAppRoute = MutableStateFlow(false)
@ -127,7 +125,7 @@ internal class DeepLinkFactory @Inject constructor(
onboardVisaDeepLink.create(deeplinkUri)
return
}
deeplinkUri.path?.startsWith("/news") == true && feedFeatureToggle.isFeedEnabled -> {
deeplinkUri.path?.startsWith("/news") == true -> {
newsDetailsDeepLink.create(coroutineScope, deeplinkUri)
return
}