Updated on 2026-08-14
This commit is contained in:
commit
4c8267738b
31 changed files with 373 additions and 124 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 8c1c53b73950698d4acfa4d925b8c14bf6f0da63
|
||||
Subproject commit b84b1e1ab11b0eb0f6ca6e28f551f9e2ca6809fe
|
||||
|
|
@ -215,6 +215,13 @@ class MainActivity : AppCompatActivity(), SnackbarHandler, ActivityResultCallbac
|
|||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
|
||||
/*
|
||||
* FIXME: Test functionality. TangemSdk is null on some devices when HomeAction.Read is called
|
||||
* inside IntentHandler.
|
||||
*/
|
||||
cardSdkLifecycleObserver.onCreate(context = this)
|
||||
|
||||
scope.launch {
|
||||
intentProcessor.handleIntent(intent)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.tangem.blockchain.blockchains.cardano.CardanoUtils
|
|||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.common.CompletionResult
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.common.card.FirmwareVersion
|
||||
import com.tangem.common.core.CardSession
|
||||
import com.tangem.common.core.CardSessionRunnable
|
||||
import com.tangem.common.core.TangemError
|
||||
|
|
@ -54,7 +55,7 @@ class ScanProductTask(
|
|||
}
|
||||
val cardDto = CardDTO(card)
|
||||
|
||||
val error = getErrorIfExcludedCard(cardDto)
|
||||
val error = getErrorIfExcludedCard(cardDto, card)
|
||||
if (error != null) {
|
||||
callback(CompletionResult.Failure(error))
|
||||
return
|
||||
|
|
@ -84,9 +85,15 @@ class ScanProductTask(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO): TangemError? {
|
||||
private fun getErrorIfExcludedCard(cardDto: CardDTO, card: Card): TangemError? {
|
||||
if (cardDto.isExcluded) return TapSdkError.CardForDifferentApp
|
||||
if (cardDto.isNotSupportedInThatRelease) return TapSdkError.CardNotSupportedByRelease
|
||||
// according ios decline card lower Ed25519Slip0010Available version and contains imported wallets
|
||||
if (card.firmwareVersion < FirmwareVersion.Ed25519Slip0010Available &&
|
||||
card.wallets.any { it.isImported }
|
||||
) {
|
||||
return TapSdkError.CardNotSupportedByRelease
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import android.os.Bundle
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.addCallback
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.MenuHost
|
||||
import androidx.core.view.MenuProvider
|
||||
|
|
@ -71,13 +71,11 @@ interface FragmentOnBackPressedHandler {
|
|||
|
||||
@SuppressLint("FragmentBackPressedCallback")
|
||||
fun Fragment.addBackPressHandler(handler: FragmentOnBackPressedHandler) {
|
||||
activity?.onBackPressedDispatcher?.addCallback(
|
||||
this,
|
||||
object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
handler.handleOnBackPressed()
|
||||
}
|
||||
},
|
||||
)
|
||||
view?.findViewById<Toolbar>(R.id.toolbar)?.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
requireActivity().onBackPressedDispatcher.addCallback {
|
||||
handler.handleOnBackPressed()
|
||||
}
|
||||
|
||||
view?.findViewById<Toolbar>(R.id.toolbar)?.setNavigationOnClickListener {
|
||||
handler.handleOnBackPressed()
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -12,11 +12,11 @@ import androidx.lifecycle.ViewModel
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.blockchain.common.derivation.DerivationStyle
|
||||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.crypto.hdWallet.HDWalletError
|
||||
import com.tangem.domain.AddCustomTokenError
|
||||
import com.tangem.domain.common.DerivationStyleProvider
|
||||
import com.tangem.domain.common.extensions.*
|
||||
import com.tangem.domain.common.util.cardTypesResolver
|
||||
import com.tangem.domain.common.util.derivationStyleProvider
|
||||
|
|
@ -145,6 +145,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
fun createDerivationPathSelectorAdditionalItem(
|
||||
blockchain: Blockchain,
|
||||
type: DerivationPathSelectorType = DerivationPathSelectorType.BLOCKCHAIN,
|
||||
derivationPath: String,
|
||||
): SelectorItem.TitleWithSubtitle {
|
||||
return when (type) {
|
||||
DerivationPathSelectorType.DEFAULT -> SelectorItem.TitleWithSubtitle(
|
||||
|
|
@ -160,8 +161,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
type = DerivationPathSelectorType.CUSTOM,
|
||||
)
|
||||
DerivationPathSelectorType.BLOCKCHAIN -> SelectorItem.TitleWithSubtitle(
|
||||
title = blockchain.derivationPath(DerivationStyle.LEGACY)?.rawPath?.let(TextReference::Str)
|
||||
?: TextReference.Res(R.string.custom_token_derivation_path_default),
|
||||
title = TextReference.Str(derivationPath),
|
||||
subtitle = TextReference.Str(blockchain.fullName),
|
||||
blockchain = blockchain,
|
||||
)
|
||||
|
|
@ -208,10 +208,12 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
private fun getNetworkSelectorItems(): List<SelectorItem.Title> {
|
||||
val defaultNetwork = createNetworkSelectorItem(blockchain = Blockchain.Unknown)
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val derivationStyle = scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
return listOf(defaultNetwork) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
scanResponse?.card?.supportedBlockchains(scanResponse.cardTypesResolver)
|
||||
?.contains(blockchain) == true
|
||||
?.contains(blockchain) == true &&
|
||||
blockchain.derivationPath(derivationStyle)?.rawPath?.isNotEmpty() == true
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createNetworkSelectorItem)
|
||||
|
|
@ -251,9 +253,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun createDerivationPathsSelectorField(): AddCustomTokenSelectorField.DerivationPath? {
|
||||
if (reduxStateHolder.scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
if (scanResponse?.card?.settings?.isHDWalletAllowed == false) return null
|
||||
|
||||
val selectorItems = getDerivationPathsSelectorItems()
|
||||
val selectorItems =
|
||||
getDerivationPathsSelectorItems(scanResponse?.derivationStyleProvider)
|
||||
return AddCustomTokenSelectorField.DerivationPath(
|
||||
label = TextReference.Res(R.string.custom_token_derivation_path_input_title),
|
||||
selectedItem = requireNotNull(selectorItems.firstOrNull()),
|
||||
|
|
@ -263,22 +267,37 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun getDerivationPathsSelectorItems(): List<SelectorItem.TitleWithSubtitle> {
|
||||
private fun getDerivationPathsSelectorItems(
|
||||
derivationStyleProvider: DerivationStyleProvider?,
|
||||
): List<SelectorItem.TitleWithSubtitle> {
|
||||
val derivationStyle = derivationStyleProvider?.getDerivationStyle()
|
||||
return listOf(
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
derivationPath = "",
|
||||
),
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.CUSTOM,
|
||||
derivationPath = "",
|
||||
),
|
||||
) + Blockchain.values()
|
||||
.filter { blockchain ->
|
||||
blockchain.isSupportedInApp() && !blockchain.isTestnet()
|
||||
}
|
||||
.sortedBy(Blockchain::fullName)
|
||||
.map(::createDerivationPathSelectorAdditionalItem)
|
||||
.mapNotNull {
|
||||
val derivationPath = it.derivationPath(derivationStyle)?.rawPath
|
||||
if (derivationPath?.isNotEmpty() == true) {
|
||||
createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = it,
|
||||
derivationPath = derivationPath,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDerivationPathInputField(): AddCustomTokenInputField.DerivationPath? {
|
||||
|
|
@ -608,11 +627,8 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
private fun getDerivationPathForBlockchain(blockchain: Blockchain?): DerivationPath? {
|
||||
if (blockchain == null) return null
|
||||
|
||||
val derivationStyle = if (!isDerivationPathSelected()) {
|
||||
reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
} else {
|
||||
DerivationStyle.LEGACY
|
||||
}
|
||||
val derivationStyle = reduxStateHolder.scanResponse?.derivationStyleProvider?.getDerivationStyle()
|
||||
|
||||
val derivationNetwork = if (blockchain == Blockchain.Unknown) {
|
||||
uiState.form.networkSelectorField.selectedItem.blockchain
|
||||
} else {
|
||||
|
|
@ -621,6 +637,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() {
|
||||
|
|
@ -733,6 +758,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 -> {
|
||||
|
|
@ -744,13 +774,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(),
|
||||
)
|
||||
}
|
||||
|
|
@ -782,6 +812,7 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun onResetButtonClick() {
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
with(uiState.form) {
|
||||
uiState = uiState.copySealed(
|
||||
form = uiState.form.copy(
|
||||
|
|
@ -799,11 +830,11 @@ internal class AddCustomTokenViewModel @Inject constructor(
|
|||
decimalsInputField = decimalsInputField.copy(value = "", isEnabled = false),
|
||||
derivationPathSelectorField = derivationPathSelectorField?.copy(
|
||||
isEnabled = true,
|
||||
selectedItem = formStateBuilder
|
||||
.createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
),
|
||||
selectedItem = formStateBuilder.createDerivationPathSelectorAdditionalItem(
|
||||
blockchain = Blockchain.Unknown,
|
||||
type = DerivationPathSelectorType.DEFAULT,
|
||||
derivationPath = "",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ internal class OnboardingSeedPhraseStateHandler(
|
|||
|
||||
private fun setMainScreenToolbarTitle(walletFragment: OnboardingWalletFragment, subScreen: SeedPhraseScreen) {
|
||||
val titleResId = when (subScreen) {
|
||||
SeedPhraseScreen.Intro,
|
||||
SeedPhraseScreen.Intro -> R.string.wallet_title
|
||||
SeedPhraseScreen.AboutSeedPhrase,
|
||||
SeedPhraseScreen.YourSeedPhrase,
|
||||
SeedPhraseScreen.CheckSeedPhrase,
|
||||
|
|
|
|||
|
|
@ -97,8 +97,7 @@ class OnboardingWalletFragment :
|
|||
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
|
||||
binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
addBackPressHandler(this)
|
||||
addBackPressHandler(handler = this)
|
||||
|
||||
store.dispatch(OnboardingWallet2Action.Init(seedPhraseViewModel.maxProgress))
|
||||
store.dispatch(OnboardingWalletAction.Init)
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@ import com.tangem.wallet.R
|
|||
object ResetBackupCardDialog {
|
||||
fun create(context: Context, cardId: String): AlertDialog {
|
||||
return AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.common_warning)
|
||||
setTitle(R.string.common_attention)
|
||||
setMessage(R.string.onboarding_linking_error_card_with_wallets)
|
||||
setPositiveButton(R.string.common_continue) { _, _ ->
|
||||
store.dispatch(BackupAction.ResetBackupCard(cardId))
|
||||
setPositiveButton(R.string.common_cancel) { _, _ ->
|
||||
/* no-op */
|
||||
}
|
||||
setNegativeButton(R.string.common_cancel) { _, _ ->
|
||||
setNegativeButton(R.string.common_reset) { _, _ ->
|
||||
store.dispatch(BackupAction.ResetBackupCard(cardId))
|
||||
}
|
||||
setOnDismissListener {
|
||||
store.dispatch(GlobalAction.HideDialog)
|
||||
|
|
|
|||
|
|
@ -261,19 +261,34 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun handleFeeState(fg: SendFragment, state: FeeState) = with(fg.binding.clNetworkFee) {
|
||||
fg.view?.findViewById<ViewGroup>(R.id.clNetworkFee)?.show(state.mainLayoutIsVisible)
|
||||
flExpandCollapse.imvExpandCollapse.rotation = if (state.controlsLayoutIsVisible) 0f else 180f
|
||||
llFeeControlsContainer.show(state.controlsLayoutIsVisible)
|
||||
chipGroup.show(state.feeChipGroupIsVisible)
|
||||
private fun handleFeeState(fg: SendFragment, state: FeeState) {
|
||||
with(fg.binding.clNetworkFee) {
|
||||
fg.view?.findViewById<ViewGroup>(R.id.clNetworkFee)?.show(state.mainLayoutIsVisible)
|
||||
flExpandCollapse.imvExpandCollapse.rotation = if (state.controlsLayoutIsVisible) 0f else 180f
|
||||
llFeeControlsContainer.show(state.controlsLayoutIsVisible)
|
||||
chipGroup.show(state.feeChipGroupIsVisible)
|
||||
|
||||
swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled
|
||||
if (swIncludeFee.isChecked != state.feeIsIncluded) {
|
||||
swIncludeFee.isChecked = state.feeIsIncluded
|
||||
swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled
|
||||
if (swIncludeFee.isChecked != state.feeIsIncluded) {
|
||||
swIncludeFee.isChecked = state.feeIsIncluded
|
||||
}
|
||||
|
||||
val chipId = FeeUiHelper.toId(state.selectedFeeType)
|
||||
if (chipGroup.checkedChipId != chipId && chipId != View.NO_ID) chipGroup.check(chipId)
|
||||
}
|
||||
with(fg.binding.clReceiptContainer) {
|
||||
when (state.progressState) {
|
||||
ProgressState.Loading -> {
|
||||
tvReceiptFeeValue.hide()
|
||||
pbReceiptFee.show()
|
||||
}
|
||||
ProgressState.Done -> {
|
||||
pbReceiptFee.hide()
|
||||
tvReceiptFeeValue.show()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
val chipId = FeeUiHelper.toId(state.selectedFeeType)
|
||||
if (chipGroup.checkedChipId != chipId && chipId != View.NO_ID) chipGroup.check(chipId)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "ComplexMethod")
|
||||
|
|
|
|||
|
|
@ -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,20 +51,20 @@ internal class DefaultTokensListRouter(
|
|||
}
|
||||
|
||||
override fun openUnsupportedNetworkAlert(blockchain: Blockchain) {
|
||||
val alert = when (blockchain) {
|
||||
Blockchain.Solana -> AppDialog.SimpleOkDialogRes(
|
||||
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,
|
||||
)
|
||||
Blockchain.Chia, Blockchain.ChiaTestnet -> AppDialog.SimpleOkDialogRes(
|
||||
headerId = R.string.common_warning,
|
||||
messageId = R.string.alert_manage_tokens_unsupported_curve_message,
|
||||
args = listOf(blockchain.fullName),
|
||||
)
|
||||
else -> null // there's no alerts for other blockchains yer
|
||||
}
|
||||
if (alert != null) {
|
||||
store.dispatchDialogShow(alert)
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -14,8 +14,10 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.core.analytics.api.AnalyticsEventHandler
|
||||
import com.tangem.core.ui.extensions.getActiveIconRes
|
||||
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
|
||||
|
|
@ -23,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
|
||||
|
|
@ -41,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
|
||||
|
||||
|
|
@ -309,7 +313,7 @@ internal class TokensListViewModel @Inject constructor(
|
|||
toggledNetwork.changeToggleState()
|
||||
}
|
||||
} else {
|
||||
if (isUnsupportedToken(blockchain)) {
|
||||
if (isUnsupportedBlockchain(blockchain)) {
|
||||
router.openUnsupportedNetworkAlert(blockchain)
|
||||
} else {
|
||||
analyticsSender.sendWhenBlockchainAdded(blockchain)
|
||||
|
|
@ -354,20 +358,43 @@ 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 = cardTypesResolver,
|
||||
)
|
||||
if (!canHandleToken) {
|
||||
return SupportTokensState.UnsupportedCurve
|
||||
}
|
||||
return SupportTokensState.SupportedToken
|
||||
}
|
||||
|
||||
private fun isUnsupportedBlockchain(blockchain: Blockchain): Boolean {
|
||||
val scanResponse = reduxStateHolder.scanResponse
|
||||
val canHandleToken = scanResponse?.card?.canHandleBlockchain(
|
||||
blockchain = blockchain,
|
||||
cardTypesResolver = scanResponse.cardTypesResolver,
|
||||
) ?: false
|
||||
|
|
|
|||
|
|
@ -424,6 +424,7 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), SafeSt
|
|||
is WalletDataModel.SameCurrencyTransactionInProgress,
|
||||
-> {
|
||||
lBalance.tvStatus.setVerifiedBalanceStatus(R.string.wallet_balance_verified)
|
||||
showPendingTransactionsIfPresent(status.pendingTransactions)
|
||||
}
|
||||
|
||||
is WalletDataModel.TransactionInProgress -> {
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ internal class ConfigManagerImpl @Inject constructor() : ConfigManager {
|
|||
testnetApiKey = configValues.tonCenterKeys.testnet,
|
||||
),
|
||||
chiaFireAcademyApiKey = configValues.chiaFireAcademyApiKey,
|
||||
chiaTangemApiKey = configValues.chiaTangemApiKey,
|
||||
),
|
||||
appsFlyerDevKey = configValues.appsFlyer.appsFlyerDevKey,
|
||||
amplitudeApiKey = configValues.amplitudeApiKey,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class ConfigValueModel(
|
|||
val walletConnectProjectId: String,
|
||||
val tangemComAuthorization: String?,
|
||||
val chiaFireAcademyApiKey: String?,
|
||||
val chiaTangemApiKey: String?,
|
||||
)
|
||||
|
||||
data class AppsFlyer(
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@
|
|||
<string name="card_settings_access_code_recovery_enabled_description">Использовать эту карту для сброса кода доступа на других картах в этом кошельке</string>
|
||||
<string name="card_settings_access_code_recovery_footer">Отключить возможность сброса кода доступа на этой карте или других картах этого кошелька</string>
|
||||
<string name="card_settings_access_code_recovery_title">Восстановление кода доступа</string>
|
||||
<string name="card_settings_action_sheet_reset">Сбросить</string>
|
||||
<string name="card_settings_action_sheet_title">Вы уверены, что хотите это сделать?</string>
|
||||
<string name="card_settings_change_access_code">Смена кода доступа</string>
|
||||
<string name="card_settings_change_access_code_footer">Код доступа будет изменен только на данной карте</string>
|
||||
|
|
@ -101,7 +100,7 @@
|
|||
<string name="common_save_changes">Сохранить изменения</string>
|
||||
<string name="common_search">Искать</string>
|
||||
<string name="common_search_tokens">Поиск токенов</string>
|
||||
<string name="common_seed_phrase">Секретная фраза</string>
|
||||
<string name="common_seed_phrase">Seed-фраза</string>
|
||||
<string name="common_select_action">Выберите действие</string>
|
||||
<string name="common_sell">Продать</string>
|
||||
<string name="common_send">Отправить</string>
|
||||
|
|
@ -252,18 +251,18 @@
|
|||
<string name="onboarding_navbar_pin">Код доступа</string>
|
||||
<string name="onboarding_navbar_register_wallet">Подключиться</string>
|
||||
<string name="onboarding_navbar_title_creating_backup">Резервная копия</string>
|
||||
<string name="onboarding_seed_button_read_more">Прочитать о секретной фразе</string>
|
||||
<string name="onboarding_seed_button_read_more">Прочитать о seed-фразе</string>
|
||||
<string name="onboarding_seed_generate_message">Запишите эти 12 слов в порядке, указанном ниже, и сохраните их в надежном месте.</string>
|
||||
<string name="onboarding_seed_generate_title">Ваша секретная фраза</string>
|
||||
<string name="onboarding_seed_import_message">Чтобы импортировать кошелек, введите секретную фразу в поле ниже</string>
|
||||
<string name="onboarding_seed_intro_button_generate">Cоздать секретную фразу</string>
|
||||
<string name="onboarding_seed_generate_title">Ваша seed-фраза</string>
|
||||
<string name="onboarding_seed_import_message">Чтобы импортировать кошелек, введите seed-фразу в поле ниже</string>
|
||||
<string name="onboarding_seed_intro_button_generate">Создать seed-фразу</string>
|
||||
<string name="onboarding_seed_intro_button_import">Импорт кошелька</string>
|
||||
<string name="onboarding_seed_intro_message">Секретная фраза — это набор слов, который дает возможность восстановить кошелек. В отличие от ключей, сгенерированных картой, seed-фраза не защищена и может быть скопирована и украдена. Используйте этот вариант на свой страх и риск.</string>
|
||||
<string name="onboarding_seed_intro_title">Использовать секретную фразу</string>
|
||||
<string name="onboarding_seed_mnemonic_invalid_checksum">Неверная секретная фраза. Пожалуйста, проверьте порядок слов.</string>
|
||||
<string name="onboarding_seed_mnemonic_wrong_words">Неверная секретная фраза. Пожалуйста, проверьте орфографию.</string>
|
||||
<string name="onboarding_seed_intro_message">Seed-фраза — это набор слов, который дает возможность восстановить кошелек. В отличие от ключей, сгенерированных картой, seed-фраза не защищена и может быть скопирована и украдена. Используйте этот вариант на свой страх и риск.</string>
|
||||
<string name="onboarding_seed_intro_title">Использовать seed-фразу</string>
|
||||
<string name="onboarding_seed_mnemonic_invalid_checksum">Неверная seed-фраза. Пожалуйста, проверьте порядок слов.</string>
|
||||
<string name="onboarding_seed_mnemonic_wrong_words">Неверная seed-фраза. Пожалуйста, проверьте орфографию.</string>
|
||||
<string name="onboarding_seed_phrase_intro_legacy">Устаревший</string>
|
||||
<string name="onboarding_seed_user_validation_message">Чтобы проверить, правильно ли вы записали секретную фразу, введите 2-е, 7-е и 11-е слова</string>
|
||||
<string name="onboarding_seed_user_validation_message">Чтобы проверить, правильно ли вы записали seed-фразу, введите 2-е, 7-е и 11-е слова</string>
|
||||
<string name="onboarding_seed_user_validation_title">Итак, проверим</string>
|
||||
<string name="onboarding_subtitle_claim">Для начала работы просто запросите начисление wxDAI на свой кошелек</string>
|
||||
<string name="onboarding_subtitle_claim_progress">Это займет несколько секунд</string>
|
||||
|
|
@ -345,7 +344,7 @@
|
|||
<string name="reset_card_to_factory_warning_message">Я понимаю, что после выполнения этого действия у меня больше не будет доступа к текущему кошельку</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек или использовать данную карту для восстановления кода доступа.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">Сброс к заводским настройкам приведет к полному удалению кошелька с выбранной карты. Вы не сможете восстановить текущий кошелек.</string>
|
||||
<string name="russian_bank_card_warning_subtitle">У вас есть карта банка другой страны или платежной системы UnionPay?</string>
|
||||
<string name="russian_bank_card_warning_subtitle">У вас есть карта банка другой страны, а также вид на жительство или регистрация вне РФ?</string>
|
||||
<string name="russian_bank_card_warning_title">Карты банков РФ в данный момент не принимаются</string>
|
||||
<string name="save_user_wallet_agreement_access_description">Войдите в приложение и следите за своим балансом без сканирования карты</string>
|
||||
<string name="save_user_wallet_agreement_access_title">Доступ в приложение</string>
|
||||
|
|
@ -573,6 +572,6 @@
|
|||
<string name="welcome_interrupted_backup_discard_title">Это необратимое действие</string>
|
||||
<string name="welcome_unlock">Войти с %s</string>
|
||||
<string name="welcome_unlock_card">Сканировать карту</string>
|
||||
<string name="welcome_unlock_description">Используйте %s или код доступа для входа в приложение</string>
|
||||
<string name="welcome_unlock_description">Используйте %s или отсканируйте карту для входа в приложение</string>
|
||||
<string name="welcome_unlock_title">C возвращением!</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@
|
|||
<string name="card_settings_access_code_recovery_enabled_description">允許您使用此卡重置此錢包中其他卡上的訪問密碼</string>
|
||||
<string name="card_settings_access_code_recovery_footer">禁用重置此卡或此錢包中其他卡上的訪問密碼的功能</string>
|
||||
<string name="card_settings_access_code_recovery_title">恢復訪問密碼</string>
|
||||
<string name="card_settings_action_sheet_reset">重置</string>
|
||||
<string name="card_settings_action_sheet_title">您確定要這麼做嗎?</string>
|
||||
<string name="card_settings_change_access_code">更改訪問密碼</string>
|
||||
<string name="card_settings_change_access_code_footer">訪問密碼將僅在此卡上更改</string>
|
||||
|
|
@ -217,16 +216,10 @@
|
|||
<string name="onboarding_navbar_title_creating_backup">創建備份</string>
|
||||
<string name="onboarding_seed_button_read_more">閱讀更多關於助記詞的訊息</string>
|
||||
<string name="onboarding_seed_generate_message">按照下面給出的順序寫下這 12 個單詞,並將它們存放在安全秘密的地方。</string>
|
||||
<string name="onboarding_seed_generate_title">您的助記詞</string>
|
||||
<string name="onboarding_seed_import_message">要導入您的錢包,請在下面的字段中輸入您的助記詞</string>
|
||||
<string name="onboarding_seed_intro_button_generate">生成助記詞</string>
|
||||
<string name="onboarding_seed_intro_button_import">導入錢包</string>
|
||||
<string name="onboarding_seed_intro_message">註記詞是一系列能夠恢復錢包的單詞。與卡片生成的密鑰不同,助記詞不受保護,可以被複製和竊取。使用此選項需要您自擔風險。</string>
|
||||
<string name="onboarding_seed_intro_title">使用助記詞</string>
|
||||
<string name="onboarding_seed_mnemonic_invalid_checksum">無效的助記詞。請檢查單詞順序。</string>
|
||||
<string name="onboarding_seed_mnemonic_wrong_words">助記詞無效。請檢查您的拼寫。</string>
|
||||
<string name="onboarding_seed_phrase_intro_legacy">Legacy</string>
|
||||
<string name="onboarding_seed_user_validation_message">為了檢查您是否正確輸入了助記詞,請輸入第 2、7 和 11 個單詞</string>
|
||||
<string name="onboarding_seed_user_validation_title">那麼,讓我們檢查一下</string>
|
||||
<string name="onboarding_subtitle_claim">要開始,只需將 wxDAI 獲取到您的錢包</string>
|
||||
<string name="onboarding_subtitle_claim_progress">這會花上幾秒</string>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@
|
|||
<string name="card_settings_access_code_recovery_enabled_description">Allows you to use this card to reset access code on other cards in this wallet</string>
|
||||
<string name="card_settings_access_code_recovery_footer">Disable the ability to reset the access code on this card or other cards in this wallet</string>
|
||||
<string name="card_settings_access_code_recovery_title">Access code recovery</string>
|
||||
<string name="card_settings_action_sheet_reset">Reset</string>
|
||||
<string name="card_settings_action_sheet_title">Are you sure you want to do this?</string>
|
||||
<string name="card_settings_change_access_code">Change Access Code</string>
|
||||
<string name="card_settings_change_access_code_footer">Access code will be changed on this card only</string>
|
||||
|
|
@ -234,7 +233,7 @@
|
|||
<string name="onboarding_button_skip_backup">Skip for later</string>
|
||||
<string name="onboarding_button_what_does_it_mean">How does it work?</string>
|
||||
<string name="onboarding_create_wallet_body">Let\'s generate all the keys on your card and create a secure wallet</string>
|
||||
<string name="onboarding_create_wallet_button_create_wallet">Create wallet</string>
|
||||
<string name="onboarding_create_wallet_button_create_wallet">Create a wallet</string>
|
||||
<string name="onboarding_create_wallet_header">Create a wallet</string>
|
||||
<string name="onboarding_create_wallet_options_button_options">Other options</string>
|
||||
<string name="onboarding_create_wallet_options_message">Your keys will be securely generated inside the card. There is no seed phrase, which means nobody can export or steal it.</string>
|
||||
|
|
@ -248,18 +247,18 @@
|
|||
<string name="onboarding_navbar_pin">Pin code</string>
|
||||
<string name="onboarding_navbar_register_wallet">Connect</string>
|
||||
<string name="onboarding_navbar_title_creating_backup">Creating a backup</string>
|
||||
<string name="onboarding_seed_button_read_more">Read more about seed phrases</string>
|
||||
<string name="onboarding_seed_button_read_more">Read more about seed phrase</string>
|
||||
<string name="onboarding_seed_generate_message">Write these 12 words down in the order given below and store them in a safe and secret place.</string>
|
||||
<string name="onboarding_seed_generate_title">Your secret phrase</string>
|
||||
<string name="onboarding_seed_import_message">To import your wallet, enter your secret phrase in the field below</string>
|
||||
<string name="onboarding_seed_generate_title">Your seed phrase</string>
|
||||
<string name="onboarding_seed_import_message">To import your wallet, enter your seed phrase in the field below</string>
|
||||
<string name="onboarding_seed_intro_button_generate">Generate seed phrase</string>
|
||||
<string name="onboarding_seed_intro_button_import">Import wallet</string>
|
||||
<string name="onboarding_seed_intro_message">A secret phrase is a series of words that allows you to recover your wallet. Unlike the keys generated by the card, secret phrases are unprotected and can be copied and stolen. Use this option at your own risk.</string>
|
||||
<string name="onboarding_seed_intro_message">A seed phrase is a series of words that allows you to recover your wallet. Unlike the keys generated by the card, seed phrases are unprotected and can be copied and stolen. Use this option at your own risk.</string>
|
||||
<string name="onboarding_seed_intro_title">Use seed phrase</string>
|
||||
<string name="onboarding_seed_mnemonic_invalid_checksum">Invalid secret phrase. Please check the word order.</string>
|
||||
<string name="onboarding_seed_mnemonic_wrong_words">Invalid secret phrase. Please check your spelling.</string>
|
||||
<string name="onboarding_seed_mnemonic_invalid_checksum">Invalid seed phrase. Please check the word order.</string>
|
||||
<string name="onboarding_seed_mnemonic_wrong_words">Invalid seed phrase. Please check your spelling.</string>
|
||||
<string name="onboarding_seed_phrase_intro_legacy">Legacy</string>
|
||||
<string name="onboarding_seed_user_validation_message">To check whether you’ve written down your secret phrase correctly, please enter the 2nd, 7th and 11th words</string>
|
||||
<string name="onboarding_seed_user_validation_message">To check whether you’ve written down your seed phrase correctly, please enter the 2nd, 7th and 11th words</string>
|
||||
<string name="onboarding_seed_user_validation_title">So, let’s check</string>
|
||||
<string name="onboarding_subtitle_claim">To get started, simply claim wxDAI to your wallet</string>
|
||||
<string name="onboarding_subtitle_claim_progress">It will take a few seconds</string>
|
||||
|
|
@ -338,8 +337,8 @@
|
|||
<string name="reset_card_to_factory_warning_message">I understand that after performing this action, I will no longer have access to the current wallet</string>
|
||||
<string name="reset_card_with_backup_to_factory_message">Factory Reset will completely delete the wallet from the selected card. You will not be able to restore the current wallet or use the card to recover the access code.</string>
|
||||
<string name="reset_card_without_backup_to_factory_message">Factory Reset will completely delete the wallet from the selected card and remove it from the app. You will not be able to restore the current wallet.</string>
|
||||
<string name="russian_bank_card_warning_subtitle">Do you have a bank card of another country or a UnionPay card?</string>
|
||||
<string name="russian_bank_card_warning_title">Russian bank cards are not accepted at the moment</string>
|
||||
<string name="russian_bank_card_warning_subtitle">Do you have a bank card from another country and a residence permit or registration outside the Russian Federation?</string>
|
||||
<string name="russian_bank_card_warning_title">Russian bank cards are not currently accepted</string>
|
||||
<string name="save_user_wallet_agreement_access_description">Log into the app and check your balance without scanning the card</string>
|
||||
<string name="save_user_wallet_agreement_access_title">Access the app</string>
|
||||
<string name="save_user_wallet_agreement_allow_biometrics">Allow to use biometrics</string>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, C
|
|||
private var _sdk: TangemSdk? = null
|
||||
|
||||
override fun onCreate(context: Context) {
|
||||
_sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config)
|
||||
if (_sdk == null) {
|
||||
_sdk = TangemSdk.initWithBiometrics(activity = context as FragmentActivity, config = config)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
|
|||
|
|
@ -51,17 +51,19 @@ object TwinsHelper {
|
|||
* cb64 <-> cb65
|
||||
*/
|
||||
fun isTwinsCompatible(firstCardId: String, secondCardId: String): Boolean {
|
||||
if (firstCardId.startsWith(FIRST_CARD_FIRST_SERIES) &&
|
||||
secondCardId.startsWith(SECOND_CARD_FIRST_SERIES)
|
||||
) {
|
||||
return true
|
||||
return secondCardId.startsWith(getCompatibleTwinCardId(firstCardId))
|
||||
}
|
||||
|
||||
private fun getCompatibleTwinCardId(cardId: String): String {
|
||||
return when {
|
||||
cardId.startsWith(FIRST_CARD_FIRST_SERIES) -> SECOND_CARD_FIRST_SERIES
|
||||
cardId.startsWith(FIRST_CARD_SECOND_SERIES) -> SECOND_CARD_SECOND_SERIES
|
||||
cardId.startsWith(SECOND_CARD_FIRST_SERIES) -> FIRST_CARD_FIRST_SERIES
|
||||
cardId.startsWith(SECOND_CARD_SECOND_SERIES) -> FIRST_CARD_SECOND_SERIES
|
||||
else -> {
|
||||
"unknown"
|
||||
}
|
||||
}
|
||||
if (firstCardId.startsWith(FIRST_CARD_SECOND_SERIES) &&
|
||||
secondCardId.startsWith(SECOND_CARD_SECOND_SERIES)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,12 +9,10 @@ object GenericCardConfig : CardConfig {
|
|||
get() = listOf(
|
||||
EllipticCurve.Secp256k1,
|
||||
EllipticCurve.Ed25519,
|
||||
EllipticCurve.Bip0340,
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,6 +214,4 @@ private val excludedBlockchains = listOf(
|
|||
Blockchain.Ducatus,
|
||||
Blockchain.Telos, // disable in 4.9
|
||||
Blockchain.TelosTestnet, // disable in 4.9
|
||||
Blockchain.OctaSpace,
|
||||
Blockchain.OctaSpaceTestnet,
|
||||
)
|
||||
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
|
@ -20,6 +21,7 @@ fun CardDTO.supportedBlockchains(cardTypesResolver: CardTypesResolver): List<Blo
|
|||
// need for old multiwallet that supports only secp256k1
|
||||
wallets.flatMap { Blockchain.fromCurve(it.curve) }.distinct().toMutableList()
|
||||
} else {
|
||||
// multiwallet supports all blockchains, move this logic to config
|
||||
Blockchain.values().toMutableList()
|
||||
}
|
||||
// disabled Cardano for wallet 2 for now, should be enabled after key processed
|
||||
|
|
@ -51,6 +53,51 @@ 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 {
|
||||
return this.supportedTokens(cardTypesResolver).contains(blockchain)
|
||||
val cardConfig = CardConfig.createConfig(this)
|
||||
val primaryCurveForBlockchain = cardConfig.primaryCurve(blockchain)
|
||||
val isContainsBlockchain = this.supportedTokens(cardTypesResolver).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.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.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
|
||||
}
|
||||
}
|
||||
|
|
@ -61,6 +61,7 @@ fun WalletManagerFactory.makeWalletManagerForApp(
|
|||
createWalletManager(
|
||||
blockchain = environmentBlockchain,
|
||||
publicKey = publicKey,
|
||||
curve = wallet.curve,
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
package com.tangem.domain.common
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class TwinsHelperTest {
|
||||
|
||||
private val pack1Twins = listOf(
|
||||
"CB610000021",
|
||||
"CB620000031",
|
||||
)
|
||||
|
||||
private val pack2Twins = listOf(
|
||||
"CB640000012",
|
||||
"CB650000011",
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `twins compatibility pack 1 success`() {
|
||||
assertTrue(TwinsHelper.isTwinsCompatible(pack1Twins[0], pack1Twins[1]))
|
||||
assertTrue(TwinsHelper.isTwinsCompatible(pack1Twins[1], pack1Twins[0]))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `twins compatibility pack 1 same cards`() {
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack1Twins[0], pack1Twins[0]))
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack1Twins[1], pack1Twins[1]))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `twins compatibility pack 2 success`() {
|
||||
assertTrue(TwinsHelper.isTwinsCompatible(pack2Twins[0], pack2Twins[1]))
|
||||
assertTrue(TwinsHelper.isTwinsCompatible(pack2Twins[1], pack2Twins[0]))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `twins compatibility pack 2 same cards`() {
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack2Twins[0], pack2Twins[0]))
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack2Twins[1], pack2Twins[1]))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `twins compatibility false for different packs`() {
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack2Twins[0], pack1Twins[1]))
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack1Twins[1], pack2Twins[0]))
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack1Twins[0], pack2Twins[1]))
|
||||
assertFalse(TwinsHelper.isTwinsCompatible(pack2Twins[1], pack1Twins[0]))
|
||||
}
|
||||
}
|
||||
|
|
@ -80,9 +80,9 @@ okHttp-prettyLogging = "3.1.0"
|
|||
# endregion Other libraries
|
||||
|
||||
# region Tangem
|
||||
tangemBlockchainSdk = "develop-331"
|
||||
tangemBlockchainSdk = "develop-337"
|
||||
#tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds
|
||||
tangemCardSdk = "develop-289"
|
||||
tangemCardSdk = "develop-293"
|
||||
#tangemCardSdk = "0.0.1" # Keep it! - used for local builds
|
||||
# endregion Tangem
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue