Updated on 2026-08-14
This commit is contained in:
parent
4570bc334c
commit
602e20a1d2
53 changed files with 489 additions and 368 deletions
22
domain/assetsdiscovery/build.gradle.kts
Normal file
22
domain/assetsdiscovery/build.gradle.kts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
plugins {
|
||||
alias(deps.plugins.android.library)
|
||||
alias(deps.plugins.kotlin.android)
|
||||
id("configuration")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.tangem.domain.assetsdiscovery"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.domain.core)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.account.status)
|
||||
implementation(projects.core.utils)
|
||||
|
||||
implementation(projects.libs.blockchainSdk)
|
||||
implementation(tangemDeps.blockchain)
|
||||
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.arrow.core)
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.domain.assetsdiscovery
|
||||
|
||||
import com.tangem.blockchain.assetsdiscovery.AssetsDiscoveryService
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
|
||||
interface AssetsDiscoveryFacade {
|
||||
|
||||
suspend fun getAssetsDiscoveryService(userWalletId: UserWalletId, network: Network): AssetsDiscoveryServiceInfo?
|
||||
|
||||
data class AssetsDiscoveryServiceInfo(
|
||||
val address: String,
|
||||
val service: AssetsDiscoveryService,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.tangem.domain.assetsdiscovery.model
|
||||
|
||||
sealed class AssetsDiscoveryProgress {
|
||||
|
||||
data object Idle : AssetsDiscoveryProgress()
|
||||
|
||||
data class InProgress(
|
||||
val completedNetworks: Int,
|
||||
val totalNetworks: Int,
|
||||
) : AssetsDiscoveryProgress() {
|
||||
val progressPercent: Int
|
||||
get() = if (totalNetworks > 0) {
|
||||
completedNetworks * 100 / totalNetworks
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
data object Completed : AssetsDiscoveryProgress()
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.domain.assetsdiscovery.repository
|
||||
|
||||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AssetsDiscoveryRepository {
|
||||
|
||||
suspend fun runDiscovery(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun completeDiscovery(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun getPendingDiscoveryWalletIds(): List<UserWalletId>
|
||||
|
||||
fun observeDiscoveryProgress(userWalletId: UserWalletId): Flow<AssetsDiscoveryProgress>
|
||||
|
||||
fun acknowledgeCompletion(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun clearPendingFlag(userWalletId: UserWalletId)
|
||||
|
||||
suspend fun getDiscoveredCurrencies(userWalletId: UserWalletId): List<CryptoCurrency>
|
||||
|
||||
suspend fun clearDiscoveredTokens(userWalletId: UserWalletId)
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.domain.assetsdiscovery.usecase
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
|
||||
class AcknowledgeAssetsDiscoveryCompletionUseCase(
|
||||
private val assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId) {
|
||||
assetsDiscoveryRepository.acknowledgeCompletion(userWalletId)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.domain.assetsdiscovery.usecase
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.assetsdiscovery.model.AssetsDiscoveryProgress
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class ObserveAssetsDiscoveryUseCase(
|
||||
private val assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId): Flow<AssetsDiscoveryProgress> {
|
||||
return assetsDiscoveryRepository.observeDiscoveryProgress(userWalletId)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
package com.tangem.domain.assetsdiscovery.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
|
||||
import com.tangem.domain.models.account.AccountId
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.assetsdiscovery.repository.AssetsDiscoveryRepository
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class StartAssetsDiscoveryUseCase(
|
||||
private val assetsDiscoveryRepository: AssetsDiscoveryRepository,
|
||||
private val manageCryptoCurrenciesUseCase: ManageCryptoCurrenciesUseCase,
|
||||
private val appCoroutineScope: AppCoroutineScope,
|
||||
) {
|
||||
|
||||
private val activeSyncJobs = ConcurrentHashMap<UserWalletId, Job>()
|
||||
|
||||
operator fun invoke(userWalletId: UserWalletId) {
|
||||
activeSyncJobs[userWalletId]?.cancel()
|
||||
activeSyncJobs[userWalletId] = appCoroutineScope.launch {
|
||||
try {
|
||||
assetsDiscoveryRepository.runDiscovery(userWalletId)
|
||||
applyDiscoveredTokens(userWalletId)
|
||||
assetsDiscoveryRepository.completeDiscovery(userWalletId)
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Token sync failed for wallet: $userWalletId", e)
|
||||
} finally {
|
||||
activeSyncJobs.remove(userWalletId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun cancel(userWalletId: UserWalletId): Either<Throwable, Unit> = Either.catch {
|
||||
activeSyncJobs.remove(userWalletId)?.cancel()
|
||||
assetsDiscoveryRepository.clearPendingFlag(userWalletId)
|
||||
assetsDiscoveryRepository.clearDiscoveredTokens(userWalletId)
|
||||
}
|
||||
|
||||
fun applyPendingAssetsDiscovery() {
|
||||
appCoroutineScope.launch {
|
||||
try {
|
||||
val pendingIds = assetsDiscoveryRepository.getPendingDiscoveryWalletIds()
|
||||
for (walletId in pendingIds) {
|
||||
val isApplied = applyDiscoveredTokens(walletId)
|
||||
if (isApplied) {
|
||||
assetsDiscoveryRepository.clearPendingFlag(walletId)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Failed to apply pending syncs", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun applyDiscoveredTokens(userWalletId: UserWalletId): Boolean {
|
||||
val currencies = assetsDiscoveryRepository.getDiscoveredCurrencies(userWalletId)
|
||||
|
||||
if (currencies.isEmpty()) return true
|
||||
|
||||
val accountId = AccountId.forMainCryptoPortfolio(userWalletId)
|
||||
return manageCryptoCurrenciesUseCase.invokeAndAwait(
|
||||
accountId = accountId,
|
||||
add = currencies,
|
||||
).fold(
|
||||
ifRight = {
|
||||
assetsDiscoveryRepository.clearDiscoveredTokens(userWalletId)
|
||||
true
|
||||
},
|
||||
ifLeft = { error ->
|
||||
TangemLogger.e("Failed to apply discovered tokens for wallet: $userWalletId, error: $error")
|
||||
false
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue