From 45e78f3985aa002193f2685c47ad8b3532c4d74b Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 22 Jan 2026 17:22:06 +0300 Subject: [PATCH] Updated on 2026-08-14 --- features/manage-tokens/impl/build.gradle.kts | 3 ++ ...aultCustomTokenDerivationInputComponent.kt | 17 +++++++++ .../model/CustomTokenSelectorModel.kt | 10 ++++++ .../utils/CardanoDerivationPathValidator.kt | 36 +++++++++++++++++++ 4 files changed, 66 insertions(+) create mode 100644 features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CardanoDerivationPathValidator.kt diff --git a/features/manage-tokens/impl/build.gradle.kts b/features/manage-tokens/impl/build.gradle.kts index 6fc7f5115a..4a0329dcad 100644 --- a/features/manage-tokens/impl/build.gradle.kts +++ b/features/manage-tokens/impl/build.gradle.kts @@ -12,6 +12,9 @@ android { } dependencies { + /* Tangem libraries */ + implementation(tangemDeps.card.core) + /* Project - API */ implementation(projects.features.manageTokens.api) implementation(projects.features.swapV2.api) diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenDerivationInputComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenDerivationInputComponent.kt index 7a8ab034ac..adef3798eb 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenDerivationInputComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenDerivationInputComponent.kt @@ -8,6 +8,7 @@ import arrow.core.getOrElse import com.tangem.core.decompose.context.AppComponentContext import com.tangem.core.ui.extensions.resourceReference import com.tangem.domain.managetokens.ValidateDerivationPathUseCase +import com.tangem.features.managetokens.utils.CardanoDerivationPathValidator import com.tangem.domain.managetokens.model.exceptoin.DerivationPathValidationException import com.tangem.domain.models.network.Network import com.tangem.features.managetokens.component.CustomTokenDerivationInputComponent @@ -27,6 +28,8 @@ internal class DefaultCustomTokenDerivationInputComponent @AssistedInject constr private val validateDerivationPathUseCase: ValidateDerivationPathUseCase, ) : CustomTokenDerivationInputComponent, AppComponentContext by context { + private val cardanoDerivationPathValidator = CardanoDerivationPathValidator() + private val state: MutableStateFlow = MutableStateFlow( value = getInitialState(), ) @@ -73,6 +76,20 @@ internal class DefaultCustomTokenDerivationInputComponent @AssistedInject constr return } + val isInvalidForCardano = cardanoDerivationPathValidator.isInvalidForCardano( + networkId = params.selectedNetwork.id, + path = value, + ) + if (isInvalidForCardano) { + state.update { state -> + state.copy( + error = resourceReference(R.string.custom_token_invalid_derivation_path), + isConfirmEnabled = false, + ) + } + return + } + state.update { state -> state.copy( error = null, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt index 2b6df47f38..2cbfe3dc7a 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/model/CustomTokenSelectorModel.kt @@ -33,6 +33,7 @@ import com.tangem.features.managetokens.entity.customtoken.SelectedNetwork import com.tangem.features.managetokens.entity.item.DerivationPathUM import com.tangem.features.managetokens.entity.item.SelectableItemUM import com.tangem.features.managetokens.impl.R +import com.tangem.features.managetokens.utils.CardanoDerivationPathValidator import com.tangem.features.managetokens.utils.mapper.toCurrencyNetworkModel import com.tangem.features.managetokens.utils.mapper.toDerivationPathModel import com.tangem.lib.crypto.derivation.AccountNodeRecognizer @@ -56,6 +57,7 @@ internal class CustomTokenSelectorModel @Inject constructor( ) : Model() { private val params: CustomTokenSelectorComponent.Params = paramsContainer.require() + private val cardanoDerivationPathValidator = CardanoDerivationPathValidator() val dialogNavigation: SlotNavigation = SlotNavigation() @@ -142,6 +144,14 @@ internal class CustomTokenSelectorModel @Inject constructor( return@mapNotNullTo null // Skip default path } + val isInvalidForCardano = cardanoDerivationPathValidator.isInvalidForCardano( + networkId = selector.selectedNetwork.id, + path = network.derivationPath.value, + ) + if (isInvalidForCardano) { + return@mapNotNullTo null + } + network.toDerivationPathModel( isSelected = network.id == selector.selectedDerivationPath?.id, onSelectedStateChange = { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CardanoDerivationPathValidator.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CardanoDerivationPathValidator.kt new file mode 100644 index 0000000000..9e3b11e015 --- /dev/null +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/utils/CardanoDerivationPathValidator.kt @@ -0,0 +1,36 @@ +package com.tangem.features.managetokens.utils + +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.toBlockchain +import com.tangem.crypto.hdWallet.DerivationPath +import com.tangem.domain.models.network.Network + +/** + * Validator for Cardano derivation paths. + * Cardano requires exactly 5 nodes in derivation path according to CIP-1852 standard. + */ +internal class CardanoDerivationPathValidator { + + /** + * Checks if the derivation path is invalid for Cardano network. + * @return true if network is Cardano AND path has insufficient nodes + */ + fun isInvalidForCardano(networkId: Network.ID, path: String?): Boolean { + if (!isCardano(networkId) || path == null) return false + return !isValidDerivationPath(path) + } + + private fun isCardano(networkId: Network.ID): Boolean { + return networkId.toBlockchain() == Blockchain.Cardano + } + + private fun isValidDerivationPath(path: String): Boolean { + return runCatching { + DerivationPath(rawPath = path).nodes.size == REQUIRED_DERIVATION_NODES + }.getOrDefault(false) + } + + private companion object { + const val REQUIRED_DERIVATION_NODES = 5 + } +} \ No newline at end of file