diff --git a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt index cfb77e6180..9f5d8aecb2 100644 --- a/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/wallet/redux/middlewares/TradeCryptoMiddleware.kt @@ -48,7 +48,6 @@ object TradeCryptoMiddleware { is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId) is TradeCryptoAction.Buy -> proceedBuyAction(state, action) is TradeCryptoAction.Sell -> proceedSellAction(action) - is TradeCryptoAction.Swap -> openSwap(currency = action.cryptoCurrency) is TradeCryptoAction.Stake -> openStaking( userWalletId = action.userWalletId, cryptoCurrencyId = action.cryptoCurrencyId, @@ -141,10 +140,6 @@ object TradeCryptoMiddleware { )?.let { store.dispatchOpenUrl(it) } } - private fun openSwap(currency: CryptoCurrency) { - store.dispatchNavigationAction { push(AppRoute.Swap(currency = currency)) } - } - private fun openStaking(userWalletId: UserWalletId, cryptoCurrencyId: CryptoCurrency.ID, yield: Yield) { store.dispatchNavigationAction { push( diff --git a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt index bae031de6d..d8e383a18e 100644 --- a/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt +++ b/common/routing/src/main/kotlin/com/tangem/common/routing/AppRoute.kt @@ -219,12 +219,14 @@ sealed class AppRoute(val path: String) : Route { @Serializable data class Swap( val currency: CryptoCurrency, - ) : AppRoute(path = "/swap/${currency.id.value}"), RouteBundleParams { + val userWalletId: UserWalletId, + ) : AppRoute(path = "/swap/${currency.id.value}/${userWalletId.stringValue}"), RouteBundleParams { override fun getBundle(): Bundle = bundle(serializer()) companion object { const val CURRENCY_BUNDLE_KEY = "currency" + const val USER_WALLET_ID_KEY = "userWalletId" } } diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt index 0b04bf321b..706493a6ea 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/legacy/TradeCryptoAction.kt @@ -40,8 +40,6 @@ sealed class TradeCryptoAction : Action { val transactionInfo: TransactionInfo? = null, ) : TradeCryptoAction() - data class Swap(val cryptoCurrency: CryptoCurrency) : TradeCryptoAction() - data class Stake( val userWalletId: UserWalletId, val cryptoCurrencyId: CryptoCurrency.ID, diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt index dafaff9a51..8c6f6a8de7 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractor.kt @@ -2,7 +2,7 @@ package com.tangem.feature.swap.domain import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus -import com.tangem.domain.wallets.models.UserWallet +import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.domain.models.SwapAmount import com.tangem.feature.swap.domain.models.domain.IncludeFeeInAmount import com.tangem.feature.swap.domain.models.domain.PermissionOptions @@ -79,12 +79,14 @@ interface SwapInteractor { */ fun getTokenBalance(token: CryptoCurrencyStatus): SwapAmount - fun getSelectedWallet(): UserWallet? - suspend fun selectInitialCurrencyToSwap( initialCryptoCurrency: CryptoCurrency, state: TokensDataStateExpress, ): CryptoCurrencyStatus? fun getNativeToken(networkId: String): CryptoCurrency + + interface Factory { + fun create(selectedWalletId: UserWalletId): SwapInteractor + } } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt index de0468d9ff..72b9def69e 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/SwapInteractorImpl.kt @@ -14,7 +14,6 @@ import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.extenstions.unwrap import com.tangem.domain.appcurrency.repository.AppCurrencyRepository -import com.tangem.domain.demo.DemoConfig import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase import com.tangem.domain.tokens.model.* @@ -29,7 +28,7 @@ import com.tangem.domain.transaction.usecase.* import com.tangem.domain.utils.convertToSdkAmount import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId -import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase +import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.converters.SwapCurrencyConverter import com.tangem.feature.swap.domain.models.DataError @@ -43,21 +42,22 @@ import com.tangem.lib.crypto.UserWalletManager import com.tangem.lib.crypto.models.ProxyAmount import com.tangem.lib.crypto.models.ProxyFee import com.tangem.lib.crypto.models.ProxyFees +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.firstOrNull import timber.log.Timber import java.math.BigDecimal import java.math.BigInteger import java.math.RoundingMode -import javax.inject.Inject @Suppress("LargeClass", "LongParameterList") -internal class SwapInteractorImpl @Inject constructor( +internal class SwapInteractorImpl @AssistedInject constructor( private val transactionManager: TransactionManager, private val userWalletManager: UserWalletManager, private val repository: SwapRepository, private val allowPermissionsHandler: AllowPermissionsHandler, - private val getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, private val getMultiCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase, private val sendTransactionUseCase: SendTransactionUseCase, private val createTransactionUseCase: CreateTransactionUseCase, @@ -69,9 +69,10 @@ internal class SwapInteractorImpl @Inject constructor( private val appCurrencyRepository: AppCurrencyRepository, private val currenciesRepository: CurrenciesRepository, private val initialToCurrencyResolver: InitialToCurrencyResolver, - private val demoConfig: DemoConfig, private val validateTransactionUseCase: ValidateTransactionUseCase, private val estimateFeeUseCase: EstimateFeeUseCase, + private val getUserWalletUseCase: GetUserWalletUseCase, + @Assisted private val userWalletId: UserWalletId, ) : SwapInteractor { private val getSelectedAppCurrencyUseCase by lazy(LazyThreadSafetyMode.NONE) { @@ -82,15 +83,13 @@ internal class SwapInteractorImpl @Inject constructor( private val amountFormatter = AmountFormatter() private val hundredPercent = BigInteger("100") + private val userWallet + get() = getUserWalletUseCase(userWalletId).getOrElse { + error("Failed to get user wallet") + } + override suspend fun getTokensDataState(currency: CryptoCurrency): TokensDataStateExpress { - val selectedWallet = getSelectedWalletSyncUseCase().fold( - ifLeft = { null }, - ifRight = { it }, - ) - - requireNotNull(selectedWallet) { "No selected wallet" } - - val walletCurrencyStatuses = getMultiCryptoCurrencyStatusUseCase(selectedWallet.walletId) + val walletCurrencyStatuses = getMultiCryptoCurrencyStatusUseCase(userWalletId) .getOrElse { emptyList() } val walletCurrencyStatusesExceptInitial = walletCurrencyStatuses @@ -133,10 +132,6 @@ internal class SwapInteractorImpl @Inject constructor( ) } - override fun getSelectedWallet(): UserWallet? { - return getSelectedWalletSyncUseCase().getOrNull() - } - private fun getToCurrenciesGroup( currency: CryptoCurrency, leastPairs: List, @@ -224,7 +219,7 @@ internal class SwapInteractorImpl @Inject constructor( memo = null, destination = getTokenAddress(permissionOptions.fromToken), network = permissionOptions.fromToken.network, - userWalletId = requireNotNull(getSelectedWallet()).walletId, + userWalletId = userWalletId, txExtras = createDexTxExtras( dataToSign, permissionOptions.fromToken.network, @@ -237,7 +232,7 @@ internal class SwapInteractorImpl @Inject constructor( val result = sendTransactionUseCase( txData = approveTransaction, - userWallet = requireNotNull(getSelectedWallet()), + userWallet = userWallet, network = permissionOptions.fromToken.network, ) return result.fold( @@ -403,7 +398,6 @@ internal class SwapInteractorImpl @Inject constructor( minAdaValue: BigDecimal?, ): List { val fromToken = fromTokenStatus.currency - val userWalletId = getSelectedWallet()?.walletId ?: return emptyList() val warnings = mutableListOf() manageExistentialDepositWarning(warnings, userWalletId, amount, fromToken, feeState) manageDustWarning(warnings, feeState, userWalletId, fromTokenStatus, amount) @@ -597,7 +591,8 @@ internal class SwapInteractorImpl @Inject constructor( """.trimIndent(), ) - val cardId = getSelectedWallet()?.scanResponse?.card?.cardId ?: return SwapTransactionState.UnknownError + val userWallet = getUserWalletUseCase(userWalletId).getOrNull() ?: return SwapTransactionState.UnknownError + val cardId = userWallet.scanResponse.card.cardId if (isDemoCardUseCase(cardId)) return SwapTransactionState.DemoMode return when (swapProvider.type) { @@ -615,7 +610,6 @@ internal class SwapInteractorImpl @Inject constructor( amount = amountToSwapWithFee, txFee = fee, swapProvider = swapProvider, - userWalletId = requireNotNull(getSelectedWallet()).walletId, ) } ExchangeProviderType.DEX, ExchangeProviderType.DEX_BRIDGE -> { @@ -627,7 +621,6 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGetStatus = currencyToGet, fee = fee, amountToSwap = amountToSwap, - userWalletId = requireNotNull(getSelectedWallet()).walletId, ) } } @@ -679,7 +672,6 @@ internal class SwapInteractorImpl @Inject constructor( currencyToGetStatus: CryptoCurrencyStatus, amountToSwap: String, fee: TxFee, - userWalletId: UserWalletId, ): SwapTransactionState { val amountDecimal = requireNotNull(toBigDecimalOrNull(amountToSwap)) { "wrong amount format" } val amount = SwapAmount(amountDecimal, currencyToSendStatus.currency.decimals) @@ -706,7 +698,7 @@ internal class SwapInteractorImpl @Inject constructor( val result = sendTransactionUseCase( txData = txData, - userWallet = requireNotNull(getSelectedWallet()), + userWallet = getUserWalletUseCase(userWalletId).getOrElse { return SwapTransactionState.UnknownError }, network = currencyToSendStatus.currency.network, ) return result.fold( @@ -766,7 +758,6 @@ internal class SwapInteractorImpl @Inject constructor( amount: SwapAmount, txFee: TxFee, swapProvider: SwapProvider, - userWalletId: UserWalletId, ): SwapTransactionState { val exchangeData = repository.getExchangeData( fromContractAddress = currencyToSend.currency.getContractAddress(), @@ -787,8 +778,9 @@ internal class SwapInteractorImpl @Inject constructor( val exchangeDataCex = exchangeData.transaction as? ExpressTransactionModel.CEX ?: return SwapTransactionState.UnknownError - val cardId = getSelectedWallet()?.scanResponse?.card?.cardId ?: return SwapTransactionState.UnknownError - if (demoConfig.isDemoCardId(cardId)) return SwapTransactionState.UnknownError + val cardId = userWallet.scanResponse.card.cardId + + if (isDemoCardUseCase(cardId)) return SwapTransactionState.UnknownError val txData = createTransactionUseCase( amount = amount.value.convertToSdkAmount(currencyToSend.currency), @@ -811,7 +803,7 @@ internal class SwapInteractorImpl @Inject constructor( val result = sendTransactionUseCase( txData = txData, - userWallet = requireNotNull(getSelectedWallet()), + userWallet = userWallet, network = currencyToSend.currency.network, ) @@ -941,9 +933,8 @@ internal class SwapInteractorImpl @Inject constructor( txExternalUrl: String? = null, txExternalId: String? = null, ) { - val selectedWallet = getSelectedWallet() ?: return swapTransactionRepository.storeTransaction( - userWalletId = selectedWallet.walletId, + userWalletId = userWalletId, fromCryptoCurrency = currencyToSend.currency, toCryptoCurrency = currencyToGet.currency, transaction = SavedSwapTransactionModel( @@ -994,23 +985,16 @@ internal class SwapInteractorImpl @Inject constructor( spenderAddress: String, ): Boolean { if (fromToken is CryptoCurrency.Coin) return true - return getSelectedWalletSyncUseCase().fold( - ifRight = { userWallet -> - val allowance = repository.getAllowance( - userWalletId = userWallet.walletId, - networkId = networkId, - derivationPath = fromToken.network.derivationPath.value, - tokenDecimalCount = fromToken.decimals, - tokenAddress = getTokenAddress(fromToken), - spenderAddress = spenderAddress, - ) - allowance >= amount.value - }, - ifLeft = { - Timber.e("Swap Error on isAllowedToSpend") - false - }, + + val allowance = repository.getAllowance( + userWalletId = userWallet.walletId, + networkId = networkId, + derivationPath = fromToken.network.derivationPath.value, + tokenDecimalCount = fromToken.decimals, + tokenAddress = getTokenAddress(fromToken), + spenderAddress = spenderAddress, ) + return allowance >= amount.value } private suspend fun createEmptyAmountState(): SwapState { @@ -1040,13 +1024,11 @@ internal class SwapInteractorImpl @Inject constructor( val fromToken = fromTokenStatus.currency val toToken = toTokenStatus.currency return coroutineScope { - val txFeeResult = getSelectedWalletSyncUseCase().getOrNull()?.let { userWallet -> - getUnhandledFee( - amount = amount.value, - userWallet = userWallet, - cryptoCurrency = fromToken, - ) - } + val txFeeResult = getUnhandledFee( + amount = amount.value, + userWallet = userWallet, + cryptoCurrency = fromToken, + ) val txFee = if (provider.type == ExchangeProviderType.CEX) { getFeeForCex(txFeeResult, fromTokenStatus) @@ -1196,7 +1178,6 @@ internal class SwapInteractorImpl @Inject constructor( is TxFeeState.SingleFeeState -> txFee.fee.feeIncludeOtherNativeFee } val feePaidCurrency = getFeePaidCurrency( - userWalletId = requireNotNull(getSelectedWallet()).walletId, currency = fromToken, ) @@ -1256,7 +1237,6 @@ internal class SwapInteractorImpl @Inject constructor( private suspend fun getFormattedFiatFees(fromToken: CryptoCurrency, vararg fees: BigDecimal): List { val appCurrency = getSelectedAppCurrencyUseCase.unwrap() val feePaidCurrency = getFeePaidCurrency( - userWalletId = requireNotNull(getSelectedWallet()).walletId, currency = fromToken, ) val feeCurrencyId: CryptoCurrency.ID = when (feePaidCurrency) { @@ -1308,7 +1288,6 @@ internal class SwapInteractorImpl @Inject constructor( val otherNativeFee = transaction.otherNativeFeeWei ?.movePointLeft(nativeCoinDecimals) ?: BigDecimal.ZERO - val userWallet = getSelectedWallet() val txFeeState = when ( val feeData = getFeeDataForDexSwap( networkId = networkId, @@ -1509,7 +1488,6 @@ internal class SwapInteractorImpl @Inject constructor( swapAmount = swapAmount, spenderAddress = requireNotNull(spenderAddress) { "Spender address is null" }, ) - val userWallet = getSelectedWallet() val cardId = userWallet?.scanResponse?.card?.cardId val feeData = if (cardId != null && isDemoCardUseCase(cardId)) { getDemoFees(fromTokenStatus.currency) @@ -1846,7 +1824,6 @@ internal class SwapInteractorImpl @Inject constructor( ): Boolean { val tokenBalance = getTokenBalance(fromToken).value val feePaidCurrency = getFeePaidCurrency( - userWalletId = requireNotNull(getSelectedWallet()).walletId, currency = fromToken.currency, ) return when (feePaidCurrency) { @@ -1861,7 +1838,7 @@ internal class SwapInteractorImpl @Inject constructor( } } - private suspend fun getFeePaidCurrency(userWalletId: UserWalletId, currency: CryptoCurrency): FeePaidCurrency { + private suspend fun getFeePaidCurrency(currency: CryptoCurrency): FeePaidCurrency { return currenciesRepository.getFeePaidCurrency( userWalletId = userWalletId, currency = currency, @@ -1894,13 +1871,12 @@ internal class SwapInteractorImpl @Inject constructor( networkId: String, fromTokenStatus: CryptoCurrencyStatus, ): SwapFeeState { - val userWalletId = requireNotNull(getSelectedWallet()).walletId if (fee == null) { return SwapFeeState.NotEnough() } val percentsToFeeIncrease = BigDecimal.ONE - return when (val feePaidCurrency = getFeePaidCurrency(userWalletId, fromTokenStatus.currency)) { + return when (val feePaidCurrency = getFeePaidCurrency(fromTokenStatus.currency)) { FeePaidCurrency.Coin -> { val nativeTokenBalance = userWalletManager.getNativeTokenBalance( networkId, @@ -1994,21 +1970,13 @@ internal class SwapInteractorImpl @Inject constructor( swapAmount: SwapAmount? = null, spenderAddress: String, ): String { - return getSelectedWalletSyncUseCase().fold( - ifRight = { userWallet -> - repository.getApproveData( - userWalletId = userWallet.walletId, - networkId = networkId, - derivationPath = derivationPath, - currency = fromToken, - amount = swapAmount?.value, - spenderAddress = spenderAddress, - ) - }, - ifLeft = { - Timber.e("Swap Error on getApproveData") - error("Swap Error on getApproveData") - }, + return repository.getApproveData( + userWalletId = userWalletId, + networkId = networkId, + derivationPath = derivationPath, + currency = fromToken, + amount = swapAmount?.value, + spenderAddress = spenderAddress, ) } @@ -2059,4 +2027,9 @@ internal class SwapInteractorImpl @Inject constructor( private val normalDemoFee = "0.0002".toBigDecimal() private val priorityDemoFee = "0.0003".toBigDecimal() } + + @AssistedFactory + interface Factory : SwapInteractor.Factory { + override fun create(selectedWalletId: UserWalletId): SwapInteractorImpl + } } \ No newline at end of file diff --git a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt index 3f20bc09bc..9f95b3e0c6 100644 --- a/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt +++ b/features/swap/domain/src/main/java/com/tangem/feature/swap/domain/di/SwapDomainModule.kt @@ -1,79 +1,34 @@ package com.tangem.feature.swap.domain.di -import com.tangem.domain.appcurrency.repository.AppCurrencyRepository -import com.tangem.domain.card.repository.CardSdkConfigRepository -import com.tangem.domain.demo.DemoConfig -import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.staking.repositories.StakingRepository -import com.tangem.domain.tokens.GetCardTokensListUseCase import com.tangem.domain.tokens.GetCryptoCurrencyStatusesSyncUseCase import com.tangem.domain.tokens.repository.CurrenciesRepository -import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.tokens.repository.NetworksRepository import com.tangem.domain.tokens.repository.QuotesRepository -import com.tangem.domain.transaction.TransactionRepository import com.tangem.domain.transaction.usecase.* -import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase import com.tangem.feature.swap.domain.* -import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.lib.crypto.TransactionManager -import com.tangem.lib.crypto.UserWalletManager import com.tangem.utils.coroutines.CoroutineDispatcherProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import javax.inject.Qualifier import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -class SwapDomainModule { +internal class SwapDomainModule { + + @Provides + fun provideAllowPermissionsHandler(): AllowPermissionsHandler { + return AllowPermissionsHandlerImpl() + } @Provides @Singleton - fun provideSwapInteractor( - swapRepository: SwapRepository, - userWalletManager: UserWalletManager, - transactionManager: TransactionManager, - @SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, - getCryptoCurrencyStatusUseCase: GetCryptoCurrencyStatusesSyncUseCase, - @SwapScope sendTransactionUseCase: SendTransactionUseCase, - @SwapScope createTransactionUseCase: CreateTransactionUseCase, - createTransactionDataExtrasUseCase: CreateTransactionDataExtrasUseCase, - isDemoCardUseCase: IsDemoCardUseCase, - quotesRepository: QuotesRepository, - swapTransactionRepository: SwapTransactionRepository, - appCurrencyRepository: AppCurrencyRepository, - currencyChecksRepository: CurrencyChecksRepository, - initialToCurrencyResolver: InitialToCurrencyResolver, - currenciesRepository: CurrenciesRepository, - validateTransactionUseCase: ValidateTransactionUseCase, - estimateFeeUseCase: EstimateFeeUseCase, - ): SwapInteractor { - return SwapInteractorImpl( - transactionManager = transactionManager, - userWalletManager = userWalletManager, - repository = swapRepository, - allowPermissionsHandler = AllowPermissionsHandlerImpl(), - getSelectedWalletSyncUseCase = getSelectedWalletSyncUseCase, - getMultiCryptoCurrencyStatusUseCase = getCryptoCurrencyStatusUseCase, - sendTransactionUseCase = sendTransactionUseCase, - createTransactionUseCase = createTransactionUseCase, - createTransactionExtrasUseCase = createTransactionDataExtrasUseCase, - isDemoCardUseCase = isDemoCardUseCase, - quotesRepository = quotesRepository, - swapTransactionRepository = swapTransactionRepository, - appCurrencyRepository = appCurrencyRepository, - currencyChecksRepository = currencyChecksRepository, - currenciesRepository = currenciesRepository, - initialToCurrencyResolver = initialToCurrencyResolver, - demoConfig = DemoConfig(), - validateTransactionUseCase = validateTransactionUseCase, - estimateFeeUseCase = estimateFeeUseCase, - ) + fun provideSwapInteractorFactory(factory: SwapInteractorImpl.Factory): SwapInteractor.Factory { + return factory } @Provides @@ -84,13 +39,6 @@ class SwapDomainModule { ) } - @SwapScope - @Provides - @Singleton - fun providesGetSelectedWalletUseCase(userWalletsListManager: UserWalletsListManager): GetSelectedWalletSyncUseCase { - return GetSelectedWalletSyncUseCase(userWalletsListManager = userWalletsListManager) - } - @Provides @Singleton fun providesGetCryptoCurrencyStatusUseCase( @@ -109,58 +57,10 @@ class SwapDomainModule { ) } - @SwapScope - @Provides - @Singleton - fun providesGetCardTokensListUseCase( - currenciesRepository: CurrenciesRepository, - quotesRepository: QuotesRepository, - networksRepository: NetworksRepository, - stakingRepository: StakingRepository, - ): GetCardTokensListUseCase { - return GetCardTokensListUseCase( - currenciesRepository = currenciesRepository, - quotesRepository = quotesRepository, - networksRepository = networksRepository, - stakingRepository = stakingRepository, - ) - } - - @SwapScope - @Provides - fun provideDemoCardUseCase(): IsDemoCardUseCase { - return IsDemoCardUseCase(config = DemoConfig()) - } - - @SwapScope - @Provides - @Singleton - fun provideCreateTransactionUseCase(transactionRepository: TransactionRepository): CreateTransactionUseCase { - return CreateTransactionUseCase( - transactionRepository = transactionRepository, - ) - } - - @SwapScope - @Provides - @Singleton - fun provideSendTransactionUseCase( - cardSdkConfigRepository: CardSdkConfigRepository, - transactionRepository: TransactionRepository, - walletManagersFacade: WalletManagersFacade, - ): SendTransactionUseCase { - return SendTransactionUseCase( - demoConfig = DemoConfig(), - cardSdkConfigRepository = cardSdkConfigRepository, - transactionRepository = transactionRepository, - walletManagersFacade = walletManagersFacade, - ) - } - @Provides @Singleton fun provideInitialToCurrencyResolver( - @SwapScope getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, + getSelectedWalletSyncUseCase: GetSelectedWalletSyncUseCase, swapTransactionRepository: SwapTransactionRepository, ): InitialToCurrencyResolver { return DefaultInitialToCurrencyResolver( @@ -168,8 +68,4 @@ class SwapDomainModule { swapTransactionRepository = swapTransactionRepository, ) } -} - -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class SwapScope \ No newline at end of file +} \ No newline at end of file diff --git a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt index 8361ef85c9..1958445de2 100644 --- a/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt +++ b/features/swap/presentation/src/main/java/com/tangem/feature/swap/viewmodels/SwapViewModel.kt @@ -25,7 +25,6 @@ import com.tangem.domain.tokens.UpdateDelayedNetworkStatusUseCase import com.tangem.domain.tokens.model.CryptoCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.Network -import com.tangem.domain.wallets.models.UserWallet import com.tangem.domain.wallets.models.UserWalletId import com.tangem.feature.swap.analytics.SwapEvents import com.tangem.feature.swap.domain.BlockchainInteractor @@ -65,7 +64,7 @@ typealias SuccessLoadedSwapData = Map @Suppress("LargeClass", "LongParameterList") @HiltViewModel internal class SwapViewModel @Inject constructor( - private val swapInteractor: SwapInteractor, + private val swapInteractorFactory: SwapInteractor.Factory, private val blockchainInteractor: BlockchainInteractor, private val dispatchers: CoroutineDispatcherProvider, private val analyticsEventHandler: AnalyticsEventHandler, @@ -79,7 +78,13 @@ internal class SwapViewModel @Inject constructor( private val initialCryptoCurrency: CryptoCurrency = savedStateHandle.get(AppRoute.Swap.CURRENCY_BUNDLE_KEY) ?.unbundle(CryptoCurrency.serializer()) - ?: error("no expected parameter CryptoCurrency found`") + ?: error("no expected parameter CryptoCurrency found") + + private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.Swap.USER_WALLET_ID_KEY) + ?.unbundle(UserWalletId.serializer()) + ?: error("no expected parameter UserWalletId found") + + private val swapInteractor = swapInteractorFactory.create(userWalletId) private lateinit var initialCryptoCurrencyStatus: CryptoCurrencyStatus @@ -126,15 +131,13 @@ internal class SwapViewModel @Inject constructor( init { viewModelScope.launch(dispatchers.io) { - swapInteractor.getSelectedWallet()?.let { - val cryptoCurrencyStatus = - getCryptoCurrencyStatusUseCase(it.walletId, initialCryptoCurrency.id).getOrNull() - if (cryptoCurrencyStatus == null) { - uiState = stateBuilder.addAlert(uiState = uiState, onClick = swapRouter::back) - } else { - initialCryptoCurrencyStatus = cryptoCurrencyStatus - initTokens() - } + val cryptoCurrencyStatus = + getCryptoCurrencyStatusUseCase(userWalletId, initialCryptoCurrency.id).getOrNull() + if (cryptoCurrencyStatus == null) { + uiState = stateBuilder.addAlert(uiState = uiState, onClick = swapRouter::back) + } else { + initialCryptoCurrencyStatus = cryptoCurrencyStatus + initTokens() } } } @@ -191,7 +194,6 @@ internal class SwapViewModel @Inject constructor( ), ) - val userWalletId = swapInteractor.getSelectedWallet()?.walletId ?: return@launch (dataState.fromCryptoCurrency?.currency as? CryptoCurrency.Coin)?.let { subscribeToCoinBalanceUpdates( userWalletId = userWalletId, @@ -707,8 +709,6 @@ internal class SwapViewModel @Inject constructor( analyticsEventHandler.send(SwapEvents.ChooseTokenScreenResult(tokenChosen = true, token = it)) } - val userWalletId = swapInteractor.getSelectedWallet()?.walletId - if (foundToken != null) { val fromToken: CryptoCurrencyStatus val toToken: CryptoCurrencyStatus @@ -717,7 +717,7 @@ internal class SwapViewModel @Inject constructor( toToken = initialCryptoCurrencyStatus val newToken = fromToken.currency as? CryptoCurrency.Coin - if (userWalletId != null && newToken != null) { + if (newToken != null) { subscribeToCoinBalanceUpdates( userWalletId = userWalletId, coin = newToken, @@ -729,7 +729,7 @@ internal class SwapViewModel @Inject constructor( toToken = foundToken.currencyStatus val newToken = toToken.currency as? CryptoCurrency.Coin - if (userWalletId != null && newToken != null) { + if (newToken != null) { subscribeToCoinBalanceUpdates( userWalletId = userWalletId, coin = newToken, @@ -985,12 +985,10 @@ internal class SwapViewModel @Inject constructor( } }, onBuyClick = { currency -> - swapInteractor.getSelectedWallet()?.let { userWallet -> - swapRouter.openTokenDetails( - userWalletId = userWallet.walletId, - currency = currency, - ) - } + swapRouter.openTokenDetails( + userWalletId = userWalletId, + currency = currency, + ) }, onRetryClick = { startLoadingQuotesFromLastState() @@ -1162,20 +1160,18 @@ internal class SwapViewModel @Inject constructor( } private fun updateWalletBalance() { - swapInteractor.getSelectedWallet()?.let { userWallet -> - dataState.fromCryptoCurrency?.currency?.network?.let { network -> - viewModelScope.launch { - withContext(NonCancellable) { - updateForBalance(userWallet, network) - } + dataState.fromCryptoCurrency?.currency?.network?.let { network -> + viewModelScope.launch { + withContext(NonCancellable) { + updateForBalance(userWalletId, network) } } } } - private suspend fun updateForBalance(userWallet: UserWallet, network: Network) { + private suspend fun updateForBalance(userWalletId: UserWalletId, network: Network) { updateDelayedCurrencyStatusUseCase( - userWalletId = userWallet.walletId, + userWalletId = userWalletId, network = network, delayMillis = UPDATE_BALANCE_DELAY_MILLIS, refresh = true, diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index d6c7da21d3..f959f9632a 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -6,6 +6,7 @@ import androidx.paging.cachedIn import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter import com.tangem.common.routing.bundle.unbundle import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.analytics.models.AnalyticsParam @@ -126,6 +127,7 @@ internal class TokenDetailsViewModel @Inject constructor( tokenDetailsFeatureToggles: TokenDetailsFeatureToggles, deepLinksRegistry: DeepLinksRegistry, savedStateHandle: SavedStateHandle, + private val appRouter: AppRouter, ) : ViewModel(), DefaultLifecycleObserver, TokenDetailsClickIntents { private val userWalletId: UserWalletId = savedStateHandle.get(AppRoute.CurrencyDetails.USER_WALLET_ID_KEY) @@ -616,7 +618,7 @@ internal class TokenDetailsViewModel @Inject constructor( if (handleUnavailabilityReason(unavailabilityReason)) return - reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrency)) + appRouter.push(AppRoute.Swap(currency = cryptoCurrency, userWalletId = userWalletId)) } override fun onDismissDialog() { diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt index d924dabe10..95f595916e 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/state/transformers/converter/MultiWalletCurrencyActionsConverter.kt @@ -77,7 +77,13 @@ internal class MultiWalletCurrencyActionsConverter( is TokenActionsState.ActionState.Swap -> { title = resourceReference(R.string.swapping_swap_action) icon = R.drawable.ic_exchange_horizontal_24 - action = { clickIntents.onSwapClick(cryptoCurrencyStatus, ScenarioUnavailabilityReason.None) } + action = { + clickIntents.onSwapClick( + cryptoCurrencyStatus = cryptoCurrencyStatus, + userWalletId = userWallet.walletId, + unavailabilityReason = ScenarioUnavailabilityReason.None, + ) + } } is TokenActionsState.ActionState.CopyAddress -> { title = resourceReference(R.string.common_copy_address) diff --git a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt index cb24122b08..f00e79aa55 100644 --- a/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt +++ b/features/wallet/impl/src/main/java/com/tangem/feature/wallet/presentation/wallet/viewmodels/intents/WalletCurrencyActionsClickIntents.kt @@ -2,6 +2,8 @@ package com.tangem.feature.wallet.presentation.wallet.viewmodels.intents import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType +import com.tangem.common.routing.AppRoute +import com.tangem.common.routing.AppRouter import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.ui.clipboard.ClipboardManager import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent @@ -57,7 +59,11 @@ interface WalletCurrencyActionsClickIntents { fun onBuyClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason) - fun onSwapClick(cryptoCurrencyStatus: CryptoCurrencyStatus, unavailabilityReason: ScenarioUnavailabilityReason) + fun onSwapClick( + cryptoCurrencyStatus: CryptoCurrencyStatus, + userWalletId: UserWalletId, + unavailabilityReason: ScenarioUnavailabilityReason, + ) fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus) @@ -95,6 +101,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( private val vibratorHapticManager: VibratorHapticManager, private val clipboardManager: ClipboardManager, private val getYieldUseCase: GetYieldUseCase, + private val appRouter: AppRouter, ) : BaseWalletClickIntents(), WalletCurrencyActionsClickIntents { override fun onSendClick( @@ -352,6 +359,7 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( override fun onSwapClick( cryptoCurrencyStatus: CryptoCurrencyStatus, + userWalletId: UserWalletId, unavailabilityReason: ScenarioUnavailabilityReason, ) { analyticsEventHandler.send( @@ -360,7 +368,12 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor( if (handleUnavailabilityReason(unavailabilityReason)) return - reduxStateHolder.dispatch(TradeCryptoAction.Swap(cryptoCurrencyStatus.currency)) + appRouter.push( + AppRoute.Swap( + currency = cryptoCurrencyStatus.currency, + userWalletId = userWalletId, + ), + ) } override fun onExploreClick() {