Updated on 2026-08-14
This commit is contained in:
parent
879c8d603b
commit
af8fc1732d
14 changed files with 215 additions and 187 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Blockchain>? = null,
|
||||
val onSuccess: ((ScanResponse) -> Unit)? = null,
|
||||
val onFailure: ((TangemError) -> Unit)? = null,
|
||||
val messageResId: Int? = null,
|
||||
) : GlobalAction()
|
||||
|
||||
object ScanFailsCounter {
|
||||
data class ChooseBehavior(val result: CompletionResult<ScanResponse>) : GlobalAction()
|
||||
object Reset : GlobalAction()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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<Blockchain>? = null,
|
||||
messageRes: Int? = null,
|
||||
allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
): CompletionResult<ScanResponse> {
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<ScanResponse> {
|
||||
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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ private class CreateWalletTangemWallet(
|
|||
|
||||
private fun getBlockchains(cardId: String, card: CardDTO): List<Blockchain> {
|
||||
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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<BlockchainToDerive> {
|
||||
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<BlockchainToDerive> {
|
||||
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<BlockchainToDerive> {
|
||||
val currencies = legacyTokensStore.getUserTokens(userWalletId.stringValue)
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?: return hashSetOf()
|
||||
|
||||
return currencies.asSequence()
|
||||
.filterIsInstance<Currency.Blockchain>()
|
||||
.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<BlockchainToDerive> {
|
||||
return DemoHelper.config.demoBlockchains.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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Blockchain>? = null,
|
||||
internal class ScanProductTask(
|
||||
private val card: Card?,
|
||||
private val derivationsFinder: DerivationsFinder?,
|
||||
override val allowsRequestAccessCodeFromRepository: Boolean = false,
|
||||
) : CardSessionRunnable<ScanResponse> {
|
||||
|
||||
|
|
@ -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<Blockchain>? = null,
|
||||
private val derivationsFinder: DerivationsFinder?,
|
||||
) : ProductCommandProcessor<ScanResponse> {
|
||||
|
||||
var primaryCard: PrimaryCard? = null
|
||||
|
|
@ -244,120 +237,15 @@ private class ScanWalletProcessor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getBlockchainsToDerive(
|
||||
card: CardDTO,
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
): List<BlockchainNetwork> {
|
||||
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<BlockchainNetwork> {
|
||||
return mutableListOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Bitcoin,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getEthereumBlockchains(derivationStyleProvider: DerivationStyleProvider): List<BlockchainNetwork> {
|
||||
return listOf(
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.Ethereum,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
BlockchainNetwork(
|
||||
blockchain = Blockchain.EthereumTestnet,
|
||||
derivationStyleProvider = derivationStyleProvider,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getAdditionalBlockchainToDerive(
|
||||
derivationStyleProvider: DerivationStyleProvider,
|
||||
collection: Collection<Blockchain>,
|
||||
): List<BlockchainNetwork> {
|
||||
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<BlockchainNetwork>,
|
||||
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<ByteArrayKey, List<DerivationPath>> {
|
||||
val blockchains = getBlockchainsToDerive(card, derivationStyleProvider)
|
||||
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.math.BigDecimal
|
|||
@Suppress("LargeClass")
|
||||
class DemoConfig {
|
||||
|
||||
val demoBlockchains = listOf(
|
||||
val demoBlockchains = setOf(
|
||||
Blockchain.Bitcoin,
|
||||
Blockchain.Ethereum,
|
||||
Blockchain.Dogecoin,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue