From aaf4419ebed66bb3e820e3b53abb990e0143fe0d Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 14 Oct 2025 15:36:53 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../swap/DefaultSwapTransactionRepository.kt | 9 +-- .../SavedSwapTransactionListConverter.kt | 13 ++-- .../usecase/SaveCryptoCurrenciesUseCase.kt | 57 ++++++++++++++- .../domain/swap/SwapTransactionRepository.kt | 9 ++- .../domain/tokens/RemoveCurrencyUseCase.kt | 2 + .../swap/DefaultSwapTransactionRepository.kt | 9 +-- .../SavedSwapTransactionListConverter.kt | 13 ++-- .../swap/domain/SwapTransactionRepository.kt | 7 +- features/tokendetails/impl/build.gradle.kts | 31 ++++---- .../tokendetails/model/TokenDetailsModel.kt | 71 ++++++++++++++----- .../factory/express/ExchangeStatusFactory.kt | 69 ++++++++++++++++-- .../WalletCurrencyActionsClickIntents.kt | 25 ++++++- 12 files changed, 257 insertions(+), 58 deletions(-) diff --git a/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapTransactionRepository.kt b/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapTransactionRepository.kt index 072cf92212..6d67e11d9d 100644 --- a/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapTransactionRepository.kt +++ b/data/swap/src/main/java/com/tangem/data/swap/DefaultSwapTransactionRepository.kt @@ -14,6 +14,7 @@ import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectList import com.tangem.datasource.local.preferences.utils.getObjectListSync import com.tangem.datasource.local.preferences.utils.getObjectMap +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -54,7 +55,7 @@ internal class DefaultSwapTransactionRepository( storeTransactionState( txId = transaction.txId, status = it, - refundTokenCurrency = null, + accountWithCurrency = null, ) } appPreferencesStore.editData { mutablePreferences -> @@ -177,7 +178,7 @@ internal class DefaultSwapTransactionRepository( override suspend fun storeTransactionState( txId: String, status: SwapStatusModel, - refundTokenCurrency: CryptoCurrency?, + accountWithCurrency: Pair?, ) { appPreferencesStore.editData { mutablePreferences -> val savedMap = mutablePreferences.getObjectMap( @@ -187,8 +188,8 @@ internal class DefaultSwapTransactionRepository( val updatesMap = savedMap.toMutableMap() updatesMap[txId] = savedStatusConverter.convert( status.copy( - refundTokensResponse = refundTokenCurrency?.let { - userTokensResponseFactory.createResponseToken(refundTokenCurrency) + refundTokensResponse = accountWithCurrency?.let { (accountId, currency) -> + userTokensResponseFactory.createResponseToken(currency, accountId) }, ), ) diff --git a/data/swap/src/main/java/com/tangem/data/swap/converter/transaction/SavedSwapTransactionListConverter.kt b/data/swap/src/main/java/com/tangem/data/swap/converter/transaction/SavedSwapTransactionListConverter.kt index d81f412486..dca9f020fc 100644 --- a/data/swap/src/main/java/com/tangem/data/swap/converter/transaction/SavedSwapTransactionListConverter.kt +++ b/data/swap/src/main/java/com/tangem/data/swap/converter/transaction/SavedSwapTransactionListConverter.kt @@ -25,10 +25,12 @@ internal class SavedSwapTransactionListConverter( fromCryptoCurrencyId = value.fromCryptoCurrencyId, toCryptoCurrencyId = value.toCryptoCurrencyId, fromTokensResponse = userTokensResponseFactory.createResponseToken( - value.fromCryptoCurrency, + currency = value.fromCryptoCurrency, + accountId = null, ), toTokensResponse = userTokensResponseFactory.createResponseToken( - value.toCryptoCurrency, + currency = value.toCryptoCurrency, + accountId = null, ), transactions = savedSwapTransactionConverter.convertList(value.transactions), ) @@ -74,8 +76,11 @@ internal class SavedSwapTransactionListConverter( userWalletId = userWalletId.stringValue, fromCryptoCurrencyId = fromCryptoCurrency.id.value, toCryptoCurrencyId = toCryptoCurrency.id.value, - fromTokensResponse = userTokensResponseFactory.createResponseToken(fromCryptoCurrency), - toTokensResponse = userTokensResponseFactory.createResponseToken(toCryptoCurrency), + fromTokensResponse = userTokensResponseFactory.createResponseToken( + currency = fromCryptoCurrency, + accountId = null, + ), + toTokensResponse = userTokensResponseFactory.createResponseToken(currency = toCryptoCurrency, accountId = null), transactions = tokenTransactions, ) } \ No newline at end of file diff --git a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/SaveCryptoCurrenciesUseCase.kt b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/SaveCryptoCurrenciesUseCase.kt index ce55e827fc..144421a34d 100644 --- a/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/SaveCryptoCurrenciesUseCase.kt +++ b/domain/account/status/src/main/java/com/tangem/domain/account/status/usecase/SaveCryptoCurrenciesUseCase.kt @@ -57,8 +57,16 @@ class SaveCryptoCurrenciesUseCase( suspend operator fun invoke( accountId: AccountId, - add: List, - remove: List, + add: CryptoCurrency? = null, + remove: CryptoCurrency? = null, + ): Either { + return invoke(accountId = accountId, add = listOfNotNull(add), remove = listOfNotNull(remove)) + } + + suspend operator fun invoke( + accountId: AccountId, + add: List = emptyList(), + remove: List = emptyList(), ): Either = eitherOn(dispatchers.default) { if (add.isEmpty() && remove.isEmpty()) { Timber.d("No currencies to add or remove, skipping") @@ -84,6 +92,34 @@ class SaveCryptoCurrenciesUseCase( } } + suspend fun add( + accountId: AccountId, + networkId: String, + contractAddress: String, + ): Either = eitherOn(dispatchers.default) { + val userWalletId = accountId.userWalletId + + withContext(NonCancellable) { + val account = getAccount(accountId = accountId) + + val foundToken = account.cryptoCurrencies + .filterIsInstance() + .firstOrNull { + it.network.backendId == networkId && + !it.isCustom && + it.contractAddress.equals(contractAddress, true) + } + + if (foundToken != null) return@withContext foundToken + + val tokenToAdd = findToken(userWalletId, contractAddress, networkId) + + refreshBalances(userWalletId = userWalletId, currencies = listOf(tokenToAdd)).joinAll() + + tokenToAdd + } + } + private suspend fun Raise.getAccount(accountId: AccountId): Account.CryptoPortfolio { val accountList = singleAccountListSupplier.getSyncOrNull( params = SingleAccountListProducer.Params(userWalletId = accountId.userWalletId), @@ -181,6 +217,23 @@ class SaveCryptoCurrenciesUseCase( return destination } + private suspend fun Raise.findToken( + userWalletId: UserWalletId, + networkId: String, + contractAddress: String, + ): CryptoCurrency.Token { + return catch( + block = { + currenciesRepository.createTokenCurrency( + userWalletId = userWalletId, + networkId = networkId, + contractAddress = contractAddress, + ) + }, + catch = ::raise, + ) + } + private suspend fun refreshBalances(userWalletId: UserWalletId, currencies: List): List { if (currencies.isEmpty()) return emptyList() diff --git a/domain/swap/src/main/java/com/tangem/domain/swap/SwapTransactionRepository.kt b/domain/swap/src/main/java/com/tangem/domain/swap/SwapTransactionRepository.kt index 0ad2638066..c1ed26365a 100644 --- a/domain/swap/src/main/java/com/tangem/domain/swap/SwapTransactionRepository.kt +++ b/domain/swap/src/main/java/com/tangem/domain/swap/SwapTransactionRepository.kt @@ -1,5 +1,6 @@ package com.tangem.domain.swap +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -59,9 +60,13 @@ interface SwapTransactionRepository { * * @param txId transaction id to update * @param status new transaction status - * @param refundTokenCurrency refund token + * @param accountWithCurrency account id with refund token */ - suspend fun storeTransactionState(txId: String, status: SwapStatusModel, refundTokenCurrency: CryptoCurrency?) + suspend fun storeTransactionState( + txId: String, + status: SwapStatusModel, + accountWithCurrency: Pair? = null, + ) /** * Save last swapped crypto currency token diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/RemoveCurrencyUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/RemoveCurrencyUseCase.kt index 59381c5e65..661f363200 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/RemoveCurrencyUseCase.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/RemoveCurrencyUseCase.kt @@ -9,12 +9,14 @@ import com.tangem.domain.tokens.model.remove.RemoveCurrencyError import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.walletmanager.WalletManagersFacade +@Deprecated("Use SaveCryptoCurrenciesUseCase") class RemoveCurrencyUseCase( private val currenciesRepository: CurrenciesRepository, private val walletManagersFacade: WalletManagersFacade, private val multiWalletCryptoCurrenciesSupplier: MultiWalletCryptoCurrenciesSupplier, ) { + @Deprecated("Use SaveCryptoCurrenciesUseCase") suspend operator fun invoke( userWalletId: UserWalletId, currency: CryptoCurrency, diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt index d4fec5e8ed..638147c85c 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapTransactionRepository.kt @@ -7,6 +7,7 @@ import com.tangem.datasource.local.preferences.PreferencesKeys import com.tangem.datasource.local.preferences.utils.getObjectList import com.tangem.datasource.local.preferences.utils.getObjectListSync import com.tangem.datasource.local.preferences.utils.getObjectMap +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -40,7 +41,7 @@ internal class DefaultSwapTransactionRepository( storeTransactionState( txId = transaction.txId, status = it, - refundTokenCurrency = null, + accountWithCurrency = null, ) } appPreferencesStore.editData { mutablePreferences -> @@ -181,7 +182,7 @@ internal class DefaultSwapTransactionRepository( override suspend fun storeTransactionState( txId: String, status: ExchangeStatusModel, - refundTokenCurrency: CryptoCurrency?, + accountWithCurrency: Pair?, ) { appPreferencesStore.editData { mutablePreferences -> val savedMap = mutablePreferences.getObjectMap( @@ -190,8 +191,8 @@ internal class DefaultSwapTransactionRepository( val updatesMap = savedMap.toMutableMap() updatesMap[txId] = status.copy( - refundTokensResponse = refundTokenCurrency?.let { - userTokensResponseFactory.createResponseToken(refundTokenCurrency) + refundTokensResponse = accountWithCurrency?.let { (accountId, currency) -> + userTokensResponseFactory.createResponseToken(currency, accountId) }, ) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt index abef06ede4..d476f5ff9c 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/converters/SavedSwapTransactionListConverter.kt @@ -22,10 +22,12 @@ internal class SavedSwapTransactionListConverter( fromCryptoCurrencyId = value.fromCryptoCurrencyId, toCryptoCurrencyId = value.toCryptoCurrencyId, fromTokensResponse = userTokensResponseFactory.createResponseToken( - value.fromCryptoCurrency, + currency = value.fromCryptoCurrency, + accountId = null, ), toTokensResponse = userTokensResponseFactory.createResponseToken( - value.toCryptoCurrency, + currency = value.toCryptoCurrency, + accountId = null, ), transactions = value.transactions, ) @@ -82,8 +84,11 @@ internal class SavedSwapTransactionListConverter( userWalletId = userWalletId.stringValue, fromCryptoCurrencyId = fromCryptoCurrency.id.value, toCryptoCurrencyId = toCryptoCurrency.id.value, - fromTokensResponse = userTokensResponseFactory.createResponseToken(fromCryptoCurrency), - toTokensResponse = userTokensResponseFactory.createResponseToken(toCryptoCurrency), + fromTokensResponse = userTokensResponseFactory.createResponseToken( + currency = fromCryptoCurrency, + accountId = null, + ), + toTokensResponse = userTokensResponseFactory.createResponseToken(currency = toCryptoCurrency, accountId = null), transactions = tokenTransactions, ) } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt index f851de1028..e815518f1c 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapTransactionRepository.kt @@ -1,5 +1,6 @@ package com.tangem.feature.swap.domain +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId @@ -29,7 +30,11 @@ interface SwapTransactionRepository { txId: String, ) - suspend fun storeTransactionState(txId: String, status: ExchangeStatusModel, refundTokenCurrency: CryptoCurrency?) + suspend fun storeTransactionState( + txId: String, + status: ExchangeStatusModel, + accountWithCurrency: Pair? = null, + ) suspend fun storeLastSwappedCryptoCurrencyId(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID) diff --git a/features/tokendetails/impl/build.gradle.kts b/features/tokendetails/impl/build.gradle.kts index 4945e2727a..c02aa188d0 100644 --- a/features/tokendetails/impl/build.gradle.kts +++ b/features/tokendetails/impl/build.gradle.kts @@ -57,35 +57,36 @@ dependencies { implementation(projects.core.decompose) implementation(projects.common.ui) + implementation(projects.libs.blockchainSdk) implementation(projects.libs.crypto) /** Domain modules */ + implementation(projects.domain.account.status) implementation(projects.domain.appCurrency) implementation(projects.domain.appCurrency.models) + implementation(projects.domain.balanceHiding) + implementation(projects.domain.balanceHiding.models) implementation(projects.domain.card) implementation(projects.domain.demo) implementation(projects.domain.legacy) - implementation(projects.libs.blockchainSdk) - implementation(projects.domain.models) - implementation(projects.domain.settings) - implementation(projects.domain.tokens) - implementation(projects.domain.tokens.models) - implementation(projects.domain.txhistory) - implementation(projects.domain.txhistory.models) - implementation(projects.domain.wallets) - implementation(projects.domain.wallets.models) - implementation(projects.domain.balanceHiding) - implementation(projects.domain.balanceHiding.models) - implementation(projects.domain.transaction) - implementation(projects.domain.transaction.models) - implementation(projects.domain.staking) implementation(projects.domain.markets.models) + implementation(projects.domain.models) + implementation(projects.domain.notifications.models) implementation(projects.domain.onramp) implementation(projects.domain.onramp.models) implementation(projects.domain.promo) implementation(projects.domain.promo.models) implementation(projects.domain.quotes) - implementation(projects.domain.notifications.models) + implementation(projects.domain.settings) + implementation(projects.domain.staking) + implementation(projects.domain.tokens) + implementation(projects.domain.tokens.models) + implementation(projects.domain.transaction) + implementation(projects.domain.transaction.models) + implementation(projects.domain.txhistory) + implementation(projects.domain.txhistory.models) + implementation(projects.domain.wallets) + implementation(projects.domain.wallets.models) /** Temp dependency to swap domain */ implementation(projects.features.swap.domain) diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt index 027e74d291..cd2a54c343 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/model/TokenDetailsModel.kt @@ -3,6 +3,7 @@ package com.tangem.feature.tokendetails.presentation.tokendetails.model import androidx.compose.runtime.Stable import arrow.core.getOrElse import arrow.core.merge +import arrow.core.right import com.arkivanov.decompose.router.slot.SlotNavigation import com.arkivanov.decompose.router.slot.activate import com.arkivanov.decompose.router.slot.dismiss @@ -31,12 +32,16 @@ import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager import com.tangem.core.ui.message.SnackbarMessage +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles +import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase +import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.GetBalanceHidingSettingsUseCase import com.tangem.domain.card.common.util.cardTypesResolver import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.TokenReceiveNotification +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 @@ -141,6 +146,9 @@ internal class TokenDetailsModel @Inject constructor( private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase, private val saveViewedTokenReceiveWarningUseCase: SaveViewedTokenReceiveWarningUseCase, private val needShowYieldSupplyDepositedWarningUseCase: NeedShowYieldSupplyDepositedWarningUseCase, + private val accountsFeatureToggles: AccountsFeatureToggles, + private val getAccountCryptoCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, + private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase, ) : Model(), TokenDetailsClickIntents, YieldSupplyDepositedWarningComponent.ModelCallback { private val params = paramsContainer.require() @@ -158,6 +166,7 @@ internal class TokenDetailsModel @Inject constructor( private val selectedAppCurrencyFlow: StateFlow = createSelectedAppCurrencyFlow() private var cryptoCurrencyStatus: CryptoCurrencyStatus? = null + private var account: Account.CryptoPortfolio? = null private var isBalanceLoadedEventSent = false private var expressTxStatusTaskScheduler = SingleTaskScheduler>() @@ -228,15 +237,26 @@ internal class TokenDetailsModel @Inject constructor( private fun initButtons() { // we need also init buttons before start all loading to avoid buttons blocking modelScope.launch { - val currentCryptoCurrencyStatus = getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync( - userWalletId = userWalletId, - cryptoCurrencyId = cryptoCurrency.id, - isSingleWalletWithTokens = false, - ).getOrNull() - currentCryptoCurrencyStatus?.let { - cryptoCurrencyStatus = it - updateButtons(it) - updateWarnings(it) + val currentCryptoCurrencyStatus = if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCryptoCurrencyStatusUseCase.invokeSync( + userWalletId = userWalletId, + currency = cryptoCurrency, + ) + .onSome { account = it.account } + .getOrNull() + ?.status + } else { + getSingleCryptoCurrencyStatusUseCase.invokeMultiWalletSync( + userWalletId = userWalletId, + cryptoCurrencyId = cryptoCurrency.id, + isSingleWalletWithTokens = false, + ).getOrNull() + } + + currentCryptoCurrencyStatus?.let { status -> + cryptoCurrencyStatus = status + updateButtons(currencyStatus = status) + updateWarnings(cryptoCurrencyStatus = status) } } } @@ -308,12 +328,18 @@ internal class TokenDetailsModel @Inject constructor( } private fun subscribeOnCurrencyStatusUpdates() { - getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet( - userWalletId = userWalletId, - currencyId = cryptoCurrency.id, - isSingleWalletWithTokens = userWallet is UserWallet.Cold && - userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), - ) + if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCryptoCurrencyStatusUseCase(userWalletId, cryptoCurrency) + .onEach { account = it.account } + .map { it.status.right() } + } else { + getSingleCryptoCurrencyStatusUseCase.invokeMultiWallet( + userWalletId = userWalletId, + currencyId = cryptoCurrency.id, + isSingleWalletWithTokens = userWallet is UserWallet.Cold && + userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(), + ) + } .distinctUntilChanged() .onEach { maybeCurrencyStatus -> internalUiState.value = stateFactory.getCurrencyLoadedBalanceState(maybeCurrencyStatus) @@ -553,7 +579,7 @@ internal class TokenDetailsModel @Inject constructor( } override fun onReceiveClick(unavailabilityReason: ScenarioUnavailabilityReason) { - val networkAddress = cryptoCurrencyStatus?.value?.networkAddress ?: return + cryptoCurrencyStatus?.value?.networkAddress ?: return analyticsEventsHandler.send( TokenScreenAnalyticsEvent.ButtonWithParams.ButtonReceive( @@ -689,7 +715,18 @@ internal class TokenDetailsModel @Inject constructor( override fun onHideConfirmed() { modelScope.launch { - removeCurrencyUseCase.invoke(userWalletId, cryptoCurrency) + if (accountsFeatureToggles.isFeatureEnabled) { + val accountId = account?.accountId + + if (accountId == null) { + Timber.e("Account ID is null, cannot hide currency ${cryptoCurrency.id}") + return@launch + } + + saveCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrency) + } else { + removeCurrencyUseCase(userWalletId, cryptoCurrency) + } .onLeft { Timber.e(it) } .onRight { router.popBackStack() } } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt index 27a03a1006..0ba2ad9f35 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/express/ExchangeStatusFactory.kt @@ -4,13 +4,17 @@ import com.tangem.common.ui.expressStatus.ExpressStatusBottomSheetConfig import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.datasource.local.swap.ExpressAnalyticsStatus import com.tangem.datasource.local.swap.SwapTransactionStatusStore +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles +import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase +import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase import com.tangem.domain.appcurrency.model.AppCurrency +import com.tangem.domain.models.account.AccountId import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.quote.QuoteStatus +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.quotes.QuotesRepository import com.tangem.domain.tokens.AddCryptoCurrenciesUseCase import com.tangem.domain.tokens.model.analytics.TokenExchangeAnalyticsEvent -import com.tangem.domain.models.wallet.UserWallet import com.tangem.feature.swap.domain.SwapTransactionRepository import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.domain.* @@ -27,6 +31,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.conflate import kotlinx.coroutines.flow.map +import timber.log.Timber @Suppress("LongParameterList") internal class ExchangeStatusFactory @AssistedInject constructor( @@ -34,6 +39,9 @@ internal class ExchangeStatusFactory @AssistedInject constructor( private val swapRepository: SwapRepository, private val quotesRepository: QuotesRepository, private val addCryptoCurrenciesUseCase: AddCryptoCurrenciesUseCase, + private val accountsFeatureToggles: AccountsFeatureToggles, + private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, + private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase, private val swapTransactionStatusStore: SwapTransactionStatusStore, private val analyticsEventsHandler: AnalyticsEventHandler, @Assisted private val clickIntents: TokenDetailsClickIntents, @@ -111,9 +119,41 @@ internal class ExchangeStatusFactory @AssistedInject constructor( ifRight = { statusModel -> sendStatusUpdateAnalytics(statusModel, provider) - val refundTokenCurrency = addRefundCurrencyIfNeeded(statusModel, provider.type) + val accountId = if (accountsFeatureToggles.isFeatureEnabled) { + getAccountCurrencyStatusUseCase.invokeSync( + userWalletId = userWallet.walletId, + currency = cryptoCurrency, + ) + .map { it.account.accountId } + .getOrNull() + } else { + null + } - swapTransactionRepository.storeTransactionState(txId, statusModel, refundTokenCurrency) + val refundTokenCurrency = if (accountsFeatureToggles.isFeatureEnabled) { + if (accountId != null) { + addRefundCurrencyIfNeededNew( + accountId = accountId, + status = statusModel, + type = provider.type, + ) + } else { + Timber.e("Account ID is null, cannot add refund currency ${cryptoCurrency.id}") + null + } + } else { + addRefundCurrencyIfNeededLegacy(status = statusModel, type = provider.type) + } + + swapTransactionRepository.storeTransactionState( + txId = txId, + status = statusModel, + accountWithCurrency = if (refundTokenCurrency != null) { + Pair(accountId, refundTokenCurrency) + } else { + null + }, + ) statusModel.copy(refundCurrency = refundTokenCurrency) }, ) @@ -135,7 +175,7 @@ internal class ExchangeStatusFactory @AssistedInject constructor( /** * For now do it only for dex-bridge provider */ - private suspend fun addRefundCurrencyIfNeeded( + private suspend fun addRefundCurrencyIfNeededLegacy( status: ExchangeStatusModel?, type: ExchangeProviderType, ): CryptoCurrency? { @@ -153,6 +193,27 @@ internal class ExchangeStatusFactory @AssistedInject constructor( return null } + private suspend fun addRefundCurrencyIfNeededNew( + accountId: AccountId, + status: ExchangeStatusModel?, + type: ExchangeProviderType, + ): CryptoCurrency? { + status ?: return null + if (type != ExchangeProviderType.DEX_BRIDGE) return null + val refundNetwork = status.refundNetwork + val refundContractAddress = status.refundContractAddress + + if (refundNetwork == null || refundContractAddress == null) return null + + return saveCryptoCurrenciesUseCase.add( + accountId = accountId, + contractAddress = refundContractAddress, + networkId = refundNetwork, + ) + .onLeft(Timber::e) + .getOrNull() + } + private fun getExchangeStatusState( savedTransactions: List?, quoteStatuses: Set, diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt index 9fd48ed6b2..e0eeaf7bd6 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/child/wallet/model/intents/WalletCurrencyActionsClickIntents.kt @@ -22,6 +22,9 @@ import com.tangem.core.ui.extensions.WrappedList import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.haptic.TangemHapticEffect import com.tangem.core.ui.haptic.VibratorHapticManager +import com.tangem.domain.account.featuretoggle.AccountsFeatureToggles +import com.tangem.domain.account.status.usecase.GetAccountCurrencyStatusUseCase +import com.tangem.domain.account.status.usecase.SaveCryptoCurrenciesUseCase import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.extenstions.unwrap import com.tangem.domain.core.lce.Lce @@ -71,6 +74,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch +import timber.log.Timber import java.math.BigDecimal import javax.inject.Inject @@ -151,6 +155,9 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private val saveViewedYieldSupplyWarningUseCase: SaveViewedYieldSupplyWarningUseCase, private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase, private val removeCurrencyUseCase: RemoveCurrencyUseCase, + private val accountsFeatureToggles: AccountsFeatureToggles, + private val getAccountCurrencyStatusUseCase: GetAccountCurrencyStatusUseCase, + private val saveCryptoCurrenciesUseCase: SaveCryptoCurrenciesUseCase, ) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents { override fun onSendClick( @@ -340,7 +347,23 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( override fun onPerformHideToken(userWalletId: UserWalletId, cryptoCurrencyStatus: CryptoCurrencyStatus) { modelScope.launch(dispatchers.io) { - removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency) + if (accountsFeatureToggles.isFeatureEnabled) { + val accountId = getAccountCurrencyStatusUseCase.invokeSync( + userWalletId = userWalletId, + currency = cryptoCurrencyStatus.currency, + ) + .map { it.account.accountId } + .getOrNull() + + if (accountId == null) { + Timber.e("Account ID is null, cannot hide currency ${cryptoCurrencyStatus.currency.id}") + return@launch + } + + saveCryptoCurrenciesUseCase(accountId = accountId, remove = cryptoCurrencyStatus.currency) + } else { + removeCurrencyUseCase(userWalletId, cryptoCurrencyStatus.currency) + } .fold( ifLeft = { walletEventSender.send(