From ce9335e3bda3dba1ceab417b3a88db8d9da54d73 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 27 Aug 2024 19:12:07 +0400 Subject: [PATCH 1/4] Updated on 2026-08-14 --- .../common/currency/CryptoCurrencyFactory.kt | 47 ++++++-- .../data/common/currency/NetworkOperations.kt | 15 +++ .../data/common/currency/TokensOperations.kt | 2 +- .../DefaultCustomTokensRepository.kt | 103 ++++++++++++++++-- .../managetokens/di/ManageTokensDataModule.kt | 14 ++- 5 files changed, 160 insertions(+), 21 deletions(-) diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/CryptoCurrencyFactory.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/CryptoCurrencyFactory.kt index 9af9e67943..38d8376ff2 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/CryptoCurrencyFactory.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/CryptoCurrencyFactory.kt @@ -12,6 +12,29 @@ import com.tangem.blockchain.common.Token as SdkToken // FIXME: Make internal class CryptoCurrencyFactory { + @Suppress("LongParameterList") // Yep, it's long + fun createToken( + network: Network, + rawId: String?, + name: String, + symbol: String, + decimals: Int, + contractAddress: String, + ): CryptoCurrency.Token { + val id = getTokenId(network, rawId, contractAddress) + + return CryptoCurrency.Token( + id = id, + network = network, + name = name, + symbol = symbol, + decimals = decimals, + iconUrl = rawId?.let(::getTokenIconUrlFromDefaultHost), + isCustom = isCustomToken(id, network), + contractAddress = contractAddress, + ) + } + fun createToken( sdkToken: SdkToken, blockchain: Blockchain, @@ -49,15 +72,7 @@ class CryptoCurrencyFactory { } val network = getNetwork(blockchain, extraDerivationPath, derivationStyleProvider) ?: return null - return CryptoCurrency.Coin( - id = getCoinId(network, blockchain.toCoinId()), - network = network, - name = blockchain.fullName, - symbol = blockchain.currency, - iconUrl = getCoinIconUrl(blockchain), - decimals = blockchain.decimals(), - isCustom = isCustomCoin(network), - ) + return createCoin(network) } fun createCoin( @@ -69,6 +84,20 @@ class CryptoCurrencyFactory { return createCoin(blockchain, extraDerivationPath, derivationStyleProvider) } + fun createCoin(network: Network): CryptoCurrency.Coin { + val blockchain = Blockchain.fromId(network.id.value) + + return CryptoCurrency.Coin( + id = getCoinId(network, blockchain.toCoinId()), + network = network, + name = blockchain.fullName, + symbol = blockchain.currency, + iconUrl = getCoinIconUrl(blockchain), + decimals = blockchain.decimals(), + isCustom = isCustomCoin(network), + ) + } + fun createToken( token: Token, networkId: String, diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt index 8f2e5b60ac..6febfc5fb7 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt @@ -11,6 +11,21 @@ fun getBlockchain(networkId: Network.ID): Blockchain { return Blockchain.fromId(networkId.value) } +fun getNetwork(networkId: Network.ID, derivationPath: Network.DerivationPath): Network { + val blockchain = getBlockchain(networkId) + + return Network( + id = networkId, + backendId = blockchain.toNetworkId(), + name = blockchain.getNetworkName(), + isTestnet = blockchain.isTestnet(), + derivationPath = derivationPath, + currencySymbol = blockchain.currency, + standardType = getNetworkStandardType(blockchain), + hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource, + ) +} + fun getNetwork( blockchain: Blockchain, extraDerivationPath: String?, diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/TokensOperations.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/TokensOperations.kt index 72018fc4ed..2c2c8d95ad 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/TokensOperations.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/TokensOperations.kt @@ -85,7 +85,7 @@ private fun getCurrencyIdBody(network: Network): CurrencyIdBody { } } -private fun getTokenIconUrlFromDefaultHost(tokenId: String): String { +fun getTokenIconUrlFromDefaultHost(tokenId: String): String { return buildString { append(DEFAULT_TOKENS_ICONS_HOST) append('/') diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt index 50f20df32c..8488ff5b54 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt @@ -1,16 +1,46 @@ package com.tangem.data.managetokens +import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchainsdk.utils.toNetworkId +import com.tangem.data.common.currency.CryptoCurrencyFactory +import com.tangem.data.common.currency.getNetwork +import com.tangem.datasource.api.common.response.getOrThrow +import com.tangem.datasource.api.tangemTech.TangemTechApi +import com.tangem.datasource.api.tangemTech.models.UserTokensResponse +import com.tangem.datasource.local.preferences.AppPreferencesStore +import com.tangem.datasource.local.preferences.PreferencesKeys +import com.tangem.datasource.local.preferences.utils.getObjectSyncOrNull +import com.tangem.datasource.local.userwallet.UserWalletsStore +import com.tangem.domain.common.extensions.supportedBlockchains +import com.tangem.domain.common.util.cardTypesResolver import com.tangem.domain.managetokens.model.AddCustomTokenForm import com.tangem.domain.managetokens.repository.CustomTokensRepository import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.Network import com.tangem.domain.wallets.models.UserWalletId +import com.tangem.utils.coroutines.CoroutineDispatcherProvider +import kotlinx.coroutines.withContext -internal class DefaultCustomTokensRepository : CustomTokensRepository { +internal class DefaultCustomTokensRepository( + private val tangemTechApi: TangemTechApi, + private val userWalletsStore: UserWalletsStore, + private val appPreferencesStore: AppPreferencesStore, + private val dispatchers: CoroutineDispatcherProvider, +) : CustomTokensRepository { - override suspend fun validateContractAddress(contractAddress: String, networkId: Network.ID): Boolean { - TODO("Should be implemented in [REDACTED_JIRA]") - } + private val cryptoCurrencyFactory = CryptoCurrencyFactory() + + override suspend fun validateContractAddress(contractAddress: String, networkId: Network.ID): Boolean = + withContext(dispatchers.io) { + when (val blockchain = Blockchain.fromId(networkId.value)) { + Blockchain.Unknown, + Blockchain.Binance, + Blockchain.BinanceTestnet, + -> true + Blockchain.Cardano -> blockchain.validateContractAddress(contractAddress.lowercase()) + else -> blockchain.validateAddress(contractAddress.lowercase()) + } + } override suspend fun isCurrencyNotAdded( userWalletId: UserWalletId, @@ -18,7 +48,17 @@ internal class DefaultCustomTokensRepository : CustomTokensRepository { derivationPath: Network.DerivationPath, contractAddress: String?, ): Boolean { - TODO("Should be implemented in [REDACTED_JIRA]") + return withContext(dispatchers.io) { + val storedCurrencies: UserTokensResponse = appPreferencesStore.getObjectSyncOrNull( + key = PreferencesKeys.getUserTokensKey(userWalletId.stringValue), + ) ?: error("User tokens not found") + + storedCurrencies.tokens.none { token -> + Blockchain.fromId(networkId.value).toNetworkId() == token.networkId && + derivationPath.value == token.derivationPath && + contractAddress.equals(token.contractAddress, ignoreCase = true) + } + } } override suspend fun findToken( @@ -26,15 +66,51 @@ internal class DefaultCustomTokensRepository : CustomTokensRepository { contractAddress: String, networkId: Network.ID, derivationPath: Network.DerivationPath, - ): CryptoCurrency.Token? { - TODO("Should be implemented in [REDACTED_JIRA]") + ): CryptoCurrency.Token? = withContext(dispatchers.io) { + val userWallet = userWalletsStore.getSyncOrNull(userWalletId) + ?: error("User wallet not found") + val network = getNetwork(networkId, derivationPath) + + val supportedTokenNetworkIds = userWallet.scanResponse.card + .supportedBlockchains(userWallet.scanResponse.cardTypesResolver) + .filter(Blockchain::canHandleTokens) + .map(Blockchain::toNetworkId) + + val response = tangemTechApi.getCoins( + contractAddress = contractAddress, + networkIds = network.backendId, + active = true, + ).getOrThrow() + + response.coins.firstNotNullOfOrNull { coin -> + val coinNetwork = coin.networks.firstOrNull { network -> + (network.contractAddress != null || network.decimalCount != null) && + network.contractAddress.equals(contractAddress, ignoreCase = true) && + network.networkId in supportedTokenNetworkIds + } + + if (coinNetwork != null) { + cryptoCurrencyFactory.createToken( + network = network, + rawId = coin.id, + name = coin.name, + symbol = coin.symbol, + decimals = coinNetwork.decimalCount!!.toInt(), + contractAddress = contractAddress, + ) + } else { + null + } + } } override suspend fun createCoin( networkId: Network.ID, derivationPath: Network.DerivationPath, ): CryptoCurrency.Coin { - TODO("Should be implemented in [REDACTED_JIRA]") + val network = getNetwork(networkId, derivationPath) + + return cryptoCurrencyFactory.createCoin(network) } override suspend fun createCustomToken( @@ -42,6 +118,15 @@ internal class DefaultCustomTokensRepository : CustomTokensRepository { derivationPath: Network.DerivationPath, formValues: AddCustomTokenForm.Validated.All, ): CryptoCurrency.Token { - TODO("Should be implemented in [REDACTED_JIRA]") + val network = getNetwork(networkId, derivationPath) + + return cryptoCurrencyFactory.createToken( + network = network, + rawId = null, + name = formValues.name, + symbol = formValues.symbol, + decimals = formValues.decimals, + contractAddress = formValues.contractAddress, + ) } } \ No newline at end of file diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt index f61ff6a0b3..64d77526c1 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/di/ManageTokensDataModule.kt @@ -42,7 +42,17 @@ internal object ManageTokensDataModule { @Provides @Singleton - fun provideCustomTokensRepository(): CustomTokensRepository { - return DefaultCustomTokensRepository() + fun provideCustomTokensRepository( + tangemTechApi: TangemTechApi, + userWalletsStore: UserWalletsStore, + appPreferencesStore: AppPreferencesStore, + dispatchers: CoroutineDispatcherProvider, + ): CustomTokensRepository { + return DefaultCustomTokensRepository( + tangemTechApi, + userWalletsStore, + appPreferencesStore, + dispatchers, + ) } } \ No newline at end of file From e59c7e5c5ab22166a5b2819a762c2bc76d22a42f Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Aug 2024 13:14:28 +0400 Subject: [PATCH 2/4] Updated on 2026-08-14 --- .../DefaultCustomTokensRepository.kt | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt index 8488ff5b54..eabde921a1 100644 --- a/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt +++ b/data/manage-tokens/src/main/kotlin/com/tangem/data/managetokens/DefaultCustomTokensRepository.kt @@ -1,8 +1,11 @@ package com.tangem.data.managetokens +import com.tangem.blockchain.blockchains.cardano.CardanoTokenAddressConverter +import com.tangem.blockchain.blockchains.hedera.HederaTokenAddressConverter import com.tangem.blockchain.common.Blockchain import com.tangem.blockchainsdk.utils.toNetworkId import com.tangem.data.common.currency.CryptoCurrencyFactory +import com.tangem.data.common.currency.getBlockchain import com.tangem.data.common.currency.getNetwork import com.tangem.datasource.api.common.response.getOrThrow import com.tangem.datasource.api.tangemTech.TangemTechApi @@ -70,6 +73,11 @@ internal class DefaultCustomTokensRepository( val userWallet = userWalletsStore.getSyncOrNull(userWalletId) ?: error("User wallet not found") val network = getNetwork(networkId, derivationPath) + val tokenAddress = convertTokenAddress( + networkId, + contractAddress, + symbol = null, + ) val supportedTokenNetworkIds = userWallet.scanResponse.card .supportedBlockchains(userWallet.scanResponse.cardTypesResolver) @@ -85,7 +93,7 @@ internal class DefaultCustomTokensRepository( response.coins.firstNotNullOfOrNull { coin -> val coinNetwork = coin.networks.firstOrNull { network -> (network.contractAddress != null || network.decimalCount != null) && - network.contractAddress.equals(contractAddress, ignoreCase = true) && + network.contractAddress.equals(tokenAddress, ignoreCase = true) && network.networkId in supportedTokenNetworkIds } @@ -96,7 +104,7 @@ internal class DefaultCustomTokensRepository( name = coin.name, symbol = coin.symbol, decimals = coinNetwork.decimalCount!!.toInt(), - contractAddress = contractAddress, + contractAddress = tokenAddress, ) } else { null @@ -119,6 +127,11 @@ internal class DefaultCustomTokensRepository( formValues: AddCustomTokenForm.Validated.All, ): CryptoCurrency.Token { val network = getNetwork(networkId, derivationPath) + val tokenAddress = convertTokenAddress( + networkId, + formValues.contractAddress, + formValues.symbol, + ) return cryptoCurrencyFactory.createToken( network = network, @@ -126,7 +139,24 @@ internal class DefaultCustomTokensRepository( name = formValues.name, symbol = formValues.symbol, decimals = formValues.decimals, - contractAddress = formValues.contractAddress, + contractAddress = tokenAddress, ) } + + private fun convertTokenAddress(networkId: Network.ID, contractAddress: String, symbol: String?): String { + val convertedAddress = when (getBlockchain(networkId)) { + Blockchain.Hedera, + Blockchain.HederaTestnet, + -> HederaTokenAddressConverter().convertToTokenId(contractAddress) + Blockchain.Cardano -> { + // TODO: [REDACTED_JIRA] + CardanoTokenAddressConverter().convertToFingerprint(contractAddress, symbol) + } + else -> contractAddress + } + + return requireNotNull(convertedAddress) { + "Token contract address is invalid" + } + } } \ No newline at end of file From ed3b894c36367530dc5ca4bc1e3701727019d40e Mon Sep 17 00:00:00 2001 From: Tangem Date: Fri, 23 Aug 2024 18:13:17 +0400 Subject: [PATCH 3/4] Updated on 2026-08-14 --- .../tangem/tap/domain/card/CryptoCurrenciesMocks.kt | 1 + .../data/common/currency/NetworkOperations.kt | 2 ++ .../java/com/tangem/domain/tokens/model/Network.kt | 1 + .../com/tangem/domain/tokens/mock/MockNetworks.kt | 3 +++ .../impl/DefaultAddCustomTokenComponent.kt | 3 ++- .../impl/DefaultCustomTokenFormComponent.kt | 2 +- .../preview/PreviewCustomTokenSelectorComponent.kt | 13 ++++++++----- .../entity/customtoken/AddCustomTokenConfig.kt | 8 +++++--- .../managetokens/entity/item/DerivationPathUM.kt | 8 +++----- .../managetokens/ui/AddCustomTokenBottomSheet.kt | 11 +++++++---- .../managetokens/ui/CustomTokenSelectorContent.kt | 13 ++++++++----- 11 files changed, 41 insertions(+), 24 deletions(-) diff --git a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt index 5ecd65378b..01faeadf30 100644 --- a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt +++ b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt @@ -68,6 +68,7 @@ internal class CryptoCurrenciesMocks(private val scanResponse: ScanResponse) { isTestnet = false, standardType = Network.StandardType.ERC20, hasFiatFeeRate = true, + canHandleTokens = true, ), name = "NEVER-MIND", symbol = "NEVER-MIND", diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt index 6febfc5fb7..4cb4fb8d6e 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt @@ -23,6 +23,7 @@ fun getNetwork(networkId: Network.ID, derivationPath: Network.DerivationPath): N currencySymbol = blockchain.currency, standardType = getNetworkStandardType(blockchain), hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource, + canHandleTokens = blockchain.canHandleTokens(), ) } @@ -45,6 +46,7 @@ fun getNetwork( currencySymbol = blockchain.currency, standardType = getNetworkStandardType(blockchain), hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource, + canHandleTokens = blockchain.canHandleTokens(), ) } diff --git a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt index 59d8d3a517..3543b7094b 100644 --- a/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt +++ b/domain/tokens/models/src/main/java/com/tangem/domain/tokens/model/Network.kt @@ -29,6 +29,7 @@ data class Network( val isTestnet: Boolean, val standardType: StandardType, val hasFiatFeeRate: Boolean, + val canHandleTokens: Boolean, ) { init { diff --git a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt index 091154dda9..cd410b3487 100644 --- a/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt +++ b/domain/tokens/src/test/kotlin/com/tangem/domain/tokens/mock/MockNetworks.kt @@ -22,6 +22,7 @@ internal object MockNetworks { currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, hasFiatFeeRate = true, + canHandleTokens = true, ) val network2 = Network( @@ -33,6 +34,7 @@ internal object MockNetworks { currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, hasFiatFeeRate = true, + canHandleTokens = true, ) val network3 = Network( @@ -44,6 +46,7 @@ internal object MockNetworks { currencySymbol = "ETH", derivationPath = Network.DerivationPath.None, hasFiatFeeRate = true, + canHandleTokens = true, ) val networkStatus1 = NetworkStatus( diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt index dd0faa0556..48e7a1b01f 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultAddCustomTokenComponent.kt @@ -124,8 +124,9 @@ internal class DefaultAddCustomTokenComponent @AssistedInject constructor( userWalletId = config.userWalletId, network = config.selectedNetwork ?: error("Network is not selected"), derivationPath = config.selectedDerivationPath ?: SelectedDerivationPath( + id = config.selectedNetwork.id, value = config.selectedNetwork.derivationPath, - name = resourceReference(R.string.custom_token_derivation_path_default), + networkName = resourceReference(R.string.custom_token_derivation_path_default), ), formValues = config.formValues, onSelectNetworkClick = ::showNetworkSelector, diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt index 982e4979e1..2ca0b7e1a1 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/impl/DefaultCustomTokenFormComponent.kt @@ -49,7 +49,7 @@ internal class DefaultCustomTokenFormComponent @AssistedInject constructor( tokenForm = getInitialTokenForm(), derivationPath = ClickableFieldUM( label = resourceReference(R.string.custom_token_derivation_path), - value = params.derivationPath.name, + value = params.derivationPath.networkName, onClick = ::selectDerivationPath, ), saveToken = { diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt index 1e773cc319..7d596d3f8d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/component/preview/PreviewCustomTokenSelectorComponent.kt @@ -29,13 +29,15 @@ internal class PreviewCustomTokenSelectorComponent( when (params) { is Params.DerivationPathSelector -> { val d = SelectedDerivationPath( - value = "m/44'/0'/0'/0/$index", - name = stringReference(value = "Network $index"), + id = Network.ID(index.toString()), + value = Network.DerivationPath.Card("m/44'/0'/0'/0/$index"), + networkName = stringReference(value = "Network $index"), ) DerivationPathUM( - value = "m/44'/0'/0'/0/$index", - blockchainName = d.name, + id = d.id.value, + value = d.value.value.orEmpty(), + networkName = d.networkName, isSelected = d.value == params.selectedDerivationPath?.value, onSelectedStateChange = { params.onDerivationPathSelected(d) }, ) @@ -44,7 +46,8 @@ internal class PreviewCustomTokenSelectorComponent( val n = SelectedNetwork( id = Network.ID(index.toString()), name = stringReference(value = "Network $index"), - derivationPath = "m/44'/0'/0'/0/$index", + derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/$index"), + canHandleTokens = false, ) CurrencyNetworkUM( diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt index 417cd15585..6a43cdc40d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/customtoken/AddCustomTokenConfig.kt @@ -28,11 +28,13 @@ internal data class AddCustomTokenConfig( internal data class SelectedNetwork( val id: Network.ID, val name: TextReference, - val derivationPath: String, + val derivationPath: Network.DerivationPath, + val canHandleTokens: Boolean, ) @Serializable internal data class SelectedDerivationPath( - val value: String, - val name: TextReference, + val id: Network.ID, + val value: Network.DerivationPath, + val networkName: TextReference, ) \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/item/DerivationPathUM.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/item/DerivationPathUM.kt index 2190c50e4f..bf6387ff0d 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/item/DerivationPathUM.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/entity/item/DerivationPathUM.kt @@ -3,11 +3,9 @@ package com.tangem.features.managetokens.entity.item import com.tangem.core.ui.extensions.TextReference internal data class DerivationPathUM( + override val id: String, val value: String, - val blockchainName: TextReference, + val networkName: TextReference, override val isSelected: Boolean, override val onSelectedStateChange: (Boolean) -> Unit, -) : SelectableItemUM { - - override val id: String = value -} \ No newline at end of file +) : SelectableItemUM \ No newline at end of file diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt index b1b3cc0f0a..69ea2418d6 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/AddCustomTokenBottomSheet.kt @@ -103,7 +103,8 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider< selectedNetwork = SelectedNetwork( id = Network.ID(value = "1"), name = stringReference("Ethereum"), - derivationPath = "m/44'/0'/0'/0/0", + derivationPath = Network.DerivationPath.None, + canHandleTokens = false, ), ), ), @@ -115,7 +116,8 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider< selectedNetwork = SelectedNetwork( id = Network.ID(value = "0"), name = stringReference("Ethereum"), - derivationPath = "m/44'/0'/0'/0/0", + derivationPath = Network.DerivationPath.None, + canHandleTokens = false, ), ), ), @@ -125,8 +127,9 @@ private class AddCustomTokenComponentPreviewProvider : PreviewParameterProvider< step = AddCustomTokenConfig.Step.DERIVATION_PATH_SELECTOR, popBack = {}, selectedDerivationPath = SelectedDerivationPath( - value = "m/44'/0'/0'/0/0", - name = stringReference("Ethereum"), + id = Network.ID(value = "0"), + value = Network.DerivationPath.None, + networkName = stringReference("Ethereum"), ), ), ), diff --git a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt index f5545db44b..67c77ff303 100644 --- a/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt +++ b/features/manage-tokens/impl/src/main/kotlin/com/tangem/features/managetokens/ui/CustomTokenSelectorContent.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import com.tangem.core.ui.components.currency.icon.CurrencyIconState import com.tangem.core.ui.components.rows.ChainRow import com.tangem.core.ui.components.rows.model.ChainRowUM +import com.tangem.core.ui.extensions.resolveReference import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -154,7 +155,7 @@ private fun NetworkItem(model: CurrencyNetworkUM, modifier: Modifier = Modifier) icon = CurrencyIconState.CoinIcon( url = null, fallbackResId = model.iconResId, - isGrayscale = !model.isSelected, + isGrayscale = false, showCustomBadge = false, ), showCustom = false, @@ -205,7 +206,7 @@ private fun DerivationPathItem(model: DerivationPathUM, modifier: Modifier = Mod contentAlignment = Alignment.CenterStart, ) { Text( - text = "${model.value} ${if (model.isSelected) "- selected" else ""}", + text = "${model.networkName.resolveReference()}: ${model.value} ${if (model.isSelected) "<" else ""}", color = TangemTheme.colors.text.primary1, ) } @@ -235,7 +236,8 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider : selectedNetwork = SelectedNetwork( id = Network.ID(value = "0"), name = stringReference(""), - derivationPath = "m/44'/0'/0'/0/0", + derivationPath = Network.DerivationPath.Card("m/44'/0'/0'/0/0"), + canHandleTokens = false, ), onNetworkSelected = {}, ), @@ -244,8 +246,9 @@ private class CustomTokenNetworkSelectorComponentPreviewProvider : params = CustomTokenSelectorComponent.Params.DerivationPathSelector( userWalletId = UserWalletId(stringValue = "321"), selectedDerivationPath = SelectedDerivationPath( - value = "m/44'/0'/0'/0/0", - name = stringReference(""), + id = Network.ID(value = "0"), + value = Network.DerivationPath.Card("m/44'/0'/0'/0/0"), + networkName = stringReference(""), ), onDerivationPathSelected = {}, ), From 01d839b4c5d807e5ea42c1797b223e0e03f4e071 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 28 Aug 2024 15:35:08 +0400 Subject: [PATCH 4/4] Updated on 2026-08-14 --- .../tap/domain/card/CryptoCurrenciesMocks.kt | 26 +++++++++++++++---- .../data/common/currency/NetworkOperations.kt | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt index 01faeadf30..a9e93345cc 100644 --- a/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt +++ b/app/src/test/kotlin/com/tangem/tap/domain/card/CryptoCurrenciesMocks.kt @@ -1,8 +1,12 @@ package com.tangem.tap.domain.card import com.tangem.blockchain.common.Blockchain +import com.tangem.blockchain.common.FeePaidCurrency import com.tangem.blockchain.common.Token +import com.tangem.blockchainsdk.utils.toNetworkId import com.tangem.data.common.currency.CryptoCurrencyFactory +import com.tangem.data.common.currency.getNetworkDerivationPath +import com.tangem.data.common.currency.getNetworkStandardType import com.tangem.domain.common.util.derivationStyleProvider import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.tokens.model.CryptoCurrency @@ -40,11 +44,23 @@ internal class CryptoCurrenciesMocks(private val scanResponse: ScanResponse) { } private fun createCoin(blockchain: Blockchain): CryptoCurrency { - return factory.createCoin( - blockchain = blockchain, - extraDerivationPath = null, - derivationStyleProvider = scanResponse.derivationStyleProvider, - )!! + val network = Network( + id = Network.ID(blockchain.id), + backendId = blockchain.toNetworkId(), + name = blockchain.getNetworkName(), + isTestnet = blockchain.isTestnet(), + derivationPath = getNetworkDerivationPath( + blockchain, + extraDerivationPath = null, + scanResponse.derivationStyleProvider, + ), + currencySymbol = blockchain.currency, + standardType = getNetworkStandardType(blockchain), + hasFiatFeeRate = blockchain.feePaidCurrency() !is FeePaidCurrency.FeeResource, + canHandleTokens = false, + ) + + return factory.createCoin(network = network) } // Impossible to create custom token by CryptoCurrencyFactory because it works with URI under the hood diff --git a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt index 4cb4fb8d6e..3666f5f012 100644 --- a/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt +++ b/data/common/src/main/kotlin/com/tangem/data/common/currency/NetworkOperations.kt @@ -50,7 +50,7 @@ fun getNetwork( ) } -private fun getNetworkDerivationPath( +fun getNetworkDerivationPath( blockchain: Blockchain, extraDerivationPath: String?, cardDerivationStyleProvider: DerivationStyleProvider?,