Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-06 17:08:05 +04:00
parent 017eece8b7
commit d96dd19f01
23 changed files with 456 additions and 8 deletions

View file

@ -9,6 +9,7 @@ import com.tangem.domain.account.status.utils.CryptoCurrencyMetadataCleaner
import com.tangem.domain.account.supplier.MultiAccountListSupplier
import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.card.IsWalletBackupProblematicUseCase
import com.tangem.domain.common.wallets.UserWalletDataCleaner
import com.tangem.domain.common.wallets.UserWalletsListRepository
import com.tangem.domain.express.ExpressServiceFetcher
import com.tangem.domain.networks.multi.MultiNetworkStatusFetcher
@ -32,6 +33,7 @@ import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dagger.multibindings.IntoSet
import javax.inject.Singleton
@Module
@ -227,4 +229,10 @@ internal object AccountStatusUseCaseModule {
dispatchers = dispatchers,
)
}
@Provides
@IntoSet
fun provideCryptoCurrencyMetadataUserWalletDataCleaner(
impl: CryptoCurrencyMetadataCleaner,
): UserWalletDataCleaner = impl
}

View file

@ -1,11 +1,14 @@
package com.tangem.domain.account.status.utils
import com.tangem.domain.common.wallets.UserWalletDataCleaner
import com.tangem.domain.models.currency.CryptoCurrency
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.networks.utils.NetworksCleaner
import com.tangem.domain.nft.utils.NFTCleaner
import com.tangem.domain.staking.utils.StakingCleaner
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.runSuspendCatching
import com.tangem.utils.logging.TangemLogger
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
@ -27,7 +30,32 @@ class CryptoCurrencyMetadataCleaner(
private val stakingCleaner: StakingCleaner,
private val nftCleaner: NFTCleaner,
private val dispatchers: CoroutineDispatcherProvider,
) {
) : UserWalletDataCleaner {
/**
* Removes all currency metadata (networks, staking balances) for the given wallets.
*
* Invoked on wallet deletion, where the concrete currencies are no longer available, so cleanup happens by
* wallet id in bulk instead of per-currency.
*
* @param userWalletIds The IDs of the deleted user wallets.
*/
override suspend fun clear(userWalletIds: List<UserWalletId>) {
if (userWalletIds.isEmpty()) return
// Best-effort: isolate failures so a failing cleaner does not cancel the other.
withContext(dispatchers.default) {
awaitAll(
async { clearSafely(target = "networks") { networksCleaner.clear(userWalletIds) } },
async { clearSafely(target = "staking") { stakingCleaner.clear(userWalletIds) } },
)
}
}
private suspend fun clearSafely(target: String, clear: suspend () -> Unit) {
runSuspendCatching { clear() }
.onFailure { TangemLogger.e("Failed to clear $target metadata", it) }
}
/**
* Cleans up data for a single cryptocurrency in the specified user wallet.

View file

@ -19,7 +19,7 @@ import org.junit.jupiter.api.TestInstance
[REDACTED_AUTHOR]
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class CryptoCurrencyCleanerTest {
class CryptoCurrencyMetadataCleanerTest {
private val networksCleaner: NetworksCleaner = mockk(relaxUnitFun = true)
private val stakingCleaner: StakingCleaner = mockk(relaxUnitFun = true)
@ -71,4 +71,31 @@ class CryptoCurrencyCleanerTest {
nftCleaner(userWalletId = userWalletId, networks = setOf(coin.network, token.network))
}
}
@Test
fun `GIVEN wallets WHEN clear THEN networks and staking cleared once with all ids`() = runTest {
// Arrange
val ids = listOf(userWalletId, UserWalletId("022"))
// Act
cleaner.clear(userWalletIds = ids)
// Assert
coVerify(exactly = 1) {
networksCleaner.clear(ids)
stakingCleaner.clear(ids)
}
}
@Test
fun `GIVEN empty list WHEN clear THEN no cleaners are called`() = runTest {
// Act
cleaner.clear(userWalletIds = emptyList())
// Assert
coVerify(inverse = true) {
networksCleaner.clear(any())
stakingCleaner.clear(any())
}
}
}

View file

@ -27,4 +27,13 @@ interface NetworksCleaner {
* @param currencies The list of cryptocurrencies whose associated network data should be cleaned.
*/
suspend operator fun invoke(userWalletId: UserWalletId, currencies: List<CryptoCurrency>)
/**
* Removes all cached network data for the given [userWalletIds].
*
* Used on wallet deletion, where the concrete networks are no longer available.
*
* @param userWalletIds The IDs of the user wallets whose network data should be removed.
*/
suspend fun clear(userWalletIds: List<UserWalletId>)
}

View file

@ -46,4 +46,13 @@ interface StakingCleaner {
* @param stakingIds The set of staking IDs whose associated data should be cleaned.
*/
suspend operator fun invoke(userWalletId: UserWalletId, stakingIds: Set<StakingID>)
/**
* Removes all cached staking balances for the given [userWalletIds].
*
* Used on wallet deletion, where the concrete staking ids are no longer available.
*
* @param userWalletIds the user wallet ids whose staking balances should be removed
*/
suspend fun clear(userWalletIds: List<UserWalletId>)
}