Updated on 2026-08-14

This commit is contained in:
Tangem 2023-08-15 17:08:46 +03:00
parent 2e09b2e3ca
commit a67518573f
9 changed files with 78 additions and 34 deletions

View file

@ -4,6 +4,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.features.customtoken.impl.data.converters.FoundTokenConverter
import com.tangem.tap.features.customtoken.impl.domain.CustomTokenRepository
import com.tangem.tap.features.customtoken.impl.domain.models.FoundToken
@ -27,8 +28,9 @@ class DefaultCustomTokenRepository(
) : CustomTokenRepository {
override suspend fun findToken(address: String, networkId: String?): FoundToken {
val supportedTokenNetworkIds = requireNotNull(reduxStateHolder.scanResponse?.card)
.supportedBlockchains()
val scanResponse = requireNotNull(reduxStateHolder.scanResponse)
val supportedTokenNetworkIds = requireNotNull(scanResponse.card)
.supportedBlockchains(scanResponse.cardTypesResolver)
.filter(Blockchain::canHandleTokens)
.map(Blockchain::toNetworkId)

View file

@ -18,6 +18,7 @@ import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.crypto.hdWallet.HDWalletError
import com.tangem.domain.AddCustomTokenError
import com.tangem.domain.common.extensions.*
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.features.addCustomToken.CustomCurrency
import com.tangem.tap.domain.model.WalletDataModel
@ -206,9 +207,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
private fun getNetworkSelectorItems(): List<SelectorItem.Title> {
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
val scanResponse = reduxStateHolder.scanResponse
return listOf(defaultNetwork) + Blockchain.values()
.filter { blockchain ->
reduxStateHolder.scanResponse?.card?.supportedBlockchains()?.contains(blockchain) == true
scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
?.contains(blockchain) == true
}
.sortedBy(Blockchain::fullName)
.map(::createNetworkSelectorItem)
@ -404,7 +407,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
val isSupportedToken = if (!isNetworkSelected()) {
true
} else {
reduxStateHolder.scanResponse?.card?.canHandleToken(networkSelectorValue) ?: false
val scanResponse = reduxStateHolder.scanResponse
scanResponse?.card?.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = scanResponse.cardTypesResolver,
) ?: false
}
return buildSet {
@ -438,8 +445,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
address = uiState.form.contractAddressInputField.value,
blockchain = networkSelectorValue,
)
val isSupportedToken = reduxStateHolder.scanResponse?.card
?.canHandleToken(networkSelectorValue)
val scanResponse = reduxStateHolder.scanResponse
val isSupportedToken = scanResponse?.card
?.canHandleToken(
blockchain = networkSelectorValue,
cardTypesResolver = scanResponse.cardTypesResolver,
)
?: false
uiState.copySealed(

View file

@ -6,6 +6,7 @@ import com.tangem.blockchain.common.Blockchain
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.features.tokens.impl.data.converters.CoinsResponseConverter
import com.tangem.tap.features.tokens.impl.domain.models.Token
import com.tangem.tap.proxy.AppStateHolder
@ -38,7 +39,8 @@ internal class TangemApiTokensPagingSource(
val page = params.key ?: 0
return runCatching(dispatchers.io) {
val supportedBlockchains = reduxStateHolder.scanResponse?.card?.supportedBlockchains()
val scanResponse = reduxStateHolder.scanResponse
val supportedBlockchains = scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
?: Blockchain.values().toList()
api.getCoins(

View file

@ -16,6 +16,7 @@ import com.tangem.core.ui.extensions.getActiveIconRes
import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
import com.tangem.domain.common.extensions.canHandleToken
import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
import com.tangem.tap.common.extensions.getGreyedOutIconRes
import com.tangem.tap.common.extensions.getNetworkName
@ -349,8 +350,14 @@ internal class TokensListViewModel @Inject constructor(
toggledNetwork.changeToggleState()
}
} else {
val scanResponse = reduxStateHolder.scanResponse
val isUnsupportedToken =
!(reduxStateHolder.scanResponse?.card?.canHandleToken(token.blockchain) ?: false)
!(
scanResponse?.card?.canHandleToken(
blockchain = token.blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
) ?: false
)
if (isUnsupportedToken) {
router.openUnsupportedSoltanaNetworkAlert()

View file

@ -8,7 +8,6 @@ import com.tangem.common.card.WalletData
import com.tangem.domain.common.TapWorkarounds.getTangemNoteBlockchain
import com.tangem.domain.common.TapWorkarounds.isStart2Coin
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.isWallet2
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ProductType
import com.tangem.operations.attestation.Attestation
@ -31,7 +30,7 @@ internal class TangemCardTypesResolver(
}
override fun isWallet2(): Boolean {
return card.isWallet2
return card.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available && card.settings.isKeysImportAllowed
}
override fun isTangemTwins(): Boolean = productType == ProductType.Twins

View file

@ -28,9 +28,6 @@ object TapWorkarounds {
val CardDTO.canSkipBackup: Boolean
get() = this.firmwareVersion < backupRequiredFirmwareVersion
val CardDTO.isWallet2: Boolean
get() = this.firmwareVersion >= FirmwareVersion.Ed25519Slip0010Available && this.settings.isKeysImportAllowed
val CardDTO.useOldStyleDerivation: Boolean
get() = batchId == "AC01" || batchId == "AC02" || batchId == "CB95"

View file

@ -3,8 +3,8 @@ package com.tangem.domain.common.extensions
import com.tangem.blockchain.common.Blockchain
import com.tangem.common.card.EllipticCurve
import com.tangem.common.card.FirmwareVersion
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.TapWorkarounds.isWallet2
import com.tangem.domain.models.scan.CardDTO
/**
@ -13,7 +13,7 @@ import com.tangem.domain.models.scan.CardDTO
val FirmwareVersion.Companion.SolanaTokensAvailable
get() = FirmwareVersion(4, 52)
fun CardDTO.supportedBlockchains(): List<Blockchain> {
fun CardDTO.supportedBlockchains(cardTypesResolver: CardTypesResolver): List<Blockchain> {
val supportedBlockchains = if (firmwareVersion < FirmwareVersion.MultiWalletAvailable) {
Blockchain.fromCurve(EllipticCurve.Secp256k1)
} else {
@ -21,7 +21,7 @@ fun CardDTO.supportedBlockchains(): List<Blockchain> {
}.toMutableList()
// disabled Cardano for wallet 2 for now, should be enabled after key processed
// ([REDACTED_JIRA])
if (this.isWallet2) {
if (cardTypesResolver.isWallet2()) {
supportedBlockchains.apply {
remove(Blockchain.Cardano)
}
@ -31,8 +31,10 @@ fun CardDTO.supportedBlockchains(): List<Blockchain> {
.filter { it.isSupportedInApp() }
}
fun CardDTO.supportedTokens(): List<Blockchain> {
val tokensSupportedByBlockchain = supportedBlockchains().filter { it.canHandleTokens() }.toMutableList()
fun CardDTO.supportedTokens(cardTypesResolver: CardTypesResolver): List<Blockchain> {
val tokensSupportedByBlockchain = supportedBlockchains(cardTypesResolver)
.filter { it.canHandleTokens() }
.toMutableList()
val tokensSupportedByCard = when {
firmwareVersion >= FirmwareVersion.SolanaTokensAvailable -> tokensSupportedByBlockchain
else -> {
@ -46,6 +48,6 @@ fun CardDTO.supportedTokens(): List<Blockchain> {
return tokensSupportedByCard.filter { isTestCard == it.isTestnet() }
}
fun CardDTO.canHandleToken(blockchain: Blockchain): Boolean {
return this.supportedTokens().contains(blockchain)
fun CardDTO.canHandleToken(blockchain: Blockchain, cardTypesResolver: CardTypesResolver): Boolean {
return this.supportedTokens(cardTypesResolver).contains(blockchain)
}

View file

@ -13,6 +13,7 @@ import com.tangem.domain.common.extensions.fromNetworkId
import com.tangem.domain.common.extensions.supportedBlockchains
import com.tangem.domain.common.extensions.toNetworkId
import com.tangem.domain.common.form.*
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.features.addCustomToken.*
import com.tangem.domain.features.addCustomToken.CustomTokenFieldId.*
@ -435,7 +436,13 @@ internal class AddCustomTokenHub : BaseStoreHub<AddCustomTokenState>("AddCustomT
private fun tokenIsSupported(blockchain: Blockchain): Boolean = when (blockchain) {
Blockchain.Unknown -> true
else -> globalState.scanResponse?.card?.canHandleToken(blockchain) ?: false
else -> {
val scanResponse = globalState.scanResponse
scanResponse?.card?.canHandleToken(
blockchain = blockchain,
cardTypesResolver = scanResponse.cardTypesResolver,
) ?: false
}
}
@Throws
@ -547,8 +554,9 @@ private class AddCustomTokenReducer(
state.copy(onTokenAddCallback = action.callback)
}
is OnCreate -> {
val card = requireNotNull(globalState.scanResponse?.card)
val supportedTokenNetworkIds = card.supportedBlockchains()
val scanResponse = requireNotNull(globalState.scanResponse)
val card = globalState.scanResponse.card
val supportedTokenNetworkIds = card.supportedBlockchains(scanResponse.cardTypesResolver)
.filter(Blockchain::canHandleTokens)
.map(Blockchain::toNetworkId)
@ -559,15 +567,22 @@ private class AddCustomTokenReducer(
)
state.copy(
cardDerivationStyle = globalState.scanResponse?.derivationStyleProvider?.getDerivationStyle(),
form = Form(AddCustomTokenState.createFormFields(card, CustomTokenType.Blockchain)),
cardDerivationStyle = globalState.scanResponse.derivationStyleProvider.getDerivationStyle(),
form = Form(
AddCustomTokenState.createFormFields(
cardTypesResolver = globalState.scanResponse.cardTypesResolver,
card = card,
type = CustomTokenType.Blockchain,
),
),
tangemTechServiceManager = tangemTechServiceManager,
screenState = createInitialScreenState(card.settings.isHDWalletAllowed),
)
}
is OnDestroy -> {
val card = requireNotNull(globalState.scanResponse?.card)
state.reset(card)
val scanResponse = requireNotNull(globalState.scanResponse)
val card = scanResponse.card
state.reset(scanResponse.cardTypesResolver, card)
}
is UpdateForm -> {
updateFormState(action.state)

View file

@ -6,6 +6,7 @@ import com.tangem.common.json.MoshiJsonConverter
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
import com.tangem.domain.AddCustomTokenError
import com.tangem.domain.DomainWrapped
import com.tangem.domain.common.CardTypesResolver
import com.tangem.domain.common.TapWorkarounds.isTestCard
import com.tangem.domain.common.extensions.derivationPath
import com.tangem.domain.common.extensions.isSupportedInApp
@ -113,12 +114,12 @@ data class AddCustomTokenState(
null
}
fun reset(card: CardDTO): AddCustomTokenState {
fun reset(cardTypesResolver: CardTypesResolver, card: CardDTO): AddCustomTokenState {
return this.copy(
appSavedCurrencies = null,
onTokenAddCallback = null,
cardDerivationStyle = null,
form = Form(createFormFields(card, CustomTokenType.Blockchain)),
form = Form(createFormFields(cardTypesResolver, card, CustomTokenType.Blockchain)),
formErrors = emptyMap(),
foundToken = null,
warnings = emptySet(),
@ -165,10 +166,14 @@ data class AddCustomTokenState(
}.derivationPath(derivationStyleToUse)
}
internal fun createFormFields(card: CardDTO, type: CustomTokenType): List<DataField<*>> {
internal fun createFormFields(
cardTypesResolver: CardTypesResolver,
card: CardDTO,
type: CustomTokenType,
): List<DataField<*>> {
return listOf(
TokenField(ContractAddress),
TokenBlockchainField(Network, getNetworksList(card, type)),
TokenBlockchainField(Network, getNetworksList(cardTypesResolver, card, type)),
TokenField(Name),
TokenField(Symbol),
TokenField(Decimals),
@ -180,7 +185,11 @@ data class AddCustomTokenState(
* Serves to determine the networks (blockchains & tokens) that can be selected by Form.Networks.
* Blockchain.Unknown - is the default selection
*/
private fun getNetworksList(card: CardDTO, type: CustomTokenType): List<Blockchain> {
private fun getNetworksList(
cardTypesResolver: CardTypesResolver,
card: CardDTO,
type: CustomTokenType,
): List<Blockchain> {
val evmBlockchains = Blockchain.values()
.filter { it.isEvm() }
.filter { card.isTestCard == it.isTestnet() }
@ -195,8 +204,8 @@ data class AddCustomTokenState(
)
val supportedByCard = when (type) {
CustomTokenType.Blockchain -> card.supportedBlockchains()
CustomTokenType.Token -> card.supportedTokens()
CustomTokenType.Blockchain -> card.supportedBlockchains(cardTypesResolver)
CustomTokenType.Token -> card.supportedTokens(cardTypesResolver)
}
val typedNetworksList = (evmBlockchains + additionalBlockchains)
.filter { supportedByCard.contains(it) }