Updated on 2026-08-14

This commit is contained in:
Tangem 2025-07-16 13:35:39 +03:00
parent 8541957ee3
commit 189ffd9927
73 changed files with 547 additions and 409 deletions

View file

@ -3,6 +3,7 @@ package com.tangem.tap.common.extensions
import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.Analytics
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.builder.UserWalletIdBuilder import com.tangem.domain.wallets.builder.UserWalletIdBuilder
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor import com.tangem.tap.common.analytics.paramsInterceptor.LinkedCardContextInterceptor
/** /**
@ -21,6 +22,15 @@ fun Analytics.setContext(scanResponse: ScanResponse) {
addParamsInterceptor(LinkedCardContextInterceptor(scanResponse)) addParamsInterceptor(LinkedCardContextInterceptor(scanResponse))
} }
fun Analytics.setContext(userWallet: UserWallet) {
setUserId(userWallet.walletId.stringValue)
// TODO add product type for hot ([REDACTED_TASK_KEY])
if (userWallet is UserWallet.Cold) {
addParamsInterceptor(LinkedCardContextInterceptor(userWallet.scanResponse))
}
}
/** /**
* Erases the context * Erases the context
*/ */

View file

@ -5,7 +5,6 @@ import com.tangem.blockchain.common.Wallet
import com.tangem.core.analytics.Analytics import com.tangem.core.analytics.Analytics
import com.tangem.domain.common.extensions.withMainContext import com.tangem.domain.common.extensions.withMainContext
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.tap.common.extensions.setContext import com.tangem.tap.common.extensions.setContext
import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.store import com.tangem.tap.store
@ -35,14 +34,15 @@ class TapWalletManager(
} }
private suspend fun loadUserWalletData(userWallet: UserWallet) { private suspend fun loadUserWalletData(userWallet: UserWallet) {
Analytics.setContext(userWallet.requireColdWallet().scanResponse) // [REDACTED_TASK_KEY] Analytics.setContext(userWallet)
val scanResponse = userWallet.scanResponse
tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse) if (userWallet is UserWallet.Cold) {
val scanResponse = userWallet.scanResponse
withMainContext { tangemSdkManager.changeDisplayedCardIdNumbersCount(scanResponse)
// Order is important withMainContext {
store.dispatch(GlobalAction.SaveScanResponse(scanResponse)) // Order is important
store.dispatch(GlobalAction.SaveScanResponse(scanResponse))
}
} }
} }
} }

View file

@ -50,7 +50,7 @@ internal class DefaultDerivationsRepository(
networkFactory.create( networkFactory.create(
blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null, blockchain = Blockchain.fromNetworkId(it.value) ?: return@mapNotNull null,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
}, },
) )
@ -91,7 +91,7 @@ internal class DefaultDerivationsRepository(
networkFactory.create( networkFactory.create(
blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null, blockchain = Blockchain.fromNetworkId(backendId) ?: return@mapNotNull null,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
}, },
) )

View file

@ -7,7 +7,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockTy
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isLocked import com.tangem.domain.wallets.models.isLocked
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey import com.tangem.tap.domain.userWalletList.model.UserWalletEncryptionKey
import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository import com.tangem.tap.domain.userWalletList.repository.SelectedUserWalletRepository
import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository import com.tangem.tap.domain.userWalletList.repository.UserWalletsKeysRepository
@ -208,8 +207,7 @@ internal class BiometricUserWalletsListManager(
changeSelectedUserWallet: Boolean, changeSelectedUserWallet: Boolean,
canOverridePublicInfo: Boolean, canOverridePublicInfo: Boolean,
): CompletionResult<Unit> { ): CompletionResult<Unit> {
userWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY] val encryptionKey = userWallet.encryptionKey
val encryptionKey = userWallet.scanResponse.card.encryptionKey
?.let { UserWalletEncryptionKey(userWallet.walletId, it) } ?.let { UserWalletEncryptionKey(userWallet.walletId, it) }
?: return CompletionResult.Success(Unit) // No encryption key, no need to save ?: return CompletionResult.Success(Unit) // No encryption key, no need to save

View file

@ -2,31 +2,44 @@ package com.tangem.tap.domain.userWalletList.model
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import com.tangem.domain.models.MobileWallet
import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.visa.model.VisaCardActivationStatus import com.tangem.domain.visa.model.VisaCardActivationStatus
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.hot.sdk.model.HotWalletId
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class UserWalletSensitiveInformation( internal data class UserWalletSensitiveInformation(
// Cold
@Json(name = "wallets") @Json(name = "wallets")
val wallets: List<CardDTO.Wallet>, val wallets: List<CardDTO.Wallet>?,
@Json(name = "visaCardActivationStatus") @Json(name = "visaCardActivationStatus")
val visaCardActivationStatus: VisaCardActivationStatus? = null, val visaCardActivationStatus: VisaCardActivationStatus? = null,
// Hot
@Json(name = "mobileWallets")
val mobileWallets: List<MobileWallet>? = null,
) )
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class UserWalletPublicInformation( internal data class UserWalletPublicInformation(
// Common
@Json(name = "name") @Json(name = "name")
val name: String, val name: String,
@Json(name = "walletId") @Json(name = "walletId")
val walletId: UserWalletId, val walletId: UserWalletId,
// Cold
@Json(name = "cardsInWallet") @Json(name = "cardsInWallet")
val cardsInWallet: Set<String>, val cardsInWallet: Set<String>,
@Json(name = "scanResponse") @Json(name = "scanResponse")
val scanResponse: ScanResponse, val scanResponse: ScanResponse?,
@Json(name = "isMultiCurrency") @Json(name = "isMultiCurrency")
val isMultiCurrency: Boolean, val isMultiCurrency: Boolean,
@Json(name = "hasBackupError") @Json(name = "hasBackupError")
val hasBackupError: Boolean = false, val hasBackupError: Boolean = false,
// Hot
@Json(name = "hotWalletId")
val hotWalletId: HotWalletId? = null,
@Json(name = "backedUp")
val backedUp: Boolean? = null,
) )

View file

@ -2,6 +2,7 @@ package com.tangem.tap.domain.userWalletList.utils
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation import com.tangem.tap.domain.userWalletList.model.UserWalletPublicInformation
import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation import com.tangem.tap.domain.userWalletList.model.UserWalletSensitiveInformation
@ -10,8 +11,12 @@ internal val UserWallet.sensitiveInformation: UserWalletSensitiveInformation
is UserWallet.Cold -> UserWalletSensitiveInformation( is UserWallet.Cold -> UserWalletSensitiveInformation(
wallets = scanResponse.card.wallets, wallets = scanResponse.card.wallets,
visaCardActivationStatus = scanResponse.visaCardActivationStatus, visaCardActivationStatus = scanResponse.visaCardActivationStatus,
mobileWallets = null,
)
is UserWallet.Hot -> UserWalletSensitiveInformation(
wallets = null,
mobileWallets = this.wallets,
) )
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
} }
internal val UserWallet.publicInformation: UserWalletPublicInformation internal val UserWallet.publicInformation: UserWalletPublicInformation
@ -28,19 +33,39 @@ internal val UserWallet.publicInformation: UserWalletPublicInformation
visaCardActivationStatus = null, visaCardActivationStatus = null,
), ),
hasBackupError = hasBackupError, hasBackupError = hasBackupError,
hotWalletId = null,
backedUp = null,
)
is UserWallet.Hot -> UserWalletPublicInformation(
name = name,
walletId = walletId,
isMultiCurrency = isMultiCurrency,
cardsInWallet = emptySet(),
scanResponse = null,
hotWalletId = hotWalletId,
backedUp = backedUp,
) )
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]")
} }
internal fun UserWalletPublicInformation.toUserWallet(): UserWallet { internal fun UserWalletPublicInformation.toUserWallet(): UserWallet {
return UserWallet.Cold( return if (hotWalletId != null) {
name = name, UserWallet.Hot(
walletId = walletId, name = name,
cardsInWallet = cardsInWallet, walletId = walletId,
scanResponse = scanResponse, hotWalletId = hotWalletId,
isMultiCurrency = isMultiCurrency, wallets = null,
hasBackupError = hasBackupError, backedUp = backedUp!!,
) )
} else {
UserWallet.Cold(
name = name,
walletId = walletId,
cardsInWallet = cardsInWallet,
scanResponse = scanResponse!!,
isMultiCurrency = isMultiCurrency,
hasBackupError = hasBackupError,
)
}
} }
internal fun List<UserWalletPublicInformation>.toUserWallets(): List<UserWallet> { internal fun List<UserWalletPublicInformation>.toUserWallets(): List<UserWallet> {
@ -53,13 +78,15 @@ internal fun UserWallet.updateWith(sensitiveInformation: UserWalletSensitiveInfo
copy( copy(
scanResponse = scanResponse.copy( scanResponse = scanResponse.copy(
card = scanResponse.card.copy( card = scanResponse.card.copy(
wallets = sensitiveInformation.wallets, wallets = sensitiveInformation.wallets!!,
), ),
visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus, visaCardActivationStatus = sensitiveInformation.visaCardActivationStatus,
), ),
) )
} }
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]") is UserWallet.Hot -> copy(
wallets = sensitiveInformation.mobileWallets,
)
} }
} }

View file

@ -1,11 +1,16 @@
package com.tangem.tap.domain.userWalletList.utils package com.tangem.tap.domain.userWalletList.utils
import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.calculateSha256
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.common.extensions.calculateHmacSha256 import com.tangem.domain.common.extensions.calculateHmacSha256
import com.tangem.domain.models.MobileWallet
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.wallets.models.UserWallet
internal val CardDTO.encryptionKey: ByteArray? internal val UserWallet.encryptionKey: ByteArray?
get() = findPublicKey(wallets)?.let { calculateEncryptionKey(it) } get() = when (this) {
is UserWallet.Cold -> findPublicKey(this.scanResponse.card.wallets)
is UserWallet.Hot -> findPublicKey(this.wallets.orEmpty())
}?.let { calculateEncryptionKey(it) }
private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray { private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray() val message = MESSAGE_FOR_ENCRYPTION_KEY.toByteArray()
@ -15,8 +20,12 @@ private fun calculateEncryptionKey(publicKey: ByteArray): ByteArray {
} }
private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? { private fun findPublicKey(wallets: List<CardDTO.Wallet>): ByteArray? {
return wallets.firstOrNull() return wallets.firstOrNull()?.publicKey
?.publicKey }
@JvmName("findPublicKeyInMobileWallets")
private fun findPublicKey(wallets: List<MobileWallet>): ByteArray? {
return wallets.firstOrNull()?.publicKey
} }
private const val MESSAGE_FOR_ENCRYPTION_KEY = "UserWalletEncryptionKey" private const val MESSAGE_FOR_ENCRYPTION_KEY = "UserWalletEncryptionKey"

View file

@ -14,7 +14,6 @@ import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase import com.tangem.domain.wallets.usecase.GetSelectedWalletUseCase
import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles import com.tangem.features.walletconnect.components.WalletConnectFeatureToggles
import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.dispatchOnMain
@ -422,8 +421,7 @@ class WalletConnectInteractor(
} }
private fun getCardId(userWallet: UserWallet): String? { private fun getCardId(userWallet: UserWallet): String? {
userWallet.requireColdWallet() // [REDACTED_TASK_KEY] return if (userWallet is UserWallet.Cold && userWallet.scanResponse.card.backupStatus?.isActive != true) {
return if (userWallet.scanResponse.card.backupStatus?.isActive != true) {
userWallet.cardId userWallet.cardId
} else { // if wallet has backup, any card from wallet can be used to sign } else { // if wallet has backup, any card from wallet can be used to sign
null null

View file

@ -39,7 +39,6 @@ import com.tangem.domain.settings.IncrementAppLaunchCounterUseCase
import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase import com.tangem.domain.settings.usercountry.FetchUserCountryUseCase
import com.tangem.domain.staking.FetchStakingTokensUseCase import com.tangem.domain.staking.FetchStakingTokensUseCase
import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.domain.wallets.usecase.AssociateWalletsWithApplicationIdUseCase import com.tangem.domain.wallets.usecase.AssociateWalletsWithApplicationIdUseCase
import com.tangem.domain.wallets.usecase.GetSavedWalletChangesUseCase import com.tangem.domain.wallets.usecase.GetSavedWalletChangesUseCase
@ -191,12 +190,7 @@ internal class MainViewModel @Inject constructor(
userWalletsListManager.selectedUserWallet userWalletsListManager.selectedUserWallet
.distinctUntilChanged() .distinctUntilChanged()
.onEach { userWallet -> .onEach { userWallet ->
when (userWallet) { Analytics.setContext(userWallet)
is UserWallet.Cold -> Analytics.setContext(userWallet.scanResponse)
is UserWallet.Hot -> {
// TODO [REDACTED_TASK_KEY]
}
}
} }
.flowOn(dispatchers.io) .flowOn(dispatchers.io)
.launchIn(viewModelScope) .launchIn(viewModelScope)

View file

@ -15,7 +15,7 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType import com.tangem.domain.wallets.legacy.UserWalletsListManager.Lockable.UnlockType
import com.tangem.domain.wallets.legacy.unlockIfLockable import com.tangem.domain.wallets.legacy.unlockIfLockable
import com.tangem.domain.wallets.models.requireColdWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.tap.backupService import com.tangem.tap.backupService
import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter import com.tangem.tap.common.analytics.converters.ParamCardCurrencyConverter
import com.tangem.tap.common.extensions.* import com.tangem.tap.common.extensions.*
@ -95,7 +95,7 @@ internal class WelcomeMiddleware {
} }
.doOnSuccess { selectedUserWallet -> .doOnSuccess { selectedUserWallet ->
sendSignedInAnalyticsEvent( sendSignedInAnalyticsEvent(
scanResponse = selectedUserWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = selectedUserWallet,
signInType = Basic.SignedIn.SignInType.Biometric, signInType = Basic.SignedIn.SignInType.Biometric,
) )
@ -129,7 +129,7 @@ internal class WelcomeMiddleware {
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error)) store.dispatchWithMain(WelcomeAction.ProceedWithCard.Error(error))
} }
.doOnSuccess { .doOnSuccess {
sendSignedInAnalyticsEvent(scanResponse = scanResponse, signInType = Basic.SignedIn.SignInType.Card) sendSignedInAnalyticsEvent(userWallet, signInType = Basic.SignedIn.SignInType.Card)
store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) } store.dispatchNavigationAction { replaceAll(AppRoute.Wallet) }
store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success) store.dispatchWithMain(WelcomeAction.ProceedWithCard.Success)
@ -142,7 +142,14 @@ internal class WelcomeMiddleware {
} }
} }
private fun sendSignedInAnalyticsEvent(scanResponse: ScanResponse, signInType: Basic.SignedIn.SignInType) { private fun sendSignedInAnalyticsEvent(userWallet: UserWallet, signInType: Basic.SignedIn.SignInType) {
// TODO [REDACTED_TASK_KEY]
if (userWallet !is UserWallet.Cold) {
return
}
val scanResponse = userWallet.scanResponse
val currency = ParamCardCurrencyConverter().convert( val currency = ParamCardCurrencyConverter().convert(
value = scanResponse.cardTypesResolver, value = scanResponse.cardTypesResolver,
) )

View file

@ -4,18 +4,17 @@ import com.tangem.common.extensions.toHexString
import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.api.common.AuthProvider
import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
internal class DefaultAuthProvider(private val userWalletsListManager: UserWalletsListManager) : AuthProvider { internal class DefaultAuthProvider(private val userWalletsListManager: UserWalletsListManager) : AuthProvider {
override fun getCardPublicKey(): String { override fun getCardPublicKey(): String {
val userWallet = userWalletsListManager.selectedUserWalletSync val userWallet = userWalletsListManager.selectedUserWalletSync
return when (userWallet) { if (userWallet !is UserWallet.Cold) {
is UserWallet.Cold -> userWallet.scanResponse.card.cardPublicKey.toHexString() return ""
is UserWallet.Hot -> userWallet.wallets?.firstOrNull()?.publicKey?.toHexString() ?: ""
null -> ""
} }
return userWallet.scanResponse.card.cardPublicKey.toHexString()
} }
override fun getCardId(): String { override fun getCardId(): String {
@ -25,7 +24,7 @@ internal class DefaultAuthProvider(private val userWalletsListManager: UserWalle
return "" return ""
} }
return userWallet.requireColdWallet().scanResponse.card.cardId return userWallet.scanResponse.card.cardId
} }
override fun getCardsPublicKeys(): Map<String, String> { override fun getCardsPublicKeys(): Map<String, String> {

View file

@ -6,7 +6,6 @@ import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.data.common.currency.CryptoCurrencyFactory import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.tap.common.extensions.inject import com.tangem.tap.common.extensions.inject
import com.tangem.tap.domain.model.Currency import com.tangem.tap.domain.model.Currency
import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.proxy.redux.DaggerGraphState
@ -25,10 +24,8 @@ internal class CryptoCurrencyConverter(
cryptoCurrencyFactory.createCoin( cryptoCurrencyFactory.createCoin(
blockchain = value.blockchain, blockchain = value.blockchain,
extraDerivationPath = value.derivationPath, extraDerivationPath = value.derivationPath,
scanResponse = requireNotNull( userWallet = requireNotNull(
store.inject(DaggerGraphState::generalUserWalletsListManager).selectedUserWalletSync store.inject(DaggerGraphState::generalUserWalletsListManager).selectedUserWalletSync,
?.requireColdWallet() // TODO [REDACTED_TASK_KEY]
?.scanResponse,
), ),
), ),
) )
@ -37,10 +34,8 @@ internal class CryptoCurrencyConverter(
sdkToken = value.token, sdkToken = value.token,
blockchain = value.blockchain, blockchain = value.blockchain,
extraDerivationPath = value.derivationPath, extraDerivationPath = value.derivationPath,
scanResponse = requireNotNull( userWallet = requireNotNull(
store.inject(DaggerGraphState::generalUserWalletsListManager).selectedUserWalletSync store.inject(DaggerGraphState::generalUserWalletsListManager).selectedUserWalletSync,
?.requireColdWallet() // TODO [REDACTED_TASK_KEY]
?.scanResponse,
), ),
), ),
) )

View file

@ -107,7 +107,7 @@ internal class DefaultDerivationsRepositoryTest {
runCatching { runCatching {
repository.derivePublicKeys( repository.derivePublicKeys(
userWalletId = defaultUserWalletId, userWalletId = defaultUserWalletId,
currencies = MockCryptoCurrencyFactory(userWallet.scanResponse).ethereum.let(::listOf), currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf),
) )
} }
.onSuccess { Truth.assertThat(it) } .onSuccess { Truth.assertThat(it) }
@ -129,7 +129,7 @@ internal class DefaultDerivationsRepositoryTest {
runCatching { runCatching {
repository.derivePublicKeys( repository.derivePublicKeys(
userWalletId = defaultUserWalletId, userWalletId = defaultUserWalletId,
currencies = MockCryptoCurrencyFactory(userWallet.scanResponse).ethereum.let(::listOf), currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf),
) )
} }
.onSuccess { error("Should throws exception") } .onSuccess { error("Should throws exception") }
@ -155,7 +155,7 @@ internal class DefaultDerivationsRepositoryTest {
runCatching { runCatching {
repository.derivePublicKeys( repository.derivePublicKeys(
userWalletId = defaultUserWalletId, userWalletId = defaultUserWalletId,
currencies = MockCryptoCurrencyFactory(userWallet.scanResponse).ethereum.let(::listOf), currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf),
) )
} }
.onSuccess { Truth.assertThat(it) } .onSuccess { Truth.assertThat(it) }

View file

@ -8,6 +8,7 @@ import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.ByteArrayKey import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.test.domain.card.MockScanResponseFactory import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.crypto.hdWallet.DerivationPath import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.common.configs.GenericCardConfig import com.tangem.domain.common.configs.GenericCardConfig
import com.tangem.domain.common.configs.MultiWalletCardConfig import com.tangem.domain.common.configs.MultiWalletCardConfig
@ -34,9 +35,10 @@ internal class MissedDerivationsFinderTest {
fun `empty derivations for non supported blockchains`() { fun `empty derivations for non supported blockchains`() {
// Bls is not supported // Bls is not supported
val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap()) val scanResponse = MockScanResponseFactory.create(cardConfig = GenericCardConfig(2), derivedKeys = emptyMap())
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).chia.let(::listOf) val currencies = MockCryptoCurrencyFactory(userWallet).chia.let(::listOf)
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).isEmpty() Truth.assertThat(actual).isEmpty()
@ -55,9 +57,10 @@ internal class MissedDerivationsFinderTest {
), ),
) )
} }
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).chiaAndEthereum val currencies = MockCryptoCurrencyFactory(userWallet).chiaAndEthereum
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).containsExactly( Truth.assertThat(actual).containsExactly(
@ -69,9 +72,10 @@ internal class MissedDerivationsFinderTest {
@Test @Test
fun `derivations for custom token`() { fun `derivations for custom token`() {
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()) val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).ethereumTokenWithBinanceDerivation val currencies = MockCryptoCurrencyFactory(userWallet).ethereumTokenWithBinanceDerivation
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).containsExactly( Truth.assertThat(actual).containsExactly(
@ -86,9 +90,10 @@ internal class MissedDerivationsFinderTest {
@Test @Test
fun `derivations for cardano`() { fun `derivations for cardano`() {
val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap()) val scanResponse = MockScanResponseFactory.create(cardConfig = MultiWalletCardConfig, derivedKeys = emptyMap())
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).cardano.let(::listOf) val currencies = MockCryptoCurrencyFactory(userWallet).cardano.let(::listOf)
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).containsExactly( Truth.assertThat(actual).containsExactly(
@ -111,9 +116,10 @@ internal class MissedDerivationsFinderTest {
cardConfig = Wallet2CardConfig, cardConfig = Wallet2CardConfig,
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys, derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
) )
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).ethereum.let(::listOf) val currencies = MockCryptoCurrencyFactory(userWallet).ethereum.let(::listOf)
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).isEmpty() Truth.assertThat(actual).isEmpty()
@ -125,9 +131,10 @@ internal class MissedDerivationsFinderTest {
cardConfig = MultiWalletCardConfig, cardConfig = MultiWalletCardConfig,
derivedKeys = DerivedKeysMocks.ethereumDerivedKeys, derivedKeys = DerivedKeysMocks.ethereumDerivedKeys,
) )
val userWallet = MockUserWalletFactory.create(scanResponse)
val finder = MissedDerivationsFinder(scanResponse) val finder = MissedDerivationsFinder(scanResponse)
val currencies = MockCryptoCurrencyFactory(scanResponse).ethereumAndStellar val currencies = MockCryptoCurrencyFactory(userWallet).ethereumAndStellar
val actual = finder.find(currencies) val actual = finder.find(currencies)
Truth.assertThat(actual).containsExactly( Truth.assertThat(actual).containsExactly(

View file

@ -6,18 +6,19 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.blockchainsdk.utils.toNetworkId import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.common.test.domain.card.MockScanResponseFactory import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.data.common.currency.CryptoCurrencyFactory import com.tangem.data.common.currency.CryptoCurrencyFactory
import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.configs.GenericCardConfig import com.tangem.domain.common.configs.GenericCardConfig
import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
/** /**
[REDACTED_AUTHOR] [REDACTED_AUTHOR]
*/ */
class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = defaultScanResponse) { class MockCryptoCurrencyFactory(private val userWallet: UserWallet.Cold = defaultUserWallet) {
private val factory = CryptoCurrencyFactory(excludedBlockchains = ExcludedBlockchains()) private val factory = CryptoCurrencyFactory(excludedBlockchains = ExcludedBlockchains())
@ -49,7 +50,7 @@ class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = default
val derivationPath = createDerivationPath( val derivationPath = createDerivationPath(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
cardDerivationStyleProvider = scanResponse.derivationStyleProvider, cardDerivationStyleProvider = userWallet.scanResponse.derivationStyleProvider,
) )
val network = Network( val network = Network(
@ -72,7 +73,7 @@ class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = default
fun createCustomToken(blockchain: Blockchain, derivationBlockchain: Blockchain): CryptoCurrency { fun createCustomToken(blockchain: Blockchain, derivationBlockchain: Blockchain): CryptoCurrency {
val derivationPath = Network.DerivationPath.Custom( val derivationPath = Network.DerivationPath.Custom(
value = derivationBlockchain.derivationPath( value = derivationBlockchain.derivationPath(
scanResponse.derivationStyleProvider.getDerivationStyle(), userWallet.scanResponse.derivationStyleProvider.getDerivationStyle(),
)!!.rawPath, )!!.rawPath,
) )
@ -114,7 +115,7 @@ class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = default
), ),
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
)!! )!!
} }
@ -161,9 +162,11 @@ class MockCryptoCurrencyFactory(private val scanResponse: ScanResponse = default
private companion object { private companion object {
val defaultScanResponse = MockScanResponseFactory.create( val defaultUserWallet = MockUserWalletFactory.create(
cardConfig = GenericCardConfig(2), scanResponse = MockScanResponseFactory.create(
derivedKeys = emptyMap(), cardConfig = GenericCardConfig(2),
derivedKeys = emptyMap(),
),
) )
} }
} }

View file

@ -2,7 +2,6 @@ package com.tangem.data.common.currency
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
@ -57,23 +56,23 @@ interface CardCryptoCurrencyFactory {
/** /**
* Create default coins for multi currency card * Create default coins for multi currency card
* *
* @param scanResponse scan response * @param userWallet user wallet
*/ */
fun createDefaultCoinsForMultiCurrencyCard(scanResponse: ScanResponse): List<CryptoCurrency.Coin> fun createDefaultCoinsForMultiCurrencyWallet(userWallet: UserWallet): List<CryptoCurrency.Coin>
/** /**
* Create primary currency for single currency card * Create primary currency for single currency card
* *
* @param scanResponse scan response * @param userWallet user wallet
*/ */
@Throws @Throws
fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency fun createPrimaryCurrencyForSingleCurrencyCard(userWallet: UserWallet.Cold): CryptoCurrency
/** /**
* Create currencies for single currency card with token (like, NODL) * Create currencies for single currency card with token (like, NODL)
* *
* @param scanResponse scan response * @param userWallet user wallet
*/ */
@Throws @Throws
fun createCurrenciesForSingleCurrencyCardWithToken(scanResponse: ScanResponse): List<CryptoCurrency> fun createCurrenciesForSingleCurrencyCardWithToken(userWallet: UserWallet.Cold): List<CryptoCurrency>
} }

View file

@ -8,7 +8,7 @@ import com.tangem.blockchainsdk.utils.toCoinId
import com.tangem.data.common.network.NetworkFactory import com.tangem.data.common.network.NetworkFactory
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber import timber.log.Timber
import com.tangem.blockchain.common.Token as SdkToken import com.tangem.blockchain.common.Token as SdkToken
@ -46,7 +46,7 @@ class CryptoCurrencyFactory(
sdkToken: SdkToken, sdkToken: SdkToken,
blockchain: Blockchain, blockchain: Blockchain,
extraDerivationPath: String?, extraDerivationPath: String?,
scanResponse: ScanResponse, userWallet: UserWallet,
): CryptoCurrency.Token? { ): CryptoCurrency.Token? {
if (blockchain == Blockchain.Unknown) { if (blockchain == Blockchain.Unknown) {
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
@ -56,7 +56,7 @@ class CryptoCurrencyFactory(
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
val id = getTokenId(network, sdkToken) val id = getTokenId(network, sdkToken)
@ -76,7 +76,7 @@ class CryptoCurrencyFactory(
fun createCoin( fun createCoin(
blockchain: Blockchain, blockchain: Blockchain,
extraDerivationPath: String?, extraDerivationPath: String?,
scanResponse: ScanResponse, userWallet: UserWallet,
): CryptoCurrency.Coin? { ): CryptoCurrency.Coin? {
if (blockchain == Blockchain.Unknown) { if (blockchain == Blockchain.Unknown) {
Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain") Timber.e("Unable to map the SDK token to the domain token with Unknown blockchain")
@ -86,15 +86,15 @@ class CryptoCurrencyFactory(
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
return createCoin(network) return createCoin(network)
} }
fun createCoin(networkId: String, extraDerivationPath: String?, scanResponse: ScanResponse): CryptoCurrency.Coin? { fun createCoin(networkId: String, extraDerivationPath: String?, userWallet: UserWallet): CryptoCurrency.Coin? {
val blockchain = Blockchain.fromNetworkId(networkId) ?: Blockchain.Unknown val blockchain = Blockchain.fromNetworkId(networkId) ?: Blockchain.Unknown
return createCoin(blockchain, extraDerivationPath, scanResponse) return createCoin(blockchain, extraDerivationPath, userWallet)
} }
fun createCoin(network: Network): CryptoCurrency.Coin { fun createCoin(network: Network): CryptoCurrency.Coin {
@ -115,7 +115,7 @@ class CryptoCurrencyFactory(
token: Token, token: Token,
networkId: String, networkId: String,
extraDerivationPath: String?, extraDerivationPath: String?,
scanResponse: ScanResponse, userWallet: UserWallet,
): CryptoCurrency.Token? { ): CryptoCurrency.Token? {
val sdkToken = SdkToken( val sdkToken = SdkToken(
name = token.name, name = token.name,
@ -129,7 +129,7 @@ class CryptoCurrencyFactory(
sdkToken = sdkToken, sdkToken = sdkToken,
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
@ -141,7 +141,8 @@ class CryptoCurrencyFactory(
decimals = cryptoCurrency.decimals, decimals = cryptoCurrency.decimals,
id = cryptoCurrency.id.rawCurrencyId?.value, id = cryptoCurrency.id.rawCurrencyId?.value,
) )
val blockchain = Blockchain.fromNetworkId(cryptoCurrency.network.backendId) ?: Blockchain.Unknown val blockchain =
Blockchain.fromNetworkId(cryptoCurrency.network.backendId) ?: Blockchain.Unknown
val id = getTokenId(network, sdkToken) val id = getTokenId(network, sdkToken)
return CryptoCurrency.Token( return CryptoCurrency.Token(
id = id, id = id,

View file

@ -11,11 +11,9 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.domain.wallets.models.requireColdWallet
/** /**
* Default implementation of factory for creating list of [CryptoCurrency] for selected card * Default implementation of factory for creating list of [CryptoCurrency] for selected card
@ -54,12 +52,12 @@ internal class DefaultCardCryptoCurrencyFactory(
// single-currency wallet with token (NODL) // single-currency wallet with token (NODL)
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) { if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
val currencies = createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse) val currencies = createCurrenciesForSingleCurrencyCardWithToken(userWallet)
return mapOf(cardNetwork to currencies) return mapOf(cardNetwork to currencies)
} }
// single-currency wallet // single-currency wallet
val primaryCurrency = createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse) val primaryCurrency = createPrimaryCurrencyForSingleCurrencyCard(userWallet)
return mapOf(cardNetwork to listOf(primaryCurrency)) return mapOf(cardNetwork to listOf(primaryCurrency))
} }
@ -82,11 +80,11 @@ internal class DefaultCardCryptoCurrencyFactory(
// single-currency wallet with token (NODL) // single-currency wallet with token (NODL)
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) { if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
return createCurrenciesForSingleCurrencyCardWithToken(userWallet.scanResponse) return createCurrenciesForSingleCurrencyCardWithToken(userWallet)
} }
// single-currency wallet // single-currency wallet
return createPrimaryCurrencyForSingleCurrencyCard(userWallet.scanResponse).let(::listOf) return createPrimaryCurrencyForSingleCurrencyCard(userWallet).let(::listOf)
} }
override suspend fun createCurrenciesForMultiCurrencyCard( override suspend fun createCurrenciesForMultiCurrencyCard(
@ -98,44 +96,54 @@ internal class DefaultCardCryptoCurrencyFactory(
return getMultiWalletCurrencies(userWallet = userWallet, networks = networks) return getMultiWalletCurrencies(userWallet = userWallet, networks = networks)
} }
override fun createDefaultCoinsForMultiCurrencyCard(scanResponse: ScanResponse): List<CryptoCurrency.Coin> { override fun createDefaultCoinsForMultiCurrencyWallet(userWallet: UserWallet): List<CryptoCurrency.Coin> {
require(scanResponse.cardTypesResolver.isMultiwalletAllowed()) { "It isn't multi-currency wallet" } require(userWallet.isMultiCurrency) { "It isn't multi-currency wallet" }
val card = scanResponse.card val blockchains = when (userWallet) {
is UserWallet.Cold -> {
val card = userWallet.scanResponse.card
var blockchains = if (demoConfig.isDemoCardId(card.cardId)) { var blockchainsInternal = if (demoConfig.isDemoCardId(card.cardId)) {
demoConfig.demoBlockchains demoConfig.demoBlockchains
} else { } else {
listOf(Blockchain.Bitcoin, Blockchain.Ethereum) listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
} }
if (card.isTestCard) { if (card.isTestCard) {
blockchains = blockchains.mapNotNull { it.getTestnetVersion() } blockchainsInternal = blockchainsInternal.mapNotNull { it.getTestnetVersion() }
}
blockchainsInternal
}
is UserWallet.Hot -> listOf(Blockchain.Bitcoin, Blockchain.Ethereum)
} }
return blockchains.mapNotNull { return blockchains.mapNotNull {
cryptoCurrencyFactory.createCoin( cryptoCurrencyFactory.createCoin(
blockchain = it, blockchain = it,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
} }
override fun createPrimaryCurrencyForSingleCurrencyCard(scanResponse: ScanResponse): CryptoCurrency { override fun createPrimaryCurrencyForSingleCurrencyCard(userWallet: UserWallet.Cold): CryptoCurrency {
require(scanResponse.cardTypesResolver.isSingleWallet()) { "It isn't single-currency wallet" } require(userWallet.scanResponse.cardTypesResolver.isSingleWallet()) {
"It isn't single-currency wallet"
}
return with(getSingleWalletCurrencies(scanResponse)) { return with(getSingleWalletCurrencies(userWallet)) {
primaryToken ?: coin primaryToken ?: coin
} }
} }
override fun createCurrenciesForSingleCurrencyCardWithToken(scanResponse: ScanResponse): List<CryptoCurrency> { override fun createCurrenciesForSingleCurrencyCardWithToken(userWallet: UserWallet.Cold): List<CryptoCurrency> {
require(scanResponse.cardTypesResolver.isSingleWalletWithToken()) { require(userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
"It isn't single-currency wallet with token" "It isn't single-currency wallet with token"
} }
return with(getSingleWalletCurrencies(scanResponse)) { return with(getSingleWalletCurrencies(userWallet)) {
listOfNotNull(coin, primaryToken) listOfNotNull(coin, primaryToken)
} }
} }
@ -151,7 +159,7 @@ internal class DefaultCardCryptoCurrencyFactory(
tokens = response.tokens.filter { token -> tokens = response.tokens.filter { token ->
networks.any { it.backendId == token.networkId && it.derivationPath.value == token.derivationPath } networks.any { it.backendId == token.networkId && it.derivationPath.value == token.derivationPath }
}, },
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
.groupBy(CryptoCurrency::network) .groupBy(CryptoCurrency::network)
@ -169,19 +177,19 @@ internal class DefaultCardCryptoCurrencyFactory(
return responseCryptoCurrenciesFactory.createCurrencies( return responseCryptoCurrenciesFactory.createCurrencies(
tokens = response.tokens.filter { token -> token.networkId in networkIds }, tokens = response.tokens.filter { token -> token.networkId in networkIds },
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
.groupBy { it.network.id.rawId } .groupBy { it.network.id.rawId }
} }
private fun getSingleWalletCurrencies(scanResponse: ScanResponse): SingleWalletCurrencies { private fun getSingleWalletCurrencies(userWallet: UserWallet.Cold): SingleWalletCurrencies {
val resolver = scanResponse.cardTypesResolver val resolver = userWallet.cardTypesResolver
val blockchain = resolver.getBlockchain() val blockchain = resolver.getBlockchain()
val coin = cryptoCurrencyFactory.createCoin( val coin = cryptoCurrencyFactory.createCoin(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
) )
requireNotNull(coin) { "Coin for the single currency card cannot be null" } requireNotNull(coin) { "Coin for the single currency card cannot be null" }
@ -191,12 +199,15 @@ internal class DefaultCardCryptoCurrencyFactory(
sdkToken = token, sdkToken = token,
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
return SingleWalletCurrencies(coin = coin, primaryToken = primaryToken) return SingleWalletCurrencies(coin = coin, primaryToken = primaryToken)
} }
private data class SingleWalletCurrencies(val coin: CryptoCurrency, val primaryToken: CryptoCurrency?) private data class SingleWalletCurrencies(
val coin: CryptoCurrency,
val primaryToken: CryptoCurrency?,
)
} }

View file

@ -8,7 +8,7 @@ import com.tangem.data.common.network.NetworkFactory
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import com.tangem.blockchain.common.Token as SdkToken import com.tangem.blockchain.common.Token as SdkToken
@ -17,41 +17,41 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
private val networkFactory: NetworkFactory, private val networkFactory: NetworkFactory,
) { ) {
fun createCurrency(currencyId: String, response: UserTokensResponse, scanResponse: ScanResponse): CryptoCurrency { fun createCurrency(currencyId: String, response: UserTokensResponse, userWallet: UserWallet): CryptoCurrency {
return response.tokens return response.tokens
.asSequence() .asSequence()
.mapNotNull { createCurrency(it, scanResponse) } .mapNotNull { createCurrency(it, userWallet) }
.first { it.id.value == currencyId } .first { it.id.value == currencyId }
} }
fun createCurrencies(response: UserTokensResponse, scanResponse: ScanResponse): List<CryptoCurrency> { fun createCurrencies(response: UserTokensResponse, userWallet: UserWallet): List<CryptoCurrency> {
return createCurrencies(tokens = response.tokens, scanResponse = scanResponse) return createCurrencies(tokens = response.tokens, userWallet = userWallet)
} }
fun createCurrencies(tokens: List<UserTokensResponse.Token>, scanResponse: ScanResponse): List<CryptoCurrency> { fun createCurrencies(tokens: List<UserTokensResponse.Token>, userWallet: UserWallet): List<CryptoCurrency> {
return tokens return tokens
.asSequence() .asSequence()
.mapNotNull { createCurrency(it, scanResponse) } .mapNotNull { createCurrency(it, userWallet) }
.distinctBy(CryptoCurrency::id) .distinctBy(CryptoCurrency::id)
.toList() .toList()
} }
fun createCurrency(responseToken: UserTokensResponse.Token, scanResponse: ScanResponse): CryptoCurrency? { fun createCurrency(responseToken: UserTokensResponse.Token, userWallet: UserWallet): CryptoCurrency? {
var blockchain = Blockchain.fromNetworkId(responseToken.networkId) var blockchain = Blockchain.fromNetworkId(responseToken.networkId)
if (blockchain == null || blockchain == Blockchain.Unknown) { if (blockchain == null || blockchain == Blockchain.Unknown) {
Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}") Timber.e("Unable to find a blockchain with the network ID: ${responseToken.networkId}")
return null return null
} }
if (scanResponse.cardTypesResolver.isTestCard()) { if (userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isTestCard()) {
blockchain = blockchain.getTestnetVersion() ?: blockchain blockchain = blockchain.getTestnetVersion() ?: blockchain
} }
val sdkToken = createSdkToken(responseToken) val sdkToken = createSdkToken(responseToken)
return if (sdkToken == null) { return if (sdkToken == null) {
createCoin(blockchain, responseToken, scanResponse) createCoin(blockchain, responseToken, userWallet)
} else { } else {
createToken(blockchain, sdkToken, responseToken.derivationPath, scanResponse) createToken(blockchain, sdkToken, responseToken.derivationPath, userWallet)
} }
} }
@ -70,12 +70,12 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
private fun createCoin( private fun createCoin(
blockchain: Blockchain, blockchain: Blockchain,
responseToken: UserTokensResponse.Token, responseToken: UserTokensResponse.Token,
scanResponse: ScanResponse, userWallet: UserWallet,
): CryptoCurrency.Coin? { ): CryptoCurrency.Coin? {
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = responseToken.derivationPath, extraDerivationPath = responseToken.derivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
return CryptoCurrency.Coin( return CryptoCurrency.Coin(
@ -105,12 +105,12 @@ class ResponseCryptoCurrenciesFactory @Inject constructor(
blockchain: Blockchain, blockchain: Blockchain,
sdkToken: Token, sdkToken: Token,
responseDerivationPath: String?, responseDerivationPath: String?,
scanResponse: ScanResponse, userWallet: UserWallet,
): CryptoCurrency.Token? { ): CryptoCurrency.Token? {
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = responseDerivationPath, extraDerivationPath = responseDerivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
val id = getTokenId(network, sdkToken) val id = getTokenId(network, sdkToken)

View file

@ -8,10 +8,9 @@ import com.tangem.blockchainsdk.utils.toBlockchain
import com.tangem.blockchainsdk.utils.toNetworkId import com.tangem.blockchainsdk.utils.toNetworkId
import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -31,19 +30,18 @@ class NetworkFactory @Inject constructor(
* *
* @param blockchain blockchain * @param blockchain blockchain
* @param extraDerivationPath extra derivation path * @param extraDerivationPath extra derivation path
* @param scanResponse scan response * @param userWallet user wallet
*/ */
fun create(blockchain: Blockchain, extraDerivationPath: String?, scanResponse: ScanResponse): Network? { fun create(blockchain: Blockchain, extraDerivationPath: String?, userWallet: UserWallet): Network? {
return create( return create(
blockchain = blockchain, blockchain = blockchain,
derivationPath = createDerivationPath( derivationPath = createDerivationPath(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
cardDerivationStyleProvider = scanResponse.derivationStyleProvider, cardDerivationStyleProvider = userWallet.derivationStyleProvider,
), ),
canHandleTokens = scanResponse.card.canHandleToken( canHandleTokens = userWallet.canHandleToken(
blockchain = blockchain, blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
excludedBlockchains = excludedBlockchains, excludedBlockchains = excludedBlockchains,
), ),
) )
@ -54,17 +52,16 @@ class NetworkFactory @Inject constructor(
* *
* @param networkId network id * @param networkId network id
* @param derivationPath derivation path * @param derivationPath derivation path
* @param scanResponse scan response * @param userWallet user wallet
*/ */
fun create(networkId: Network.ID, derivationPath: Network.DerivationPath, scanResponse: ScanResponse): Network? { fun create(networkId: Network.ID, derivationPath: Network.DerivationPath, userWallet: UserWallet): Network? {
val blockchain = networkId.toBlockchain() val blockchain = networkId.toBlockchain()
return create( return create(
blockchain = blockchain, blockchain = blockchain,
derivationPath = derivationPath, derivationPath = derivationPath,
canHandleTokens = scanResponse.card.canHandleToken( canHandleTokens = userWallet.canHandleToken(
blockchain = blockchain, blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
excludedBlockchains = excludedBlockchains, excludedBlockchains = excludedBlockchains,
), ),
) )

View file

@ -308,7 +308,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
val multiWallet = model.multiWallet val multiWallet = model.multiWallet
// Act // Act
val actual = factory.createDefaultCoinsForMultiCurrencyCard(scanResponse = multiWallet.scanResponse) val actual = factory.createDefaultCoinsForMultiCurrencyWallet(multiWallet)
// Assert // Assert
val expected = model.expected val expected = model.expected
@ -355,7 +355,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
// Act // Act
val actual = runCatching { val actual = runCatching {
factory.createPrimaryCurrencyForSingleCurrencyCard(scanResponse = singleWallet.scanResponse) factory.createPrimaryCurrencyForSingleCurrencyCard(singleWallet)
} }
// Assert // Assert
@ -405,7 +405,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
// Act // Act
val actual = runCatching { val actual = runCatching {
factory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = userWallet.scanResponse) factory.createCurrenciesForSingleCurrencyCardWithToken(userWallet)
} }
// Assert // Assert
@ -554,7 +554,7 @@ internal class DefaultCardCryptoCurrencyFactoryTest {
sdkToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken()!!, sdkToken = userWallet.scanResponse.cardTypesResolver.getPrimaryToken()!!,
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
)!! )!!
} }

View file

@ -5,6 +5,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchainsdk.utils.ExcludedBlockchains import com.tangem.blockchainsdk.utils.ExcludedBlockchains
import com.tangem.common.test.domain.card.MockScanResponseFactory import com.tangem.common.test.domain.card.MockScanResponseFactory
import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory import com.tangem.common.test.domain.token.MockCryptoCurrencyFactory
import com.tangem.common.test.domain.wallet.MockUserWalletFactory
import com.tangem.common.test.utils.ProvideTestModels import com.tangem.common.test.utils.ProvideTestModels
import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.configs.GenericCardConfig import com.tangem.domain.common.configs.GenericCardConfig
@ -12,6 +13,7 @@ import com.tangem.domain.common.configs.MultiWalletCardConfig
import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.wallets.models.UserWallet
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Nested
@ -43,7 +45,7 @@ class NetworkFactoryTest {
val actual = networkFactory.create( val actual = networkFactory.create(
blockchain = Blockchain.Ethereum, blockchain = Blockchain.Ethereum,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
) )
// Assert // Assert
@ -59,14 +61,14 @@ class NetworkFactoryTest {
networkFactory.create( networkFactory.create(
blockchain = model.blockchain, blockchain = model.blockchain,
extraDerivationPath = model.extraDerivationPath, extraDerivationPath = model.extraDerivationPath,
scanResponse = model.scanResponse, userWallet = model.userWallet,
) )
} }
is CreateTestModel.Second -> { is CreateTestModel.Second -> {
networkFactory.create( networkFactory.create(
networkId = model.networkId, networkId = model.networkId,
derivationPath = model.derivationPath, derivationPath = model.derivationPath,
scanResponse = model.scanResponse, userWallet = model.userWallet,
) )
} }
is CreateTestModel.Third -> { is CreateTestModel.Third -> {
@ -89,27 +91,27 @@ class NetworkFactoryTest {
CreateTestModel.First( CreateTestModel.First(
blockchain = Blockchain.Unknown, blockchain = Blockchain.Unknown,
extraDerivationPath = null, // never-mind extraDerivationPath = null, // never-mind
scanResponse = createMultiWalletScanResponse(), // never-mind userWallet = createUserWallet(),
expected = null, expected = null,
), ),
createFirst( createFirst(
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = createGenericScanResponse(), // default derivation path is null userWallet = createUserWallet(createGenericScanResponse()), // default derivation path is null
expectedDerivationPath = Network.DerivationPath.None, expectedDerivationPath = Network.DerivationPath.None,
), ),
createFirst( createFirst(
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"), // use default expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"), // use default
), ),
createFirst( createFirst(
extraDerivationPath = "m/44'/60'/0'/0/0", // as default extraDerivationPath = "m/44'/60'/0'/0/0", // as default
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"), expectedDerivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"),
), ),
createFirst( createFirst(
extraDerivationPath = "m/84'/0'/0'/0/0", extraDerivationPath = "m/84'/0'/0'/0/0",
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
expectedDerivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"), expectedDerivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"),
), ),
// endregion // endregion
@ -118,23 +120,23 @@ class NetworkFactoryTest {
CreateTestModel.Second( CreateTestModel.Second(
networkId = Network.ID(value = "1", derivationPath = Network.DerivationPath.None), networkId = Network.ID(value = "1", derivationPath = Network.DerivationPath.None),
derivationPath = Network.DerivationPath.None, // never-mind derivationPath = Network.DerivationPath.None, // never-mind
scanResponse = createMultiWalletScanResponse(), // never-mind userWallet = createUserWallet(), // never-mind
expected = null, expected = null,
), ),
createSecond( createSecond(
scanResponse = createGenericScanResponse(), // default derivation path is null userWallet = createUserWallet(createGenericScanResponse()), // default derivation path is null
derivationPath = Network.DerivationPath.None, derivationPath = Network.DerivationPath.None,
), ),
createSecond( createSecond(
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.None, derivationPath = Network.DerivationPath.None,
), ),
createSecond( createSecond(
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"), derivationPath = Network.DerivationPath.Card(value = "m/44'/60'/0'/0/0"),
), ),
createSecond( createSecond(
scanResponse = createMultiWalletScanResponse(), userWallet = createUserWallet(),
derivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"), derivationPath = Network.DerivationPath.Custom(value = "m/84'/0'/0'/0/0"),
), ),
// endregion // endregion
@ -176,13 +178,13 @@ class NetworkFactoryTest {
private fun createFirst( private fun createFirst(
extraDerivationPath: String?, extraDerivationPath: String?,
scanResponse: ScanResponse, userWallet: UserWallet,
expectedDerivationPath: Network.DerivationPath, expectedDerivationPath: Network.DerivationPath,
): CreateTestModel.First { ): CreateTestModel.First {
return CreateTestModel.First( return CreateTestModel.First(
blockchain = Blockchain.Ethereum, blockchain = Blockchain.Ethereum,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
scanResponse = scanResponse, userWallet = userWallet,
expected = MockCryptoCurrencyFactory().ethereum.network.copy( expected = MockCryptoCurrencyFactory().ethereum.network.copy(
id = Network.ID( id = Network.ID(
value = Blockchain.Ethereum.id, value = Blockchain.Ethereum.id,
@ -195,13 +197,13 @@ class NetworkFactoryTest {
} }
private fun createSecond( private fun createSecond(
scanResponse: ScanResponse, userWallet: UserWallet,
derivationPath: Network.DerivationPath, derivationPath: Network.DerivationPath,
): CreateTestModel.Second { ): CreateTestModel.Second {
return CreateTestModel.Second( return CreateTestModel.Second(
networkId = Network.ID(value = Blockchain.Ethereum.id, derivationPath = derivationPath), networkId = Network.ID(value = Blockchain.Ethereum.id, derivationPath = derivationPath),
derivationPath = derivationPath, derivationPath = derivationPath,
scanResponse = scanResponse, userWallet = userWallet,
expected = MockCryptoCurrencyFactory().ethereum.network.copy( expected = MockCryptoCurrencyFactory().ethereum.network.copy(
id = Network.ID( id = Network.ID(
value = Blockchain.Ethereum.id, value = Blockchain.Ethereum.id,
@ -232,6 +234,10 @@ class NetworkFactoryTest {
) )
} }
private fun createUserWallet(scanResponse: ScanResponse = createMultiWalletScanResponse()): UserWallet.Cold {
return MockUserWalletFactory.create(scanResponse)
}
private fun createMultiWalletScanResponse(): ScanResponse { private fun createMultiWalletScanResponse(): ScanResponse {
return MockScanResponseFactory.create( return MockScanResponseFactory.create(
cardConfig = MultiWalletCardConfig, cardConfig = MultiWalletCardConfig,
@ -254,14 +260,14 @@ class NetworkFactoryTest {
data class First( data class First(
val blockchain: Blockchain, val blockchain: Blockchain,
val extraDerivationPath: String?, val extraDerivationPath: String?,
val scanResponse: ScanResponse, val userWallet: UserWallet,
override val expected: Network?, override val expected: Network?,
) : CreateTestModel ) : CreateTestModel
data class Second( data class Second(
val networkId: Network.ID, val networkId: Network.ID,
val derivationPath: Network.DerivationPath, val derivationPath: Network.DerivationPath,
val scanResponse: ScanResponse, val userWallet: UserWallet,
override val expected: Network?, override val expected: Network?,
) : CreateTestModel ) : CreateTestModel

View file

@ -95,7 +95,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create( networkFactory.create(
networkId = networkId, networkId = networkId,
derivationPath = derivationPath, derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
), ),
) { ) {
"Network [$networkId] not found while finding token" "Network [$networkId] not found while finding token"
@ -106,8 +106,8 @@ internal class DefaultCustomTokensRepository(
symbol = null, symbol = null,
) )
val supportedTokenNetworkIds = userWallet.scanResponse.card val supportedTokenNetworkIds = userWallet
.supportedBlockchains(userWallet.scanResponse.cardTypesResolver, excludedBlockchains) .supportedBlockchains(excludedBlockchains = excludedBlockchains)
.filter(Blockchain::canHandleTokens) .filter(Blockchain::canHandleTokens)
.map(Blockchain::toNetworkId) .map(Blockchain::toNetworkId)
@ -151,7 +151,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create( networkFactory.create(
networkId = networkId, networkId = networkId,
derivationPath = derivationPath, derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
), ),
) { ) {
"Network [$networkId] not found while creating coin" "Network [$networkId] not found while creating coin"
@ -188,7 +188,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create( networkFactory.create(
networkId = networkId, networkId = networkId,
derivationPath = derivationPath, derivationPath = derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
), ),
) { ) {
"Network [$networkId] not found while creating custom token" "Network [$networkId] not found while creating custom token"
@ -261,7 +261,7 @@ internal class DefaultCustomTokensRepository(
networkFactory.create( networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
) )
} else { } else {
null null

View file

@ -31,7 +31,6 @@ import com.tangem.domain.managetokens.repository.ManageTokensRepository
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.pagination.BatchFetchResult import com.tangem.pagination.BatchFetchResult
import com.tangem.pagination.BatchListSource import com.tangem.pagination.BatchListSource
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
@ -142,13 +141,13 @@ internal class DefaultManageTokensRepository(
managedCryptoCurrencyFactory.createWithCustomTokens( managedCryptoCurrencyFactory.createWithCustomTokens(
coinsResponse = updatedCoinsResponse, coinsResponse = updatedCoinsResponse,
tokensResponse = tokensResponse, tokensResponse = tokensResponse,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} else { } else {
managedCryptoCurrencyFactory.create( managedCryptoCurrencyFactory.create(
coinsResponse = updatedCoinsResponse, coinsResponse = updatedCoinsResponse,
tokensResponse = tokensResponse, tokensResponse = tokensResponse,
scanResponse = userWallet?.requireColdWallet()?.scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} }
@ -178,7 +177,7 @@ internal class DefaultManageTokensRepository(
testnetTokensConfig testnetTokensConfig
}, },
tokensResponse = getSavedUserTokensResponseSync(userWallet.walletId), tokensResponse = getSavedUserTokensResponseSync(userWallet.walletId),
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
return BatchFetchResult.Success( return BatchFetchResult.Success(
@ -190,8 +189,8 @@ internal class DefaultManageTokensRepository(
private fun createDefaultUserTokensResponse(userWallet: UserWallet) = private fun createDefaultUserTokensResponse(userWallet: UserWallet) =
userTokensResponseFactory.createUserTokensResponse( userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard( currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(
userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
), ),
isGroupedByNetwork = false, isGroupedByNetwork = false,
isSortedByBalance = false, isSortedByBalance = false,

View file

@ -15,13 +15,12 @@ import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig import com.tangem.datasource.local.config.testnet.models.TestnetTokensConfig
import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.extensions.canHandleToken import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency import com.tangem.domain.managetokens.model.ManagedCryptoCurrency
import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork import com.tangem.domain.managetokens.model.ManagedCryptoCurrency.SourceNetwork
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
import timber.log.Timber import timber.log.Timber
internal class ManagedCryptoCurrencyFactory( internal class ManagedCryptoCurrencyFactory(
@ -32,20 +31,20 @@ internal class ManagedCryptoCurrencyFactory(
fun create( fun create(
coinsResponse: CoinsResponse, coinsResponse: CoinsResponse,
tokensResponse: UserTokensResponse?, tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse?, userWallet: UserWallet?,
): List<ManagedCryptoCurrency> { ): List<ManagedCryptoCurrency> {
return coinsResponse.coins.mapNotNull { coin -> return coinsResponse.coins.mapNotNull { coin ->
createToken(coin, tokensResponse, coinsResponse.imageHost, scanResponse) createToken(coin, tokensResponse, coinsResponse.imageHost, userWallet)
} }
} }
fun createWithCustomTokens( fun createWithCustomTokens(
coinsResponse: CoinsResponse, coinsResponse: CoinsResponse,
tokensResponse: UserTokensResponse, tokensResponse: UserTokensResponse,
scanResponse: ScanResponse, userWallet: UserWallet,
): List<ManagedCryptoCurrency> { ): List<ManagedCryptoCurrency> {
val customTokens = createCustomTokens(tokensResponse, scanResponse) val customTokens = createCustomTokens(tokensResponse, userWallet)
val tokens = create(coinsResponse, tokensResponse, scanResponse) val tokens = create(coinsResponse, tokensResponse, userWallet)
return customTokens + tokens return customTokens + tokens
} }
@ -53,10 +52,10 @@ internal class ManagedCryptoCurrencyFactory(
fun createTestnetWithCustomTokens( fun createTestnetWithCustomTokens(
testnetTokensConfig: TestnetTokensConfig, testnetTokensConfig: TestnetTokensConfig,
tokensResponse: UserTokensResponse?, tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse, userWallet: UserWallet,
): List<ManagedCryptoCurrency> { ): List<ManagedCryptoCurrency> {
val customTokens = tokensResponse val customTokens = tokensResponse
?.let { createCustomTokens(it, scanResponse) } ?.let { createCustomTokens(it, userWallet) }
?: emptyList() ?: emptyList()
val testnetTokens = testnetTokensConfig.tokens.map { testnetToken -> val testnetTokens = testnetTokensConfig.tokens.map { testnetToken ->
ManagedCryptoCurrency.Token( ManagedCryptoCurrency.Token(
@ -69,10 +68,10 @@ internal class ManagedCryptoCurrencyFactory(
networkId = network.id, networkId = network.id,
contractAddress = network.address, contractAddress = network.address,
decimals = network.decimalCount, decimals = network.decimalCount,
scanResponse = scanResponse, userWallet = userWallet,
) )
} ?: emptyList(), } ?: emptyList(),
addedIn = findAddedInNetworks(testnetToken.id, tokensResponse, scanResponse), addedIn = findAddedInNetworks(testnetToken.id, tokensResponse, userWallet),
) )
} }
@ -81,28 +80,28 @@ internal class ManagedCryptoCurrencyFactory(
private fun createCustomTokens( private fun createCustomTokens(
tokensResponse: UserTokensResponse, tokensResponse: UserTokensResponse,
scanResponse: ScanResponse, userWallet: UserWallet,
): List<ManagedCryptoCurrency> = tokensResponse.tokens ): List<ManagedCryptoCurrency> = tokensResponse.tokens
.mapNotNull { token -> .mapNotNull { token ->
maybeCreateCustomToken(token, scanResponse) maybeCreateCustomToken(token, userWallet)
} }
private fun maybeCreateCustomToken( private fun maybeCreateCustomToken(
token: UserTokensResponse.Token, token: UserTokensResponse.Token,
scanResponse: ScanResponse, userWallet: UserWallet,
): ManagedCryptoCurrency? { ): ManagedCryptoCurrency? {
val blockchain = Blockchain.fromNetworkId(token.networkId) val blockchain = Blockchain.fromNetworkId(token.networkId)
?.takeUnless { it in excludedBlockchains } ?.takeUnless { it in excludedBlockchains }
?: return null ?: return null
if (!checkIsCustomToken(token, blockchain, scanResponse.derivationStyleProvider)) { if (!checkIsCustomToken(token, blockchain, userWallet.derivationStyleProvider)) {
return null return null
} }
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = token.derivationPath, extraDerivationPath = token.derivationPath,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
val contractAddress = token.contractAddress val contractAddress = token.contractAddress
@ -135,7 +134,7 @@ internal class ManagedCryptoCurrencyFactory(
coinResponse: CoinsResponse.Coin, coinResponse: CoinsResponse.Coin,
tokensResponse: UserTokensResponse?, tokensResponse: UserTokensResponse?,
imageHost: String?, imageHost: String?,
scanResponse: ScanResponse?, userWallet: UserWallet?,
): ManagedCryptoCurrency? { ): ManagedCryptoCurrency? {
if (coinResponse.networks.isEmpty() || !coinResponse.active) return null if (coinResponse.networks.isEmpty() || !coinResponse.active) return null
@ -146,7 +145,7 @@ internal class ManagedCryptoCurrencyFactory(
networkId = network.networkId, networkId = network.networkId,
contractAddress = network.contractAddress, contractAddress = network.contractAddress,
decimals = network.decimalCount?.toInt(), decimals = network.decimalCount?.toInt(),
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
.ifEmpty { return null } .ifEmpty { return null }
@ -157,7 +156,7 @@ internal class ManagedCryptoCurrencyFactory(
symbol = coinResponse.symbol, symbol = coinResponse.symbol,
iconUrl = getIconUrl(coinResponse.id, imageHost), iconUrl = getIconUrl(coinResponse.id, imageHost),
availableNetworks = availableNetworks, availableNetworks = availableNetworks,
addedIn = findAddedInNetworks(coinResponse.id, tokensResponse, scanResponse), addedIn = findAddedInNetworks(coinResponse.id, tokensResponse, userWallet),
) )
} }
@ -165,7 +164,7 @@ internal class ManagedCryptoCurrencyFactory(
networkId: String, networkId: String,
contractAddress: String?, contractAddress: String?,
decimals: Int?, decimals: Int?,
scanResponse: ScanResponse?, userWallet: UserWallet?,
extraDerivationPath: String? = null, extraDerivationPath: String? = null,
): SourceNetwork? { ): SourceNetwork? {
val blockchain = Blockchain.fromNetworkId(networkId) val blockchain = Blockchain.fromNetworkId(networkId)
@ -175,10 +174,8 @@ internal class ManagedCryptoCurrencyFactory(
val network = networkFactory.create( val network = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = extraDerivationPath, extraDerivationPath = extraDerivationPath,
derivationStyleProvider = scanResponse?.derivationStyleProvider, derivationStyleProvider = userWallet?.derivationStyleProvider,
canHandleTokens = scanResponse?.let { canHandleTokens = userWallet?.canHandleToken(blockchain, excludedBlockchains) ?: false,
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
} ?: false, // use card specific check if available
) ?: return null ) ?: return null
return when { return when {
@ -207,7 +204,7 @@ internal class ManagedCryptoCurrencyFactory(
private fun findAddedInNetworks( private fun findAddedInNetworks(
currencyId: String, currencyId: String,
tokensResponse: UserTokensResponse?, tokensResponse: UserTokensResponse?,
scanResponse: ScanResponse?, userWallet: UserWallet?,
): Set<Network> { ): Set<Network> {
if (tokensResponse == null) return emptySet() if (tokensResponse == null) return emptySet()
@ -220,10 +217,8 @@ internal class ManagedCryptoCurrencyFactory(
networkFactory.create( networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = token.derivationPath, extraDerivationPath = token.derivationPath,
derivationStyleProvider = scanResponse?.derivationStyleProvider, derivationStyleProvider = userWallet?.derivationStyleProvider,
canHandleTokens = scanResponse?.let { canHandleTokens = userWallet?.canHandleToken(blockchain, excludedBlockchains) ?: true,
it.card.canHandleToken(blockchain, it.cardTypesResolver, excludedBlockchains)
} ?: true,
) )
} else { } else {
null null

View file

@ -24,7 +24,6 @@ import com.tangem.domain.markets.*
import com.tangem.domain.markets.repositories.MarketsTokenRepository import com.tangem.domain.markets.repositories.MarketsTokenRepository
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.pagination.* import com.tangem.pagination.*
import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher import com.tangem.pagination.fetcher.LimitOffsetBatchFetcher
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -259,13 +258,13 @@ internal class DefaultMarketsTokenRepository(
cryptoCurrencyFactory.createCoin( cryptoCurrencyFactory.createCoin(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} else { } else {
val currencyNetwork = networkFactory.create( val currencyNetwork = networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) ?: return null ) ?: return null
cryptoCurrencyFactory.createToken( cryptoCurrencyFactory.createToken(

View file

@ -5,7 +5,6 @@ import com.tangem.data.networks.store.NetworksStatusesStore
import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.network.NetworkStatus import com.tangem.domain.models.network.NetworkStatus
import com.tangem.domain.networks.multi.MultiNetworkStatusProducer import com.tangem.domain.networks.multi.MultiNetworkStatusProducer
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
@ -48,7 +47,7 @@ internal class DefaultMultiNetworkStatusProducer @AssistedInject constructor(
val network = networkFactory.create( val network = networkFactory.create(
networkId = status.id, networkId = status.id,
derivationPath = status.id.derivationPath, derivationPath = status.id.derivationPath,
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) ?: return@mapNotNullTo null ) ?: return@mapNotNullTo null
NetworkStatus(network = network, value = status.value) NetworkStatus(network = network, value = status.value)

View file

@ -67,7 +67,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.first().network } returns statuses.first().network
@ -75,7 +75,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.last().network } returns statuses.last().network
@ -94,12 +94,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -130,7 +130,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.first().network } returns statuses.first().network
@ -138,7 +138,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.last().network } returns statuses.last().network
@ -146,7 +146,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = updatedSimpleStatuses.first().id, networkId = updatedSimpleStatuses.first().id,
derivationPath = updatedSimpleStatuses.first().id.derivationPath, derivationPath = updatedSimpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns updatedStatuses.first().network } returns updatedStatuses.first().network
@ -154,7 +154,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = updatedSimpleStatuses.last().id, networkId = updatedSimpleStatuses.last().id,
derivationPath = updatedSimpleStatuses.last().id.derivationPath, derivationPath = updatedSimpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns updatedStatuses.last().network } returns updatedStatuses.last().network
// endregion // endregion
@ -177,12 +177,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
@ -202,12 +202,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = updatedSimpleStatuses.first().id, networkId = updatedSimpleStatuses.first().id,
derivationPath = updatedSimpleStatuses.first().id.derivationPath, derivationPath = updatedSimpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = updatedSimpleStatuses.last().id, networkId = updatedSimpleStatuses.last().id,
derivationPath = updatedSimpleStatuses.last().id.derivationPath, derivationPath = updatedSimpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -232,7 +232,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.first().network } returns statuses.first().network
@ -240,7 +240,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.last().network } returns statuses.last().network
// endregion // endregion
@ -263,12 +263,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
@ -312,14 +312,14 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.first().network } returns statuses.first().network
every { every {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns statuses.last().network } returns statuses.last().network
// endregion // endregion
@ -336,7 +336,7 @@ internal class DefaultMultiNetworkStatusProducerTest {
verifyOrder(inverse = true) { verifyOrder(inverse = true) {
userWalletsStore.getSyncOrNull(any()) userWalletsStore.getSyncOrNull(any())
networkFactory.create(networkId = any(), derivationPath = any(), scanResponse = any()) networkFactory.create(networkId = any(), derivationPath = any(), userWallet = any())
} }
// Act 2 (emit) // Act 2 (emit)
@ -353,12 +353,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -410,12 +410,12 @@ internal class DefaultMultiNetworkStatusProducerTest {
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.first().id, networkId = simpleStatuses.first().id,
derivationPath = simpleStatuses.first().id.derivationPath, derivationPath = simpleStatuses.first().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
networkFactory.create( networkFactory.create(
networkId = simpleStatuses.last().id, networkId = simpleStatuses.last().id,
derivationPath = simpleStatuses.last().id.derivationPath, derivationPath = simpleStatuses.last().id.derivationPath,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -429,10 +429,10 @@ internal class DefaultMultiNetworkStatusProducerTest {
val userWallet = MockUserWalletFactory.create(scanResponse = scanResponse) val userWallet = MockUserWalletFactory.create(scanResponse = scanResponse)
val ethNetwork = MockCryptoCurrencyFactory(scanResponse = scanResponse).ethereum.network.copy( val ethNetwork = MockCryptoCurrencyFactory(userWallet = userWallet).ethereum.network.copy(
canHandleTokens = true, canHandleTokens = true,
) )
val cardanoNetwork = MockCryptoCurrencyFactory(scanResponse = scanResponse).cardano.network val cardanoNetwork = MockCryptoCurrencyFactory(userWallet = userWallet).cardano.network
} }
} }

View file

@ -208,7 +208,7 @@ internal class DefaultNFTRepository @Inject constructor(
networkFactory.create( networkFactory.create(
blockchain = it, blockchain = it,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} }
.filter { it.canHandleNFTs(userWalletId) } .filter { it.canHandleNFTs(userWalletId) }

View file

@ -27,7 +27,6 @@ import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.onramp.repositories.HotCryptoRepository import com.tangem.domain.onramp.repositories.HotCryptoRepository
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.JobHolder
import com.tangem.utils.coroutines.runCatching import com.tangem.utils.coroutines.runCatching
@ -93,7 +92,7 @@ internal class DefaultHotCryptoRepository(
?: error("UserWalletId [$userWalletId] not found") ?: error("UserWalletId [$userWalletId] not found")
HotCryptoCurrencyConverter( HotCryptoCurrencyConverter(
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
imageHost = it.imageHost, imageHost = it.imageHost,
excludedBlockchains = excludedBlockchains, excludedBlockchains = excludedBlockchains,
) )

View file

@ -10,22 +10,22 @@ import com.tangem.domain.models.StatusSource
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.models.quote.QuoteStatus import com.tangem.domain.models.quote.QuoteStatus
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.onramp.model.HotCryptoCurrency import com.tangem.domain.onramp.model.HotCryptoCurrency
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import java.math.BigDecimal import java.math.BigDecimal
/** /**
* Converter from [HotCryptoResponse.Token] to [HotCryptoCurrency] * Converter from [HotCryptoResponse.Token] to [HotCryptoCurrency]
* *
* @property scanResponse scan response * @property userWallet scan response
* @property imageHost image host * @property imageHost image host
* @param excludedBlockchains excluded blockchains * @param excludedBlockchains excluded blockchains
* *
[REDACTED_AUTHOR] [REDACTED_AUTHOR]
*/ */
internal class HotCryptoCurrencyConverter( internal class HotCryptoCurrencyConverter(
private val scanResponse: ScanResponse, private val userWallet: UserWallet,
private val imageHost: String?, private val imageHost: String?,
excludedBlockchains: ExcludedBlockchains, excludedBlockchains: ExcludedBlockchains,
) : Converter<HotCryptoResponse.Token, HotCryptoCurrency?> { ) : Converter<HotCryptoResponse.Token, HotCryptoCurrency?> {
@ -81,7 +81,7 @@ internal class HotCryptoCurrencyConverter(
return networkFactory.create( return networkFactory.create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }

View file

@ -21,7 +21,6 @@ import com.tangem.domain.swap.models.SwapTransactionListModel
import com.tangem.domain.swap.models.SwapTransactionModel import com.tangem.domain.swap.models.SwapTransactionModel
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.extensions.addOrReplace import com.tangem.utils.extensions.addOrReplace
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -119,7 +118,7 @@ internal class DefaultSwapTransactionRepository(
currencyTxs?.mapNotNull { currencyTxs?.mapNotNull {
listConverter.convertBack( listConverter.convertBack(
value = it, value = it,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
txStatuses = txStatuses, txStatuses = txStatuses,
) )
} }

View file

@ -3,8 +3,8 @@ package com.tangem.data.swap.converter.transaction
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.swap.models.SwapStatusDTO import com.tangem.data.swap.models.SwapStatusDTO
import com.tangem.data.swap.models.SwapTransactionDTO import com.tangem.data.swap.models.SwapTransactionDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.swap.models.SwapTransactionModel import com.tangem.domain.swap.models.SwapTransactionModel
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.utils.converter.TwoWayConverter import com.tangem.utils.converter.TwoWayConverter
internal class SavedSwapTransactionConverter( internal class SavedSwapTransactionConverter(
@ -35,14 +35,14 @@ internal class SavedSwapTransactionConverter(
fun convertBack( fun convertBack(
value: SwapTransactionDTO, value: SwapTransactionDTO,
scanResponse: ScanResponse, userWallet: UserWallet,
txStatuses: Map<String, SwapStatusDTO>, txStatuses: Map<String, SwapStatusDTO>,
): SwapTransactionModel { ): SwapTransactionModel {
val status = txStatuses[value.txId] val status = txStatuses[value.txId]
val refundCurrency = status?.refundTokensResponse?.let { id -> val refundCurrency = status?.refundTokensResponse?.let { id ->
responseCryptoCurrenciesFactory.createCurrency( responseCryptoCurrenciesFactory.createCurrency(
responseToken = id, responseToken = id,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency) val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency)

View file

@ -6,8 +6,8 @@ import com.tangem.data.swap.models.SwapStatusDTO
import com.tangem.data.swap.models.SwapTransactionDTO import com.tangem.data.swap.models.SwapTransactionDTO
import com.tangem.data.swap.models.SwapTransactionListDTO import com.tangem.data.swap.models.SwapTransactionListDTO
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.swap.models.SwapTransactionListModel import com.tangem.domain.swap.models.SwapTransactionListModel
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
@ -35,7 +35,7 @@ internal class SavedSwapTransactionListConverter(
fun convertBack( fun convertBack(
value: SwapTransactionListDTO, value: SwapTransactionListDTO,
scanResponse: ScanResponse, userWallet: UserWallet,
txStatuses: Map<String, SwapStatusDTO>, txStatuses: Map<String, SwapStatusDTO>,
): SwapTransactionListModel? { ): SwapTransactionListModel? {
val fromToken = value.fromTokensResponse val fromToken = value.fromTokensResponse
@ -45,16 +45,16 @@ internal class SavedSwapTransactionListConverter(
} else { } else {
val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency( val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = fromToken, responseToken = fromToken,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency( val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = toToken, responseToken = toToken,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
return SwapTransactionListModel( return SwapTransactionListModel(
transactions = value.transactions.map { tx -> transactions = value.transactions.map { tx ->
savedSwapTransactionConverter.convertBack(tx, scanResponse, txStatuses) savedSwapTransactionConverter.convertBack(tx, userWallet, txStatuses)
}, },
userWalletId = value.userWalletId, userWalletId = value.userWalletId,
fromCryptoCurrencyId = value.fromCryptoCurrencyId, fromCryptoCurrencyId = value.fromCryptoCurrencyId,

View file

@ -16,7 +16,6 @@ import com.tangem.datasource.local.token.UserTokensResponseStore
import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.core.utils.catchOn import com.tangem.domain.core.utils.catchOn
import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.DemoConfig
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher
import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher.Params import com.tangem.domain.tokens.MultiWalletCryptoCurrenciesFetcher.Params
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
@ -60,7 +59,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
if (!userWallet.isMultiCurrency) error("${this::class.simpleName} supports only multi-currency wallet") if (!userWallet.isMultiCurrency) error("${this::class.simpleName} supports only multi-currency wallet")
val response = if (userWallet is UserWallet.Cold && userWallet.isDemoWalletWithoutSavedTokens()) { val response = if (userWallet is UserWallet.Cold && userWallet.isDemoWalletWithoutSavedTokens()) {
createDefaultUserTokensResponse(scanResponse = userWallet.scanResponse) createDefaultUserTokensResponse(userWallet = userWallet)
} else { } else {
safeApiCall( safeApiCall(
call = { call = {
@ -99,7 +98,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
val userWalletId = userWallet.walletId val userWalletId = userWallet.walletId
val response = userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) val response = userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
?: createDefaultUserTokensResponse(scanResponse = userWallet.requireColdWallet().scanResponse) ?: createDefaultUserTokensResponse(userWallet = userWallet)
if (error is ApiResponseError.HttpException && error.code == ApiResponseError.HttpException.Code.NOT_FOUND) { if (error is ApiResponseError.HttpException && error.code == ApiResponseError.HttpException.Code.NOT_FOUND) {
Timber.w(error, "Requested currencies could not be found in the remote store for: $userWalletId") Timber.w(error, "Requested currencies could not be found in the remote store for: $userWalletId")
@ -121,9 +120,9 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcher(
expressServiceLoader.update(userWallet = userWallet, userTokens = tokens) expressServiceLoader.update(userWallet = userWallet, userTokens = tokens)
} }
private fun createDefaultUserTokensResponse(scanResponse: ScanResponse): UserTokensResponse { private fun createDefaultUserTokensResponse(userWallet: UserWallet): UserTokensResponse {
return userTokensResponseFactory.createUserTokensResponse( return userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse), currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(userWallet),
isGroupedByNetwork = false, isGroupedByNetwork = false,
isSortedByBalance = false, isSortedByBalance = false,
) )

View file

@ -48,7 +48,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducer @AssistedInject constr
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = response, response = response,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
).toSet() ).toSet()
} }
.onEmpty { emit(fallback) } .onEmpty { emit(fallback) }

View file

@ -184,7 +184,8 @@ internal class DefaultCurrenciesRepository(
) )
val token = userTokensResponseFactory.createResponseToken(currency) val token = userTokensResponseFactory.createResponseToken(currency)
val updatedResponse = savedCurrencies.copy(tokens = savedCurrencies.tokens.filterNot { it == token }) val updatedResponse =
savedCurrencies.copy(tokens = savedCurrencies.tokens.filterNot { it == token })
userTokensSaver.storeAndPush( userTokensSaver.storeAndPush(
userWalletId = userWalletId, userWalletId = userWalletId,
response = updatedResponse, response = updatedResponse,
@ -229,10 +230,11 @@ internal class DefaultCurrenciesRepository(
): CryptoCurrency { ): CryptoCurrency {
return withContext(dispatchers.io) { return withContext(dispatchers.io) {
val userWallet = userWalletsStore.getSyncStrict(userWalletId) val userWallet = userWalletsStore.getSyncStrict(userWalletId)
userWallet.requireColdWallet()
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false) ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false)
val currency = cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard( val currency = cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(
userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
fetchExpressAssetsByNetworkIds( fetchExpressAssetsByNetworkIds(
@ -254,11 +256,12 @@ internal class DefaultCurrenciesRepository(
val scanResponse = userWallet.requireColdWallet().scanResponse val scanResponse = userWallet.requireColdWallet().scanResponse
val currencies = if (scanResponse.cardTypesResolver.isSingleWalletWithToken()) { val currencies = if (scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(scanResponse = scanResponse) cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(userWallet = userWallet)
} else { } else {
cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(scanResponse = scanResponse).run { cardCryptoCurrencyFactory.createPrimaryCurrencyForSingleCurrencyCard(userWallet = userWallet)
listOf(this) .run {
} listOf(this)
}
} }
fetchExpressAssetsByNetworkIds( fetchExpressAssetsByNetworkIds(
@ -277,10 +280,11 @@ internal class DefaultCurrenciesRepository(
): CryptoCurrency { ): CryptoCurrency {
return withContext(dispatchers.io) { return withContext(dispatchers.io) {
val userWallet = userWalletsStore.getSyncStrict(userWalletId) val userWallet = userWalletsStore.getSyncStrict(userWalletId)
userWallet.requireColdWallet()
ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false) ensureIsCorrectUserWallet(userWallet, isMultiCurrencyWalletExpected = false)
val currency = cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken( val currency = cardCryptoCurrencyFactory.createCurrenciesForSingleCurrencyCardWithToken(
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
.find { it.id == id } .find { it.id == id }
requireNotNull(currency) { "Unable to find currency with provided ID: $id" } requireNotNull(currency) { "Unable to find currency with provided ID: $id" }
@ -320,7 +324,10 @@ internal class DefaultCurrenciesRepository(
}, },
) )
responseCryptoCurrenciesFactory.createCurrencies(storedTokens, userWallet.requireColdWallet().scanResponse) responseCryptoCurrenciesFactory.createCurrencies(
storedTokens,
userWallet = userWallet,
)
} }
override suspend fun getMultiCurrencyWalletCachedCurrenciesSync(userWalletId: UserWalletId) = override suspend fun getMultiCurrencyWalletCachedCurrenciesSync(userWalletId: UserWalletId) =
@ -335,7 +342,10 @@ internal class DefaultCurrenciesRepository(
}, },
) )
responseCryptoCurrenciesFactory.createCurrencies(storedTokens, userWallet.requireColdWallet().scanResponse) responseCryptoCurrenciesFactory.createCurrencies(
storedTokens,
userWallet = userWallet,
)
} }
override suspend fun getMultiCurrencyWalletCurrency( override suspend fun getMultiCurrencyWalletCurrency(
@ -360,7 +370,7 @@ internal class DefaultCurrenciesRepository(
responseCryptoCurrenciesFactory.createCurrency( responseCryptoCurrenciesFactory.createCurrency(
currencyId = id, currencyId = id,
response = response, response = response,
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
} }
@ -394,7 +404,7 @@ internal class DefaultCurrenciesRepository(
val coin = responseCryptoCurrenciesFactory.createCurrency( val coin = responseCryptoCurrenciesFactory.createCurrency(
responseToken = storedCoin, responseToken = storedCoin,
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
coin as? CryptoCurrency.Coin ?: error("Unable to create currency") coin as? CryptoCurrency.Coin ?: error("Unable to create currency")
@ -438,12 +448,15 @@ internal class DefaultCurrenciesRepository(
cryptoCurrencyStatus: CryptoCurrencyStatus, cryptoCurrencyStatus: CryptoCurrencyStatus,
): Boolean { ): Boolean {
val blockchain = cryptoCurrencyStatus.currency.network.toBlockchain() val blockchain = cryptoCurrencyStatus.currency.network.toBlockchain()
val isBitcoinBlockchain = blockchain == Blockchain.Bitcoin || blockchain == Blockchain.BitcoinTestnet val isBitcoinBlockchain =
blockchain == Blockchain.Bitcoin || blockchain == Blockchain.BitcoinTestnet
return when { return when {
cryptoCurrencyStatus.currency is CryptoCurrency.Coin && isBitcoinBlockchain -> { cryptoCurrencyStatus.currency is CryptoCurrency.Coin && isBitcoinBlockchain -> {
val outgoingTransactions = cryptoCurrencyStatus.value.pendingTransactions.filter { it.isOutgoing } val outgoingTransactions =
cryptoCurrencyStatus.value.pendingTransactions.filter { it.isOutgoing }
outgoingTransactions.isNotEmpty() outgoingTransactions.isNotEmpty()
} }
blockchain.isEvm() -> false blockchain.isEvm() -> false
blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet -> false blockchain == Blockchain.Tron || blockchain == Blockchain.TronTestnet -> false
else -> { else -> {
@ -481,6 +494,7 @@ internal class DefaultCurrenciesRepository(
balance = balance, balance = balance,
) )
} }
is FeePaidSdkCurrency.FeeResource -> FeePaidCurrency.FeeResource(currency = feePaidCurrency.currency) is FeePaidSdkCurrency.FeeResource -> FeePaidCurrency.FeeResource(currency = feePaidCurrency.currency)
} }
} }
@ -508,7 +522,8 @@ internal class DefaultCurrenciesRepository(
.coins .coins
.firstOrNull() .firstOrNull()
?: error("Token not found") ?: error("Token not found")
val network = foundToken.networks.firstOrNull { it.networkId == networkId } ?: error("Network not found") val network = foundToken.networks.firstOrNull { it.networkId == networkId }
?: error("Network not found")
CryptoCurrencyFactory.Token( CryptoCurrencyFactory.Token(
symbol = foundToken.symbol, symbol = foundToken.symbol,
name = foundToken.name, name = foundToken.name,
@ -521,7 +536,7 @@ internal class DefaultCurrenciesRepository(
token = token, token = token,
networkId = networkId, networkId = networkId,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) ?: error("Unable to create token") ) ?: error("Unable to create token")
} }
@ -559,23 +574,25 @@ internal class DefaultCurrenciesRepository(
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = storedTokens.copy(tokens = filterResponse), response = storedTokens.copy(tokens = filterResponse),
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
} }
} }
else -> {
val currencies = if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
getSingleCurrencyWalletWithCardCurrencies(userWallet.walletId)
} else {
val currency =
getSingleCurrencyWalletPrimaryCurrency(userWalletId = userWallet.walletId)
if (currency.id.rawCurrencyId == currencyRawId) { else -> {
listOf(currency) val currencies =
if (userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken()) {
getSingleCurrencyWalletWithCardCurrencies(userWallet.walletId)
} else { } else {
emptyList() val currency =
getSingleCurrencyWalletPrimaryCurrency(userWalletId = userWallet.walletId)
if (currency.id.rawCurrencyId == currencyRawId) {
listOf(currency)
} else {
emptyList()
}
} }
}
flow { flow {
emit(currencies) emit(currencies)
} }
@ -603,14 +620,15 @@ internal class DefaultCurrenciesRepository(
} }
override fun getCardTypesResolver(userWalletId: UserWalletId): CardTypesResolver { override fun getCardTypesResolver(userWalletId: UserWalletId): CardTypesResolver {
return userWalletsStore.getSyncStrict(userWalletId).requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY] return userWalletsStore.getSyncStrict(userWalletId)
.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
} }
private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<List<CryptoCurrency>> { private fun getMultiCurrencyWalletCurrencies(userWallet: UserWallet): Flow<List<CryptoCurrency>> {
return getSavedUserTokensResponse(userWallet.walletId).map { storedTokens -> return getSavedUserTokensResponse(userWallet.walletId).map { storedTokens ->
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = storedTokens, response = storedTokens,
scanResponse = userWallet.requireColdWallet().scanResponse, userWallet = userWallet,
) )
} }
} }
@ -700,7 +718,10 @@ internal class DefaultCurrenciesRepository(
?: createDefaultUserTokensResponse(userWallet = userWallet) ?: createDefaultUserTokensResponse(userWallet = userWallet)
if (e is ApiResponseError.HttpException && e.code == ApiResponseError.HttpException.Code.NOT_FOUND) { if (e is ApiResponseError.HttpException && e.code == ApiResponseError.HttpException.Code.NOT_FOUND) {
Timber.w(e, "Requested currencies could not be found in the remote store for: $userWalletId") Timber.w(
e,
"Requested currencies could not be found in the remote store for: $userWalletId",
)
userTokensSaver.push(userWalletId, response) userTokensSaver.push(userWalletId, response)
} else { } else {
@ -712,8 +733,8 @@ internal class DefaultCurrenciesRepository(
private fun createDefaultUserTokensResponse(userWallet: UserWallet) = private fun createDefaultUserTokensResponse(userWallet: UserWallet) =
userTokensResponseFactory.createUserTokensResponse( userTokensResponseFactory.createUserTokensResponse(
currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard( currencies = cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(
userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
), ),
isGroupedByNetwork = false, isGroupedByNetwork = false,
isSortedByBalance = false, isSortedByBalance = false,
@ -732,9 +753,11 @@ internal class DefaultCurrenciesRepository(
!userWallet.isMultiCurrency && isMultiCurrencyWalletExpected -> { !userWallet.isMultiCurrency && isMultiCurrencyWalletExpected -> {
"Multi currency wallet expected, but single currency wallet was found: $userWalletId" "Multi currency wallet expected, but single currency wallet was found: $userWalletId"
} }
userWallet.isMultiCurrency && !isMultiCurrencyWalletExpected -> { userWallet.isMultiCurrency && !isMultiCurrencyWalletExpected -> {
"Single currency wallet expected, but multi currency wallet was found: $userWalletId" "Single currency wallet expected, but multi currency wallet was found: $userWalletId"
} }
else -> null else -> null
} }

View file

@ -125,7 +125,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
every { userWalletsStore.getSyncStrict(params.userWalletId) } returns mockUserWallet every { userWalletsStore.getSyncStrict(params.userWalletId) } returns mockUserWallet
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId) } returns null coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId) } returns null
every { every {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins } returns defaultCoins
coEvery { coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse) customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -141,7 +141,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerifyOrder { coVerifyOrder {
userWalletsStore.getSyncStrict(key = params.userWalletId) userWalletsStore.getSyncStrict(key = params.userWalletId)
userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId) userTokensResponseStore.getSyncOrNull(userWalletId = params.userWalletId)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = mockUserWallet.scanResponse) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse) customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse) userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens()) expressServiceLoader.update(userWallet = mockUserWallet, userTokens = userTokensResponse.toLeastTokens())
@ -187,7 +187,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
} }
coVerify(inverse = true) { coVerify(inverse = true) {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any()) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
} }
} }
@ -229,7 +229,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerify(inverse = true) { coVerify(inverse = true) {
userTokensResponseStore.getSyncOrNull(userWalletId = any()) userTokensResponseStore.getSyncOrNull(userWalletId = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any()) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
} }
} }
@ -267,7 +267,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null
coEvery { coEvery {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins } returns defaultCoins
coEvery { coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse) customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -335,7 +335,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coVerify(inverse = true) { coVerify(inverse = true) {
userTokensSaver.push(userWalletId = any(), response = any()) userTokensSaver.push(userWalletId = any(), response = any())
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any()) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
} }
} }
@ -377,7 +377,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse coEvery { tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) } returns apiResponse
coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null coEvery { userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) } returns null
coEvery { coEvery {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
} returns defaultCoins } returns defaultCoins
coEvery { coEvery {
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse) customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
@ -394,7 +394,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
userWalletsStore.getSyncStrict(key = params.userWalletId) userWalletsStore.getSyncStrict(key = params.userWalletId)
tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue) tangemTechApi.getUserTokens(userId = params.userWalletId.stringValue)
userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId) userTokensResponseStore.getSyncOrNull(userWalletId = userWalletId)
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(mockUserWallet.scanResponse) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(mockUserWallet)
userTokensSaver.push(userWalletId = params.userWalletId, response = userTokensResponse) userTokensSaver.push(userWalletId = params.userWalletId, response = userTokensResponse)
customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse) customTokensMerger.mergeIfPresented(userWalletId = params.userWalletId, response = userTokensResponse)
userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse) userTokensSaver.store(userWalletId = params.userWalletId, response = userTokensResponse)
@ -447,7 +447,7 @@ internal class DefaultMultiWalletCryptoCurrenciesFetcherTest {
} }
coVerify(inverse = true) { coVerify(inverse = true) {
cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyCard(scanResponse = any()) cardCryptoCurrencyFactory.createDefaultCoinsForMultiCurrencyWallet(any())
} }
} }

View file

@ -72,7 +72,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
} }
verify(inverse = true) { verify(inverse = true) {
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any()) responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
} }
} }
@ -114,14 +114,14 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every { every {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns cryptoCurrencies.toList() } returns cryptoCurrencies.toList()
every { every {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = updatedUserTokensResponse, response = updatedUserTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns updatedCryptoCurrencies.toList() } returns updatedCryptoCurrencies.toList()
@ -143,7 +143,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
userTokensResponseStore.get(params.userWalletId) userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
@ -161,7 +161,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verifyOrder { verifyOrder {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = updatedUserTokensResponse, response = updatedUserTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -185,7 +185,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every { every {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns cryptoCurrencies.toList() } returns cryptoCurrencies.toList()
@ -207,7 +207,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
userTokensResponseStore.get(params.userWalletId) userTokensResponseStore.get(params.userWalletId)
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
@ -251,7 +251,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
every { every {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} returns cryptoCurrencies.toList() } returns cryptoCurrencies.toList()
@ -282,7 +282,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verifyOrder { verifyOrder {
responseCryptoCurrenciesFactory.createCurrencies( responseCryptoCurrenciesFactory.createCurrencies(
response = userTokensResponse, response = userTokensResponse,
scanResponse = userWallet.scanResponse, userWallet = userWallet,
) )
} }
} }
@ -307,7 +307,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
} }
verify(inverse = true) { verify(inverse = true) {
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any()) responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
} }
} }
@ -335,7 +335,7 @@ internal class DefaultMultiWalletCryptoCurrenciesProducerTest {
verify(inverse = true) { verify(inverse = true) {
userTokensResponseStore.get(any()) userTokensResponseStore.get(any())
responseCryptoCurrenciesFactory.createCurrencies(response = any(), scanResponse = any()) responseCryptoCurrenciesFactory.createCurrencies(response = any(), userWallet = any())
} }
} }

View file

@ -7,7 +7,6 @@ import com.tangem.data.walletconnect.model.CAIP2
import com.tangem.data.walletconnect.model.NamespaceKey import com.tangem.data.walletconnect.model.NamespaceKey
import com.tangem.domain.models.network.Network import com.tangem.domain.models.network.Network
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
internal interface WcNamespaceConverter { internal interface WcNamespaceConverter {
@ -27,7 +26,7 @@ internal interface WcNamespaceConverter {
return NetworkFactory(excludedBlockchains).create( return NetworkFactory(excludedBlockchains).create(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = wallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = wallet,
) )
} }
} }

View file

@ -23,4 +23,8 @@ internal class TangemDerivationStyleProvider(
private fun firstBatchesOfWallet1(card: CardDTO): Boolean { private fun firstBatchesOfWallet1(card: CardDTO): Boolean {
return card.batchId == "AC01" || card.batchId == "AC02" || card.batchId == "CB95" return card.batchId == "AC01" || card.batchId == "AC02" || card.batchId == "CB95"
} }
}
internal class TangemHotDerivationStyleProvider : DerivationStyleProvider {
override fun getDerivationStyle(): DerivationStyle? = DerivationStyle.V3
} }

View file

@ -7,7 +7,9 @@ import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.CardTypesResolver import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.configs.CardConfig import com.tangem.domain.common.configs.CardConfig
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.models.scan.CardDTO import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.wallets.models.UserWallet
// TODO: refactor [REDACTED_JIRA] // TODO: refactor [REDACTED_JIRA]
@ -17,6 +19,20 @@ import com.tangem.domain.models.scan.CardDTO
val FirmwareVersion.Companion.SolanaTokensAvailable val FirmwareVersion.Companion.SolanaTokensAvailable
get() = FirmwareVersion(4, 52) get() = FirmwareVersion(4, 52)
fun UserWallet.supportedBlockchains(excludedBlockchains: ExcludedBlockchains): List<Blockchain> {
return when (this) {
is UserWallet.Cold -> {
scanResponse.card.supportedBlockchains(
excludedBlockchains = excludedBlockchains,
cardTypesResolver = this.cardTypesResolver,
)
}
is UserWallet.Hot -> {
Blockchain.entries.filter { it !in excludedBlockchains }
}
}
}
fun CardDTO.supportedBlockchains( fun CardDTO.supportedBlockchains(
cardTypesResolver: CardTypesResolver, cardTypesResolver: CardTypesResolver,
excludedBlockchains: ExcludedBlockchains, excludedBlockchains: ExcludedBlockchains,
@ -55,6 +71,33 @@ fun CardDTO.supportedTokens(
return tokensSupportedByCard.filter { isTestCard == it.isTestnet() } return tokensSupportedByCard.filter { isTestCard == it.isTestnet() }
} }
fun UserWallet.canHandleToken(supportedTokens: List<Blockchain>, blockchain: Blockchain): Boolean {
return when (this) {
is UserWallet.Cold -> {
scanResponse.card.canHandleToken(
supportedTokens = supportedTokens,
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
)
}
is UserWallet.Hot -> blockchain in supportedTokens
}
}
fun UserWallet.canHandleToken(blockchain: Blockchain, excludedBlockchains: ExcludedBlockchains): Boolean {
return when (this) {
is UserWallet.Cold -> {
scanResponse.card.canHandleToken(
blockchain = blockchain,
excludedBlockchains = excludedBlockchains,
cardTypesResolver = scanResponse.cardTypesResolver,
)
}
is UserWallet.Hot -> blockchain !in excludedBlockchains
}
}
/** /**
* The same as [CardDTO.supportedTokens] but with supportedTokens input, if previously calculated * The same as [CardDTO.supportedTokens] but with supportedTokens input, if previously calculated
*/ */
@ -101,7 +144,8 @@ fun CardDTO.canHandleBlockchain(
): Boolean { ): Boolean {
val cardConfig = CardConfig.createConfig(this) val cardConfig = CardConfig.createConfig(this)
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain) val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
val isContainsBlockchain = blockchain in supportedBlockchains(cardTypesResolver, excludedBlockchains) val isContainsBlockchain =
blockchain in supportedBlockchains(cardTypesResolver, excludedBlockchains)
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain } val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
// fixme: check for first wallets with 1 curve and remove condition // fixme: check for first wallets with 1 curve and remove condition
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) { return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {

View file

@ -8,6 +8,7 @@ import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.DerivationStyleProvider import com.tangem.domain.common.DerivationStyleProvider
import com.tangem.domain.common.TangemCardTypesResolver import com.tangem.domain.common.TangemCardTypesResolver
import com.tangem.domain.common.TangemDerivationStyleProvider import com.tangem.domain.common.TangemDerivationStyleProvider
import com.tangem.domain.common.TangemHotDerivationStyleProvider
import com.tangem.domain.common.TapWorkarounds.isTangemTwins import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.TapWorkarounds.isTestCard import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.configs.CardConfig import com.tangem.domain.common.configs.CardConfig
@ -23,6 +24,12 @@ val ScanResponse.cardTypesResolver: CardTypesResolver
walletData = walletData, walletData = walletData,
) )
val UserWallet.derivationStyleProvider: DerivationStyleProvider
get() = when (this) {
is UserWallet.Cold -> this.scanResponse.derivationStyleProvider
is UserWallet.Hot -> TangemHotDerivationStyleProvider()
}
val ScanResponse.derivationStyleProvider: DerivationStyleProvider val ScanResponse.derivationStyleProvider: DerivationStyleProvider
get() = card.derivationStyleProvider get() = card.derivationStyleProvider

View file

@ -10,7 +10,7 @@ import kotlinx.serialization.Serializable
@Serializable(with = MobileWalletAsStringSerializer::class) @Serializable(with = MobileWalletAsStringSerializer::class)
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
class MobileWallet( data class MobileWallet(
@Json(name = "publicKey") @Json(name = "publicKey")
val publicKey: ByteArray, val publicKey: ByteArray,
@Json(name = "chainCode") @Json(name = "chainCode")

View file

@ -10,7 +10,7 @@ import com.tangem.domain.tokens.operations.BaseCurrencyStatusOperations
import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations import com.tangem.domain.tokens.operations.CurrenciesStatusesOperations
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
@ -44,11 +44,10 @@ class GetNetworkCoinStatusUseCase(
derivationPath: Network.DerivationPath, derivationPath: Network.DerivationPath,
): Either<CurrencyStatusError, CryptoCurrencyStatus> { ): Either<CurrencyStatusError, CryptoCurrencyStatus> {
val userWalletId = userWallet.walletId val userWalletId = userWallet.walletId
val cardTypesResolver = userWallet.requireColdWallet().cardTypesResolver // TODO [REDACTED_TASK_KEY]
val maybeCurrency = if (userWallet.isMultiCurrency) { val maybeCurrency = if (userWallet.isMultiCurrency) {
currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath) currencyStatusOperations.getNetworkCoinSync(userWalletId, networkId, derivationPath)
} else if (cardTypesResolver.isSingleWalletWithToken()) { } else if (userWallet is UserWallet.Cold && userWallet.cardTypesResolver.isSingleWalletWithToken()) {
currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenSync(userWalletId, networkId) currencyStatusOperations.getNetworkCoinForSingleWalletWithTokenSync(userWalletId, networkId)
} else { } else {
currencyStatusOperations.getPrimaryCurrencyStatusSync(userWalletId) currencyStatusOperations.getPrimaryCurrencyStatusSync(userWalletId)

View file

@ -59,6 +59,7 @@ sealed interface UserWallet {
override val walletId: UserWalletId, override val walletId: UserWalletId,
val hotWalletId: HotWalletId, val hotWalletId: HotWalletId,
val wallets: List<MobileWallet>?, val wallets: List<MobileWallet>?,
val backedUp: Boolean,
) : UserWallet { ) : UserWallet {
val isLocked: Boolean get() = wallets == null val isLocked: Boolean get() = wallets == null

View file

@ -11,29 +11,31 @@ import com.tangem.hot.sdk.model.DeriveWalletRequest
import com.tangem.hot.sdk.model.HotAuth import com.tangem.hot.sdk.model.HotAuth
import com.tangem.hot.sdk.model.HotWalletId import com.tangem.hot.sdk.model.HotWalletId
import com.tangem.hot.sdk.model.UnlockHotWallet import com.tangem.hot.sdk.model.UnlockHotWallet
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import kotlinx.coroutines.withContext
class HotUserWalletBuilder @AssistedInject constructor( class HotUserWalletBuilder @AssistedInject constructor(
@Assisted private val hotWalletId: HotWalletId, @Assisted private val hotWalletId: HotWalletId,
private val hotSdk: TangemHotSdk, private val hotSdk: TangemHotSdk,
private val generateWalletNameUseCase: GenerateWalletNameUseCase, private val generateWalletNameUseCase: GenerateWalletNameUseCase,
private val dispatcherProvider: CoroutineDispatcherProvider,
) { ) {
suspend fun build(): UserWallet.Hot { suspend fun build(): UserWallet.Hot = withContext(dispatcherProvider.default) {
val allNetworks = Blockchain.entries // TODO use HotDerivationsRepository to get supported networks val allNetworks = Blockchain.entries // TODO use HotDerivationsRepository to get supported networks
val requests = allNetworks.map { val curves = allNetworks.map { it.getSupportedCurves() }.flatten().toSet()
val curves = it.getSupportedCurves() val requests = curves.sortedBy { it.ordinal }.map { curve ->
val derivationPath = it.derivationPath(DerivationStyle.V3) val derivationPaths = allNetworks.filter { curve in it.getSupportedCurves() }
.mapNotNull { it.derivationPath(DerivationStyle.V3) }
curves.map { DeriveWalletRequest.Request(
DeriveWalletRequest.Request( curve = curve,
curve = it, paths = derivationPaths,
paths = listOfNotNull(derivationPath), )
) }
}
}.flatten()
val derivationResult = hotSdk.derivePublicKey( val derivationResult = hotSdk.derivePublicKey(
unlockHotWallet = UnlockHotWallet( unlockHotWallet = UnlockHotWallet(
@ -54,11 +56,12 @@ class HotUserWalletBuilder @AssistedInject constructor(
) )
} }
return UserWallet.Hot( UserWallet.Hot(
name = generateWalletNameUseCase.invokeForHot(), name = generateWalletNameUseCase.invokeForHot(),
walletId = UserWalletId(wallets.first().publicKey), walletId = UserWalletId(wallets.first().publicKey),
hotWalletId = hotWalletId, hotWalletId = hotWalletId,
wallets = wallets, wallets = wallets,
backedUp = false,
) )
} }

View file

@ -22,7 +22,7 @@ class GenerateWalletNameUseCase(
} }
fun invokeForHot(): String { fun invokeForHot(): String {
val defaultName = "Mobile Wallet" val defaultName = "Wallet"
val existingNames = userWalletsListManager.userWalletsSync.map { it.name }.toSet() val existingNames = userWalletsListManager.userWalletsSync.map { it.name }.toSet()
return suggestedWalletName(defaultName, existingNames) return suggestedWalletName(defaultName, existingNames)
} }

View file

@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ModelScoped @ModelScoped
@ -49,6 +50,8 @@ internal class CreateMobileWalletModel @Inject constructor(
) )
router.push(AppRoute.Wallet) router.push(AppRoute.Wallet)
}.onFailure { }.onFailure {
Timber.e(it)
uiState.update { uiState.update {
it.copy(createButtonLoading = false) it.copy(createButtonLoading = false)
} }

View file

@ -7,30 +7,18 @@ import com.tangem.features.hotwallet.createmobilewallet.DefaultCreateMobileWalle
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import dagger.multibindings.ClassKey import dagger.multibindings.ClassKey
import dagger.multibindings.IntoMap import dagger.multibindings.IntoMap
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
internal object CreateMobileWalletModule internal interface CreateMobileWalletModuleBinds {
@Module
@InstallIn(ActivityComponent::class)
internal interface CreateMobileWalletModuleActivityBinds {
@Binds @Binds
@ActivityScoped
fun bindCreateMobileWalletComponentFactory( fun bindCreateMobileWalletComponentFactory(
impl: DefaultCreateMobileWalletComponent.Factory, impl: DefaultCreateMobileWalletComponent.Factory,
): CreateMobileWalletComponent.Factory ): CreateMobileWalletComponent.Factory
}
@Module
@InstallIn(SingletonComponent::class)
internal interface CreateMobileWalletModuleBinds {
@Binds @Binds
@IntoMap @IntoMap

View file

@ -11,7 +11,6 @@ import com.tangem.datasource.api.tangemTech.models.StartReferralBody
import com.tangem.datasource.local.userwallet.UserWalletsStore import com.tangem.datasource.local.userwallet.UserWalletsStore
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.referral.converters.ReferralConverter import com.tangem.feature.referral.converters.ReferralConverter
import com.tangem.feature.referral.domain.ReferralRepository import com.tangem.feature.referral.domain.ReferralRepository
import com.tangem.feature.referral.domain.models.ReferralData import com.tangem.feature.referral.domain.models.ReferralData
@ -97,13 +96,13 @@ internal class ReferralRepositoryImpl @Inject constructor(
sdkToken = sdkToken, sdkToken = sdkToken,
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} else { } else {
cryptoCurrencyFactory.createCoin( cryptoCurrencyFactory.createCoin(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
) )
} }
} }

View file

@ -30,7 +30,6 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.legacy.UserWalletsListManager
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.swap.converters.* import com.tangem.feature.swap.converters.*
import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.api.SwapRepository
import com.tangem.feature.swap.domain.models.ExpressDataError import com.tangem.feature.swap.domain.models.ExpressDataError
@ -404,12 +403,7 @@ internal class DefaultSwapRepository(
cryptoCurrencyFactory.createCoin( cryptoCurrencyFactory.createCoin(
blockchain = blockchain, blockchain = blockchain,
extraDerivationPath = null, extraDerivationPath = null,
scanResponse = requireNotNull( userWallet = requireNotNull(userWalletsListManager.selectedUserWalletSync),
userWalletsListManager
.selectedUserWalletSync
?.requireColdWallet() // TODO [REDACTED_TASK_KEY]
?.scanResponse,
),
), ),
) )
} }

View file

@ -10,7 +10,6 @@ import com.tangem.datasource.local.preferences.utils.getObjectMap
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.swap.converters.SavedSwapTransactionListConverter import com.tangem.feature.swap.converters.SavedSwapTransactionListConverter
import com.tangem.feature.swap.domain.SwapTransactionRepository import com.tangem.feature.swap.domain.SwapTransactionRepository
import com.tangem.feature.swap.domain.models.domain.* import com.tangem.feature.swap.domain.models.domain.*
@ -104,7 +103,7 @@ internal class DefaultSwapTransactionRepository(
currencyTxs?.mapNotNull { currencyTxs?.mapNotNull {
converter.convertBack( converter.convertBack(
value = it, value = it,
scanResponse = userWallet.requireColdWallet().scanResponse, // TODO [REDACTED_TASK_KEY] userWallet = userWallet,
txStatuses = txStatuses, txStatuses = txStatuses,
) )
} }

View file

@ -3,7 +3,7 @@ package com.tangem.feature.swap.converters
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
import com.tangem.data.common.currency.UserTokensResponseFactory import com.tangem.data.common.currency.UserTokensResponseFactory
import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel import com.tangem.feature.swap.domain.models.domain.ExchangeStatusModel
import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel import com.tangem.feature.swap.domain.models.domain.SavedSwapTransactionListModel
@ -32,7 +32,7 @@ internal class SavedSwapTransactionListConverter(
fun convertBack( fun convertBack(
value: SavedSwapTransactionListModelInner, value: SavedSwapTransactionListModelInner,
scanResponse: ScanResponse, userWallet: UserWallet,
txStatuses: Map<String, ExchangeStatusModel>, txStatuses: Map<String, ExchangeStatusModel>,
): SavedSwapTransactionListModel? { ): SavedSwapTransactionListModel? {
val fromToken = value.fromTokensResponse val fromToken = value.fromTokensResponse
@ -42,11 +42,11 @@ internal class SavedSwapTransactionListConverter(
} else { } else {
val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency( val fromCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = fromToken, responseToken = fromToken,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency( val toCryptoCurrency = responseCryptoCurrenciesFactory.createCurrency(
responseToken = toToken, responseToken = toToken,
scanResponse = scanResponse, userWallet = userWallet,
) ?: return null ) ?: return null
return SavedSwapTransactionListModel( return SavedSwapTransactionListModel(
@ -55,7 +55,7 @@ internal class SavedSwapTransactionListConverter(
val refundCurrency = status?.refundTokensResponse?.let { id -> val refundCurrency = status?.refundTokensResponse?.let { id ->
responseCryptoCurrenciesFactory.createCurrency( responseCryptoCurrenciesFactory.createCurrency(
responseToken = id, responseToken = id,
scanResponse = scanResponse, userWallet = userWallet,
) )
} }
val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency) val statusWithRefundCurrency = status?.copy(refundCurrency = refundCurrency)

View file

@ -39,10 +39,22 @@ internal object WalletAdditionalInfoFactory {
wallet.resolveSingleCurrencyInfo(currencyAmount) wallet.resolveSingleCurrencyInfo(currencyAmount)
} }
} }
is UserWallet.Hot -> TODO("[REDACTED_TASK_KEY]") is UserWallet.Hot -> wallet.resolveAdditionalInfo()
} }
} }
private fun UserWallet.Hot.resolveAdditionalInfo(): WalletAdditionalInfo {
return WalletAdditionalInfo(
hideable = false,
content = TextReference.Res(R.string.hw_mobile_wallet) +
when {
isLocked -> DIVIDER + TextReference.Res(R.string.common_locked)
backedUp.not() -> DIVIDER + TextReference.Res(R.string.hw_backup_no_backup)
else -> TextReference.Str("")
},
)
}
private fun UserWallet.Cold.resolveMultiCurrencyInfo(): WalletAdditionalInfo { private fun UserWallet.Cold.resolveMultiCurrencyInfo(): WalletAdditionalInfo {
return if (isLocked) { return if (isLocked) {
WalletAdditionalInfo( WalletAdditionalInfo(

View file

@ -24,7 +24,11 @@ internal class WalletImageResolver @Inject constructor(
/** Get a specified wallet [userWallet] image */ /** Get a specified wallet [userWallet] image */
@Suppress("CyclomaticComplexMethod") @Suppress("CyclomaticComplexMethod")
@DrawableRes @DrawableRes
fun resolve(userWallet: UserWallet.Cold): Int? { fun resolve(userWallet: UserWallet): Int? {
if (userWallet !is UserWallet.Cold) {
return null
}
val cardTypesResolver = userWallet.scanResponse.cardTypesResolver val cardTypesResolver = userWallet.scanResponse.cardTypesResolver
val cobrandImage = Wallet2CobrandImage.entries.firstOrNull { val cobrandImage = Wallet2CobrandImage.entries.firstOrNull {

View file

@ -31,7 +31,7 @@ internal class WalletContentLoaderFactory @Inject constructor(
userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isVisaWallet() -> { userWallet is UserWallet.Cold && userWallet.scanResponse.cardTypesResolver.isVisaWallet() -> {
visaWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh) visaWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
} }
!userWallet.isMultiCurrency -> { userWallet is UserWallet.Cold && !userWallet.isMultiCurrency -> {
singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh) singleWalletContentLoaderFactory.create(userWallet, clickIntents, isRefresh)
} }
else -> null else -> null

View file

@ -19,7 +19,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.*
@Suppress("LongParameterList") @Suppress("LongParameterList")
internal class SingleWalletContentLoader( internal class SingleWalletContentLoader(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents, private val clickIntents: WalletClickIntents,
private val isRefresh: Boolean, private val isRefresh: Boolean,
private val stateHolder: WalletStateController, private val stateHolder: WalletStateController,

View file

@ -36,7 +36,7 @@ internal class SingleWalletContentLoaderFactory @Inject constructor(
private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender, private val walletWarningsAnalyticsSender: WalletWarningsAnalyticsSender,
) { ) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader { fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
return SingleWalletContentLoader( return SingleWalletContentLoader(
userWallet = userWallet, userWallet = userWallet,
clickIntents = clickIntents, clickIntents = clickIntents,

View file

@ -17,7 +17,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.*
@Suppress("LongParameterList") @Suppress("LongParameterList")
internal class SingleWalletWithTokenContentLoader( internal class SingleWalletWithTokenContentLoader(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents, private val clickIntents: WalletClickIntents,
private val stateHolder: WalletStateController, private val stateHolder: WalletStateController,
private val tokenListAnalyticsSender: TokenListAnalyticsSender, private val tokenListAnalyticsSender: TokenListAnalyticsSender,

View file

@ -33,7 +33,7 @@ internal class SingleWalletWithTokenContentLoaderFactory @Inject constructor(
private val getStoryContentUseCase: GetStoryContentUseCase, private val getStoryContentUseCase: GetStoryContentUseCase,
) { ) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader { fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents): SingleWalletWithTokenContentLoader {
return SingleWalletWithTokenContentLoader( return SingleWalletWithTokenContentLoader(
userWallet = userWallet, userWallet = userWallet,
clickIntents = clickIntents, clickIntents = clickIntents,

View file

@ -9,7 +9,7 @@ import com.tangem.feature.wallet.presentation.wallet.subscribers.WalletSubscribe
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
internal class VisaWalletContentLoader( internal class VisaWalletContentLoader(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val clickIntents: WalletClickIntents, private val clickIntents: WalletClickIntents,
private val isRefresh: Boolean, private val isRefresh: Boolean,
private val stateController: WalletStateController, private val stateController: WalletStateController,

View file

@ -15,7 +15,7 @@ internal class VisaWalletContentLoaderFactory @Inject constructor(
private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase, private val getVisaTxHistoryUseCase: GetVisaTxHistoryUseCase,
) { ) {
fun create(userWallet: UserWallet, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader { fun create(userWallet: UserWallet.Cold, clickIntents: WalletClickIntents, isRefresh: Boolean): WalletContentLoader {
return VisaWalletContentLoader( return VisaWalletContentLoader(
userWallet = userWallet, userWallet = userWallet,
clickIntents = clickIntents, clickIntents = clickIntents,

View file

@ -3,7 +3,6 @@ package com.tangem.feature.wallet.presentation.wallet.state.transformers
import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.isLocked import com.tangem.domain.wallets.models.isLocked
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
import com.tangem.feature.wallet.presentation.wallet.state.model.* import com.tangem.feature.wallet.presentation.wallet.state.model.*
@ -55,8 +54,6 @@ internal class InitializeWalletsTransformer(
} }
private fun createLockedState(userWallet: UserWallet): WalletState { private fun createLockedState(userWallet: UserWallet): WalletState {
userWallet.requireColdWallet()
return userWallet.createStateByWalletType( return userWallet.createStateByWalletType(
multiCurrencyCreator = { multiCurrencyCreator = {
WalletState.MultiCurrency.Locked( WalletState.MultiCurrency.Locked(
@ -87,7 +84,7 @@ internal class InitializeWalletsTransformer(
) )
} }
private fun UserWallet.Cold.toLockedWalletCardState(): WalletCardState { private fun UserWallet.toLockedWalletCardState(): WalletCardState {
return WalletCardState.LockedContent( return WalletCardState.LockedContent(
id = walletId, id = walletId,
title = name, title = name,

View file

@ -6,7 +6,6 @@ import com.tangem.domain.appcurrency.model.AppCurrency
import com.tangem.domain.common.util.getCardsCount import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.error.TokenListError
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
@ -57,8 +56,6 @@ internal class SetTokenListErrorTransformer(
} }
private fun WalletCardState.toLoadedState(): WalletCardState { private fun WalletCardState.toLoadedState(): WalletCardState {
selectedWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
return WalletCardState.Content( return WalletCardState.Content(
id = id, id = id,
title = title, title = title,
@ -68,7 +65,10 @@ internal class SetTokenListErrorTransformer(
balance = BigDecimal.ZERO.format { balance = BigDecimal.ZERO.format {
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
}, },
cardCount = selectedWallet.getCardsCount(), cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isZeroBalance = true, isZeroBalance = true,
isBalanceFlickering = false, isBalanceFlickering = false,
) )

View file

@ -13,7 +13,6 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.visa.exception.RefreshTokenExpiredException import com.tangem.domain.visa.exception.RefreshTokenExpiredException
import com.tangem.domain.visa.model.VisaCurrency import com.tangem.domain.visa.model.VisaCurrency
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState import com.tangem.feature.wallet.presentation.wallet.state.model.BalancesAndLimitsBlockState
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo import com.tangem.feature.wallet.presentation.wallet.state.model.WalletAdditionalInfo
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
@ -27,7 +26,7 @@ import org.joda.time.DateTime
import org.joda.time.Days import org.joda.time.Days
internal class SetVisaInfoTransformer( internal class SetVisaInfoTransformer(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val maybeVisaCurrency: Either<Throwable, VisaCurrency>, private val maybeVisaCurrency: Either<Throwable, VisaCurrency>,
private val clickIntents: WalletClickIntents, private val clickIntents: WalletClickIntents,
) : TypedWalletStateTransformer<WalletState.Visa.Content>( ) : TypedWalletStateTransformer<WalletState.Visa.Content>(
@ -76,8 +75,6 @@ internal class SetVisaInfoTransformer(
} }
private fun getContentWalletCardState(prevState: WalletCardState, visaCurrency: VisaCurrency): WalletCardState { private fun getContentWalletCardState(prevState: WalletCardState, visaCurrency: VisaCurrency): WalletCardState {
userWallet.requireColdWallet() // TODO [REDACTED_TASK_KEY]
return with(prevState) { return with(prevState) {
WalletCardState.Content( WalletCardState.Content(
id = id, id = id,

View file

@ -7,7 +7,6 @@ import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.models.StatusSource import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.TotalFiatBalance import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
@ -48,8 +47,6 @@ internal class MultiWalletCardStateConverter(
} }
private fun WalletCardState.toWalletCardState(fiatBalance: TotalFiatBalance.Loaded): WalletCardState { private fun WalletCardState.toWalletCardState(fiatBalance: TotalFiatBalance.Loaded): WalletCardState {
selectedWallet.requireColdWallet()
return WalletCardState.Content( return WalletCardState.Content(
id = id, id = id,
title = title, title = title,
@ -60,7 +57,10 @@ internal class MultiWalletCardStateConverter(
fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol) fiat(fiatCurrencyCode = appCurrency.code, fiatCurrencySymbol = appCurrency.symbol)
}, },
isZeroBalance = fiatBalance.amount.isZero(), isZeroBalance = fiatBalance.amount.isZero(),
cardCount = selectedWallet.getCardsCount(), cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isBalanceFlickering = fiatBalance.source == StatusSource.CACHE, isBalanceFlickering = fiatBalance.source == StatusSource.CACHE,
) )
} }

View file

@ -7,7 +7,6 @@ import com.tangem.domain.common.util.getCardsCount
import com.tangem.domain.models.StatusSource import com.tangem.domain.models.StatusSource
import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory import com.tangem.feature.wallet.presentation.wallet.domain.WalletAdditionalInfoFactory
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletCardState
import com.tangem.utils.StringsSigns.DASH_SIGN import com.tangem.utils.StringsSigns.DASH_SIGN
@ -64,7 +63,10 @@ internal class SingleWalletCardStateConverter(
imageResId = imageResId, imageResId = imageResId,
dropDownItems = dropDownItems, dropDownItems = dropDownItems,
balance = formatFiatAmount(status = status, appCurrency = appCurrency), balance = formatFiatAmount(status = status, appCurrency = appCurrency),
cardCount = selectedWallet.requireColdWallet().getCardsCount(), // TODO [REDACTED_TASK_KEY] cardCount = when (selectedWallet) {
is UserWallet.Cold -> selectedWallet.getCardsCount()
is UserWallet.Hot -> null
},
isZeroBalance = status.fiatAmount?.isZero(), isZeroBalance = status.fiatAmount?.isZero(),
isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.sources?.total == StatusSource.CACHE, isBalanceFlickering = (status as? CryptoCurrencyStatus.Loaded)?.sources?.total == StatusSource.CACHE,
) )

View file

@ -4,14 +4,17 @@ import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState import com.tangem.feature.wallet.presentation.wallet.state.model.WalletState
internal inline fun UserWallet.Cold.createStateByWalletType( internal inline fun UserWallet.createStateByWalletType(
multiCurrencyCreator: () -> WalletState.MultiCurrency, multiCurrencyCreator: () -> WalletState.MultiCurrency,
singleCurrencyCreator: () -> WalletState.SingleCurrency, singleCurrencyCreator: () -> WalletState.SingleCurrency,
visaWalletCreator: () -> WalletState.Visa, visaWalletCreator: () -> WalletState.Visa,
): WalletState = when { ): WalletState = when (this) {
isVisaWallet() -> visaWalletCreator() is UserWallet.Cold -> when {
isWalletWithTokens() -> multiCurrencyCreator() isVisaWallet() -> visaWalletCreator()
else -> singleCurrencyCreator() isWalletWithTokens() -> multiCurrencyCreator()
else -> singleCurrencyCreator()
}
is UserWallet.Hot -> multiCurrencyCreator()
} }
private fun UserWallet.Cold.isWalletWithTokens(): Boolean { private fun UserWallet.Cold.isWalletWithTokens(): Boolean {

View file

@ -16,7 +16,7 @@ import kotlinx.coroutines.CoroutineScope
@Suppress("LongParameterList") @Suppress("LongParameterList")
internal class SingleWalletWithTokenListSubscriber( internal class SingleWalletWithTokenListSubscriber(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val tokenListStore: MultiWalletTokenListStore, private val tokenListStore: MultiWalletTokenListStore,
stateHolder: WalletStateController, stateHolder: WalletStateController,
clickIntents: WalletClickIntents, clickIntents: WalletClickIntents,

View file

@ -13,7 +13,6 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsCountUseCase
import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase import com.tangem.domain.txhistory.usecase.GetTxHistoryItemsUseCase
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest import com.tangem.feature.wallet.presentation.wallet.domain.collectLatest
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
@ -32,7 +31,7 @@ typealias MaybeTxHistoryItems = Either<TxHistoryListError, Flow<PagingData<TxInf
@Suppress("LongParameterList") @Suppress("LongParameterList")
internal class TxHistorySubscriber( internal class TxHistorySubscriber(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val isRefresh: Boolean, private val isRefresh: Boolean,
private val stateHolder: WalletStateController, private val stateHolder: WalletStateController,
private val clickIntents: WalletClickIntents, private val clickIntents: WalletClickIntents,
@ -97,7 +96,7 @@ internal class TxHistorySubscriber(
) )
}, },
ifRight = { itemsFlow -> ifRight = { itemsFlow ->
val blockchain = userWallet.requireColdWallet().scanResponse.cardTypesResolver.getBlockchain() val blockchain = userWallet.scanResponse.cardTypesResolver.getBlockchain()
val itemConverter = TxHistoryItemStateConverter( val itemConverter = TxHistoryItemStateConverter(
symbol = blockchain.currency, symbol = blockchain.currency,
decimals = blockchain.decimals(), decimals = blockchain.decimals(),

View file

@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.map
import timber.log.Timber import timber.log.Timber
internal class VisaWalletSubscriber( internal class VisaWalletSubscriber(
private val userWallet: UserWallet, private val userWallet: UserWallet.Cold,
private val stateController: WalletStateController, private val stateController: WalletStateController,
private val isRefresh: Boolean, private val isRefresh: Boolean,
private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase, private val getVisaCurrencyUseCase: GetVisaCurrencyUseCase,

View file

@ -22,7 +22,6 @@ import com.tangem.domain.tokens.model.TotalFiatBalance
import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.models.isMultiCurrency import com.tangem.domain.wallets.models.isMultiCurrency
import com.tangem.domain.wallets.models.requireColdWallet
import com.tangem.domain.wallets.usecase.GetCardImageUseCase import com.tangem.domain.wallets.usecase.GetCardImageUseCase
import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase
import com.tangem.feature.wallet.impl.R import com.tangem.feature.wallet.impl.R
@ -88,8 +87,7 @@ internal class DefaultUserWalletsFetcher @AssistedInject constructor(
private fun loadArtworks(wallets: List<UserWallet>): Flow<HashMap<UserWalletId, ArtworkModel>> { private fun loadArtworks(wallets: List<UserWallet>): Flow<HashMap<UserWalletId, ArtworkModel>> {
return flow { return flow {
emit(hashMapOf()) // emits right away so the transform doesn't wait for the images' loading to finish emit(hashMapOf()) // emits right away so the transform doesn't wait for the images' loading to finish
wallets.forEach { wallet -> wallets.filterIsInstance<UserWallet.Cold>().forEach { wallet ->
wallet.requireColdWallet()
val artwork = getCardImageUseCase( val artwork = getCardImageUseCase(
cardId = wallet.cardId, cardId = wallet.cardId,
manufacturerName = wallet.scanResponse.card.manufacturer.name, manufacturerName = wallet.scanResponse.card.manufacturer.name,