Updated on 2026-08-14
This commit is contained in:
parent
7cda9d6726
commit
e5825252f2
5 changed files with 88 additions and 30 deletions
|
|
@ -7,6 +7,7 @@ import com.tangem.blockchainsdk.utils.toNetworkId
|
|||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.data.common.currency.CryptoCurrencyFactory
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.data.managetokens.utils.HederaTokenAddressResolver
|
||||
import com.tangem.data.managetokens.utils.TokenAddressesConverter
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
|
|
@ -32,6 +33,7 @@ internal class DefaultCustomTokensRepository(
|
|||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val networkFactory: NetworkFactory,
|
||||
hederaTokenAddressResolver: HederaTokenAddressResolver,
|
||||
) : CustomTokensRepository {
|
||||
|
||||
private val excludedBlockchainsForCustom = setOf(
|
||||
|
|
@ -40,7 +42,7 @@ internal class DefaultCustomTokensRepository(
|
|||
)
|
||||
|
||||
private val cryptoCurrencyFactory = CryptoCurrencyFactory(excludedBlockchains)
|
||||
private val tokenAddressConverter = TokenAddressesConverter()
|
||||
private val tokenAddressConverter = TokenAddressesConverter(hederaTokenAddressResolver)
|
||||
|
||||
override suspend fun validateContractAddress(contractAddress: String, networkId: Network.ID): Boolean =
|
||||
withContext(dispatchers.io) {
|
||||
|
|
@ -53,6 +55,8 @@ internal class DefaultCustomTokensRepository(
|
|||
Blockchain.TerraV2,
|
||||
-> true
|
||||
Blockchain.Cardano,
|
||||
Blockchain.Hedera,
|
||||
Blockchain.HederaTestnet,
|
||||
Blockchain.Sui,
|
||||
Blockchain.Stellar,
|
||||
Blockchain.XRP,
|
||||
|
|
@ -89,30 +93,39 @@ internal class DefaultCustomTokensRepository(
|
|||
.filter(Blockchain::canHandleTokens)
|
||||
.map(Blockchain::toNetworkId)
|
||||
|
||||
val response = tangemTechApi.getCoins(
|
||||
contractAddress = contractAddress,
|
||||
networkIds = network.rawId,
|
||||
active = true,
|
||||
).getOrThrow()
|
||||
|
||||
response.coins.firstNotNullOfOrNull { coin ->
|
||||
val coinNetwork = coin.networks.firstOrNull { network ->
|
||||
(network.contractAddress != null || network.decimalCount != null) &&
|
||||
network.contractAddress.equals(tokenAddress, ignoreCase = true) &&
|
||||
network.networkId in supportedTokenNetworkIds
|
||||
val addressesToTry = buildList {
|
||||
add(tokenAddress)
|
||||
if (!contractAddress.equals(tokenAddress, ignoreCase = true)) {
|
||||
add(contractAddress)
|
||||
}
|
||||
}
|
||||
|
||||
if (coinNetwork != null) {
|
||||
cryptoCurrencyFactory.createToken(
|
||||
network = network,
|
||||
rawId = CryptoCurrency.RawID(coin.id),
|
||||
name = coin.name,
|
||||
symbol = coin.symbol,
|
||||
decimals = requireNotNull(coinNetwork.decimalCount).toInt(),
|
||||
contractAddress = tokenAddress,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
addressesToTry.firstNotNullOfOrNull { searchAddress ->
|
||||
val response = tangemTechApi.getCoins(
|
||||
contractAddress = searchAddress,
|
||||
networkIds = network.rawId,
|
||||
active = true,
|
||||
).getOrThrow()
|
||||
|
||||
response.coins.firstNotNullOfOrNull { coin ->
|
||||
val coinNetwork = coin.networks.firstOrNull { network ->
|
||||
(network.contractAddress != null || network.decimalCount != null) &&
|
||||
network.contractAddress.equals(tokenAddress, ignoreCase = true) &&
|
||||
network.networkId in supportedTokenNetworkIds
|
||||
}
|
||||
|
||||
if (coinNetwork != null) {
|
||||
cryptoCurrencyFactory.createToken(
|
||||
network = network,
|
||||
rawId = CryptoCurrency.RawID(coin.id),
|
||||
name = coin.name,
|
||||
symbol = coin.symbol,
|
||||
decimals = requireNotNull(coinNetwork.decimalCount).toInt(),
|
||||
contractAddress = tokenAddress,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
package com.tangem.data.managetokens.di
|
||||
|
||||
import com.tangem.blockchainsdk.providers.BlockchainProviderTypesStore
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.account.WalletAccountsFetcher
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.data.managetokens.DefaultCustomTokensRepository
|
||||
import com.tangem.data.managetokens.DefaultManageTokensRepository
|
||||
import com.tangem.data.managetokens.utils.HederaTokenAddressResolver
|
||||
import com.tangem.data.managetokens.utils.ManageTokensUpdateFetcher
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.config.testnet.TestnetTokensStorage
|
||||
|
|
@ -54,6 +56,7 @@ internal object ManageTokensDataModule {
|
|||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
networkFactory: NetworkFactory,
|
||||
blockchainProviderTypesStore: BlockchainProviderTypesStore,
|
||||
): CustomTokensRepository {
|
||||
return DefaultCustomTokensRepository(
|
||||
tangemTechApi = tangemTechApi,
|
||||
|
|
@ -61,6 +64,7 @@ internal object ManageTokensDataModule {
|
|||
excludedBlockchains = excludedBlockchains,
|
||||
dispatchers = dispatchers,
|
||||
networkFactory = networkFactory,
|
||||
hederaTokenAddressResolver = HederaTokenAddressResolver(blockchainProviderTypesStore),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.tangem.data.managetokens.utils
|
||||
|
||||
import com.tangem.blockchain.blockchains.hedera.HederaContractIdResolver
|
||||
import com.tangem.blockchain.blockchains.hedera.HederaTokenAddressConverter
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.network.providers.ProviderType
|
||||
import com.tangem.blockchainsdk.providers.BlockchainProviderTypesStore
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
internal class HederaTokenAddressResolver(
|
||||
private val blockchainProviderTypesStore: BlockchainProviderTypesStore,
|
||||
) {
|
||||
private val tokenAddressConverter = HederaTokenAddressConverter()
|
||||
private val cache = ConcurrentHashMap<String, String>()
|
||||
|
||||
suspend fun resolveAddress(blockchain: Blockchain, contractAddress: String): String {
|
||||
cache[contractAddress.lowercase()]?.let { return it }
|
||||
|
||||
val resolver = HederaContractIdResolver(baseUrl = getBaseUrl(blockchain))
|
||||
val resolved = tokenAddressConverter.resolveTokenId(contractAddress) { resolver.resolve(it) }
|
||||
|
||||
require(!resolved.startsWith("0x", ignoreCase = true)) {
|
||||
"Failed to resolve Hedera contract ID for EVM address: $contractAddress"
|
||||
}
|
||||
|
||||
cache[contractAddress.lowercase()] = resolved
|
||||
return resolved
|
||||
}
|
||||
|
||||
private fun getBaseUrl(blockchain: Blockchain): String {
|
||||
val providerTypes = blockchainProviderTypesStore.get().value
|
||||
return requireNotNull(
|
||||
providerTypes[blockchain]
|
||||
?.filterIsInstance<ProviderType.Public>()
|
||||
?.firstOrNull()
|
||||
?.url,
|
||||
) {
|
||||
"Hedera provider URL not found for $blockchain"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.data.managetokens.utils
|
||||
|
||||
import com.tangem.blockchain.blockchains.cardano.CardanoTokenAddressConverter
|
||||
import com.tangem.blockchain.blockchains.hedera.HederaTokenAddressConverter
|
||||
import com.tangem.blockchain.blockchains.stellar.StellarTokenAddressConverter
|
||||
import com.tangem.blockchain.blockchains.sui.SuiTokenAddressConverter
|
||||
import com.tangem.blockchain.blockchains.xrp.XrpTokenAddressConverter
|
||||
|
|
@ -9,18 +8,19 @@ import com.tangem.blockchain.common.Blockchain
|
|||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.domain.models.network.Network
|
||||
|
||||
internal class TokenAddressesConverter {
|
||||
private val hederaTokenAddressConverter = HederaTokenAddressConverter()
|
||||
internal class TokenAddressesConverter(
|
||||
private val hederaTokenAddressResolver: HederaTokenAddressResolver,
|
||||
) {
|
||||
private val cardanoTokenAddressConverter = CardanoTokenAddressConverter()
|
||||
private val xrpTokenAddressConverter = XrpTokenAddressConverter()
|
||||
private val stellarTokenAddressConverter = StellarTokenAddressConverter()
|
||||
private val suiTokenAddressConverter = SuiTokenAddressConverter()
|
||||
|
||||
fun convertTokenAddress(networkId: Network.ID, contractAddress: String, symbol: String?): String {
|
||||
val convertedAddress = when (networkId.toBlockchain()) {
|
||||
suspend fun convertTokenAddress(networkId: Network.ID, contractAddress: String, symbol: String?): String {
|
||||
val convertedAddress = when (val blockchain = networkId.toBlockchain()) {
|
||||
Blockchain.Hedera,
|
||||
Blockchain.HederaTestnet,
|
||||
-> hederaTokenAddressConverter.convertToTokenId(contractAddress)
|
||||
-> hederaTokenAddressResolver.resolveAddress(blockchain, contractAddress)
|
||||
Blockchain.Sui,
|
||||
Blockchain.SuiTestnet,
|
||||
-> suiTokenAddressConverter.normalizeAddress(contractAddress)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue