Updated on 2026-08-14
This commit is contained in:
parent
cd02ce7bc0
commit
e421ca8d32
11 changed files with 160 additions and 31 deletions
|
|
@ -1,5 +1,7 @@
|
|||
package com.tangem.tap.features.customtoken.impl.presentation.routers
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
|
||||
/**
|
||||
* Custom token feature router
|
||||
*
|
||||
|
|
@ -12,4 +14,10 @@ internal interface CustomTokenRouter {
|
|||
|
||||
/** Open wallet (main) screen */
|
||||
fun openWalletScreen()
|
||||
|
||||
/** Open alert if solana network is unsupported
|
||||
*
|
||||
* @param blockchain blockchain to show alert
|
||||
*/
|
||||
fun openUnsupportedNetworkAlert(blockchain: Blockchain)
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
package com.tangem.tap.features.customtoken.impl.presentation.routers
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.core.navigation.AppScreen
|
||||
import com.tangem.core.navigation.NavigationAction
|
||||
import com.tangem.tap.common.extensions.dispatchDialogShow
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
|
||||
/** Default implementation of custom token feature router */
|
||||
internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
||||
|
|
@ -14,4 +18,13 @@ internal class DefaultCustomTokenRouter : CustomTokenRouter {
|
|||
override fun openWalletScreen() {
|
||||
store.dispatch(NavigationAction.PopBackTo(screen = AppScreen.Wallet))
|
||||
}
|
||||
|
||||
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
||||
val alert = AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_curve_message,
|
||||
args = listOf(blockchain.fullName),
|
||||
)
|
||||
store.dispatchDialogShow(alert)
|
||||
}
|
||||
}
|
||||
|
|
@ -635,6 +635,15 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
return derivationNetwork.derivationPath(derivationStyle)
|
||||
}
|
||||
|
||||
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val canHandleToken = scanResponse?.card?.canHandleBlockchain(
|
||||
blockchain = blockchain,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
) ?: false
|
||||
return !canHandleToken
|
||||
}
|
||||
|
||||
private inner class ActionsHandler(private val featureRouter: CustomTokenRouter) {
|
||||
|
||||
fun onBackButtonClick() {
|
||||
|
|
@ -747,6 +756,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
|
||||
fun onAddCustomTokenClick() {
|
||||
if (!isNetworkSelected()) return
|
||||
val blockchain = uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
if (isUnsupportedBlockchain(blockchain)) {
|
||||
featureRouter.openUnsupportedNetworkAlert(blockchain)
|
||||
return
|
||||
}
|
||||
|
||||
val currency = when (getCustomTokenType()) {
|
||||
CustomTokenType.TOKEN -> {
|
||||
|
|
@ -758,13 +772,13 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
decimals = requireNotNull(uiState.form.decimalsInputField.value.toIntOrNull()),
|
||||
id = foundToken?.id,
|
||||
),
|
||||
network = uiState.form.networkSelectorField.selectedItem.blockchain,
|
||||
network = blockchain,
|
||||
derivationPath = getDerivationPath(),
|
||||
)
|
||||
}
|
||||
CustomTokenType.BLOCKCHAIN -> {
|
||||
CustomCurrency.CustomBlockchain(
|
||||
network = uiState.form.networkSelectorField.selectedItem.blockchain,
|
||||
network = blockchain,
|
||||
derivationPath = getDerivationPath(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package com.tangem.tap.features.tokens.impl.presentation.models
|
||||
|
||||
/**
|
||||
* State that shows is token support by given card
|
||||
*/
|
||||
sealed class SupportTokensState {
|
||||
|
||||
object SolanaNetworkUnsupported : SupportTokensState()
|
||||
object UnsupportedCurve : SupportTokensState()
|
||||
object SupportedToken : SupportTokensState()
|
||||
}
|
||||
|
|
@ -51,17 +51,20 @@ internal class DefaultTokensListRouter(
|
|||
}
|
||||
|
||||
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
||||
val alert = when (blockchain) {
|
||||
Blockchain.Solana -> AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_message,
|
||||
)
|
||||
else -> AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_curve_message,
|
||||
args = listOf(blockchain.fullName),
|
||||
)
|
||||
}
|
||||
val alert = AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_curve_message,
|
||||
args = listOf(blockchain.fullName),
|
||||
)
|
||||
store.dispatchDialogShow(alert)
|
||||
}
|
||||
|
||||
override fun openSolanaTokensNotSupportAlert() {
|
||||
store.dispatchDialogShow(
|
||||
AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_message,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -35,4 +35,9 @@ internal interface TokensListRouter {
|
|||
* @param blockchain blockchain to show alert
|
||||
*/
|
||||
fun openUnsupportedNetworkAlert(blockchain: Blockchain)
|
||||
|
||||
/**
|
||||
* Open alert with Solana tokens error
|
||||
*/
|
||||
fun openSolanaTokensNotSupportAlert()
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ import com.tangem.domain.common.TapWorkarounds.useOldStyleDerivation
|
|||
import com.tangem.domain.common.extensions.canHandleBlockchain
|
||||
import com.tangem.domain.common.extensions.canHandleToken
|
||||
import com.tangem.domain.common.extensions.fromNetworkId
|
||||
import com.tangem.domain.common.extensions.supportedTokens
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.tap.common.extensions.fullNameWithoutTestnet
|
||||
import com.tangem.tap.common.extensions.getGreyedOutIconRes
|
||||
|
|
@ -24,6 +25,7 @@ import com.tangem.tap.common.extensions.getNetworkName
|
|||
import com.tangem.tap.features.tokens.impl.domain.TokensListInteractor
|
||||
import com.tangem.tap.features.tokens.impl.domain.models.Token
|
||||
import com.tangem.tap.features.tokens.impl.domain.models.Token.Network
|
||||
import com.tangem.tap.features.tokens.impl.presentation.models.SupportTokensState
|
||||
import com.tangem.tap.features.tokens.impl.presentation.models.TokensListArgs
|
||||
import com.tangem.tap.features.tokens.impl.presentation.router.TokensListRouter
|
||||
import com.tangem.tap.features.tokens.impl.presentation.states.NetworkItemState
|
||||
|
|
@ -42,6 +44,7 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.plus
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import com.tangem.blockchain.common.Token as BlockchainToken
|
||||
|
||||
|
|
@ -355,24 +358,38 @@ internal class TokensListViewModel @Inject constructor(
|
|||
toggledNetwork.changeToggleState()
|
||||
}
|
||||
} else {
|
||||
if (isUnsupportedToken(token.blockchain)) {
|
||||
router.openUnsupportedNetworkAlert(token.blockchain)
|
||||
} else {
|
||||
analyticsSender.sendWhenTokenAdded(token.token)
|
||||
changedTokensList.add(token)
|
||||
toggledNetwork.changeToggleState()
|
||||
when (isUnsupportedToken(token.blockchain)) {
|
||||
SupportTokensState.SolanaNetworkUnsupported -> router.openSolanaTokensNotSupportAlert()
|
||||
SupportTokensState.SupportedToken -> {
|
||||
analyticsSender.sendWhenTokenAdded(token.token)
|
||||
changedTokensList.add(token)
|
||||
toggledNetwork.changeToggleState()
|
||||
}
|
||||
SupportTokensState.UnsupportedCurve -> router.openUnsupportedNetworkAlert(token.blockchain)
|
||||
null -> Timber.e("Something went wrong in isUnsupportedToken (no scanResponse found)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isUnsupportedToken(blockchain: Blockchain): Boolean {
|
||||
private fun isUnsupportedToken(blockchain: Blockchain): SupportTokensState? {
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val canHandleToken = scanResponse?.card?.canHandleToken(
|
||||
val cardTypesResolver = scanResponse?.cardTypesResolver ?: return null
|
||||
val supportedTokens = scanResponse.card.supportedTokens(cardTypesResolver)
|
||||
|
||||
// refactor this later by moving all this logic in card config
|
||||
if (!supportedTokens.contains(Blockchain.Solana)) {
|
||||
return SupportTokensState.SolanaNetworkUnsupported
|
||||
}
|
||||
val canHandleToken = scanResponse.card.canHandleToken(
|
||||
supportedTokens = supportedTokens,
|
||||
blockchain = blockchain,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
) ?: false
|
||||
return !canHandleToken
|
||||
cardTypesResolver = cardTypesResolver,
|
||||
)
|
||||
if (!canHandleToken) {
|
||||
return SupportTokensState.UnsupportedCurve
|
||||
}
|
||||
return SupportTokensState.SupportedToken
|
||||
}
|
||||
|
||||
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ sealed interface CardConfig {
|
|||
if (cardDTO.settings.isBackupAllowed && cardDTO.settings.isHDWalletAllowed &&
|
||||
cardDTO.firmwareVersion >= FirmwareVersion.MultiWalletAvailable
|
||||
) {
|
||||
return GenericCardConfig
|
||||
return MultiWalletCardConfig
|
||||
}
|
||||
return GenericCardConfig
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@ object GenericCardConfig : CardConfig {
|
|||
get() = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
)
|
||||
|
||||
/**
|
||||
* Old logic to determine primary curve for blockchain in TangemWallet
|
||||
* Old logic to determine primary curve for blockchain
|
||||
*/
|
||||
override fun primaryCurve(blockchain: Blockchain): EllipticCurve? {
|
||||
return when {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.domain.common.configs
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.card.EllipticCurve
|
||||
import timber.log.Timber
|
||||
|
||||
object MultiWalletCardConfig : CardConfig {
|
||||
override val mandatoryCurves: List<EllipticCurve>
|
||||
get() = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bls12381G2Aug,
|
||||
)
|
||||
|
||||
/**
|
||||
* Old logic to determine primary curve for blockchain in TangemWallet
|
||||
*/
|
||||
override fun primaryCurve(blockchain: Blockchain): EllipticCurve? {
|
||||
return when {
|
||||
blockchain.getSupportedCurves().contains(EllipticCurve.Secp256k1) -> {
|
||||
EllipticCurve.Secp256k1
|
||||
}
|
||||
blockchain.getSupportedCurves().contains(EllipticCurve.Ed25519) -> {
|
||||
EllipticCurve.Ed25519
|
||||
}
|
||||
blockchain.getSupportedCurves().contains(EllipticCurve.Bls12381G2Aug) -> {
|
||||
EllipticCurve.Bls12381G2Aug
|
||||
}
|
||||
else -> {
|
||||
Timber.e("Unsupported blockchain, curve not found")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ 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.configs.CardConfig
|
||||
import com.tangem.domain.models.scan.CardDTO
|
||||
|
||||
/**
|
||||
|
|
@ -52,10 +53,32 @@ fun CardDTO.supportedTokens(cardTypesResolver: CardTypesResolver): List<Blockcha
|
|||
return tokensSupportedByCard.filter { isTestCard == it.isTestnet() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as [CardDTO.supportedTokens] but with supportedTokens input, if previously calculated
|
||||
*/
|
||||
fun CardDTO.canHandleToken(
|
||||
supportedTokens: List<Blockchain>,
|
||||
blockchain: Blockchain,
|
||||
cardTypesResolver: CardTypesResolver,
|
||||
): Boolean {
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = supportedTokens.contains(blockchain)
|
||||
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
|
||||
// fixme: check for first wallets with 1 curve and remove condition
|
||||
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {
|
||||
// if there's no wallet on card for blockchain with given curve
|
||||
isContainsBlockchain && isWalletForCurveExists
|
||||
} else {
|
||||
isContainsBlockchain
|
||||
}
|
||||
}
|
||||
|
||||
fun CardDTO.canHandleToken(blockchain: Blockchain, cardTypesResolver: CardTypesResolver): Boolean {
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = this.supportedTokens(cardTypesResolver).contains(blockchain)
|
||||
val isWalletForCurveExists =
|
||||
wallets.map { it.curve }.intersect(blockchain.getSupportedCurves().toSet()).isNotEmpty()
|
||||
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
|
||||
// fixme: check for first wallets with 1 curve and remove condition
|
||||
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {
|
||||
// if there's no wallet on card for blockchain with given curve
|
||||
|
|
@ -66,9 +89,10 @@ fun CardDTO.canHandleToken(blockchain: Blockchain, cardTypesResolver: CardTypesR
|
|||
}
|
||||
|
||||
fun CardDTO.canHandleBlockchain(blockchain: Blockchain, cardTypesResolver: CardTypesResolver): Boolean {
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = this.supportedBlockchains(cardTypesResolver).contains(blockchain)
|
||||
val isWalletForCurveExists =
|
||||
wallets.map { it.curve }.intersect(blockchain.getSupportedCurves().toSet()).isNotEmpty()
|
||||
val isWalletForCurveExists = wallets.any { it.curve == primaryCurveForBlockchain }
|
||||
// fixme: check for first wallets with 1 curve and remove condition
|
||||
return if (cardTypesResolver.isTangemWallet() || cardTypesResolver.isWallet2()) {
|
||||
// if there's no wallet on card for blockchain with given curve
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue