Updated on 2026-08-14

This commit is contained in:
Tangem 2024-08-27 19:12:07 +04:00
parent 297a006e3d
commit ce9335e3bd
5 changed files with 160 additions and 21 deletions

View file

@ -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,
)
}
}

View file

@ -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,
)
}
}