Updated on 2026-08-14

This commit is contained in:
Tangem 2022-11-12 03:46:02 +04:00
parent 4375e7687f
commit 0d993b5141
53 changed files with 430 additions and 356 deletions

View file

@ -74,7 +74,7 @@ object TangemSdk {
is TangemSdkError.UnsupportedWalletConfig -> TangemSdkError.UnsupportedWalletConfig()
is TangemSdkError.CryptoUtilsError -> TangemSdkError.CryptoUtilsError(error.customMessage)
is TangemSdkError.NetworkError -> TangemSdkError.NetworkError(error.customMessage)
is TangemSdkError.ExceptionError -> TangemSdkError.ExceptionError(error.throwable)
is TangemSdkError.ExceptionError -> TangemSdkError.ExceptionError(error.cause)
is TangemSdkError.TooMuchBackupCards -> TangemSdkError.TooMuchBackupCards()
is TangemSdkError.BackupCardRequired -> TangemSdkError.BackupCardRequired()
is TangemSdkError.CertificateSignatureRequired -> TangemSdkError.CertificateSignatureRequired()
@ -107,6 +107,8 @@ object TangemSdk {
is TangemSdkError.BackupFailedFirmware -> TangemSdkError.BackupFailedFirmware()
is TangemSdkError.UserForgotTheCode -> TangemSdkError.UserForgotTheCode()
is TangemSdkError.BackupFailedIncompatibleBatch -> TangemSdkError.BackupFailedIncompatibleBatch()
is TangemSdkError.BiometricsUnavailable -> error
is TangemSdkError.BiometricsAuthenticationFailed -> error
}
}

View file

@ -3,10 +3,10 @@ package com.tangem.tap.common.analytics.converters
import com.tangem.common.Converter
import com.tangem.common.extensions.isZero
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.util.userWalletId
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.common.analytics.filters.BasicTopUpFilter
import com.tangem.tap.domain.extensions.getUserWalletId
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.features.wallet.redux.ProgressState
import com.tangem.tap.features.wallet.redux.WalletData
@ -29,7 +29,7 @@ class BasicSignInEventConverter(
currency = cardCurrency,
batch = scanResponse.card.batchId,
).apply {
filterData = scanResponse.card.getUserWalletId()
filterData = scanResponse.card.userWalletId.stringValue
}
}
}
@ -43,7 +43,7 @@ class BasicTopUpEventConverter(
val cardCurrency = ParamCardCurrencyConverter().convert(scanResponse) ?: return null
val data = BasicTopUpFilter.Data(
walletId = scanResponse.card.getUserWalletId(),
walletId = scanResponse.card.userWalletId.stringValue,
cardBalanceState = AnalyticsParam.CardBalanceState.from(value.walletsData),
)

View file

@ -8,7 +8,7 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.Address
import com.tangem.common.card.CardWallet
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.extensions.stripZeroPlainString
import com.tangem.tap.domain.extensions.getUserWalletId
@ -92,7 +92,7 @@ class AdditionalFeedbackInfo {
)
}
private fun formatSignedHashes(wallets: List<CardWallet>): String {
private fun formatSignedHashes(wallets: List<CardDTO.Wallet>): String {
return wallets.joinToString("\n") { "Signed hashes: ${it.curve.curve} - ${it.totalSignedHashes}" }
}

View file

@ -2,6 +2,7 @@ package com.tangem.tap.common.redux.global
import com.tangem.domain.redux.domainStore
import com.tangem.domain.redux.global.DomainGlobalAction
import com.tangem.tap.common.extensions.replaceBy
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.features.onboarding.OnboardingManager
import com.tangem.tap.preferencesStorage
@ -49,12 +50,19 @@ fun globalReducer(action: Action, state: AppState, appStateHolder: AppStateHolde
is GlobalAction.SetWarningManager -> globalState.copy(warningManager = action.warningManager)
is GlobalAction.UpdateWalletSignedHashes -> {
val card = globalState.scanResponse?.card ?: return globalState
val wallet = card.wallet(action.walletPublicKey) ?: return globalState
val newCardInstance = card.updateWallet(
wallet.copy(
totalSignedHashes = action.walletSignedHashes,
remainingSignatures = action.remainingSignatures,
),
val wallet = card.wallets
.firstOrNull { it.publicKey.contentEquals(action.walletPublicKey) }
?: return globalState
val newCardInstance = card.copy(
wallets = card.wallets.toMutableList().also { walletsMutable ->
walletsMutable.replaceBy(
item = wallet.copy(
totalSignedHashes = action.walletSignedHashes,
remainingSignatures = action.remainingSignatures,
),
) { it.index == wallet.index }
},
)
globalState.copy(scanResponse = globalState.scanResponse.copy(card = newCardInstance))
}

View file

@ -1,7 +1,5 @@
package com.tangem.tap.domain
import CreateProductWalletTask
import CreateProductWalletTaskResponse
import android.content.Context
import androidx.annotation.StringRes
import com.tangem.Message
@ -10,7 +8,6 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CardFilter
import com.tangem.common.CompletionResult
import com.tangem.common.SuccessResponse
import com.tangem.common.card.Card
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.CardIdDisplayFormat
import com.tangem.common.core.CardSessionRunnable
@ -18,6 +15,8 @@ import com.tangem.common.core.Config
import com.tangem.common.core.TangemSdkError
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.map
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.operations.CommandResponse
import com.tangem.operations.ScanTask
@ -29,6 +28,8 @@ import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.Basic
import com.tangem.tap.domain.tasks.CreateWalletAndRescanTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.tap.domain.tokens.UserTokensRepository
@ -73,12 +74,13 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
}
}
suspend fun createWallet(cardId: String?): CompletionResult<Card> {
suspend fun createWallet(cardId: String?): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
CreateWalletAndRescanTask(),
cardId,
initialMessage = Message(context.getString(R.string.initial_message_create_wallet_body)),
)
.map { CardDTO(it) }
}
suspend fun derivePublicKeys(
@ -88,12 +90,13 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
}
suspend fun resetToFactorySettings(card: Card): CompletionResult<Card> {
suspend fun resetToFactorySettings(cardId: String): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
ResetToFactorySettingsTask(),
card.cardId,
runnable = ResetToFactorySettingsTask(),
cardId = cardId,
initialMessage = Message(context.getString(R.string.card_settings_reset_card_to_factory)),
)
.map { CardDTO(it) }
}
suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse> {
@ -128,11 +131,12 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
)
}
suspend fun scanCard(): CompletionResult<Card> {
suspend fun scanCard(): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
ScanTask(),
runnable = ScanTask(),
initialMessage = Message(context.getString(R.string.initial_message_tap_header)),
)
.map { CardDTO(it) }
}
suspend fun <T : CommandResponse> runTaskAsync(
@ -150,7 +154,9 @@ class TangemSdkManager(private val tangemSdk: TangemSdk, private val context: Co
}
private suspend fun <T : CommandResponse> runTaskAsyncReturnOnMain(
runnable: CardSessionRunnable<T>, cardId: String? = null, initialMessage: Message? = null,
runnable: CardSessionRunnable<T>,
cardId: String? = null,
initialMessage: Message? = null,
): CompletionResult<T> {
val result = runTaskAsync(runnable, cardId, initialMessage)
return withContext(Dispatchers.Main) { result }

View file

@ -5,13 +5,13 @@ import com.tangem.TangemSdk
import com.tangem.blockchain.common.TransactionSigner
import com.tangem.blockchain.common.Wallet
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.tap.domain.tasks.SignHashesTask
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class TangemSigner(
private val card: Card,
private val card: CardDTO,
private val tangemSdk: TangemSdk,
private val initialMessage: Message,
private val accessCode: String? = null,

View file

@ -64,8 +64,7 @@ sealed class TapError(
) : TapError(-1), MultiMessageError
}
sealed class TapSdkError(override val messageResId: Int?) : Throwable(), TangemError {
final override val code: Int = 50100
sealed class TapSdkError(override val messageResId: Int?) : TangemError(code = 50100) {
override var customMessage: String = code.toString()
object CardForDifferentApp : TapSdkError(R.string.alert_unsupported_card)
@ -88,4 +87,4 @@ fun TangemTechError.toTapError(): TapError {
}
}
class NoDataError(message: String) : TapError.CustomError(customMessage = message)
class NoDataError(message: String) : TapError.CustomError(customMessage = message)

View file

@ -6,8 +6,8 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.Card
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTestCard
@ -96,7 +96,7 @@ class TapWalletManager {
store.dispatch(
WalletAction.MultiWallet.ShowWalletBackupWarning(
show = data.card.settings.isBackupAllowed
&& data.card.backupStatus == Card.BackupStatus.NoBackup,
&& data.card.backupStatus == CardDTO.BackupStatus.NoBackup,
),
)
loadData(data)

View file

@ -1,58 +1,45 @@
package com.tangem.tap.domain.extensions
import com.tangem.common.card.Card
import com.tangem.common.card.CardWallet
import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.extensions.calculateSha256
import com.tangem.common.extensions.toHexString
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemNote
import com.tangem.domain.common.TwinCardNumber
import com.tangem.domain.common.extensions.calculateHmacSha256
import com.tangem.domain.common.getTwinCardNumber
import com.tangem.domain.common.isTangemTwin
import com.tangem.operations.attestation.CardVerifyAndGetInfo
import com.tangem.operations.attestation.OnlineCardVerifier
import com.tangem.tap.features.wallet.redux.Artwork
val Card.remainingSignatures: Int?
get() = this.getSingleWallet()?.remainingSignatures
val CardDTO.remainingSignatures: Int?
get() = this.wallets.firstOrNull()?.remainingSignatures
val Card.isWalletDataSupported: Boolean
val CardDTO.isWalletDataSupported: Boolean
get() = this.firmwareVersion.major >= 4
val Card.isMultiwalletAllowed: Boolean
val CardDTO.isMultiwalletAllowed: Boolean
get() {
return !isTangemTwin() && !isStart2Coin && !isTangemNote && !isSaltPay
&& (firmwareVersion >= FirmwareVersion.MultiWalletAvailable ||
getSingleWallet()?.curve == EllipticCurve.Secp256k1)
return !isTangemTwin() && !isStart2Coin && !isTangemNote && !isSaltPay &&
(firmwareVersion >= FirmwareVersion.MultiWalletAvailable ||
wallets.firstOrNull()?.curve == EllipticCurve.Secp256k1)
}
val Card.isHdWalletAllowedByApp: Boolean
val CardDTO.isHdWalletAllowedByApp: Boolean
get() = settings.isHDWalletAllowed && !isSaltPay
fun Card.getSingleWallet(): CardWallet? {
return wallets.firstOrNull()
fun CardDTO.hasSignedHashes(): Boolean {
return wallets.any { (it.totalSignedHashes ?: 0) > 0 }
}
fun Card.hasWallets(): Boolean = wallets.isNotEmpty()
fun Card.hasNoWallets(): Boolean = wallets.isEmpty()
fun Card.hasSingleWallet(): Boolean = wallets.size == 1
fun Card.hasSignedHashes(): Boolean {
return wallets.any { it.totalSignedHashes ?: 0 > 0 }
fun CardDTO.signedHashesCount(): Int {
return wallets.sumOf { it.totalSignedHashes ?: 0 }
}
fun Card.signedHashesCount(): Int {
return wallets.map { it.totalSignedHashes ?: 0 }.sum()
}
suspend fun Card.getOrLoadCardArtworkUrl(cardInfo: Result<CardVerifyAndGetInfo.Response.Item>? = null): String {
suspend fun CardDTO.getOrLoadCardArtworkUrl(cardInfo: Result<CardVerifyAndGetInfo.Response.Item>? = null): String {
fun ifAnyError(): String {
return when {
cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL
@ -67,42 +54,28 @@ suspend fun Card.getOrLoadCardArtworkUrl(cardInfo: Result<CardVerifyAndGetInfo.R
}
}
val cardInfoResult = cardInfo ?: OnlineCardVerifier().getCardInfo(cardId, cardPublicKey)
return when (cardInfoResult) {
return when (val cardInfoResult = cardInfo ?: OnlineCardVerifier().getCardInfo(cardId, cardPublicKey)) {
is Result.Success -> {
val artworkId = cardInfoResult.data.artwork?.id
if (artworkId == null || artworkId.isEmpty()) {
if (artworkId.isNullOrEmpty()) {
ifAnyError()
} else {
OnlineCardVerifier.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
}
}
is Result.Failure -> ifAnyError()
}
}
fun Card.getArtworkUrl(artworkId: String?): String? {
fun CardDTO.getArtworkUrl(artworkId: String?): String? {
return when {
artworkId != null -> {
OnlineCardVerifier.getUrlForArtwork(cardId, cardPublicKey.toHexString(), artworkId)
}
cardId.startsWith(Artwork.SERGIO_CARD_ID) -> Artwork.SERGIO_CARD_URL
cardId.startsWith(Artwork.MARTA_CARD_ID) -> Artwork.MARTA_CARD_URL
else -> null
}
}
fun Card.getUserWalletId(): String {
val walletPublicKey = this.wallets.firstOrNull()?.publicKey ?: return ""
return UserWalletId(walletPublicKey).stringValue
}
class UserWalletId(val walletPublicKey: ByteArray) {
val stringValue: String = calculateUserId(walletPublicKey)
private fun calculateUserId(walletPublicKey: ByteArray): String {
val message = "UserWalletID".toByteArray()
val keyHash = walletPublicKey.calculateSha256()
return message.calculateHmacSha256(keyHash).toHexString()
}
}

View file

@ -7,13 +7,12 @@ import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.Card
import com.tangem.common.card.CardWallet
import com.tangem.common.card.EllipticCurve
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.SaltPayWorkaround
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isTestCard
@ -82,7 +81,7 @@ fun WalletManagerFactory.makeWalletManagerForApp(
)
}
private fun getDerivationParams(derivationPath: String?, card: Card): DerivationParams? {
private fun getDerivationParams(derivationPath: String?, card: CardDTO): DerivationParams? {
return derivationPath?.let {
DerivationParams.Custom(
DerivationPath(it),
@ -132,7 +131,7 @@ fun WalletManagerFactory.makePrimaryWalletManager(
)
}
private fun selectWallet(wallets: List<CardWallet>): CardWallet? {
private fun selectWallet(wallets: List<CardDTO.Wallet>): CardDTO.Wallet? {
return when (wallets.size) {
0 -> null
1 -> wallets[0]

View file

@ -1,3 +1,5 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
@ -9,6 +11,8 @@ import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.common.map
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.KeyWalletPublicKey
import com.tangem.domain.common.ProductType
import com.tangem.domain.common.TapWorkarounds.derivationStyle
@ -19,19 +23,37 @@ import com.tangem.operations.backup.PrimaryCard
import com.tangem.operations.backup.StartPrimaryCardLinkingTask
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.derivation.ExtendedPublicKeysMap
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.tap.domain.tasks.product.CreateWalletsTask
import com.tangem.tap.domain.tasks.product.ProductCommandProcessor
import com.tangem.tap.domain.tasks.product.getCurvesForNonCreatedWallets
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.operations.wallet.CreateWalletResponse as SdkCreateWalletResponse
data class CreateProductWalletTaskResponse(
val card: Card,
val card: CardDTO,
val derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap> = mapOf(),
val primaryCard: PrimaryCard? = null
) : CommandResponse
val primaryCard: PrimaryCard? = null,
) : CommandResponse {
constructor(
card: Card,
derivedKeys: Map<KeyWalletPublicKey, ExtendedPublicKeysMap> = mapOf(),
primaryCard: PrimaryCard? = null,
) : this(
card = CardDTO(card),
derivedKeys = derivedKeys,
primaryCard = primaryCard,
)
}
private data class CreateWalletResponse(
val cardId: String,
val wallet: CardDTO.Wallet,
) {
constructor(
sdkResponse: SdkCreateWalletResponse,
) : this(
cardId = sdkResponse.cardId,
wallet = CardDTO.Wallet(sdkResponse.wallet),
)
}
class CreateProductWalletTask(
private val type: ProductType,
@ -39,29 +61,32 @@ class CreateProductWalletTask(
override fun run(
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val card = session.environment.card.guard {
callback(CompletionResult.Failure(TangemSdkError.CardError()))
return
}
val cardDto = CardDTO(card)
val commandProcessor = when (type) {
ProductType.Note -> CreateWalletTangemNote()
ProductType.Twins -> throw UnsupportedOperationException("Use the TwinCardsManager to create a wallet")
else -> CreateWalletTangemWallet()
}
commandProcessor.proceed(card, session) {
commandProcessor.proceed(cardDto, session) {
when (it) {
is CompletionResult.Success -> {
val result = when (commandProcessor) {
is CreateWalletTangemWallet -> {
it.data as CreateProductWalletTaskResponse
}
else -> CreateProductWalletTaskResponse(card = session.environment.card!!)
}
callback(CompletionResult.Success(result))
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(it.error))
}
}
@ -70,7 +95,7 @@ class CreateProductWalletTask(
private class CreateWalletTangemNote : ProductCommandProcessor<CreateWalletResponse> {
override fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit,
) {
@ -94,52 +119,65 @@ private class CreateWalletTangemNote : ProductCommandProcessor<CreateWalletRespo
} else {
intersectCurves[0]
}
CreateWalletTask(curve).run(session, callback)
CreateWalletTask(curve).run(session) { result ->
callback(result.map { CreateWalletResponse(it) })
}
}
}
}
private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWalletTaskResponse> {
private lateinit var card: Card
private var primaryCard: PrimaryCard? = null
override fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
this.card = card
val curves = card.getCurvesForNonCreatedWallets()
if (curves.isEmpty()) {
val createWalletResponses = card.wallets.map { CreateWalletResponse(card.cardId, it) }
proceedWithCreatedWallets(createWalletResponses, session, callback)
val createWalletResponses = card.wallets.map { wallet ->
CreateWalletResponse(card.cardId, wallet)
}
proceedWithCreatedWallets(card, createWalletResponses, session, callback)
return
}
CreateWalletsTask(curves).run(session) { result ->
when (result) {
is CompletionResult.Success -> {
proceedWithCreatedWallets(result.data.createWalletResponses, session, callback)
proceedWithCreatedWallets(
card = card,
createWalletResponses = result.data.createWalletResponses.map { CreateWalletResponse(it) },
session = session,
callback = callback,
)
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
private fun proceedWithCreatedWallets(
card: CardDTO,
createWalletResponses: List<CreateWalletResponse>,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
when {
card.settings.isBackupAllowed -> {
linkPrimaryCard(createWalletResponses, session, callback)
linkPrimaryCard(card, createWalletResponses, session, callback)
}
card.settings.isHDWalletAllowed -> {
deriveKeys(createWalletResponses, session, callback)
deriveKeys(card, createWalletResponses, session, callback)
}
else -> {
callback(
CompletionResult.Success(
@ -151,6 +189,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
}
private fun linkPrimaryCard(
card: CardDTO,
createWalletResponse: List<CreateWalletResponse>,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
@ -161,8 +200,9 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
primaryCard = result.data
when {
card.settings.isHDWalletAllowed -> {
deriveKeys(createWalletResponse, session, callback)
deriveKeys(card, createWalletResponse, session, callback)
}
else -> {
callback(
CompletionResult.Success(
@ -174,6 +214,7 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
}
}
}
is CompletionResult.Failure -> {
callback(CompletionResult.Failure(result.error))
}
@ -182,13 +223,14 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
}
private fun deriveKeys(
card: CardDTO,
createWalletResponse: List<CreateWalletResponse>,
session: CardSession,
callback: (result: CompletionResult<CreateProductWalletTaskResponse>) -> Unit,
) {
val map = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
createWalletResponse.forEach { response ->
val blockchainsForCurve = getBlockchains(response.cardId).filter {
val blockchainsForCurve = getBlockchains(response.cardId, card).filter {
it.getSupportedCurves().contains(response.wallet.curve)
}
val derivationPaths = blockchainsForCurve.mapNotNull { it.derivationPath(card.derivationStyle) }
@ -210,17 +252,21 @@ private class CreateWalletTangemWallet : ProductCommandProcessor<CreateProductWa
CreateProductWalletTaskResponse(
card = session.environment.card!!,
derivedKeys = result.data.entries,
primaryCard = primaryCard
)
)
primaryCard = primaryCard,
),
),
)
}
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
}
}
private fun getBlockchains(cardId: String): List<Blockchain> {
private fun getBlockchains(
cardId: String,
card: CardDTO,
): List<Blockchain> {
return when {
DemoHelper.isDemoCardId(cardId) -> DemoHelper.config.demoBlockchains
card.isTestCard -> listOf(Blockchain.BitcoinTestnet, Blockchain.EthereumTestnet)

View file

@ -1,15 +1,15 @@
package com.tangem.tap.domain.tasks.product
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.core.CardSession
import com.tangem.domain.common.CardDTO
/**
[REDACTED_AUTHOR]
*/
interface ProductCommandProcessor<T> {
fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<T>) -> Unit,
)

View file

@ -13,6 +13,7 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.toHexString
import com.tangem.common.extensions.toMapKey
import com.tangem.common.hdWallet.DerivationPath
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ProductType
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isExcluded
@ -31,7 +32,6 @@ import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.tap.domain.TapSdkError
import com.tangem.tap.domain.extensions.getPrimaryCurve
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.domain.tokens.UserTokensRepository
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
@ -53,19 +53,20 @@ class ScanProductTask(
callback(CompletionResult.Failure(TangemSdkError.MissingPreflightRead()))
return
}
val cardDto = CardDTO(card)
val error = getErrorIfExcludedCard(card)
val error = getErrorIfExcludedCard(cardDto)
if (error != null) {
callback(CompletionResult.Failure(error))
return
}
val commandProcessor = when {
card.isTangemNote -> ScanNoteProcessor()
card.isTangemTwins -> ScanTwinProcessor()
cardDto.isTangemNote -> ScanNoteProcessor()
cardDto.isTangemTwins -> ScanTwinProcessor()
else -> ScanWalletProcessor(userTokensRepository, additionalBlockchainsToDerive)
}
commandProcessor.proceed(card, session) { processorResult ->
commandProcessor.proceed(cardDto, session) { processorResult ->
when (processorResult) {
is CompletionResult.Success -> ScanTask().run(session) { scanTaskResult ->
when (scanTaskResult) {
@ -73,7 +74,7 @@ class ScanProductTask(
// it need because processorResult.data.card doesn't contains attestation result
// and CardWallet.derivedKeys
val processorScanResponseWithNewCard = processorResult.data.copy(
card = scanTaskResult.data,
card = CardDTO(scanTaskResult.data),
)
callback(CompletionResult.Success(processorScanResponseWithNewCard))
}
@ -85,7 +86,7 @@ class ScanProductTask(
}
}
private fun getErrorIfExcludedCard(card: Card): TangemError? {
private fun getErrorIfExcludedCard(card: CardDTO): TangemError? {
if (card.isExcluded) return TapSdkError.CardForDifferentApp
if (card.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease
return null
@ -94,7 +95,7 @@ class ScanProductTask(
private class ScanNoteProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
@ -117,7 +118,7 @@ private class ScanWalletProcessor(
var primaryCard: PrimaryCard? = null
override fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
@ -125,7 +126,7 @@ private class ScanWalletProcessor(
}
private fun createMissingWalletsIfNeeded(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
@ -159,13 +160,13 @@ private class ScanWalletProcessor(
}
private fun startLinkingForBackupIfNeeded(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
val activationInProgress = preferencesStorage.usedCardsPrefStorage.isActivationInProgress(card.cardId)
if ((card.backupStatus == Card.BackupStatus.NoBackup && card.wallets.isNotEmpty())
if ((card.backupStatus == CardDTO.BackupStatus.NoBackup && card.wallets.isNotEmpty())
&& (activationInProgress || card.isSaltPay)
) {
StartPrimaryCardLinkingTask().run(session) { linkingResult ->
@ -185,7 +186,7 @@ private class ScanWalletProcessor(
}
private fun deriveKeysIfNeeded(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
@ -227,25 +228,46 @@ private class ScanWalletProcessor(
}
}
private suspend fun getBlockchainsToDerive(card: Card): List<BlockchainNetwork> {
private suspend fun getBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> {
val userTokensRepository = userTokensRepository ?: return emptyList()
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card).toMutableList().ifEmpty {
mutableListOf(
BlockchainNetwork(Blockchain.Bitcoin, card),
BlockchainNetwork(Blockchain.Ethereum, card),
)
}
val blockchainsToDerive = userTokensRepository.loadBlockchainsToDerive(card)
.toMutableList()
.ifEmpty {
mutableListOf(
BlockchainNetwork(
blockchain = Blockchain.Bitcoin,
card = card,
),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
card = card,
),
)
}
if (card.settings.isHDWalletAllowed) {
blockchainsToDerive.addAll(
listOf(
BlockchainNetwork(Blockchain.Ethereum, card),
BlockchainNetwork(Blockchain.EthereumTestnet, card),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
card = card,
),
BlockchainNetwork(
blockchain = Blockchain.EthereumTestnet,
card = card,
),
),
)
}
if (additionalBlockchainsToDerive != null) {
blockchainsToDerive.addAll(additionalBlockchainsToDerive.map { BlockchainNetwork(it, card) })
blockchainsToDerive.addAll(
additionalBlockchainsToDerive.map {
BlockchainNetwork(
blockchain = it,
card = card,
)
},
)
}
if (!card.useOldStyleDerivation) {
blockchainsToDerive.removeAll(
@ -255,13 +277,18 @@ private class ScanWalletProcessor(
Blockchain.RSK,
Blockchain.Fantom, Blockchain.FantomTestnet,
Blockchain.Avalanche, Blockchain.AvalancheTestnet,
).map { BlockchainNetwork(it, card) },
).map {
BlockchainNetwork(
blockchain = it,
card = card,
)
},
)
}
return blockchainsToDerive.distinct()
}
private suspend fun collectDerivations(card: Card): Map<ByteArrayKey, List<DerivationPath>> {
private suspend fun collectDerivations(card: CardDTO): Map<ByteArrayKey, List<DerivationPath>> {
val blockchains = getBlockchainsToDerive(card)
val derivations = mutableMapOf<ByteArrayKey, List<DerivationPath>>()
@ -287,14 +314,14 @@ private class ScanWalletProcessor(
private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
override fun proceed(
card: Card,
card: CardDTO,
session: CardSession,
callback: (result: CompletionResult<ScanResponse>) -> Unit,
) {
ReadIssuerDataCommand().run(session) { readDataResult ->
when (readDataResult) {
is CompletionResult.Success -> {
val publicKey = card.getSingleWallet()?.publicKey
val publicKey = card.wallets.firstOrNull()?.publicKey
if (publicKey == null) {
val response = ScanResponse(
card = card,
@ -332,7 +359,7 @@ private class ScanTwinProcessor : ProductCommandProcessor<ScanResponse> {
}
}
fun Card.getCurvesForNonCreatedWallets(): List<EllipticCurve> {
fun CardDTO.getCurvesForNonCreatedWallets(): List<EllipticCurve> {
val curvesPresent = wallets.map { it.curve }.toSet()
val curvesForNonCreatedWallets = supportedCurves.subtract(curvesPresent + EllipticCurve.Secp256r1)
return curvesForNonCreatedWallets.toList()

View file

@ -3,8 +3,8 @@ package com.tangem.tap.domain.termsOfUse
import android.content.res.Resources
import android.net.Uri
import androidx.core.os.ConfigurationCompat
import com.tangem.common.card.Card
import java.util.Locale
import com.tangem.domain.common.CardDTO
import java.util.*
/**
[REDACTED_AUTHOR]
@ -13,7 +13,7 @@ class CardTou {
private val locale: Locale =
ConfigurationCompat.getLocales(Resources.getSystem().configuration).get(0)!!
fun getUrl(card: Card): Uri? {
fun getUrl(card: CardDTO): Uri? {
val issuerName = card.issuer.name
if (issuerName.lowercase(Locale.getDefault()) != "start2coin") return null

View file

@ -2,10 +2,11 @@ package com.tangem.tap.domain.tokens
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.CardDTO
object CurrenciesRepository {
fun getBlockchains(
cardFirmware: FirmwareVersion,
cardFirmware: CardDTO.FirmwareVersion,
isTestNet: Boolean = false,
): List<Blockchain> {
val blockchains = if (cardFirmware < FirmwareVersion.MultiWalletAvailable) {
@ -26,6 +27,4 @@ object CurrenciesRepository {
)
}
}
}
}

View file

@ -2,13 +2,13 @@ package com.tangem.tap.domain.tokens
import android.content.Context
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.common.card.Card
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.util.userWalletId
import com.tangem.network.api.tangemTech.TangemTechService
import com.tangem.network.api.tangemTech.UserTokensResponse
import com.tangem.tap.common.AndroidFileReader
import com.tangem.tap.domain.NoDataError
import com.tangem.tap.domain.extensions.getUserWalletId
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.wallet.models.Currency
@ -23,8 +23,8 @@ class UserTokensRepository(
private val storageService: UserTokensStorageService,
private val networkService: UserTokensNetworkService,
) {
suspend fun getUserTokens(card: Card): List<Currency> {
val userId = card.getUserWalletId()
suspend fun getUserTokens(card: CardDTO): List<Currency> {
val userId = card.userWalletId.stringValue
if (DemoHelper.isDemoCardId(card.cardId)) {
return loadTokensOffline(card, userId).ifEmpty { loadDemoCurrencies() }
}
@ -36,25 +36,28 @@ class UserTokensRepository(
return when (val networkResult = networkService.getUserTokens(userId)) {
is Result.Success -> {
val tokens = networkResult.data.tokens.mapNotNull { Currency.fromTokenResponse(it) }
storageService.saveUserTokens(card.getUserWalletId(), tokens.toUserTokensResponse())
storageService.saveUserTokens(userId, tokens.toUserTokensResponse())
tokens.distinct()
}
is Result.Failure -> {
handleGetUserTokensFailure(card = card, userId = userId, error = networkResult.error)
}
}
}
suspend fun saveUserTokens(card: Card, tokens: List<Currency>) {
suspend fun saveUserTokens(card: CardDTO, tokens: List<Currency>) {
val userId = card.userWalletId.stringValue
val userTokens = tokens.toUserTokensResponse()
networkService.saveUserTokens(card.getUserWalletId(), userTokens)
storageService.saveUserTokens(card.getUserWalletId(), userTokens)
networkService.saveUserTokens(userId, userTokens)
storageService.saveUserTokens(userId, userTokens)
}
suspend fun removeUserTokens(card: Card) {
suspend fun removeUserTokens(card: CardDTO) {
val userId = card.userWalletId.stringValue
val userTokens = emptyList<Currency>().toUserTokensResponse()
networkService.saveUserTokens(card.getUserWalletId(), userTokens)
storageService.saveUserTokens(card.getUserWalletId(), userTokens)
networkService.saveUserTokens(userId, userTokens)
storageService.saveUserTokens(userId, userTokens)
}
private fun List<Currency>.toUserTokensResponse(): UserTokensResponse {
@ -66,8 +69,8 @@ class UserTokensRepository(
)
}
suspend fun loadBlockchainsToDerive(card: Card): List<BlockchainNetwork> {
val userId = card.getUserWalletId()
suspend fun loadBlockchainsToDerive(card: CardDTO): List<BlockchainNetwork> {
val userId = card.userWalletId.stringValue
val blockchainNetworks = loadTokensOffline(card, userId).toBlockchainNetworks()
if (DemoHelper.isDemoCardId(card.cardId)) {
@ -89,7 +92,7 @@ class UserTokensRepository(
}
private suspend fun handleGetUserTokensFailure(
card: Card,
card: CardDTO,
userId: String,
error: Throwable,
): List<Currency> {
@ -107,7 +110,7 @@ class UserTokensRepository(
}
}
private suspend fun loadTokensOffline(card: Card, userId: String): List<Currency> {
private suspend fun loadTokensOffline(card: CardDTO, userId: String): List<Currency> {
return storageService.getUserTokens(userId) ?: storageService.getUserTokens(card)
}

View file

@ -2,7 +2,7 @@ package com.tangem.tap.domain.tokens
import com.squareup.moshi.JsonAdapter
import com.tangem.Log
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.network.api.tangemTech.UserTokensResponse
import com.tangem.network.common.MoshiConverter
import com.tangem.tap.common.FileReader
@ -28,7 +28,7 @@ class UserTokensStorageService(
}
@Deprecated("")
suspend fun getUserTokens(card: Card): List<Currency> {
suspend fun getUserTokens(card: CardDTO): List<Currency> {
val blockchainNetworks =
oldUserTokensRepository.loadSavedCurrencies(card.cardId, card.settings.isHDWalletAllowed)
return blockchainNetworks.flatMap { it.toCurrencies() }

View file

@ -4,8 +4,8 @@ import com.squareup.moshi.JsonClass
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.WalletManager
import com.tangem.common.card.Card
import com.tangem.common.extensions.calculateHashCode
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.derivationStyle
@JsonClass(generateAdapter = true)
@ -15,16 +15,18 @@ data class BlockchainNetwork(
val tokens: List<Token>
) {
constructor(blockchain: Blockchain, card: Card) : this(
constructor(
blockchain: Blockchain,
card: CardDTO,
) : this(
blockchain = blockchain,
derivationPath = if (card.settings.isHDWalletAllowed) blockchain.derivationPath(card.derivationStyle)?.rawPath else null,
tokens = emptyList()
tokens = emptyList(),
)
fun updateTokens(tokens: List<Token>): BlockchainNetwork {
return copy(
tokens = (this.tokens + tokens).distinct()
tokens = (this.tokens + tokens).distinct(),
)
}

View file

@ -9,7 +9,6 @@ import com.tangem.domain.common.TwinsHelper
import com.tangem.operations.wallet.CreateWalletResponse
import com.tangem.operations.wallet.CreateWalletTask
import com.tangem.operations.wallet.PurgeWalletCommand
import com.tangem.tap.domain.extensions.getSingleWallet
class CreateFirstTwinWalletTask : CardSessionRunnable<CreateWalletResponse> {
override fun run(

View file

@ -23,7 +23,7 @@ class CreateSecondTwinWalletTask(
override fun run(session: CardSession, callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
val card = session.environment.card
val publicKey = card?.getSingleWallet()?.publicKey
val publicKey = card?.wallets?.firstOrNull()?.publicKey
if (publicKey != null) {
if (TwinsHelper.getTwinCardNumber(card.cardId) == TwinCardNumber.First) {
callback(CompletionResult.Failure(WrongTwinCard(TwinCardNumber.Second)))
@ -63,4 +63,4 @@ class CreateSecondTwinWalletTask(
}
}
}
}
}

View file

@ -6,9 +6,9 @@ import com.tangem.Message
import com.tangem.blockchain.extensions.Result
import com.tangem.common.CompletionResult
import com.tangem.common.KeyPair
import com.tangem.common.card.Card
import com.tangem.common.extensions.hexToBytes
import com.tangem.common.extensions.toHexString
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.network.common.MoshiConverter
import com.tangem.operations.wallet.CreateWalletResponse
@ -16,7 +16,7 @@ import com.tangem.tap.common.AssetReader
import com.tangem.tap.tangemSdkManager
class TwinCardsManager(
card: Card,
card: CardDTO,
assetReader: AssetReader,
) {
@ -91,7 +91,6 @@ class TwinCardsManager(
}
private class Issuer(
val id: String,
val privateKey: String,
val publicKey: String,
)

View file

@ -13,7 +13,6 @@ import com.tangem.operations.issuerAndUserData.ReadIssuerDataCommand
import com.tangem.operations.issuerAndUserData.ReadIssuerDataResponse
import com.tangem.operations.issuerAndUserData.WriteIssuerDataCommand
import com.tangem.operations.sign.SignHashCommand
import com.tangem.tap.domain.extensions.getSingleWallet
class WriteProtectedIssuerDataTask(
private val twinPublicKey: ByteArray, private val issuerKeys: KeyPair,
@ -25,7 +24,7 @@ class WriteProtectedIssuerDataTask(
) {
SignHashCommand(
twinPublicKey.calculateSha256(),
session.environment.card!!.getSingleWallet()!!.publicKey
session.environment.card!!.wallets.first().publicKey,
)
.run(session) { signResult ->
when (signResult) {

View file

@ -1,10 +1,10 @@
package com.tangem.tap.features.demo
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
/**
[REDACTED_AUTHOR]
*/
fun ScanResponse.isDemoCard(): Boolean = DemoHelper.isDemoCardId(card.cardId)
fun Card.isDemoCard(): Boolean = DemoHelper.isDemoCardId(cardId)
fun CardDTO.isDemoCard(): Boolean = DemoHelper.isDemoCardId(cardId)

View file

@ -1,7 +1,7 @@
package com.tangem.tap.features.details.redux
import com.tangem.blockchain.common.Wallet
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.domain.termsOfUse.CardTou
@ -30,7 +30,7 @@ sealed class DetailsAction : Action {
object ScanCard : DetailsAction()
data class PrepareCardSettingsData(val card: Card) : DetailsAction()
data class PrepareCardSettingsData(val card: CardDTO) : DetailsAction()
object ResetCardSettingsData : DetailsAction()
sealed class ManageSecurity : DetailsAction() {

View file

@ -3,6 +3,7 @@ package com.tangem.tap.features.details.redux
import com.tangem.common.CompletionResult
import com.tangem.common.core.TangemSdkError
import com.tangem.domain.common.TapWorkarounds.isTangemTwins
import com.tangem.domain.common.util.userWalletId
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.analytics.events.Settings
@ -13,7 +14,6 @@ import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.extensions.getUserWalletId
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.onboarding.products.twins.redux.CreateTwinWalletMode
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsAction
@ -67,11 +67,12 @@ class DetailsMiddleware {
scope.launch {
when (val result = tangemSdkManager.scanCard()) {
is CompletionResult.Success -> {
val card = result.data
if (card.getUserWalletId() ==
store.state.globalState.scanResponse?.card?.getUserWalletId()
) {
store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(card))
val scannedCard = result.data
val currentCardId = store.state.globalState.scanResponse?.card
?.userWalletId
?.stringValue
if (scannedCard.userWalletId.stringValue == currentCardId) {
store.dispatchOnMain(DetailsAction.PrepareCardSettingsData(scannedCard))
} else {
store.dispatchDialogShow(
AppDialog.SimpleOkDialogRes(
@ -81,8 +82,7 @@ class DetailsMiddleware {
)
}
}
is CompletionResult.Failure -> {
}
is CompletionResult.Failure -> Unit
}
}
}
@ -104,22 +104,20 @@ class DetailsMiddleware {
is DetailsAction.ResetToFactory.Proceed -> {
val card = store.state.detailsState.cardSettingsState?.card ?: return
scope.launch {
val result = tangemSdkManager.resetToFactorySettings(card)
when (result) {
when (val result = tangemSdkManager.resetToFactorySettings(card.cardId)) {
is CompletionResult.Success -> {
Analytics.send(Settings.CardSettings.FactoryResetFinished())
store.dispatchOnMain(NavigationAction.PopBackTo(AppScreen.Home))
}
is CompletionResult.Failure -> {
(result.error as? TangemSdkError)?.let { error ->
Analytics.send(Settings.CardSettings.FactoryResetFinished(error))
}
Analytics.send(Settings.CardSettings.FactoryResetFinished(error)) }
}
}
}
}
else -> { /* no-op */
}
else -> Unit
}
}
}
@ -156,8 +154,7 @@ class DetailsMiddleware {
}
store.dispatch(DetailsAction.ManageSecurity.SaveChanges.Failure)
}
else -> { /* no-op */
}
else -> Unit
}
}
}
@ -171,8 +168,7 @@ class DetailsMiddleware {
}
}
}
else -> { /* no-op */
}
else -> Unit
}
}
}
@ -186,4 +182,4 @@ class DetailsMiddleware {
}
}
}
}
}

View file

@ -1,6 +1,6 @@
package com.tangem.tap.features.details.redux
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTangemNote
@ -51,12 +51,12 @@ private fun handlePrepareScreen(
scanResponse = action.scanResponse,
wallets = action.wallets,
cardTermsOfUseUrl = action.cardTou.getUrl(action.scanResponse.card),
createBackupAllowed = action.scanResponse.card.backupStatus == Card.BackupStatus.NoBackup,
createBackupAllowed = action.scanResponse.card.backupStatus == CardDTO.BackupStatus.NoBackup,
appCurrency = store.state.globalState.appCurrency,
)
}
private fun handlePrepareCardSettingsScreen(card: Card, state: DetailsState): DetailsState {
private fun handlePrepareCardSettingsScreen(card: CardDTO, state: DetailsState): DetailsState {
val cardSettingsState = CardSettingsState(
cardInfo = card.toCardInfo(),
manageSecurityState = prepareSecurityOptions(card),
@ -66,14 +66,16 @@ private fun handlePrepareCardSettingsScreen(card: Card, state: DetailsState): De
return state.copy(cardSettingsState = cardSettingsState)
}
private fun prepareSecurityOptions(card: Card): ManageSecurityState {
private fun prepareSecurityOptions(card: CardDTO): ManageSecurityState {
val securityOption = when {
card.isAccessCodeSet -> {
SecurityOption.AccessCode
}
card.isPasscodeSet == true -> {
SecurityOption.PassCode
}
else -> {
SecurityOption.LongTap
}
@ -94,7 +96,7 @@ private fun prepareSecurityOptions(card: Card): ManageSecurityState {
)
}
private fun isResetToFactoryAllowedByCard(card: Card): Boolean {
private fun isResetToFactoryAllowedByCard(card: CardDTO): Boolean {
val notAllowedByAnyWallet = card.wallets.any { it.settings.isPermanent }
val notAllowedByCard = notAllowedByAnyWallet ||
(card.isWalletDataSupported && (!card.isTangemNote && !card.settings.isBackupAllowed)) ||
@ -114,7 +116,8 @@ private fun handleEraseWallet(
}
private fun handleSecurityAction(
action: DetailsAction.ManageSecurity, state: DetailsState,
action: DetailsAction.ManageSecurity,
state: DetailsState,
): DetailsState {
return when (action) {
is DetailsAction.ManageSecurity.SelectOption -> {
@ -144,7 +147,8 @@ private fun handleSecurityAction(
}
private fun handlePrivacyAction(
action: DetailsAction.AppSettings, state: DetailsState,
action: DetailsAction.AppSettings,
state: DetailsState,
): DetailsState {
return when (action) {
is DetailsAction.AppSettings.SwitchPrivacySetting -> {
@ -157,7 +161,8 @@ private fun handlePrivacyAction(
}
private fun prepareAllowedSecurityOptions(
card: Card?, currentSecurityOption: SecurityOption?,
card: CardDTO?,
currentSecurityOption: SecurityOption?,
): EnumSet<SecurityOption> {
val allowedSecurityOptions = EnumSet.of(SecurityOption.LongTap)
@ -173,7 +178,7 @@ private fun prepareAllowedSecurityOptions(
return allowedSecurityOptions
}
private fun Card.toCardInfo(): CardInfo {
private fun CardDTO.toCardInfo(): CardInfo {
val cardId = this.cardId.chunked(4).joinToString(separator = " ")
val issuer = this.issuer.name
val signedHashes = this.signedHashesCount()

View file

@ -2,7 +2,7 @@ package com.tangem.tap.features.details.redux
import android.net.Uri
import com.tangem.blockchain.common.Wallet
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.entities.Button
import com.tangem.tap.common.entities.FiatCurrency
@ -20,13 +20,13 @@ data class DetailsState(
val privacyPolicyUrl: String? = null,
val createBackupAllowed: Boolean = false,
val appCurrency: FiatCurrency = FiatCurrency.Default,
val saveWallets: Boolean = true,
val saveAccessCodes: Boolean = true,
val saveWallets: Boolean = false,
val saveAccessCodes: Boolean = false,
) : StateType {
// if you do not delegate - the application crashes on startup,
// because twinCardsState has not been created yet
val twinCardsState: TwinCardsState by ReadOnlyProperty<Any, TwinCardsState> { thisRef, property ->
val twinCardsState: TwinCardsState by ReadOnlyProperty<Any, TwinCardsState> { _, _ ->
store.state.twinCardsState
}
@ -42,7 +42,7 @@ data class CardInfo(
data class CardSettingsState(
val cardInfo: CardInfo,
val card: Card,
val card: CardDTO,
val manageSecurityState: ManageSecurityState?,
val resetCardAllowed: Boolean,
val resetConfirmed: Boolean = false,

View file

@ -3,8 +3,8 @@ package com.tangem.tap.features.details.redux.walletconnect
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.WalletManager
import com.tangem.common.card.Card
import com.tangem.common.extensions.guard
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.extensions.withMainContext
@ -240,7 +240,7 @@ class WalletConnectMiddleware {
handleScanResponse(scanResponse = scanResponse, session = session, blockchain = blockchain)
}
private fun getAvailableBlockchains(card: Card, walletState: WalletState): List<Blockchain> {
private fun getAvailableBlockchains(card: CardDTO, walletState: WalletState): List<Blockchain> {
return walletState.currencies.filter {
it.isBlockchain() && !it.isCustomCurrency(card.derivationStyle) && it.blockchain.isEvm()
}.map { it.blockchain }

View file

@ -1,8 +1,8 @@
package com.tangem.tap.features.disclaimer.redux
import android.net.Uri
import com.tangem.common.card.Card
import com.tangem.common.extensions.VoidCallback
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import org.rekotlin.StateType
@ -22,7 +22,7 @@ sealed class DisclaimerType(
companion object {
fun get(scanResponse: ScanResponse): DisclaimerType = get(scanResponse.card)
fun get(card: Card): DisclaimerType = when {
fun get(card: CardDTO): DisclaimerType = when {
card.isSaltPay -> SaltPay
else -> Tangem
}

View file

@ -14,4 +14,4 @@ sealed class HomeAction : Action {
data class GoToShop(val userCountryCode: String?) : HomeAction()
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
}
}

View file

@ -1,8 +1,8 @@
package com.tangem.tap.features.home.redux
import com.tangem.common.card.Card
import com.tangem.common.core.TangemError
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.extensions.withIOContext
import com.tangem.domain.common.extensions.withMainContext
@ -45,7 +45,6 @@ import com.tangem.wallet.R
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.DispatchFunction
import org.rekotlin.Middleware
class HomeMiddleware {
@ -56,22 +55,23 @@ class HomeMiddleware {
}
}
private val homeMiddleware: Middleware<AppState> = { dispatch, state ->
private val homeMiddleware: Middleware<AppState> = { _, _ ->
{ next ->
{ action ->
handleHomeAction(state, action, dispatch)
handleHomeAction(action)
next(action)
}
}
}
private fun handleHomeAction(appState: () -> AppState?, action: Action, dispatch: DispatchFunction) {
private fun handleHomeAction(action: Action) {
when (action) {
is HomeAction.Init -> {
store.dispatch(GlobalAction.RestoreAppCurrency)
store.dispatch(GlobalAction.ExchangeManager.Init)
store.dispatch(GlobalAction.FetchUserCountry)
}
is HomeAction.ShouldScanCardOnResume -> {
if (action.shouldScanCard) {
store.dispatch(HomeAction.ShouldScanCardOnResume(false))
@ -123,7 +123,7 @@ private fun checkForUnfinishedBackupForSaltPay(
return
}
fun isTheSamePrimaryCard(card: Card): Boolean {
fun isTheSamePrimaryCard(card: CardDTO): Boolean {
return backupService.primaryCardId?.let { it == card.cardId } ?: false
}

View file

@ -3,7 +3,6 @@ package com.tangem.tap.features.onboarding
import com.tangem.domain.common.ProductType
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.preferencesStorage
/**
@ -23,7 +22,7 @@ class OnboardingHelper {
cardInfoStorage.isActivationInProgress(cardId)
}
}
response.card.hasWallets() -> cardInfoStorage.isActivationInProgress(cardId)
response.card.wallets.isNotEmpty() -> cardInfoStorage.isActivationInProgress(cardId)
else -> true
}
}

View file

@ -22,7 +22,6 @@ import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.domain.extensions.makePrimaryWalletManager
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.RUSSIA_COUNTRY_CODE
@ -79,7 +78,7 @@ private fun handleNoteAction(appState: () -> AppState?, action: Action, dispatch
}
is OnboardingNoteAction.DetermineStepOfScreen -> {
val step = when {
!card.hasWallets() -> OnboardingNoteStep.CreateWallet
card.wallets.isEmpty() -> OnboardingNoteStep.CreateWallet
noteState.walletBalance.balanceIsToppedUp() -> OnboardingNoteStep.Done
else -> OnboardingNoteStep.TopUpWallet
}

View file

@ -12,7 +12,6 @@ import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.scope
@ -21,7 +20,6 @@ import com.tangem.tap.tangemSdkManager
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.rekotlin.Action
import org.rekotlin.DispatchFunction
import org.rekotlin.Middleware
class OnboardingOtherCardsMiddleware {
@ -30,16 +28,16 @@ class OnboardingOtherCardsMiddleware {
}
}
private val onboardingOtherCardsMiddleware: Middleware<AppState> = { dispatch, state ->
private val onboardingOtherCardsMiddleware: Middleware<AppState> = { dispatch, _ ->
{ next ->
{ action ->
handleOtherCardsAction(action, dispatch)
handleOtherCardsAction(action)
next(action)
}
}
}
private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) {
private fun handleOtherCardsAction(action: Action) {
if (action !is OnboardingOtherCardsAction) return
val globalState = store.state.globalState
val onboardingManager = globalState.onboardingState.onboardingManager ?: return
@ -60,7 +58,7 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) {
}
is OnboardingOtherCardsAction.DetermineStepOfScreen -> {
val step = when {
!card.hasWallets() -> OnboardingOtherCardsStep.CreateWallet
card.wallets.isEmpty() -> OnboardingOtherCardsStep.CreateWallet
else -> OnboardingOtherCardsStep.Done
}
store.dispatch((OnboardingOtherCardsAction.SetStepOfScreen(step)))
@ -87,21 +85,32 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) {
val updatedResponse = onboardingManager.scanResponse.copy(
card = result.data.card,
)
val updatedCard = updatedResponse.card
onboardingManager.scanResponse = updatedResponse
onboardingManager.activationStarted(updatedResponse.card.cardId)
onboardingManager.activationStarted(updatedCard.cardId)
val primaryBlockchain = updatedResponse.getBlockchain()
val blockchainNetworks = if (primaryBlockchain != Blockchain.Unknown) {
val primaryToken = updatedResponse.getPrimaryToken()
val blockchainNetwork =
BlockchainNetwork(primaryBlockchain, updatedResponse.card).updateTokens(
listOfNotNull(primaryToken),
BlockchainNetwork(
blockchain = primaryBlockchain,
card = updatedCard,
)
.updateTokens(
listOfNotNull(primaryToken),
)
listOf(blockchainNetwork)
} else {
listOf(
BlockchainNetwork(Blockchain.Bitcoin, updatedResponse.card),
BlockchainNetwork(Blockchain.Ethereum, updatedResponse.card),
BlockchainNetwork(
blockchain = Blockchain.Bitcoin,
card = updatedCard,
),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
card = updatedCard,
),
)
}
@ -126,5 +135,9 @@ private fun handleOtherCardsAction(action: Action, dispatch: DispatchFunction) {
withMainContext { store.dispatch(NavigationAction.NavigateTo(AppScreen.Wallet)) }
}
}
is OnboardingOtherCardsAction.Confetti.Hide,
is OnboardingOtherCardsAction.SetArtworkUrl,
is OnboardingOtherCardsAction.Confetti.Show,
-> Unit
}
}

View file

@ -150,6 +150,13 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
finishCardActivation()
postUi(500) { store.dispatch(TwinCardsAction.Confetti.Show) }
}
TwinCardsStep.None,
TwinCardsStep.Warning,
TwinCardsStep.CreateFirstWallet,
TwinCardsStep.CreateSecondWallet,
TwinCardsStep.CreateThirdWallet,
-> Unit
}
}
is TwinCardsAction.Wallet.LaunchFirstStep -> {
@ -299,4 +306,4 @@ private fun handle(action: Action, dispatch: DispatchFunction) {
}
}
}
}
}

View file

@ -2,8 +2,8 @@ package com.tangem.tap.features.onboarding.products.wallet.redux
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.CompletionResult
import com.tangem.common.card.Card
import com.tangem.common.extensions.ifNotNull
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isSaltPay
import com.tangem.domain.common.extensions.withMainContext
@ -18,7 +18,6 @@ import com.tangem.tap.common.redux.AppState
import com.tangem.tap.common.redux.global.GlobalAction
import com.tangem.tap.common.redux.navigation.AppScreen
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.domain.extensions.hasWallets
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.demo.DemoHelper
import com.tangem.tap.features.home.redux.HomeAction
@ -76,19 +75,23 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch:
// it's possible when found unfinished backup for standard Wallet cards
store.dispatch(OnboardingWalletAction.ResumeBackup)
}
card.hasWallets() && card.backupStatus == Card.BackupStatus.NoBackup -> {
card.wallets.isNotEmpty() && card.backupStatus == CardDTO.BackupStatus.NoBackup -> {
store.dispatch(OnboardingWalletAction.ResumeBackup)
}
card.hasWallets() && card.backupStatus?.isActive == true -> {
card.wallets.isNotEmpty() && card.backupStatus?.isActive == true -> {
when {
// check for unfinished backup for saltPay cards. See more
scanResponse.isSaltPay() && backupService.hasIncompletedBackup -> {
store.dispatch(OnboardingWalletAction.ResumeBackup)
}
scanResponse.isSaltPay() -> {
store.dispatch(OnboardingWalletAction.GetToSaltPayStep)
store.dispatch(BackupAction.FinishBackup)
}
else -> store.dispatch(BackupAction.FinishBackup)
}
}
@ -125,8 +128,14 @@ private fun handleWalletAction(action: Action, state: () -> AppState?, dispatch:
)
onboardingManager.scanResponse = updatedResponse
val blockchainNetworks = listOf(
BlockchainNetwork(Blockchain.Bitcoin, result.data.card),
BlockchainNetwork(Blockchain.Ethereum, result.data.card),
BlockchainNetwork(
blockchain = Blockchain.Bitcoin,
card = result.data.card,
),
BlockchainNetwork(
blockchain = Blockchain.Ethereum,
card = result.data.card,
),
)
store.dispatch(
WalletAction.MultiWallet.SaveCurrencies(
@ -193,7 +202,7 @@ private fun updateScanResponseAfterBackup(
val card = if (backupState.backupCardsNumber > 0) {
val cardsCount = backupState.backupCardsNumber
scanResponse.card.copy(
backupStatus = Card.BackupStatus.Active(cardCount = cardsCount),
backupStatus = CardDTO.BackupStatus.Active(cardCount = cardsCount),
isAccessCodeSet = true,
)
} else {
@ -366,9 +375,10 @@ private fun startCardActivation(scanResponse: ScanResponse) {
* Standard Wallet cards finish activation at BackupAction.FinishBackup
* SaltPay cards finish activation at OnboardingWalletAction.FinishOnboarding
*/
internal fun finishCardActivation(backupState: BackupState, card: Card?) {
internal fun finishCardActivation(backupState: BackupState, card: CardDTO?) {
(listOf(backupState.primaryCardId, card?.cardId) + backupState.backupCardIds)
.distinct().filterNotNull()
.distinct()
.filterNotNull()
.forEach { cardId ->
preferencesStorage.usedCardsPrefStorage.activationFinished(cardId)
}

View file

@ -11,6 +11,7 @@ import com.tangem.common.extensions.guard
import com.tangem.common.extensions.isZero
import com.tangem.common.services.Result
import com.tangem.domain.common.extensions.successOr
import com.tangem.domain.common.util.UserWalletId
import com.tangem.network.api.paymentology.AttestationResponse
import com.tangem.network.api.paymentology.PaymentologyApiService
import com.tangem.network.api.paymentology.RegisterKYCRequest
@ -20,7 +21,6 @@ import com.tangem.network.api.paymentology.RegistrationResponse
import com.tangem.network.api.paymentology.tryExtractError
import com.tangem.operations.attestation.AttestWalletKeyResponse
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.domain.extensions.UserWalletId
import com.tangem.tap.domain.getFirstToken
import com.tangem.tap.features.onboarding.products.wallet.saltPay.message.SaltPayActivationError
import java.math.BigDecimal
@ -123,7 +123,7 @@ class SaltPayActivationManager(
}
suspend fun claim(amountToClaim: BigDecimal, signer: TransactionSigner): Result<Unit> {
val result = gnosisRegistrator.transferFrom(amountToClaim, signer).successOr {
gnosisRegistrator.transferFrom(amountToClaim, signer).successOr {
return Result.Failure(SaltPayActivationError.ClaimTransactionFailed)
}
return Result.Success(Unit)
@ -192,4 +192,4 @@ class KYCUrlProvider(
.appendQueryParameter(kycProvider.externalIdParameterKey, kycRefId)
.build().toString()
}
}
}

View file

@ -11,9 +11,9 @@ import com.tangem.blockchain.common.TransactionError
import com.tangem.blockchain.common.TransactionSender
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import com.tangem.common.services.Result
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.extensions.withMainContext
import com.tangem.tap.DELAY_SDK_DIALOG_CLOSE
@ -150,7 +150,7 @@ private fun sendTransaction(
feeAmount: Amount,
destinationAddress: String,
transactionExtras: TransactionExtrasState,
card: Card,
card: CardDTO,
externalTransactionData: ExternalTransactionData?,
dispatch: (Action) -> Unit,
) {

View file

@ -1,8 +1,6 @@
package com.tangem.tap.features.wallet.models
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.Token
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.toCoinId
import com.tangem.domain.common.extensions.toNetworkId
@ -11,6 +9,8 @@ import com.tangem.network.api.tangemTech.TokenResponse
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.tokens.redux.TokenWithBlockchain
import com.tangem.blockchain.common.Blockchain as SdkBlockchain
import com.tangem.blockchain.common.Token as SdkToken
sealed interface Currency {
val coinId: String?
@ -18,7 +18,7 @@ sealed interface Currency {
is Blockchain -> blockchain.toCoinId()
is Token -> token.id
}
val blockchain: com.tangem.blockchain.common.Blockchain
val blockchain: SdkBlockchain
val currencySymbol: CryptoCurrencyName
val derivationPath: String?
val currencyName: String
@ -33,15 +33,15 @@ sealed interface Currency {
}
data class Token(
val token: com.tangem.blockchain.common.Token,
override val blockchain: com.tangem.blockchain.common.Blockchain,
val token: SdkToken,
override val blockchain: SdkBlockchain,
override val derivationPath: String?,
) : Currency {
override val currencySymbol = token.symbol
}
data class Blockchain(
override val blockchain: com.tangem.blockchain.common.Blockchain,
override val blockchain: SdkBlockchain,
override val derivationPath: String?,
) : Currency {
override val currencySymbol: CryptoCurrencyName = blockchain.currency
@ -72,7 +72,7 @@ sealed interface Currency {
companion object {
fun fromBlockchainNetwork(
blockchainNetwork: BlockchainNetwork,
token: com.tangem.blockchain.common.Token? = null,
token: SdkToken? = null,
): Currency {
return if (token != null) {
Token(
@ -115,7 +115,7 @@ sealed interface Currency {
?: return null
return when {
tokenResponse.contractAddress != null -> Token(
com.tangem.blockchain.common.Token(
token = SdkToken(
name = tokenResponse.name,
symbol = tokenResponse.symbol,
contractAddress = tokenResponse.contractAddress!!,
@ -148,8 +148,8 @@ fun List<Currency>.toBlockchainNetworks(): List<BlockchainNetwork> {
return this.filter { it.isBlockchain() }.map { BlockchainNetwork(it.blockchain, it.derivationPath, getTokens(it)) }
}
private fun List<Currency>.getTokens(currency: Currency): List<Token> {
fun List<Currency>.getTokens(currency: Currency): List<SdkToken> {
return this
.filter { it.isToken() && it.blockchain == currency.blockchain && it.derivationPath == currency.derivationPath }
.mapNotNull { if (it is Currency.Token) it.token else null }
}
}

View file

@ -7,9 +7,8 @@ import com.tangem.blockchain.common.Token
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.common.WalletManager
import com.tangem.blockchain.common.address.AddressType
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.tap.common.entities.FiatCurrency
import com.tangem.tap.common.redux.ErrorAction
import com.tangem.tap.common.redux.NotificationAction
import com.tangem.tap.domain.TapError
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
@ -70,7 +69,7 @@ sealed class WalletAction : Action {
data class AddToken(val token: Token, val blockchain: BlockchainNetwork, val save: Boolean) : MultiWallet()
data class SaveCurrencies(
val blockchainNetworks: List<BlockchainNetwork>, val card: Card? = null,
val blockchainNetworks: List<BlockchainNetwork>, val card: CardDTO? = null,
) : MultiWallet()
data class TokenLoaded(
@ -123,9 +122,9 @@ sealed class WalletAction : Action {
object Failure : WalletAction()
}
class LoadCardInfo(val card: Card) : WalletAction()
class LoadCardInfo(val card: CardDTO) : WalletAction()
data class LoadArtwork(val card: Card, val artworkId: String?) : WalletAction() {
data class LoadArtwork(val card: CardDTO, val artworkId: String?) : WalletAction() {
data class Success(val artwork: Artwork) : WalletAction()
object Failure : WalletAction()
}
@ -134,10 +133,6 @@ sealed class WalletAction : Action {
data class Send(val amount: Amount? = null) : WalletAction()
object EmptyField : WalletAction(), ErrorAction {
override val error = TapError.PayIdEmptyField
}
data class CopyAddress(val address: String, val context: Context) : WalletAction() {
object Success : WalletAction(), NotificationAction {
override val messageResource = R.string.wallet_notification_address_copied
@ -186,7 +181,7 @@ sealed class WalletAction : Action {
data class SetWalletRent(
val wallet: Wallet,
val minRent: String,
val rentExempt: String
val rentExempt: String,
) : WalletAction()
data class RemoveWalletRent(val wallet: Wallet) : WalletAction()

View file

@ -4,8 +4,8 @@ import com.tangem.blockchain.common.BlockchainSdkError
import com.tangem.blockchain.common.SignatureCountValidator
import com.tangem.blockchain.common.Wallet
import com.tangem.blockchain.extensions.SimpleResult
import com.tangem.common.card.Card
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.tap.common.extensions.dispatchOnMain
@ -13,10 +13,8 @@ import com.tangem.tap.common.extensions.isGreaterThan
import com.tangem.tap.common.redux.global.GlobalState
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
import com.tangem.tap.domain.configurable.warningMessage.WarningMessagesManager
import com.tangem.tap.domain.extensions.getSingleWallet
import com.tangem.tap.domain.extensions.hasSignedHashes
import com.tangem.tap.domain.extensions.isMultiwalletAllowed
import com.tangem.tap.domain.extensions.remainingSignatures
import com.tangem.tap.features.demo.isDemoCard
import com.tangem.tap.features.wallet.redux.WalletAction
import com.tangem.tap.network.NetworkConnectivity
@ -108,8 +106,8 @@ class WarningsMiddleware {
}
}
private fun showWarningLowRemainingSignaturesIfNeeded(card: Card) {
val remainingSignatures = card.remainingSignatures
private fun showWarningLowRemainingSignaturesIfNeeded(card: CardDTO) {
val remainingSignatures = card.wallets.firstOrNull()?.remainingSignatures
if (remainingSignatures != null &&
remainingSignatures <= WarningMessagesManager.REMAINING_SIGNATURES_WARNING
) {
@ -159,7 +157,7 @@ class WarningsMiddleware {
val validator = store.state.walletState.walletManagers.firstOrNull()
as? SignatureCountValidator
scope.launch {
val signedHashes = card.getSingleWallet()?.totalSignedHashes ?: 0
val signedHashes = card.wallets.firstOrNull()?.totalSignedHashes ?: 0
val result = validator?.validateSignatureCount(signedHashes)
withContext(Dispatchers.Main) {
when (result) {

View file

@ -3,7 +3,7 @@ package com.tangem.tap.features.wallet.ui.wallet
import android.widget.Button
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.tap.common.analytics.Analytics
@ -54,8 +54,8 @@ class MultiWalletView : WalletView() {
private fun setupWalletCardNumber(binding: FragmentWalletBinding) = with(binding) {
val card = store.state.globalState.scanResponse?.card
if (card?.backupStatus is Card.BackupStatus.Active) {
val cardCount = (card.backupStatus as Card.BackupStatus.Active).cardCount + 1
if (card?.backupStatus is CardDTO.BackupStatus.Active) {
val cardCount = (card.backupStatus as CardDTO.BackupStatus.Active).cardCount + 1
tvTwinCardNumber.show()
tvTwinCardNumber.text = tvTwinCardNumber.getQuantityString(R.plurals.card_label_card_count, cardCount)
} else {

View file

@ -1,6 +1,6 @@
package com.tangem.tap.network.exchangeServices
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.tap.features.demo.isDemoCard
import com.tangem.tap.features.wallet.models.Currency
@ -9,7 +9,7 @@ import com.tangem.tap.features.wallet.models.Currency
[REDACTED_AUTHOR]
*/
class CardExchangeRules(
val cardProvider: () -> Card?,
val cardProvider: () -> CardDTO?,
) : ExchangeRules {
override fun featureIsSwitchedOn(): Boolean {

View file

@ -7,7 +7,7 @@ import com.tangem.blockchain.common.AmountType
import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.Token
import com.tangem.blockchain.extensions.Result
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.tap.common.extensions.safeUpdate
import com.tangem.tap.common.redux.global.CryptoCurrencyName
import com.tangem.tap.common.redux.global.GlobalAction
@ -86,8 +86,9 @@ class CurrencyExchangeManager(
}
}
@Suppress("unused")
suspend fun CurrencyExchangeManager.buyErc20TestnetTokens(
card: Card,
card: CardDTO,
walletManager: EthereumWalletManager,
token: Token,
) {

View file

@ -1,6 +1,6 @@
package com.tangem.tap.proxy
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.ScanResponse
import com.tangem.tap.common.redux.AppState
import com.tangem.tap.domain.TangemSdkManager
@ -20,7 +20,7 @@ class AppStateHolder {
var mainStore: Store<AppState>? = null
var tangemSdkManager: TangemSdkManager? = null
fun getActualCard(): Card? {
fun getActualCard(): CardDTO? {
return scanResponse?.card
}
}

View file

@ -4,15 +4,15 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.blockchain.common.DerivationParams
import com.tangem.blockchain.common.DerivationStyle
import com.tangem.blockchain.common.WalletManagerFactory
import com.tangem.common.card.Card
import com.tangem.domain.common.CardDTO
import com.tangem.domain.common.TapWorkarounds.derivationStyle
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.userWalletId
import com.tangem.lib.crypto.UserWalletManager
import com.tangem.lib.crypto.models.Currency
import com.tangem.lib.crypto.models.NativeToken
import com.tangem.lib.crypto.models.NonNativeToken
import com.tangem.tap.domain.extensions.getUserWalletId
import com.tangem.tap.domain.extensions.makeWalletManagerForApp
import com.tangem.tap.domain.tokens.models.BlockchainNetwork
import com.tangem.tap.features.wallet.redux.WalletAction
@ -54,7 +54,7 @@ class UserWalletManagerImpl(
}
override fun getWalletId(): String {
return appStateHolder.getActualCard()?.getUserWalletId() ?: ""
return appStateHolder.getActualCard()?.userWalletId?.stringValue ?: ""
}
override suspend fun isTokenAdded(currency: Currency): Boolean {
@ -100,7 +100,7 @@ class UserWalletManagerImpl(
}
}
private fun addNativeTokenToWalletAction(token: NativeToken, card: Card): Action {
private fun addNativeTokenToWalletAction(token: NativeToken, card: CardDTO): Action {
val blockchain = Blockchain.fromNetworkId(token.networkId)
val scanResponse = appStateHolder.scanResponse
if (blockchain != null && scanResponse != null) {