Updated on 2026-08-14
This commit is contained in:
parent
4570bc334c
commit
602e20a1d2
53 changed files with 489 additions and 368 deletions
|
|
@ -7,22 +7,25 @@ plugins {
|
|||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.data.tokensync"
|
||||
namespace = "com.tangem.data.assetsdiscovery"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.domain.tokensync)
|
||||
api(projects.domain.assetsdiscovery)
|
||||
implementation(projects.domain.tokens)
|
||||
implementation(projects.domain.tokens.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.walletManager)
|
||||
implementation(projects.domain.wallets)
|
||||
implementation(projects.data.common)
|
||||
implementation(projects.data.walletManager)
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
implementation(projects.libs.tangemSdkApi)
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(tangemDeps.blockchain)
|
||||
implementation(tangemDeps.card.core)
|
||||
|
||||
implementation(deps.androidx.datastore)
|
||||
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.data.assetsdiscovery
|
||||
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.address.AddressType
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.utils.toBlockchain
|
||||
import com.tangem.crypto.hdWallet.DerivationPath
|
||||
import com.tangem.data.walletmanager.extensions.makePublicKey
|
||||
import com.tangem.domain.assetsdiscovery.AssetsDiscoveryFacade
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.getSyncStrict
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.wallets.config.curvesConfig
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultAssetsDiscoveryFacade @Inject constructor(
|
||||
private val blockchainSDKFactory: BlockchainSDKFactory,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) : AssetsDiscoveryFacade {
|
||||
|
||||
override suspend fun getAssetsDiscoveryService(
|
||||
userWalletId: UserWalletId,
|
||||
network: Network,
|
||||
): AssetsDiscoveryFacade.AssetsDiscoveryServiceInfo? = withContext(dispatchers.io) {
|
||||
val userWallet = userWalletsListRepository.getSyncStrict(userWalletId)
|
||||
if (userWallet !is UserWallet.Hot) return@withContext null
|
||||
|
||||
val assetsDiscoveryServiceFactory = blockchainSDKFactory.getAssetsDiscoveryServiceFactorySync()
|
||||
?: return@withContext null
|
||||
|
||||
val blockchain = network.toBlockchain()
|
||||
val address = makeAddress(userWallet, blockchain, network.derivationPath.value)
|
||||
?: return@withContext null
|
||||
|
||||
AssetsDiscoveryFacade.AssetsDiscoveryServiceInfo(
|
||||
address = address,
|
||||
service = assetsDiscoveryServiceFactory.create(blockchain),
|
||||
)
|
||||
}
|
||||
|
||||
private fun makeAddress(hotWallet: UserWallet.Hot, blockchain: Blockchain, derivationPath: String?): String? {
|
||||
val curve = hotWallet.curvesConfig.primaryCurve(blockchain)
|
||||
val selectedWallet = hotWallet.wallets.orEmpty().firstOrNull { it.curve == curve }
|
||||
?: return null
|
||||
|
||||
val path = derivationPath?.let { DerivationPath(rawPath = it) }
|
||||
|
||||
val publicKey = if (path != null) {
|
||||
makePublicKey(
|
||||
seedKey = selectedWallet.publicKey,
|
||||
blockchain = blockchain,
|
||||
derivationPath = path,
|
||||
derivedWalletKeys = selectedWallet.derivedKeys,
|
||||
isWallet2 = true,
|
||||
) ?: return null
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
return try {
|
||||
val addresses = if (publicKey != null) {
|
||||
blockchain.makeAddresses(
|
||||
walletPublicKey = publicKey.blockchainKey,
|
||||
pairPublicKey = null,
|
||||
curve = selectedWallet.curve,
|
||||
)
|
||||
} else {
|
||||
blockchain.makeAddresses(
|
||||
walletPublicKey = selectedWallet.publicKey,
|
||||
pairPublicKey = null,
|
||||
curve = selectedWallet.curve,
|
||||
)
|
||||
}
|
||||
addresses.find { it.type == AddressType.Default }?.value
|
||||
} catch (e: Throwable) {
|
||||
TangemLogger.w("Failed to derive address for $blockchain", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.tangem.data.assetsdiscovery.di
|
||||
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.assetsdiscovery.DefaultAssetsDiscoveryFacade
|
||||
import com.tangem.data.assetsdiscovery.repository.DefaultAssetsDiscoveryRepository
|
||||
import com.tangem.data.assetsdiscovery.store.AssetsDiscoveryStoreFactory
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.assetsdiscovery.AssetsDiscoveryFacade
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object AssetsDiscoveryDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAssetsDiscoveryFacade(
|
||||
blockchainSDKFactory: BlockchainSDKFactory,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
): AssetsDiscoveryFacade = DefaultAssetsDiscoveryFacade(
|
||||
blockchainSDKFactory = blockchainSDKFactory,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideAssetsDiscoveryRepository(
|
||||
assetsDiscoveryFacade: AssetsDiscoveryFacade,
|
||||
tangemTechApi: TangemTechApi,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
networkFactory: NetworkFactory,
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
assetsDiscoveryStoreFactory: AssetsDiscoveryStoreFactory,
|
||||
responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): AssetsDiscoveryRepository = DefaultAssetsDiscoveryRepository(
|
||||
assetsDiscoveryFacade = assetsDiscoveryFacade,
|
||||
tangemTechApi = tangemTechApi,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
networkFactory = networkFactory,
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
assetsDiscoveryStoreFactory = assetsDiscoveryStoreFactory,
|
||||
responseCryptoCurrenciesFactory = responseCryptoCurrenciesFactory,
|
||||
dispatchers = dispatchers,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.data.tokensync.repository
|
||||
package com.tangem.data.assetsdiscovery.repository
|
||||
|
||||
import com.tangem.blockchain.assetsdiscovery.models.DiscoveredAsset
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.tokenbalance.models.TokenBalance
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.assetsdiscovery.store.AssetsDiscoveryStore
|
||||
import com.tangem.data.assetsdiscovery.store.AssetsDiscoveryStoreFactory
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.data.tokensync.store.TokenSyncStore
|
||||
import com.tangem.data.tokensync.store.TokenSyncStoreFactory
|
||||
import com.tangem.datasource.api.common.response.getOrThrow
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.api.tangemTech.models.CoinsResponse
|
||||
|
|
@ -14,15 +14,15 @@ 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.getObjectMapSync
|
||||
import com.tangem.domain.assetsdiscovery.AssetsDiscoveryFacade
|
||||
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.common.wallets.getSyncStrict
|
||||
import com.tangem.domain.models.account.DerivationIndex
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.tokensync.model.TokenSyncProgress
|
||||
import com.tangem.domain.tokensync.repository.TokenSyncRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.async
|
||||
|
|
@ -30,42 +30,39 @@ import kotlinx.coroutines.awaitAll
|
|||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.math.BigDecimal
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
internal class DefaultTokenSyncRepository(
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
internal class DefaultAssetsDiscoveryRepository(
|
||||
private val assetsDiscoveryFacade: AssetsDiscoveryFacade,
|
||||
private val tangemTechApi: TangemTechApi,
|
||||
private val userWalletsListRepository: UserWalletsListRepository,
|
||||
private val networkFactory: NetworkFactory,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val tokenSyncStoreFactory: TokenSyncStoreFactory,
|
||||
private val assetsDiscoveryStoreFactory: AssetsDiscoveryStoreFactory,
|
||||
private val responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
private val excludedBlockchains: ExcludedBlockchains,
|
||||
) : TokenSyncRepository {
|
||||
) : AssetsDiscoveryRepository {
|
||||
|
||||
private val semaphore = Semaphore(MAX_CONCURRENT_REQUESTS)
|
||||
private val progressStates = ConcurrentHashMap<String, MutableStateFlow<TokenSyncProgress>>()
|
||||
private val progressStates = ConcurrentHashMap<String, MutableStateFlow<AssetsDiscoveryProgress>>()
|
||||
|
||||
override fun observeSyncProgress(userWalletId: UserWalletId): Flow<TokenSyncProgress> {
|
||||
override fun observeDiscoveryProgress(userWalletId: UserWalletId): Flow<AssetsDiscoveryProgress> {
|
||||
return getProgressFlow(userWalletId)
|
||||
}
|
||||
|
||||
override fun acknowledgeCompletion(userWalletId: UserWalletId) {
|
||||
val key = userWalletId.stringValue
|
||||
val stateFlow = progressStates[key] ?: return
|
||||
stateFlow.value = TokenSyncProgress.Idle
|
||||
stateFlow.value = AssetsDiscoveryProgress.Idle
|
||||
progressStates.remove(key, stateFlow)
|
||||
}
|
||||
|
||||
override suspend fun getDiscoveredCurrencies(userWalletId: UserWalletId): List<CryptoCurrency> {
|
||||
val tokenSyncStore = tokenSyncStoreFactory.provide(userWalletId)
|
||||
val storedTokens = tokenSyncStore.get()
|
||||
val assetsDiscoveryStore = assetsDiscoveryStoreFactory.provide(userWalletId)
|
||||
val storedTokens = assetsDiscoveryStore.get()
|
||||
if (storedTokens.isEmpty()) return emptyList()
|
||||
|
||||
val userWallet = userWalletsListRepository.getSyncStrict(userWalletId)
|
||||
|
|
@ -77,34 +74,34 @@ internal class DefaultTokenSyncRepository(
|
|||
}
|
||||
|
||||
override suspend fun clearDiscoveredTokens(userWalletId: UserWalletId) {
|
||||
val tokenSyncStore = tokenSyncStoreFactory.provide(userWalletId)
|
||||
tokenSyncStore.clear()
|
||||
val assetsDiscoveryStore = assetsDiscoveryStoreFactory.provide(userWalletId)
|
||||
assetsDiscoveryStore.clear()
|
||||
}
|
||||
|
||||
override suspend fun clearPendingFlag(userWalletId: UserWalletId) {
|
||||
setPendingFlag(userWalletId, value = false)
|
||||
}
|
||||
|
||||
override suspend fun getPendingSyncWalletIds(): List<UserWalletId> {
|
||||
override suspend fun getPendingDiscoveryWalletIds(): List<UserWalletId> {
|
||||
val pendingMap = appPreferencesStore
|
||||
.getObjectMapSync<Boolean>(PreferencesKeys.PENDING_DISCOVERY_SYNC_KEY)
|
||||
.getObjectMapSync<Boolean>(PreferencesKeys.PENDING_ASSETS_DISCOVERY_KEY)
|
||||
return pendingMap
|
||||
.filter { it.value }
|
||||
.map { UserWalletId(it.key) }
|
||||
}
|
||||
|
||||
override suspend fun runSync(userWalletId: UserWalletId) {
|
||||
override suspend fun runDiscovery(userWalletId: UserWalletId) {
|
||||
val networks = getSupportedNetworks(userWalletId)
|
||||
|
||||
if (networks.isEmpty()) return
|
||||
|
||||
setPendingFlag(userWalletId, value = true)
|
||||
val tokenSyncStore = tokenSyncStoreFactory.provide(userWalletId)
|
||||
tokenSyncStore.clear()
|
||||
val assetsDiscoveryStore = assetsDiscoveryStoreFactory.provide(userWalletId)
|
||||
assetsDiscoveryStore.clear()
|
||||
|
||||
val batches = networks.chunked(MAX_CONCURRENT_REQUESTS)
|
||||
var completedNetworks = 0
|
||||
getProgressFlow(userWalletId).value = TokenSyncProgress.InProgress(
|
||||
getProgressFlow(userWalletId).value = AssetsDiscoveryProgress.InProgress(
|
||||
completedNetworks = 0,
|
||||
totalNetworks = networks.size,
|
||||
)
|
||||
|
|
@ -114,25 +111,23 @@ internal class DefaultTokenSyncRepository(
|
|||
completedNetworks = handleBatchResults(
|
||||
userWalletId = userWalletId,
|
||||
results = batchResults,
|
||||
tokenSyncStore = tokenSyncStore,
|
||||
assetsDiscoveryStore = assetsDiscoveryStore,
|
||||
completedNetworks = completedNetworks,
|
||||
totalNetworks = networks.size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun completeSync(userWalletId: UserWalletId) {
|
||||
override suspend fun completeDiscovery(userWalletId: UserWalletId) {
|
||||
setPendingFlag(userWalletId, value = false)
|
||||
getProgressFlow(userWalletId).value = TokenSyncProgress.Completed
|
||||
getProgressFlow(userWalletId).value = AssetsDiscoveryProgress.Completed
|
||||
}
|
||||
|
||||
private suspend fun processBatch(userWalletId: UserWalletId, batch: List<Network>): List<NetworkResult> {
|
||||
return coroutineScope {
|
||||
batch.map { network ->
|
||||
async(dispatchers.io) {
|
||||
semaphore.withPermit {
|
||||
processNetwork(userWalletId, network)
|
||||
}
|
||||
processNetwork(userWalletId, network)
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
|
|
@ -141,7 +136,7 @@ internal class DefaultTokenSyncRepository(
|
|||
private suspend fun handleBatchResults(
|
||||
userWalletId: UserWalletId,
|
||||
results: List<NetworkResult>,
|
||||
tokenSyncStore: TokenSyncStore,
|
||||
assetsDiscoveryStore: AssetsDiscoveryStore,
|
||||
completedNetworks: Int,
|
||||
totalNetworks: Int,
|
||||
): Int {
|
||||
|
|
@ -150,8 +145,8 @@ internal class DefaultTokenSyncRepository(
|
|||
|
||||
for (result in results) {
|
||||
completed++
|
||||
handleNetworkResult(result, tokenSyncStore)
|
||||
progressFlow.value = TokenSyncProgress.InProgress(
|
||||
handleNetworkResult(result, assetsDiscoveryStore)
|
||||
progressFlow.value = AssetsDiscoveryProgress.InProgress(
|
||||
completedNetworks = completed,
|
||||
totalNetworks = totalNetworks,
|
||||
)
|
||||
|
|
@ -160,35 +155,35 @@ internal class DefaultTokenSyncRepository(
|
|||
return completed
|
||||
}
|
||||
|
||||
private suspend fun handleNetworkResult(result: NetworkResult, tokenSyncStore: TokenSyncStore) {
|
||||
private suspend fun handleNetworkResult(result: NetworkResult, assetsDiscoveryStore: AssetsDiscoveryStore) {
|
||||
when (result) {
|
||||
is NetworkResult.Success -> {
|
||||
if (result.responseTokens.isNotEmpty()) {
|
||||
try {
|
||||
tokenSyncStore.append(result.responseTokens)
|
||||
assetsDiscoveryStore.append(result.responseTokens)
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Failed to store discovered tokens for network: ${result.networkId}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
is NetworkResult.Error -> {
|
||||
TangemLogger.e("Token sync failed for network: ${result.networkId}", result.cause)
|
||||
TangemLogger.e("Assets discovery failed for network: ${result.networkId}", result.cause)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processNetwork(userWalletId: UserWalletId, network: Network): NetworkResult {
|
||||
return try {
|
||||
val tokenBalances = fetchAndFilterTokenBalances(userWalletId, network)
|
||||
val discoveredAssets = discoverAndFilterAssets(userWalletId, network)
|
||||
|
||||
if (tokenBalances.isEmpty()) {
|
||||
if (discoveredAssets.isEmpty()) {
|
||||
return NetworkResult.Success(
|
||||
networkId = network.rawId,
|
||||
responseTokens = emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
val enrichedTokens = enrichTokensWithCatalog(tokenBalances, network)
|
||||
val enrichedTokens = enrichTokensWithCatalog(discoveredAssets, network)
|
||||
|
||||
val responseTokens = enrichedTokens
|
||||
.filter { it.contractAddress != null }
|
||||
|
|
@ -203,36 +198,35 @@ internal class DefaultTokenSyncRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchAndFilterTokenBalances(userWalletId: UserWalletId, network: Network): List<TokenBalance> {
|
||||
return withContext(dispatchers.io) {
|
||||
walletManagersFacade.getTokenBalances(userWalletId, network)
|
||||
private suspend fun discoverAndFilterAssets(userWalletId: UserWalletId, network: Network): List<DiscoveredAsset> =
|
||||
withContext(dispatchers.io) {
|
||||
val providerInfo = assetsDiscoveryFacade.getAssetsDiscoveryService(userWalletId, network)
|
||||
?: return@withContext emptyList()
|
||||
providerInfo.service.discoverAssets(providerInfo.address)
|
||||
.filter { it.amount > BigDecimal.ZERO }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun enrichTokensWithCatalog(
|
||||
tokenBalances: List<TokenBalance>,
|
||||
assets: List<DiscoveredAsset>,
|
||||
network: Network,
|
||||
): List<DiscoveredToken> = withContext(dispatchers.io) {
|
||||
val tokensToEnrich = tokenBalances.filter { !it.isNativeToken }
|
||||
): List<EnrichedDiscoveredAsset> = withContext(dispatchers.io) {
|
||||
val tokensToEnrich = assets.filterIsInstance<DiscoveredAsset.Token>()
|
||||
|
||||
val catalogMap = fetchCatalogInfo(
|
||||
networkId = network.rawId,
|
||||
contractAddresses = tokensToEnrich.mapNotNull(TokenBalance::contractAddress),
|
||||
contractAddresses = tokensToEnrich.map { it.contractAddress },
|
||||
)
|
||||
|
||||
tokenBalances.mapNotNull { balance ->
|
||||
if (balance.isNativeToken) return@mapNotNull null
|
||||
|
||||
val contractAddressLower = balance.contractAddress?.lowercase()
|
||||
val coin = contractAddressLower?.let { catalogMap[it] } ?: return@mapNotNull null
|
||||
tokensToEnrich.mapNotNull { balance ->
|
||||
val contractAddressLower = balance.contractAddress.lowercase()
|
||||
val coin = catalogMap[contractAddressLower] ?: return@mapNotNull null
|
||||
val decimals = coin.networks
|
||||
.find { it.contractAddress?.lowercase() == contractAddressLower }
|
||||
?.decimalCount
|
||||
?.toInt()
|
||||
?: 0
|
||||
|
||||
DiscoveredToken(
|
||||
EnrichedDiscoveredAsset(
|
||||
contractAddress = balance.contractAddress,
|
||||
symbol = coin.symbol,
|
||||
name = coin.name,
|
||||
|
|
@ -290,23 +284,23 @@ internal class DefaultTokenSyncRepository(
|
|||
}
|
||||
}
|
||||
|
||||
private fun getProgressFlow(userWalletId: UserWalletId): MutableStateFlow<TokenSyncProgress> {
|
||||
private fun getProgressFlow(userWalletId: UserWalletId): MutableStateFlow<AssetsDiscoveryProgress> {
|
||||
return progressStates.getOrPut(userWalletId.stringValue) {
|
||||
MutableStateFlow(TokenSyncProgress.Idle)
|
||||
MutableStateFlow(AssetsDiscoveryProgress.Idle)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun setPendingFlag(userWalletId: UserWalletId, value: Boolean) {
|
||||
appPreferencesStore.editData { prefs ->
|
||||
prefs.setObjectMap(
|
||||
key = PreferencesKeys.PENDING_DISCOVERY_SYNC_KEY,
|
||||
value = prefs.getObjectMap<Boolean>(PreferencesKeys.PENDING_DISCOVERY_SYNC_KEY)
|
||||
key = PreferencesKeys.PENDING_ASSETS_DISCOVERY_KEY,
|
||||
value = prefs.getObjectMap<Boolean>(PreferencesKeys.PENDING_ASSETS_DISCOVERY_KEY)
|
||||
.plus(userWalletId.stringValue to value),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun DiscoveredToken.toResponseToken(): UserTokensResponse.Token {
|
||||
private fun EnrichedDiscoveredAsset.toResponseToken(): UserTokensResponse.Token {
|
||||
return UserTokensResponse.Token(
|
||||
id = currencyId,
|
||||
networkId = networkId,
|
||||
|
|
@ -317,7 +311,7 @@ internal class DefaultTokenSyncRepository(
|
|||
)
|
||||
}
|
||||
|
||||
private data class DiscoveredToken(
|
||||
private data class EnrichedDiscoveredAsset(
|
||||
val contractAddress: String?,
|
||||
val symbol: String,
|
||||
val name: String,
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.tangem.data.tokensync.store
|
||||
package com.tangem.data.assetsdiscovery.store
|
||||
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
|
||||
interface TokenSyncStore {
|
||||
interface AssetsDiscoveryStore {
|
||||
|
||||
suspend fun get(): List<UserTokensResponse.Token>
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.tangem.data.tokensync.store
|
||||
package com.tangem.data.assetsdiscovery.store
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
|
|
@ -17,18 +17,18 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TokenSyncStoreFactory @Inject constructor(
|
||||
class AssetsDiscoveryStoreFactory @Inject constructor(
|
||||
@NetworkMoshi private val moshi: Moshi,
|
||||
@ApplicationContext private val context: Context,
|
||||
private val appScope: AppCoroutineScope,
|
||||
) {
|
||||
|
||||
private val stores = ConcurrentHashMap<String, TokenSyncStore>()
|
||||
private val stores = ConcurrentHashMap<String, AssetsDiscoveryStore>()
|
||||
|
||||
fun provide(userWalletId: UserWalletId): TokenSyncStore {
|
||||
fun provide(userWalletId: UserWalletId): AssetsDiscoveryStore {
|
||||
val userWalletStringId = userWalletId.formatted()
|
||||
return stores.computeIfAbsent(userWalletStringId) {
|
||||
DefaultTokenSyncStore(
|
||||
DefaultAssetsDiscoveryStore(
|
||||
persistenceStore = createPersistenceStore(
|
||||
fileName = "token_sync_$userWalletStringId",
|
||||
types = listTypes<UserTokensResponse.Token>(),
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package com.tangem.data.tokensync.store
|
||||
package com.tangem.data.assetsdiscovery.store
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import com.tangem.datasource.api.tangemTech.models.UserTokensResponse
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
|
||||
internal class DefaultTokenSyncStore(
|
||||
internal class DefaultAssetsDiscoveryStore(
|
||||
private val persistenceStore: DataStore<List<UserTokensResponse.Token>>,
|
||||
) : TokenSyncStore {
|
||||
) : AssetsDiscoveryStore {
|
||||
|
||||
override suspend fun get(): List<UserTokensResponse.Token> {
|
||||
return persistenceStore.data.firstOrNull().orEmpty()
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.tangem.data.tokensync.di
|
||||
|
||||
import com.tangem.blockchainsdk.utils.ExcludedBlockchains
|
||||
import com.tangem.data.common.currency.ResponseCryptoCurrenciesFactory
|
||||
import com.tangem.data.common.network.NetworkFactory
|
||||
import com.tangem.data.tokensync.repository.DefaultTokenSyncRepository
|
||||
import com.tangem.data.tokensync.store.TokenSyncStoreFactory
|
||||
import com.tangem.datasource.api.tangemTech.TangemTechApi
|
||||
import com.tangem.datasource.local.preferences.AppPreferencesStore
|
||||
import com.tangem.domain.common.wallets.UserWalletsListRepository
|
||||
import com.tangem.domain.tokensync.repository.TokenSyncRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object TokenSyncDataModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideTokenSyncRepository(
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
tangemTechApi: TangemTechApi,
|
||||
userWalletsListRepository: UserWalletsListRepository,
|
||||
networkFactory: NetworkFactory,
|
||||
appPreferencesStore: AppPreferencesStore,
|
||||
tokenSyncStoreFactory: TokenSyncStoreFactory,
|
||||
responseCryptoCurrenciesFactory: ResponseCryptoCurrenciesFactory,
|
||||
dispatchers: CoroutineDispatcherProvider,
|
||||
excludedBlockchains: ExcludedBlockchains,
|
||||
): TokenSyncRepository {
|
||||
return DefaultTokenSyncRepository(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
tangemTechApi = tangemTechApi,
|
||||
userWalletsListRepository = userWalletsListRepository,
|
||||
networkFactory = networkFactory,
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
tokenSyncStoreFactory = tokenSyncStoreFactory,
|
||||
responseCryptoCurrenciesFactory = responseCryptoCurrenciesFactory,
|
||||
dispatchers = dispatchers,
|
||||
excludedBlockchains = excludedBlockchains,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ import com.tangem.blockchain.extensions.Result
|
|||
import com.tangem.blockchain.extensions.SimpleResult
|
||||
import com.tangem.blockchain.nft.models.NFTAsset
|
||||
import com.tangem.blockchain.nft.models.NFTCollection
|
||||
import com.tangem.blockchain.tokenbalance.models.TokenBalance
|
||||
import com.tangem.blockchain.transactionhistory.models.TransactionHistoryRequest
|
||||
import com.tangem.blockchain.yieldsupply.YieldSupplyContractCallDataProviderFactory
|
||||
import com.tangem.blockchainsdk.BlockchainSDKFactory
|
||||
|
|
@ -850,17 +849,6 @@ internal class DefaultWalletManagersFacade @Inject constructor(
|
|||
return blockchain.getNFTExploreUrl(assetIdentifier)
|
||||
}
|
||||
|
||||
override suspend fun getTokenBalances(userWalletId: UserWalletId, network: Network): List<TokenBalance> {
|
||||
val blockchain = network.toBlockchain()
|
||||
val walletManager = getOrCreateWalletManager(
|
||||
userWalletId = userWalletId,
|
||||
blockchain = blockchain,
|
||||
derivationPath = network.derivationPath.value,
|
||||
) ?: return emptyList()
|
||||
val address = walletManager.wallet.address
|
||||
return walletManager.getTokenBalances(address)
|
||||
}
|
||||
|
||||
override suspend fun isAccountInitialized(userWalletId: UserWalletId, network: Network): Boolean {
|
||||
val walletManager = getOrCreateWalletManager(userWalletId = userWalletId, network = network)
|
||||
val initializableAccountWalletManger = walletManager as? InitializableAccount ?: return true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue