Updated on 2026-08-14
This commit is contained in:
parent
33cb6d92b5
commit
15d8fde8ad
11 changed files with 11 additions and 479 deletions
|
|
@ -55,18 +55,6 @@ internal object CardDomainModule {
|
|||
return IsNeedToBackupUseCase(userWalletsListRepository = userWalletsListRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideHasSingleWalletSignedHashesUseCase(
|
||||
cardRepository: CardRepository,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
): HasSingleWalletSignedHashesUseCase {
|
||||
return HasSingleWalletSignedHashesUseCase(
|
||||
cardRepository = cardRepository,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideGetExtendedPublicKeyForCurrencyUseCase(
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ dependencies {
|
|||
implementation(projects.domain.dynamicAddresses)
|
||||
implementation(projects.domain.dynamicAddresses.models)
|
||||
implementation(projects.domain.feedback)
|
||||
implementation(projects.domain.feedback.models)
|
||||
implementation(projects.domain.markets.models)
|
||||
implementation(projects.domain.models)
|
||||
implementation(projects.domain.notifications.models)
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.domain
|
||||
|
||||
import com.tangem.domain.card.IsWalletBackupProblematicUseCase
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.HasSingleWalletSignedHashesUseCase
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Produces card/wallet-level warnings for the Token Details screen.
|
||||
*
|
||||
* These banners mirror the ones the main screen shows via `GetWalletNotificationsFactory`, but they only apply to
|
||||
* a single-currency cold wallet (a multi-currency wallet keeps them on the main screen only).
|
||||
*/
|
||||
internal class GetWalletCardWarningsUseCase @Inject constructor(
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase,
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase,
|
||||
private val isWalletBackupProblematicUseCase: IsWalletBackupProblematicUseCase,
|
||||
private val dispatchers: CoroutineDispatcherProvider,
|
||||
) {
|
||||
|
||||
operator fun invoke(userWallet: UserWallet, network: Network): Flow<Set<WalletCardWarning>> {
|
||||
if (userWallet !is UserWallet.Cold || userWallet.isMultiCurrency) {
|
||||
return flowOf(emptySet())
|
||||
}
|
||||
|
||||
return hasSingleWalletSignedHashesUseCase(userWallet, network)
|
||||
.map { hasIncorrectSignedHashes ->
|
||||
buildWarnings(
|
||||
userWallet = userWallet,
|
||||
hasIncorrectSignedHashes = hasIncorrectSignedHashes,
|
||||
)
|
||||
}
|
||||
.flowOn(dispatchers.io)
|
||||
}
|
||||
|
||||
private fun buildWarnings(userWallet: UserWallet.Cold, hasIncorrectSignedHashes: Boolean): Set<WalletCardWarning> {
|
||||
val cardTypesResolver = userWallet.cardTypesResolver
|
||||
|
||||
return buildSet {
|
||||
if (isWalletBackupProblematicUseCase(userWallet)) {
|
||||
add(WalletCardWarning.BackupError)
|
||||
}
|
||||
if (!cardTypesResolver.isReleaseFirmwareType()) {
|
||||
add(WalletCardWarning.DevCard)
|
||||
}
|
||||
if (cardTypesResolver.isReleaseFirmwareType() && cardTypesResolver.isAttestationFailed()) {
|
||||
add(WalletCardWarning.FailedCardValidation)
|
||||
}
|
||||
cardTypesResolver.getRemainingSignatures()?.let { remainingSignatures ->
|
||||
if (remainingSignatures <= MAX_REMAINING_SIGNATURES_COUNT) {
|
||||
add(WalletCardWarning.LowSignatures(count = remainingSignatures))
|
||||
}
|
||||
}
|
||||
if (isDemoCardUseCase(cardId = cardTypesResolver.getCardId())) {
|
||||
add(WalletCardWarning.DemoCard)
|
||||
}
|
||||
if (cardTypesResolver.isTestCard()) {
|
||||
add(WalletCardWarning.TestnetCard)
|
||||
}
|
||||
if (hasIncorrectSignedHashes) {
|
||||
add(WalletCardWarning.NumberOfSignedHashesIncorrect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_REMAINING_SIGNATURES_COUNT = 10
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.domain
|
||||
|
||||
/**
|
||||
* Card/wallet-level warnings that are shown on the main screen for a single-currency wallet and must also be
|
||||
* displayed in Token Details (redesign), since single-currency wallets now have a Token Details screen.
|
||||
*
|
||||
* Currency-level warnings are produced separately by [GetCurrencyWarningsUseCase].
|
||||
*/
|
||||
internal sealed interface WalletCardWarning {
|
||||
|
||||
data object BackupError : WalletCardWarning
|
||||
|
||||
data object DevCard : WalletCardWarning
|
||||
|
||||
data object FailedCardValidation : WalletCardWarning
|
||||
|
||||
data object TestnetCard : WalletCardWarning
|
||||
|
||||
data class LowSignatures(val count: Int) : WalletCardWarning
|
||||
|
||||
data object NumberOfSignedHashesIncorrect : WalletCardWarning
|
||||
|
||||
data object DemoCard : WalletCardWarning
|
||||
}
|
||||
|
|
@ -78,14 +78,6 @@ interface TokenDetailsClickIntents {
|
|||
|
||||
fun onYieldInfoClick()
|
||||
|
||||
// region Wallet card warnings
|
||||
|
||||
fun onSupportClick()
|
||||
|
||||
fun onCloseSignedHashesWarning()
|
||||
|
||||
// endregion Wallet card warnings
|
||||
|
||||
// region Clore migration
|
||||
// TODO: Remove after 2025-04-01 when Clore migration ends ([REDACTED_TASK_KEY])
|
||||
|
||||
|
|
@ -169,10 +161,6 @@ internal class EmptyTokenDetailsClickIntents : TokenDetailsClickIntents {
|
|||
|
||||
override fun onCloseRentInfoNotification() { /* no op */ }
|
||||
|
||||
override fun onSupportClick() { /* no op */ }
|
||||
|
||||
override fun onCloseSignedHashesWarning() { /* no op */ }
|
||||
|
||||
override fun onRetryIncompleteTransactionClick() { /* no op */ }
|
||||
|
||||
override fun onOpenTrustlineClick() { /* no op */ }
|
||||
|
|
|
|||
|
|
@ -63,10 +63,6 @@ import com.tangem.domain.models.account.Account
|
|||
import com.tangem.domain.models.currency.CryptoCurrency
|
||||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.network.NetworkAddress
|
||||
import com.tangem.domain.card.SetCardWasScannedUseCase
|
||||
import com.tangem.domain.feedback.GetWalletMetaInfoUseCase
|
||||
import com.tangem.domain.feedback.SendFeedbackEmailUseCase
|
||||
import com.tangem.domain.feedback.models.FeedbackEmailType
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.offramp.GetOfframpUrlUseCase
|
||||
|
|
@ -102,7 +98,6 @@ import com.tangem.domain.yield.supply.models.YieldSupplyRewardBalance
|
|||
import com.tangem.domain.yield.supply.usecase.YieldSupplyGetRewardsBalanceUseCase
|
||||
import com.tangem.feature.tokendetails.deeplink.TokenDetailsDeepLinkActionListener
|
||||
import com.tangem.feature.tokendetails.domain.GetCurrencyWarningsUseCase
|
||||
import com.tangem.feature.tokendetails.domain.GetWalletCardWarningsUseCase
|
||||
import com.tangem.feature.tokendetails.presentation.router.InnerTokenDetailsRouter
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsCurrencyStatusAnalyticsSender
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.analytics.TokenDetailsNotificationsAnalyticsSender
|
||||
|
|
@ -128,7 +123,6 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.transform
|
|||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.ToggleBalanceTypeTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateStakingNotificationTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateNotificationsTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateWalletCardWarningsTransformer
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer.UpdateTopBarMenuTransformer
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsEvent
|
||||
import com.tangem.features.tokendetails.ExpressTransactionsEventListener
|
||||
|
|
@ -161,10 +155,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
private val isCryptoCurrencyCouldHideUseCase: IsCryptoCurrencyCouldHideUseCase,
|
||||
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
|
||||
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
|
||||
private val getWalletCardWarningsUseCase: GetWalletCardWarningsUseCase,
|
||||
private val setCardWasScannedUseCase: SetCardWasScannedUseCase,
|
||||
private val getWalletMetaInfoUseCase: GetWalletMetaInfoUseCase,
|
||||
private val sendFeedbackEmailUseCase: SendFeedbackEmailUseCase,
|
||||
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
|
||||
private val getExtendedPublicKeyForCurrencyUseCase: GetExtendedPublicKeyForCurrencyUseCase,
|
||||
private val getStakingEntryInfoUseCase: GetStakingEntryInfoUseCase,
|
||||
|
|
@ -433,20 +423,13 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
|
||||
private fun updateWarnings(cryptoCurrencyStatus: CryptoCurrencyStatus) {
|
||||
modelScope.launch(dispatchers.main) {
|
||||
combine(
|
||||
flow = getCurrencyWarningsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyStatus = cryptoCurrencyStatus,
|
||||
derivationPath = cryptoCurrency.network.derivationPath,
|
||||
),
|
||||
flow2 = getWalletCardWarningsUseCase(
|
||||
userWallet = userWallet,
|
||||
network = cryptoCurrency.network,
|
||||
),
|
||||
transform = ::Pair,
|
||||
getCurrencyWarningsUseCase(
|
||||
userWalletId = userWalletId,
|
||||
currencyStatus = cryptoCurrencyStatus,
|
||||
derivationPath = cryptoCurrency.network.derivationPath,
|
||||
)
|
||||
.distinctUntilChanged()
|
||||
.onEach { (warnings, cardWarnings) ->
|
||||
.onEach { warnings ->
|
||||
val updatedState = stateFactory.getStateWithNotifications(warnings)
|
||||
notificationsAnalyticsSender.send(uiState.value, updatedState.notifications)
|
||||
uiState.value = updatedState
|
||||
|
|
@ -457,12 +440,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
redesignStateController.update(
|
||||
UpdateWalletCardWarningsTransformer(
|
||||
walletCardWarnings = cardWarnings,
|
||||
clickIntents = this@TokenDetailsModel,
|
||||
),
|
||||
)
|
||||
}
|
||||
.launchIn(modelScope)
|
||||
.saveIn(warningsJobHolder)
|
||||
|
|
@ -1032,21 +1009,6 @@ internal class TokenDetailsModel @Inject constructor(
|
|||
uiState.value = stateFactory.getStateWithRemovedRentNotification()
|
||||
}
|
||||
|
||||
override fun onSupportClick() {
|
||||
modelScope.launch {
|
||||
val metaInfo = getWalletMetaInfoUseCase(userWalletId).getOrNull() ?: return@launch
|
||||
sendFeedbackEmailUseCase(type = FeedbackEmailType.DirectUserRequest(walletMetaInfo = metaInfo))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCloseSignedHashesWarning() {
|
||||
modelScope.launch {
|
||||
(userWallet as? UserWallet.Cold)?.let { coldWallet ->
|
||||
setCardWasScannedUseCase(cardId = coldWallet.cardId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCopyAddress(): TextReference? {
|
||||
val networkAddress = cryptoCurrencyStatus?.value?.networkAddress ?: return null
|
||||
val addresses = networkAddress.availableAddresses.mapToAddressModels(cryptoCurrency).toImmutableList()
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.presentation.tokendetails.state.transformer
|
||||
|
||||
import com.tangem.core.ui.R
|
||||
import com.tangem.core.ui.ds.button.TangemButtonType
|
||||
import com.tangem.core.ui.ds.image.TangemIconUM
|
||||
import com.tangem.core.ui.ds.message.TangemMessageButtonUM
|
||||
import com.tangem.core.ui.ds.message.TangemMessageEffect
|
||||
import com.tangem.core.ui.ds.message.TangemMessageUM
|
||||
import com.tangem.core.ui.extensions.resourceReference
|
||||
import com.tangem.core.ui.extensions.wrappedList
|
||||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.feature.tokendetails.domain.WalletCardWarning
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.model.TokenDetailsClickIntents
|
||||
import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsUM
|
||||
import com.tangem.utils.transformer.Transformer
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import com.tangem.core.res.R as CoreResR
|
||||
|
||||
/**
|
||||
* Maps card/wallet-level warnings (produced by `GetWalletCardWarningsUseCase` for a single-currency wallet) into
|
||||
* Token Details notifications and prepends them to the existing currency-level notifications.
|
||||
*/
|
||||
internal class UpdateWalletCardWarningsTransformer(
|
||||
private val walletCardWarnings: Set<WalletCardWarning>,
|
||||
private val clickIntents: TokenDetailsClickIntents,
|
||||
) : Transformer<TokenDetailsUM> {
|
||||
|
||||
override fun transform(prevState: TokenDetailsUM): TokenDetailsUM {
|
||||
val others = prevState.notifications.filterNot { it.id in WALLET_CARD_WARNING_IDS }
|
||||
val messages = walletCardWarnings.map(::mapWarning)
|
||||
|
||||
return prevState.copy(
|
||||
notifications = (messages + others).toImmutableList(),
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun mapWarning(warning: WalletCardWarning): TangemMessageUM {
|
||||
return when (warning) {
|
||||
WalletCardWarning.BackupError -> TangemMessageUM(
|
||||
id = ID_BACKUP_ERROR,
|
||||
title = resourceReference(CoreResR.string.warning_backup_errors_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_backup_errors_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = attentionIcon(),
|
||||
buttonsUM = persistentListOf(
|
||||
TangemMessageButtonUM(
|
||||
text = resourceReference(CoreResR.string.common_contact_support),
|
||||
type = TangemButtonType.Secondary,
|
||||
onClick = clickIntents::onSupportClick,
|
||||
),
|
||||
),
|
||||
)
|
||||
WalletCardWarning.DevCard -> TangemMessageUM(
|
||||
id = ID_DEV_CARD,
|
||||
title = resourceReference(CoreResR.string.warning_developer_card_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_developer_card_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = attentionIcon(),
|
||||
)
|
||||
WalletCardWarning.FailedCardValidation -> TangemMessageUM(
|
||||
id = ID_FAILED_CARD_VALIDATION,
|
||||
title = resourceReference(CoreResR.string.warning_failed_to_verify_card_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_failed_to_verify_card_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = attentionIcon(),
|
||||
)
|
||||
WalletCardWarning.TestnetCard -> TangemMessageUM(
|
||||
id = ID_TESTNET_CARD,
|
||||
title = resourceReference(CoreResR.string.warning_testnet_card_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_testnet_card_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = attentionIcon(),
|
||||
)
|
||||
is WalletCardWarning.LowSignatures -> TangemMessageUM(
|
||||
id = ID_LOW_SIGNATURES,
|
||||
title = resourceReference(CoreResR.string.warning_low_signatures_title),
|
||||
subtitle = resourceReference(
|
||||
id = CoreResR.string.warning_low_signatures_message,
|
||||
formatArgs = wrappedList(warning.count.toString()),
|
||||
),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = attentionIcon(),
|
||||
)
|
||||
WalletCardWarning.NumberOfSignedHashesIncorrect -> TangemMessageUM(
|
||||
id = ID_NUMBER_OF_SIGNED_HASHES_INCORRECT,
|
||||
title = resourceReference(CoreResR.string.warning_number_of_signed_hashes_incorrect_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_number_of_signed_hashes_incorrect_message),
|
||||
messageEffect = TangemMessageEffect.Warning,
|
||||
iconUM = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.img_knight_shield_32,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
),
|
||||
onCloseClick = clickIntents::onCloseSignedHashesWarning,
|
||||
)
|
||||
WalletCardWarning.DemoCard -> TangemMessageUM(
|
||||
id = ID_DEMO_CARD,
|
||||
title = resourceReference(CoreResR.string.warning_demo_mode_title),
|
||||
subtitle = resourceReference(CoreResR.string.warning_demo_mode_message),
|
||||
messageEffect = TangemMessageEffect.None,
|
||||
iconUM = attentionIcon(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun attentionIcon(): TangemIconUM.Icon = TangemIconUM.Icon(
|
||||
iconRes = R.drawable.ic_attention_default_24,
|
||||
tintReference = { TangemTheme.colors2.graphic.neutral.primary },
|
||||
)
|
||||
|
||||
private companion object {
|
||||
const val ID_BACKUP_ERROR = "BackupErrorNotification"
|
||||
const val ID_DEV_CARD = "DevCardNotification"
|
||||
const val ID_FAILED_CARD_VALIDATION = "FailedCardValidationNotification"
|
||||
const val ID_TESTNET_CARD = "TestnetCardNotification"
|
||||
const val ID_LOW_SIGNATURES = "LowSignaturesNotification"
|
||||
const val ID_NUMBER_OF_SIGNED_HASHES_INCORRECT = "NumberOfSignedHashesIncorrectNotification"
|
||||
const val ID_DEMO_CARD = "DemoCardNotification"
|
||||
|
||||
val WALLET_CARD_WARNING_IDS = setOf(
|
||||
ID_BACKUP_ERROR,
|
||||
ID_DEV_CARD,
|
||||
ID_FAILED_CARD_VALIDATION,
|
||||
ID_TESTNET_CARD,
|
||||
ID_LOW_SIGNATURES,
|
||||
ID_NUMBER_OF_SIGNED_HASHES_INCORRECT,
|
||||
ID_DEMO_CARD,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
package com.tangem.feature.tokendetails.domain
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.card.CardTypesResolver
|
||||
import com.tangem.domain.card.IsWalletBackupProblematicUseCase
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.demo.IsDemoCardUseCase
|
||||
import com.tangem.domain.models.network.Network
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.wallets.usecase.HasSingleWalletSignedHashesUseCase
|
||||
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
|
||||
import io.mockk.clearMocks
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.unmockkStatic
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class GetWalletCardWarningsUseCaseTest {
|
||||
|
||||
private val isDemoCardUseCase: IsDemoCardUseCase = mockk()
|
||||
private val hasSingleWalletSignedHashesUseCase: HasSingleWalletSignedHashesUseCase = mockk()
|
||||
private val isWalletBackupProblematicUseCase: IsWalletBackupProblematicUseCase = mockk()
|
||||
private val network: Network = mockk(relaxed = true)
|
||||
|
||||
private val useCase = GetWalletCardWarningsUseCase(
|
||||
isDemoCardUseCase = isDemoCardUseCase,
|
||||
hasSingleWalletSignedHashesUseCase = hasSingleWalletSignedHashesUseCase,
|
||||
isWalletBackupProblematicUseCase = isWalletBackupProblematicUseCase,
|
||||
dispatchers = TestingCoroutineDispatcherProvider(),
|
||||
)
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
clearMocks(
|
||||
isDemoCardUseCase,
|
||||
hasSingleWalletSignedHashesUseCase,
|
||||
isWalletBackupProblematicUseCase,
|
||||
)
|
||||
mockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
|
||||
// Default: nothing flagged
|
||||
every { isDemoCardUseCase(any()) } returns false
|
||||
every { hasSingleWalletSignedHashesUseCase(any(), any()) } returns flowOf(false)
|
||||
every { isWalletBackupProblematicUseCase(any()) } returns false
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
unmockkStatic(UserWallet.Cold::cardTypesResolver)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN multi-currency cold wallet WHEN invoke THEN empty set`() = runTest {
|
||||
// Arrange
|
||||
val wallet = coldWallet(isMultiCurrency = true)
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN hot wallet WHEN invoke THEN empty set`() = runTest {
|
||||
// Arrange
|
||||
val wallet = mockk<UserWallet.Hot>(relaxed = true)
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN single-currency cold wallet with clean card WHEN invoke THEN empty set`() = runTest {
|
||||
// Arrange
|
||||
val wallet = coldWallet(isMultiCurrency = false, resolver = cleanResolver())
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).isEmpty()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN single-currency dev card WHEN invoke THEN only dev card warning`() = runTest {
|
||||
// Arrange
|
||||
val resolver = cleanResolver().also { every { it.isReleaseFirmwareType() } returns false }
|
||||
val wallet = coldWallet(isMultiCurrency = false, resolver = resolver)
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).containsExactly(WalletCardWarning.DevCard)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN single-currency release card with every condition WHEN invoke THEN full warning set`() = runTest {
|
||||
// Arrange
|
||||
val resolver = cleanResolver().also {
|
||||
every { it.isReleaseFirmwareType() } returns true
|
||||
every { it.isAttestationFailed() } returns true
|
||||
every { it.getRemainingSignatures() } returns LOW_SIGNATURES
|
||||
every { it.isTestCard() } returns true
|
||||
}
|
||||
val wallet = coldWallet(isMultiCurrency = false, resolver = resolver)
|
||||
every { isWalletBackupProblematicUseCase(any()) } returns true
|
||||
every { isDemoCardUseCase(any()) } returns true
|
||||
every { hasSingleWalletSignedHashesUseCase(any(), any()) } returns flowOf(true)
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).containsExactly(
|
||||
WalletCardWarning.BackupError,
|
||||
WalletCardWarning.FailedCardValidation,
|
||||
WalletCardWarning.TestnetCard,
|
||||
WalletCardWarning.LowSignatures(count = LOW_SIGNATURES),
|
||||
WalletCardWarning.DemoCard,
|
||||
WalletCardWarning.NumberOfSignedHashesIncorrect,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN single-currency cold wallet with backup problem WHEN invoke THEN backup error warning`() = runTest {
|
||||
// Arrange
|
||||
val wallet = coldWallet(isMultiCurrency = false, resolver = cleanResolver())
|
||||
every { isWalletBackupProblematicUseCase(any()) } returns true
|
||||
|
||||
// Act
|
||||
val result = useCase(userWallet = wallet, network = network).first()
|
||||
|
||||
// Assert
|
||||
assertThat(result).containsExactly(WalletCardWarning.BackupError)
|
||||
}
|
||||
|
||||
private fun coldWallet(
|
||||
isMultiCurrency: Boolean,
|
||||
resolver: CardTypesResolver = cleanResolver(),
|
||||
): UserWallet.Cold {
|
||||
return mockk<UserWallet.Cold>(relaxed = true) {
|
||||
every { this@mockk.isMultiCurrency } returns isMultiCurrency
|
||||
every { cardTypesResolver } returns resolver
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanResolver(): CardTypesResolver = mockk {
|
||||
every { isReleaseFirmwareType() } returns true
|
||||
every { isAttestationFailed() } returns false
|
||||
every { getRemainingSignatures() } returns null
|
||||
every { isTestCard() } returns false
|
||||
every { getCardId() } returns "card"
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val LOW_SIGNATURES = 5
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ import com.tangem.domain.models.wallet.UserWallet
|
|||
import com.tangem.domain.settings.IsReadyToShowRateAppUseCase
|
||||
import com.tangem.domain.tokens.error.CurrencyStatusError
|
||||
import com.tangem.domain.wallets.usecase.GetWalletsUseCase
|
||||
import com.tangem.domain.wallets.usecase.HasSingleWalletSignedHashesUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.presentation.wallet.state.model.WalletNotification
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import com.tangem.domain.models.currency.CryptoCurrency
|
|||
import com.tangem.domain.models.currency.CryptoCurrencyStatus
|
||||
import com.tangem.domain.models.wallet.UserWallet
|
||||
import com.tangem.domain.models.wallet.isMultiCurrency
|
||||
import com.tangem.domain.wallets.usecase.HasSingleWalletSignedHashesUseCase
|
||||
import com.tangem.domain.wallets.usecase.IsNeedToBackupUseCase
|
||||
import com.tangem.feature.wallet.child.wallet.model.intents.WalletClickIntents
|
||||
import com.tangem.feature.wallet.impl.R
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.wallets.usecase
|
||||
package com.tangem.feature.wallet.presentation.wallet.domain
|
||||
|
||||
import com.tangem.core.decompose.di.ModelScoped
|
||||
import com.tangem.domain.card.common.util.cardTypesResolver
|
||||
import com.tangem.domain.card.repository.CardRepository
|
||||
import com.tangem.domain.demo.models.DemoConfig
|
||||
|
|
@ -9,8 +10,10 @@ import com.tangem.domain.walletmanager.WalletManagersFacade
|
|||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
class HasSingleWalletSignedHashesUseCase(
|
||||
@ModelScoped
|
||||
class HasSingleWalletSignedHashesUseCase @Inject constructor(
|
||||
private val cardRepository: CardRepository,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
) {
|
||||
|
|
@ -25,16 +28,11 @@ class HasSingleWalletSignedHashesUseCase(
|
|||
return@map false
|
||||
}
|
||||
|
||||
val signedHashes = userWallet.scanResponse.card.wallets
|
||||
.firstOrNull()
|
||||
?.totalSignedHashes
|
||||
?: 0
|
||||
|
||||
return@map try {
|
||||
walletManagersFacade.validateSignatureCount(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = network,
|
||||
signedHashes = signedHashes,
|
||||
signedHashes = userWallet.scanResponse.card.wallets.firstOrNull()?.totalSignedHashes ?: 0,
|
||||
)
|
||||
.fold(
|
||||
ifLeft = { true },
|
||||
Loading…
Add table
Add a link
Reference in a new issue