Updated on 2026-08-14

This commit is contained in:
Tangem 2025-10-23 10:44:51 +04:00
parent 68615198ae
commit 9c296c7ced
10 changed files with 226 additions and 80 deletions

View file

@ -113,6 +113,7 @@ dependencies {
implementation(projects.domain.legacy)
implementation(projects.libs.blockchainSdk)
implementation(projects.domain.account)
implementation(projects.domain.account.status)
implementation(projects.domain.models)
implementation(projects.domain.core)
api(projects.domain.common)

View file

@ -3,6 +3,8 @@ package com.tangem.tap.di.domain
import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles
import com.tangem.domain.account.fetcher.SingleAccountListFetcher
import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.account.status.usecase.RecoverCryptoPortfolioUseCase
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
import com.tangem.domain.account.tokens.MainAccountTokensMigration
import com.tangem.domain.account.usecase.*
import dagger.Module
@ -50,10 +52,12 @@ internal object AccountDomainModule {
fun provideRecoverCryptoPortfolioUseCase(
accountsCRUDRepository: AccountsCRUDRepository,
mainAccountTokensMigration: MainAccountTokensMigration,
cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
): RecoverCryptoPortfolioUseCase {
return RecoverCryptoPortfolioUseCase(
crudRepository = accountsCRUDRepository,
mainAccountTokensMigration = mainAccountTokensMigration,
cryptoCurrencyBalanceFetcher = cryptoCurrencyBalanceFetcher,
)
}

View file

@ -6,6 +6,7 @@ import com.tangem.domain.account.status.usecase.GetAccountCurrencyByAddressUseCa
import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase
import com.tangem.domain.account.status.usecase.GetCryptoCurrencyActionsUseCaseV2
import com.tangem.domain.account.status.usecase.ManageCryptoCurrenciesUseCase
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.express.ExpressServiceFetcher
@ -70,14 +71,12 @@ internal object AccountStatusUseCaseModule {
@Provides
@Singleton
fun provideSaveCryptoCurrenciesUseCase(
fun provideManageCryptoCurrenciesUseCase(
singleAccountListSupplier: SingleAccountListSupplier,
accountsCRUDRepository: AccountsCRUDRepository,
currenciesRepository: CurrenciesRepository,
derivationsRepository: DerivationsRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
stakingIdFactory: StakingIdFactory,
networksCleaner: NetworksCleaner,
stakingCleaner: StakingCleaner,
@ -89,9 +88,7 @@ internal object AccountStatusUseCaseModule {
accountsCRUDRepository = accountsCRUDRepository,
currenciesRepository = currenciesRepository,
derivationsRepository = derivationsRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
cryptoCurrencyBalanceFetcher = cryptoCurrencyBalanceFetcher,
stakingIdFactory = stakingIdFactory,
networksCleaner = networksCleaner,
stakingCleaner = stakingCleaner,
@ -100,4 +97,24 @@ internal object AccountStatusUseCaseModule {
dispatchers = dispatchers,
)
}
@Provides
@Singleton
fun provideCryptoCurrencyBalanceFetcher(
accountsCRUDRepository: AccountsCRUDRepository,
multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
stakingIdFactory: StakingIdFactory,
dispatchers: CoroutineDispatcherProvider,
): CryptoCurrencyBalanceFetcher {
return CryptoCurrencyBalanceFetcher(
accountsCRUDRepository = accountsCRUDRepository,
multiNetworkStatusFetcher = multiNetworkStatusFetcher,
multiQuoteStatusFetcher = multiQuoteStatusFetcher,
multiYieldBalanceFetcher = multiYieldBalanceFetcher,
stakingIdFactory = stakingIdFactory,
parallelUpdatingScope = CoroutineScope(SupervisorJob() + dispatchers.default),
)
}
}

View file

@ -5,6 +5,7 @@ import arrow.core.raise.Raise
import arrow.core.raise.catch
import com.tangem.domain.account.producer.SingleAccountListProducer
import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.core.utils.eitherOn
import com.tangem.domain.express.ExpressServiceFetcher
@ -14,11 +15,8 @@ import com.tangem.domain.models.account.AccountId
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.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.networks.utils.NetworksCleaner
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.staking.utils.StakingCleaner
import com.tangem.domain.tokens.repository.CurrenciesRepository
import com.tangem.domain.wallets.derivations.DerivationsRepository
@ -30,14 +28,15 @@ import timber.log.Timber
* Use case for saving crypto currencies to a specific account.
*
* @property singleAccountListSupplier Supplier to get account details.
* @property accountsCRUDRepository Repository for performing CRUD operations on accounts.
* @property currenciesRepository Repository for managing currencies.
* @property derivationsRepository Repository for deriving public keys.
* @property multiNetworkStatusFetcher Fetcher for updating network statuses.
* @property multiQuoteStatusFetcher Fetcher for updating quote statuses.
* @property multiYieldBalanceFetcher Fetcher for updating yield balances.
* @property cryptoCurrencyBalanceFetcher Fetcher for updating crypto currency balances.
* @property stakingIdFactory Factory for creating staking IDs.
* @property networksCleaner Cleaner for removing obsolete network data.
* @property stakingCleaner Cleaner for removing obsolete staking data.
* @property expressServiceFetcher Fetcher for updating express service data.
* @property parallelUpdatingScope Coroutine scope for parallel updates.
* @property dispatchers Coroutine dispatchers for managing threading.
*
[REDACTED_AUTHOR]
@ -48,9 +47,7 @@ class ManageCryptoCurrenciesUseCase(
private val accountsCRUDRepository: AccountsCRUDRepository,
private val currenciesRepository: CurrenciesRepository,
private val derivationsRepository: DerivationsRepository,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
private val stakingIdFactory: StakingIdFactory,
private val networksCleaner: NetworksCleaner,
private val stakingCleaner: StakingCleaner,
@ -98,7 +95,7 @@ class ManageCryptoCurrenciesUseCase(
launch { accountsCRUDRepository.syncTokens(userWalletId) }
}
refreshBalances(userWalletId = userWalletId, currencies = modifiedCurrencyList.added)
cryptoCurrencyBalanceFetcher(userWalletId = userWalletId, currencies = modifiedCurrencyList.added)
refreshExpress(userWalletId = userWalletId, currencies = modifiedCurrencyList.total)
clearMetadata(userWalletId = userWalletId, currencies = modifiedCurrencyList.removed)
}
@ -132,7 +129,7 @@ class ManageCryptoCurrenciesUseCase(
saveAccount(account = account.copy(cryptoCurrencies = modifiedCurrencyList.total.toSet()))
parallelUpdatingScope.launch {
refreshBalances(userWalletId = userWalletId, currencies = listOf(tokenToAdd))
cryptoCurrencyBalanceFetcher(userWalletId = userWalletId, currencies = listOf(tokenToAdd))
refreshExpress(userWalletId = userWalletId, currencies = modifiedCurrencyList.total)
}
@ -253,46 +250,6 @@ class ManageCryptoCurrenciesUseCase(
)
}
private suspend fun refreshBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
if (currencies.isEmpty()) return
coroutineScope {
launch { refreshNetworks(userWalletId = userWalletId, currencies = currencies) }
launch { refreshYieldBalances(userWalletId = userWalletId, currencies = currencies) }
launch { refreshQuotes(currencies = currencies) }
}
}
private suspend fun refreshNetworks(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
multiNetworkStatusFetcher(
params = MultiNetworkStatusFetcher.Params(
userWalletId = userWalletId,
networks = currencies.mapTo(hashSetOf(), CryptoCurrency::network),
),
)
accountsCRUDRepository.syncTokens(userWalletId)
}
private suspend fun refreshYieldBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
val stakingIds = currencies.mapNotNullTo(hashSetOf()) {
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it).getOrNull()
}
multiYieldBalanceFetcher(
params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = stakingIds),
)
}
private suspend fun refreshQuotes(currencies: List<CryptoCurrency>) {
multiQuoteStatusFetcher(
params = MultiQuoteStatusFetcher.Params(
currenciesIds = currencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
appCurrencyId = null,
),
)
}
private suspend fun refreshExpress(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
if (currencies.isEmpty()) return

View file

@ -1,4 +1,4 @@
package com.tangem.domain.account.usecase
package com.tangem.domain.account.status.usecase
import arrow.core.Either
import arrow.core.getOrElse
@ -9,6 +9,7 @@ import arrow.core.raise.ensure
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.models.ArchivedAccount
import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
import com.tangem.domain.account.tokens.MainAccountTokensMigration
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountId
@ -25,6 +26,7 @@ import com.tangem.domain.models.wallet.UserWalletId
class RecoverCryptoPortfolioUseCase(
private val crudRepository: AccountsCRUDRepository,
private val mainAccountTokensMigration: MainAccountTokensMigration,
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher,
) {
/**
@ -53,6 +55,8 @@ class RecoverCryptoPortfolioUseCase(
derivationIndex = recoveredAccount.derivationIndex,
)
refreshBalances(accountId = accountId)
recoveredAccount
}
@ -93,6 +97,23 @@ class RecoverCryptoPortfolioUseCase(
)
}
private suspend fun refreshBalances(accountId: AccountId): Either<Error, Unit> = either {
val currencies = catch(
block = { crudRepository.getAccountSync(accountId = accountId) },
catch = { raise(Error.DataOperationFailed(cause = it)) },
)
.getOrElse { raise(Error.DataOperationFailed(message = "Account not found: $accountId")) }
.cryptoCurrencies
.toList()
catch(
block = {
cryptoCurrencyBalanceFetcher(userWalletId = accountId.userWalletId, currencies = currencies)
},
catch = { raise(Error.DataOperationFailed(cause = it)) },
)
}
/**
* Represents possible errors that can occur during the add operation
*/

View file

@ -0,0 +1,124 @@
package com.tangem.domain.account.status.utils
import arrow.core.Either
import arrow.core.raise.either
import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher
import com.tangem.domain.staking.StakingIdFactory
import com.tangem.domain.staking.multi.MultiYieldBalanceFetcher
import com.tangem.domain.tokens.wallet.FetchingSource
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
/**
* Utility class responsible for fetching and refreshing the balances of various crypto currencies
* associated with a user's wallet.
*
* @property accountsCRUDRepository Repository for managing account data.
* @property multiNetworkStatusFetcher Fetcher for updating network statuses.
* @property multiQuoteStatusFetcher Fetcher for updating quote statuses.
* @property multiYieldBalanceFetcher Fetcher for updating yield balances.
* @property stakingIdFactory Factory for creating staking IDs.
* @property parallelUpdatingScope Coroutine scope for parallel balance updates.
*
[REDACTED_AUTHOR]
*/
class CryptoCurrencyBalanceFetcher(
private val accountsCRUDRepository: AccountsCRUDRepository,
private val multiNetworkStatusFetcher: MultiNetworkStatusFetcher,
private val multiQuoteStatusFetcher: MultiQuoteStatusFetcher,
private val multiYieldBalanceFetcher: MultiYieldBalanceFetcher,
private val stakingIdFactory: StakingIdFactory,
private val parallelUpdatingScope: CoroutineScope,
) {
private val mutex = Mutex()
operator fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
if (currencies.isEmpty()) return
parallelUpdatingScope.launch {
mutex.withLock {
refreshBalances(userWalletId, currencies)
}
}
}
private suspend fun refreshBalances(userWalletId: UserWalletId, currencies: List<CryptoCurrency>) {
coroutineScope {
val results = listOf(
async {
FetchingSource.NETWORK to refreshNetworks(userWalletId = userWalletId, currencies = currencies)
},
async {
FetchingSource.STAKING to refreshYieldBalances(userWalletId = userWalletId, currencies = currencies)
},
async { FetchingSource.QUOTE to refreshQuotes(currencies = currencies) },
)
.awaitAll()
val errors = results.mapNotNull { (source, maybeResult) ->
val error = maybeResult.leftOrNull() ?: return@mapNotNull null
source to error
}
check(errors.isEmpty()) {
val message = "Failed to fetch next sources for $userWalletId:\n" +
errors.joinToString(separator = "\n") { "${it.first.name} ${it.second}" }
Timber.e(message)
message
}
}
}
private suspend fun refreshNetworks(
userWalletId: UserWalletId,
currencies: List<CryptoCurrency>,
): Either<Throwable, Unit> = either {
val either = multiNetworkStatusFetcher(
params = MultiNetworkStatusFetcher.Params(
userWalletId = userWalletId,
networks = currencies.mapTo(hashSetOf(), CryptoCurrency::network),
),
)
arrow.core.raise.catch(
block = { accountsCRUDRepository.syncTokens(userWalletId) },
catch = {
Timber.e(it, "Failed to sync tokens for wallet: $userWalletId")
},
)
return either
}
private suspend fun refreshYieldBalances(
userWalletId: UserWalletId,
currencies: List<CryptoCurrency>,
): Either<Throwable, Unit> {
val stakingIds = currencies.mapNotNullTo(hashSetOf()) {
stakingIdFactory.create(userWalletId = userWalletId, cryptoCurrency = it).getOrNull()
}
return multiYieldBalanceFetcher(
params = MultiYieldBalanceFetcher.Params(userWalletId = userWalletId, stakingIds = stakingIds),
)
}
private suspend fun refreshQuotes(currencies: List<CryptoCurrency>): Either<Throwable, Unit> {
return multiQuoteStatusFetcher(
params = MultiQuoteStatusFetcher.Params(
currenciesIds = currencies.mapNotNullTo(hashSetOf()) { it.id.rawCurrencyId },
appCurrencyId = null,
),
)
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.domain.account.usecase
package com.tangem.domain.account.status.usecase
import arrow.core.None
import arrow.core.left
@ -8,17 +8,17 @@ import com.google.common.truth.Truth
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.models.ArchivedAccount
import com.tangem.domain.account.repository.AccountsCRUDRepository
import com.tangem.domain.account.status.usecase.RecoverCryptoPortfolioUseCase.Error.DataOperationFailed
import com.tangem.domain.account.status.utils.CryptoCurrencyBalanceFetcher
import com.tangem.domain.account.tokens.MainAccountTokensMigration
import com.tangem.domain.account.usecase.RecoverCryptoPortfolioUseCase.Error
import com.tangem.domain.account.utils.createAccount
import com.tangem.domain.models.account.AccountId
import com.tangem.domain.models.account.DerivationIndex
import com.tangem.domain.models.account.*
import com.tangem.domain.models.wallet.UserWalletId
import io.mockk.*
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import kotlin.random.Random
/**
[REDACTED_AUTHOR]
@ -28,14 +28,16 @@ class RecoverCryptoPortfolioUseCaseTest {
private val crudRepository: AccountsCRUDRepository = mockk(relaxUnitFun = true)
private val mainAccountTokensMigration: MainAccountTokensMigration = mockk()
private val cryptoCurrencyBalanceFetcher: CryptoCurrencyBalanceFetcher = mockk(relaxUnitFun = true)
private val useCase = RecoverCryptoPortfolioUseCase(
crudRepository = crudRepository,
mainAccountTokensMigration = mainAccountTokensMigration,
cryptoCurrencyBalanceFetcher = cryptoCurrencyBalanceFetcher,
)
@BeforeEach
fun resetMocks() {
clearMocks(crudRepository)
clearMocks(crudRepository, mainAccountTokensMigration, cryptoCurrencyBalanceFetcher)
}
@Test
@ -57,6 +59,7 @@ class RecoverCryptoPortfolioUseCaseTest {
coEvery { crudRepository.getAccountListSync(userWalletId) } returns accountList.toOption()
coEvery { crudRepository.getArchivedAccountSync(account.accountId) } returns archivedAccount.toOption()
coEvery { mainAccountTokensMigration.migrate(userWalletId, account.derivationIndex) } returns Unit.right()
coEvery { crudRepository.getAccountSync(account.accountId) } returns account.toOption()
// Act
val actual = useCase(account.accountId)
@ -69,21 +72,23 @@ class RecoverCryptoPortfolioUseCaseTest {
crudRepository.getAccountListSync(userWalletId)
crudRepository.getArchivedAccountSync(account.accountId)
crudRepository.saveAccounts(updatedAccountList)
crudRepository.getAccountSync(account.accountId)
cryptoCurrencyBalanceFetcher(userWalletId, account.cryptoCurrencies.toList())
}
}
@Test
fun `invoke should return error if getAccounts returns None`() = runTest {
// Arrange
val accountId = AccountId.forCryptoPortfolio(
val accountId = AccountId.Companion.forCryptoPortfolio(
userWalletId = userWalletId,
derivationIndex = DerivationIndex.Main,
derivationIndex = DerivationIndex.Companion.Main,
)
coEvery { crudRepository.getAccountListSync(userWalletId) } returns None
// Act
val actual = useCase(accountId).leftOrNull() as Error.DataOperationFailed
val actual = useCase(accountId).leftOrNull() as DataOperationFailed
// Assert
val expected = IllegalStateException("Account list not found for wallet $userWalletId")
@ -100,9 +105,9 @@ class RecoverCryptoPortfolioUseCaseTest {
@Test
fun `invoke should return error if getAccounts throws exception`() = runTest {
// Arrange
val accountId = AccountId.forCryptoPortfolio(
val accountId = AccountId.Companion.forCryptoPortfolio(
userWalletId = userWalletId,
derivationIndex = DerivationIndex.Main,
derivationIndex = DerivationIndex.Companion.Main,
)
val exception = IllegalStateException("Test error")
@ -112,7 +117,7 @@ class RecoverCryptoPortfolioUseCaseTest {
val actual = useCase(accountId)
// Assert
val expected = Error.DataOperationFailed(exception).left()
val expected = DataOperationFailed(exception).left()
Truth.assertThat(actual).isEqualTo(expected)
coVerifySequence { crudRepository.getAccountListSync(userWalletId) }
@ -126,7 +131,7 @@ class RecoverCryptoPortfolioUseCaseTest {
fun `invoke should return error if getArchivedAccount throws exception`() = runTest {
// Arrange
val account = createAccount(userWalletId)
val accountList = AccountList.empty(userWalletId)
val accountList = AccountList.Companion.empty(userWalletId)
val exception = IllegalStateException("Test error")
coEvery { crudRepository.getAccountListSync(userWalletId) } returns accountList.toOption()
@ -136,7 +141,7 @@ class RecoverCryptoPortfolioUseCaseTest {
val actual = useCase(account.accountId)
// Assert
val expected = Error.DataOperationFailed(exception).left()
val expected = DataOperationFailed(exception).left()
Truth.assertThat(actual).isEqualTo(expected)
coVerifySequence {
@ -150,13 +155,13 @@ class RecoverCryptoPortfolioUseCaseTest {
fun `invoke should return error if getArchivedAccount returns null`() = runTest {
// Arrange
val account = createAccount(userWalletId)
val accountList = AccountList.empty(userWalletId)
val accountList = AccountList.Companion.empty(userWalletId)
coEvery { crudRepository.getAccountListSync(userWalletId) } returns accountList.toOption()
coEvery { crudRepository.getArchivedAccountSync(account.accountId) } returns None
// Act
val actual = useCase(account.accountId).leftOrNull() as Error.DataOperationFailed
val actual = useCase(account.accountId).leftOrNull() as DataOperationFailed
// Assert
val expected = IllegalStateException("Account not found: ${account.accountId}")
@ -174,7 +179,7 @@ class RecoverCryptoPortfolioUseCaseTest {
fun `invoke should return error if saveAccounts throws exception`() = runTest {
// Arrange
val account = createAccount(userWalletId)
val accountList = AccountList.empty(userWalletId)
val accountList = AccountList.Companion.empty(userWalletId)
val archivedAccount = ArchivedAccount(
accountId = account.accountId,
name = account.accountName,
@ -195,7 +200,7 @@ class RecoverCryptoPortfolioUseCaseTest {
val actual = useCase(account.accountId)
// Assert
val expected = Error.DataOperationFailed(exception).left()
val expected = DataOperationFailed(exception).left()
Truth.assertThat(actual).isEqualTo(expected)
coVerifySequence {
@ -205,6 +210,23 @@ class RecoverCryptoPortfolioUseCaseTest {
}
}
private fun createAccount(
userWalletId: UserWalletId,
name: String = "Test Account",
icon: CryptoPortfolioIcon = CryptoPortfolioIcon.ofDefaultCustomAccount(),
derivationIndex: Int = Random.nextInt(1, 21),
): Account.CryptoPortfolio {
val derivationIndex = DerivationIndex(derivationIndex).getOrNull()!!
return Account.CryptoPortfolio(
accountId = AccountId.forCryptoPortfolio(userWalletId = userWalletId, derivationIndex = derivationIndex),
accountName = AccountName(name).getOrNull()!!,
icon = icon,
derivationIndex = derivationIndex,
cryptoCurrencies = emptySet(),
)
}
private companion object {
val userWalletId = UserWalletId("011")
}

View file

@ -5,7 +5,7 @@ package com.tangem.domain.tokens.wallet
*
[REDACTED_AUTHOR]
*/
internal enum class FetchingSource {
enum class FetchingSource {
NETWORK,
QUOTE,
STAKING,

View file

@ -14,8 +14,8 @@ import com.tangem.core.ui.message.EventMessageAction
import com.tangem.core.ui.message.ToastMessage
import com.tangem.core.ui.utils.showErrorDialog
import com.tangem.domain.account.models.AccountList
import com.tangem.domain.account.status.usecase.RecoverCryptoPortfolioUseCase
import com.tangem.domain.account.usecase.GetArchivedAccountsUseCase
import com.tangem.domain.account.usecase.RecoverCryptoPortfolioUseCase
import com.tangem.domain.models.account.AccountId
import com.tangem.features.account.ArchivedAccountListComponent
import com.tangem.features.account.archived.entity.AccountArchivedUM

View file

@ -1,9 +1,9 @@
package com.tangem.features.account.createedit.error
import com.tangem.core.error.UniversalError
import com.tangem.domain.account.status.usecase.RecoverCryptoPortfolioUseCase
import com.tangem.domain.account.usecase.AddCryptoPortfolioUseCase
import com.tangem.domain.account.usecase.GetUnoccupiedAccountIndexUseCase
import com.tangem.domain.account.usecase.RecoverCryptoPortfolioUseCase
import com.tangem.domain.account.usecase.UpdateCryptoPortfolioUseCase
sealed interface AccountFeatureError : UniversalError {