diff --git a/app/src/main/java/com/tangem/tap/di/domain/DynamicAddressesDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/DynamicAddressesDomainModule.kt index 0ab55063f9..6fc115d8f3 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/DynamicAddressesDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/DynamicAddressesDomainModule.kt @@ -1,11 +1,11 @@ package com.tangem.tap.di.domain import com.tangem.domain.dynamicaddresses.CreateConsolidationTransactionUseCase -import com.tangem.domain.dynamicaddresses.DisableDynamicAddressesUseCase import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesUseCase import com.tangem.domain.dynamicaddresses.GetDynamicAddressesStatusUseCase import com.tangem.domain.dynamicaddresses.GetDynamicReceiveAddressUseCase import com.tangem.domain.dynamicaddresses.GetDerivedXpubUseCase +import com.tangem.domain.dynamicaddresses.IsDynamicAddressesConsolidationRequiredUseCase import com.tangem.domain.dynamicaddresses.IsXpubSupportedUseCase import com.tangem.domain.dynamicaddresses.repository.ConsolidationRepository import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository @@ -31,10 +31,10 @@ internal object DynamicAddressesDomainModule { @Provides @Singleton - fun provideDisableDynamicAddressesUseCase( + fun provideIsDynamicAddressesConsolidationRequiredUseCase( dynamicAddressesRepository: DynamicAddressesRepository, - ): DisableDynamicAddressesUseCase { - return DisableDynamicAddressesUseCase(dynamicAddressesRepository) + ): IsDynamicAddressesConsolidationRequiredUseCase { + return IsDynamicAddressesConsolidationRequiredUseCase(dynamicAddressesRepository) } @Provides diff --git a/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/DisableDynamicAddressesUseCase.kt b/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/DisableDynamicAddressesUseCase.kt deleted file mode 100644 index 17d8139c00..0000000000 --- a/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/DisableDynamicAddressesUseCase.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.tangem.domain.dynamicaddresses - -import arrow.core.Either -import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository -import com.tangem.domain.models.network.Network -import com.tangem.domain.models.wallet.UserWalletId - -class DisableDynamicAddressesUseCase( - private val dynamicAddressesRepository: DynamicAddressesRepository, -) { - - /** - * Returns true when consolidation is required before disabling (non-base balances exist), - * or false when dynamic addresses were disabled immediately. - */ - suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either = - Either.catch { - val hasNonBaseBalances = dynamicAddressesRepository.hasNonBaseBalances(userWalletId, network) - - if (!hasNonBaseBalances) { - dynamicAddressesRepository.disable(userWalletId, network) - return@catch false - } - - true - } -} \ No newline at end of file diff --git a/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/IsDynamicAddressesConsolidationRequiredUseCase.kt b/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/IsDynamicAddressesConsolidationRequiredUseCase.kt new file mode 100644 index 0000000000..18b6de5aa3 --- /dev/null +++ b/domain/dynamic-addresses/src/main/kotlin/com/tangem/domain/dynamicaddresses/IsDynamicAddressesConsolidationRequiredUseCase.kt @@ -0,0 +1,20 @@ +package com.tangem.domain.dynamicaddresses + +import arrow.core.Either +import com.tangem.domain.dynamicaddresses.repository.DynamicAddressesRepository +import com.tangem.domain.models.network.Network +import com.tangem.domain.models.wallet.UserWalletId + +/** + * Returns `true` if a consolidation transaction must be broadcast before + * [DynamicAddressesRepository.disable] is called (non-base balances exist). + */ +class IsDynamicAddressesConsolidationRequiredUseCase( + private val dynamicAddressesRepository: DynamicAddressesRepository, +) { + + suspend operator fun invoke(userWalletId: UserWalletId, network: Network): Either = + Either.catch { + dynamicAddressesRepository.hasNonBaseBalances(userWalletId, network) + } +} \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegate.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegate.kt index b2c42270c5..6fdffa5d34 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegate.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegate.kt @@ -11,7 +11,7 @@ import com.tangem.core.ui.message.SnackbarMessage import com.tangem.common.ui.amountScreen.utils.getFiatString import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.dynamicaddresses.CreateConsolidationTransactionUseCase -import com.tangem.domain.dynamicaddresses.DisableDynamicAddressesUseCase +import com.tangem.domain.dynamicaddresses.IsDynamicAddressesConsolidationRequiredUseCase import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesError import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesUseCase import com.tangem.domain.dynamicaddresses.GetDerivedXpubUseCase @@ -43,7 +43,7 @@ import kotlinx.coroutines.launch @Suppress("LongParameterList", "LargeClass") internal class DynamicAddressesDelegate @AssistedInject constructor( private val enableDynamicAddressesUseCase: EnableDynamicAddressesUseCase, - private val disableDynamicAddressesUseCase: DisableDynamicAddressesUseCase, + private val isConsolidationRequiredUseCase: IsDynamicAddressesConsolidationRequiredUseCase, private val createConsolidationTransactionUseCase: CreateConsolidationTransactionUseCase, private val getFeeUseCase: GetFeeUseCase, private val sendTransactionUseCase: SendTransactionUseCase, @@ -180,7 +180,7 @@ internal class DynamicAddressesDelegate @AssistedInject constructor( private fun onDisableFlow(network: Network) { coroutineScope.launch(dispatchers.main) { - disableDynamicAddressesUseCase(userWalletId, network).fold( + isConsolidationRequiredUseCase(userWalletId, network).fold( ifLeft = { error -> TangemLogger.e("Failed to check disable: ${error.message}") _bottomSheetConfig.value = DynamicAddressesBottomSheetConfig.ServiceUnavailable( diff --git a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegateTest.kt b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegateTest.kt index 5c47799232..beb9ad3931 100644 --- a/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegateTest.kt +++ b/features/tokendetails/impl/src/test/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/DynamicAddressesDelegateTest.kt @@ -10,7 +10,7 @@ import com.tangem.core.analytics.models.AnalyticsEvent import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.dynamicaddresses.CreateConsolidationTransactionUseCase -import com.tangem.domain.dynamicaddresses.DisableDynamicAddressesUseCase +import com.tangem.domain.dynamicaddresses.IsDynamicAddressesConsolidationRequiredUseCase import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesError import com.tangem.domain.dynamicaddresses.EnableDynamicAddressesUseCase import com.tangem.domain.dynamicaddresses.GetDerivedXpubUseCase @@ -57,7 +57,7 @@ internal class DynamicAddressesDelegateTest { private val analyticsEventHandler: AnalyticsEventHandler = mockk(relaxed = true) private val enableDynamicAddressesUseCase: EnableDynamicAddressesUseCase = mockk() - private val disableDynamicAddressesUseCase: DisableDynamicAddressesUseCase = mockk() + private val isConsolidationRequiredUseCase: IsDynamicAddressesConsolidationRequiredUseCase = mockk() private val createConsolidationTransactionUseCase: CreateConsolidationTransactionUseCase = mockk() private val getFeeUseCase: GetFeeUseCase = mockk(relaxed = true) private val sendTransactionUseCase: SendTransactionUseCase = mockk(relaxed = true) @@ -264,7 +264,7 @@ internal class DynamicAddressesDelegateTest { // GIVEN every { dynamicAddressesRepository.getStatus(userWalletId, network) } returns flowOf(DynamicAddressesStatus.ENABLED) - coEvery { disableDynamicAddressesUseCase(userWalletId, network) } returns false.right() + coEvery { isConsolidationRequiredUseCase(userWalletId, network) } returns false.right() coEvery { dynamicAddressesRepository.disable(userWalletId, network) } returns Unit val delegate = createDelegate(cryptoCurrencyStatus = cryptoCurrencyStatus) @@ -289,6 +289,22 @@ internal class DynamicAddressesDelegateTest { } } + @Test + fun `GIVEN ENABLED status AND no consolidation WHEN menu tapped without confirmation THEN repository disable is NOT called`() = + runTest { + every { dynamicAddressesRepository.getStatus(userWalletId, network) } returns + flowOf(DynamicAddressesStatus.ENABLED) + coEvery { isConsolidationRequiredUseCase(userWalletId, network) } returns false.right() + + val delegate = createDelegate(cryptoCurrencyStatus = cryptoCurrencyStatus) + delegate.onDynamicAddressesClick() + + // The simple disable sheet must be shown but no backend write must happen yet. + assertThat(delegate.bottomSheetConfig.value) + .isInstanceOf(DynamicAddressesBottomSheetConfig.DisableWithoutConsolidation::class.java) + coVerify(exactly = 0) { dynamicAddressesRepository.disable(any(), any()) } + } + @Test fun `GIVEN consolidation required AND fee fails WHEN load fee THEN NotEnoughFee with DynamicAddresses source is sent`() = runTest { @@ -406,7 +422,7 @@ internal class DynamicAddressesDelegateTest { private fun setupConsolidationFlow() { every { dynamicAddressesRepository.getStatus(userWalletId, network) } returns flowOf(DynamicAddressesStatus.ENABLED) - coEvery { disableDynamicAddressesUseCase(userWalletId, network) } returns true.right() + coEvery { isConsolidationRequiredUseCase(userWalletId, network) } returns true.right() val address = NetworkAddress.Address(value = TEST_ADDRESS, type = NetworkAddress.Address.Type.Primary) every { cryptoCurrencyStatus.value } returns mockk(relaxed = true) { every { amount } returns BigDecimal.ONE @@ -419,7 +435,7 @@ internal class DynamicAddressesDelegateTest { val scope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) return DynamicAddressesDelegate( enableDynamicAddressesUseCase = enableDynamicAddressesUseCase, - disableDynamicAddressesUseCase = disableDynamicAddressesUseCase, + isConsolidationRequiredUseCase = isConsolidationRequiredUseCase, createConsolidationTransactionUseCase = createConsolidationTransactionUseCase, getFeeUseCase = getFeeUseCase, sendTransactionUseCase = sendTransactionUseCase,