Updated on 2026-08-14

This commit is contained in:
Tangem 2024-12-19 17:34:43 +03:00
parent 796ceab5dc
commit db0d566db2
6 changed files with 34 additions and 285 deletions

View file

@ -49,8 +49,6 @@ object TradeCryptoMiddleware {
is TradeCryptoAction.FinishSelling -> openReceiptUrl(action.transactionId)
is TradeCryptoAction.Buy -> proceedBuyAction(state, action)
is TradeCryptoAction.Sell -> proceedSellAction(action)
is TradeCryptoAction.SendToken -> handleNewSendToken(action = action)
is TradeCryptoAction.SendCoin -> handleNewSendCoin(action = action)
}
}
@ -166,37 +164,4 @@ object TradeCryptoMiddleware {
transactionId = transactionId,
)?.let { store.dispatchOpenUrl(it) }
}
private fun handleNewSendToken(action: TradeCryptoAction.SendToken) {
handleNewSend(
userWalletId = action.userWallet.walletId,
txInfo = action.transactionInfo,
currency = action.tokenCurrency,
)
}
private fun handleNewSendCoin(action: TradeCryptoAction.SendCoin) {
handleNewSend(
userWalletId = action.userWallet.walletId,
txInfo = action.transactionInfo,
currency = action.coinStatus.currency,
)
}
private fun handleNewSend(
userWalletId: UserWalletId,
txInfo: TradeCryptoAction.TransactionInfo?,
currency: CryptoCurrency,
) {
val route = AppRoute.Send(
currency = currency,
userWalletId = userWalletId,
transactionId = txInfo?.transactionId,
destinationAddress = txInfo?.destinationAddress,
amount = txInfo?.amount,
tag = txInfo?.tag,
)
store.dispatchNavigationAction { push(route) }
}
}

View file

@ -1,11 +1,9 @@
package com.tangem.domain.tokens.legacy
import com.tangem.domain.onramp.model.OnrampSource
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.wallets.models.UserWallet
import org.rekotlin.Action
import java.math.BigDecimal
sealed class TradeCryptoAction : Action {
@ -23,29 +21,4 @@ sealed class TradeCryptoAction : Action {
val cryptoCurrencyStatus: CryptoCurrencyStatus,
val appCurrencyCode: String,
) : TradeCryptoAction()
@Deprecated("Use AppRoute instead")
data class SendToken(
val userWallet: UserWallet,
val tokenCurrency: CryptoCurrency.Token,
val tokenFiatRate: BigDecimal?,
val coinFiatRate: BigDecimal?,
val feeCurrencyStatus: CryptoCurrencyStatus?,
val transactionInfo: TransactionInfo? = null,
) : TradeCryptoAction()
@Deprecated("Use AppRoute instead")
data class SendCoin(
val userWallet: UserWallet,
val coinStatus: CryptoCurrencyStatus,
val feeCurrencyStatus: CryptoCurrencyStatus?,
val transactionInfo: TransactionInfo? = null,
) : TradeCryptoAction()
data class TransactionInfo(
val transactionId: String,
val destinationAddress: String,
val amount: String,
val tag: String? = null,
)
}

View file

@ -378,10 +378,9 @@ internal class SendViewModel @Inject constructor(
when {
uiState.value.sendState?.isSuccess == true -> return
transactionId != null && amount != null && destinationAddress != null -> {
loadFee()
uiState.value = stateFactory.getReadyState(amount, destinationAddress, memo)
stateRouter.showSend()
updateNotifications()
loadFee()
}
else -> {
uiState.value = stateFactory.getReadyState()

View file

@ -40,7 +40,6 @@ import com.tangem.domain.staking.model.StakingAvailability
import com.tangem.domain.staking.model.StakingEntryInfo
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.model.NetworkAddress
@ -83,7 +82,6 @@ import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import timber.log.Timber
import java.math.BigDecimal
import javax.inject.Inject
@Suppress("LongParameterList", "LargeClass", "TooManyFunctions")
@ -98,8 +96,6 @@ internal class TokenDetailsViewModel @Inject constructor(
private val getExploreUrlUseCase: GetExploreUrlUseCase,
private val getCryptoCurrencyActionsUseCase: GetCryptoCurrencyActionsUseCase,
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
private val getCurrencyWarningsUseCase: GetCurrencyWarningsUseCase,
private val getExplorerTransactionUrlUseCase: GetExplorerTransactionUrlUseCase,
@ -517,68 +513,16 @@ internal class TokenDetailsViewModel @Inject constructor(
return
}
sendCurrency(status = cryptoCurrencyStatus ?: return)
sendCurrency()
}
private fun sendCurrency(status: CryptoCurrencyStatus, transactionInfo: TransactionInfo? = null) {
viewModelScope.launch(dispatchers.main) {
val maybeFeeCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWalletId, status).getOrNull()
private fun sendCurrency() {
val route = AppRoute.Send(
currency = cryptoCurrency,
userWalletId = userWallet.walletId,
)
when (val currency = status.currency) {
is CryptoCurrency.Coin -> {
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = status,
feeCurrencyStatus = maybeFeeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
is CryptoCurrency.Token -> {
sendToken(
tokenCurrency = currency,
tokenFiatRate = status.value.fiatRate,
feeCurrencyStatus = maybeFeeCurrencyStatus,
transactionInfo = transactionInfo,
)
}
}
}
}
private fun sendToken(
tokenCurrency: CryptoCurrency.Token,
tokenFiatRate: BigDecimal?,
feeCurrencyStatus: CryptoCurrencyStatus?,
transactionInfo: TransactionInfo?,
) {
viewModelScope.launch(dispatchers.main) {
val maybeCoinStatus = getNetworkCoinStatusUseCase(
userWalletId = userWalletId,
networkId = tokenCurrency.network.id,
derivationPath = tokenCurrency.network.derivationPath,
isSingleWalletWithTokens = userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
)
.conflate()
.distinctUntilChanged()
.firstOrNull()
reduxStateHolder.dispatchWithMain(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = tokenCurrency,
tokenFiatRate = tokenFiatRate,
coinFiatRate = maybeCoinStatus?.fold(
ifLeft = { null },
ifRight = { it.value.fiatRate },
),
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
appRouter.push(route)
}
override fun onReceiveClick(unavailabilityReason: ScenarioUnavailabilityReason) {

View file

@ -2,25 +2,22 @@ package com.tangem.feature.wallet.presentation.deeplink
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.common.routing.AppRoute
import com.tangem.common.routing.AppRouter
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.deeplink.DeepLink
import com.tangem.core.deeplink.DeepLinksRegistry
import com.tangem.core.deeplink.global.BuyCurrencyDeepLink
import com.tangem.core.deeplink.global.SellCurrencyDeepLink
import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.legacy.TradeCryptoAction.TransactionInfo
import com.tangem.domain.tokens.model.CryptoCurrency
import com.tangem.domain.tokens.model.CryptoCurrencyStatus
import com.tangem.domain.tokens.GetCryptoCurrencyUseCase
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.feature.wallet.presentation.wallet.viewmodels.intents.WalletClickIntents
import com.tangem.features.onramp.OnrampFeatureToggles
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@Suppress("LongParameterList")
@ -28,13 +25,9 @@ internal class WalletDeepLinksHandler @Inject constructor(
private val deepLinksRegistry: DeepLinksRegistry,
private val analyticsEventHandler: AnalyticsEventHandler,
private val getCryptoCurrencyUseCase: GetCryptoCurrencyUseCase,
private val getCryptoCurrencyStatusSyncUseCase: GetCryptoCurrencyStatusSyncUseCase,
private val getCryptoCurrencyStatusesSyncUseCase: GetCryptoCurrencyStatusesSyncUseCase,
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
private val reduxStateHolder: ReduxStateHolder,
private val clickIntents: WalletClickIntents,
private val onrampFeatureToggles: OnrampFeatureToggles,
private val router: AppRouter,
) {
private var deepLinksMap = mutableMapOf<UserWalletId, List<DeepLink>>()
@ -75,35 +68,23 @@ internal class WalletDeepLinksHandler @Inject constructor(
}
private suspend fun onSellCurrencyDeepLink(userWallet: UserWallet, data: SellCurrencyDeepLink.Data) {
val cryptoCurrencyStatus = findCryptoCurrencyStatus(userWallet, data.currencyId) ?: return
val feeCurrencyStatus = getFeePaidCryptoCurrencyStatusSyncUseCase(
userWallet.walletId,
cryptoCurrencyStatus,
).getOrNull()
val cryptoCurrency = getCryptoCurrencyUseCase(userWallet.walletId, data.currencyId).getOrNull()
val transactionInfo = data.let {
TransactionInfo(
amount = it.baseCurrencyAmount,
destinationAddress = it.depositWalletAddress,
transactionId = it.transactionId,
tag = it.depositWalletAddressTag,
)
if (cryptoCurrency == null) {
Timber.e("onSellCurrencyDeepLink cryptoCurrency is null")
return
}
when (cryptoCurrencyStatus.currency) {
is CryptoCurrency.Coin -> sendCoin(
userWallet = userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
)
is CryptoCurrency.Token -> sendToken(
userWallet = userWallet,
cryptoCurrencyStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
)
}
val route = AppRoute.Send(
currency = cryptoCurrency,
userWalletId = userWallet.walletId,
transactionId = data.transactionId,
destinationAddress = data.depositWalletAddress,
amount = data.baseCurrencyAmount,
tag = data.depositWalletAddressTag,
)
router.push(route)
}
private suspend fun onBuyCurrencyDeepLink(externalTxId: String, userWallet: UserWallet) {
@ -114,62 +95,4 @@ internal class WalletDeepLinksHandler @Inject constructor(
analyticsEventHandler.send(TokenScreenAnalyticsEvent.Bought(cryptoCurrency.symbol))
}
}
private suspend fun findCryptoCurrencyStatus(
userWallet: UserWallet,
currencyIdValue: String,
): CryptoCurrencyStatus? {
return if (userWallet.isMultiCurrency) {
getCryptoCurrencyStatusesSyncUseCase(userWallet.walletId).getOrNull()?.let { currencies ->
currencies.find { currencyIdValue == it.currency.id.value }
}
} else {
getCryptoCurrencyStatusSyncUseCase(userWallet.walletId).getOrNull()
}
}
private fun sendCoin(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
feeCurrencyStatus: CryptoCurrencyStatus?,
transactionInfo: TransactionInfo,
) {
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
private suspend fun sendToken(
userWallet: UserWallet,
cryptoCurrencyStatus: CryptoCurrencyStatus,
feeCurrencyStatus: CryptoCurrencyStatus?,
transactionInfo: TransactionInfo,
) {
val cryptoCurrency = cryptoCurrencyStatus.currency as? CryptoCurrency.Token ?: return
val coinStatus = getNetworkCoinStatusUseCase(
userWalletId = userWallet.walletId,
networkId = cryptoCurrency.network.id,
derivationPath = cryptoCurrency.network.derivationPath,
isSingleWalletWithTokens = false,
)
.firstOrNull()
?.getOrNull()
?: return
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = cryptoCurrency,
tokenFiatRate = cryptoCurrencyStatus.value.fiatRate,
coinFiatRate = coinStatus.value.fiatRate,
feeCurrencyStatus = feeCurrencyStatus,
transactionInfo = transactionInfo,
),
)
}
}

View file

@ -21,7 +21,6 @@ import com.tangem.core.ui.haptic.TangemHapticEffect
import com.tangem.core.ui.haptic.VibratorHapticManager
import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase
import com.tangem.domain.appcurrency.extenstions.unwrap
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.core.utils.lceError
import com.tangem.domain.demo.IsDemoCardUseCase
@ -32,13 +31,14 @@ import com.tangem.domain.redux.ReduxStateHolder
import com.tangem.domain.settings.usercountry.GetUserCountryUseCase
import com.tangem.domain.settings.usercountry.models.UserCountry
import com.tangem.domain.staking.model.stakekit.Yield
import com.tangem.domain.tokens.*
import com.tangem.domain.tokens.GetPrimaryCurrencyStatusUpdatesUseCase
import com.tangem.domain.tokens.IsCryptoCurrencyCoinCouldHideUseCase
import com.tangem.domain.tokens.RemoveCurrencyUseCase
import com.tangem.domain.tokens.legacy.TradeCryptoAction
import com.tangem.domain.tokens.model.*
import com.tangem.domain.tokens.model.analytics.TokenReceiveAnalyticsEvent
import com.tangem.domain.tokens.model.analytics.TokenScreenAnalyticsEvent
import com.tangem.domain.walletmanager.WalletManagersFacade
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.domain.wallets.usecase.GetExploreUrlUseCase
import com.tangem.domain.wallets.usecase.GetSelectedWalletSyncUseCase
@ -53,9 +53,7 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import java.math.BigDecimal
import javax.inject.Inject
@ -108,8 +106,6 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
private val getPrimaryCurrencyStatusUpdatesUseCase: GetPrimaryCurrencyStatusUpdatesUseCase,
private val isCryptoCurrencyCoinCouldHide: IsCryptoCurrencyCoinCouldHideUseCase,
private val removeCurrencyUseCase: RemoveCurrencyUseCase,
private val getNetworkCoinStatusUseCase: GetNetworkCoinStatusUseCase,
private val getFeePaidCryptoCurrencyStatusSyncUseCase: GetFeePaidCryptoCurrencyStatusSyncUseCase,
private val getExploreUrlUseCase: GetExploreUrlUseCase,
private val getSelectedAppCurrencyUseCase: GetSelectedAppCurrencyUseCase,
private val analyticsEventHandler: AnalyticsEventHandler,
@ -136,63 +132,12 @@ internal class WalletCurrencyActionsClickIntentsImplementor @Inject constructor(
if (handleUnavailabilityReason(unavailabilityReason)) return
stateHolder.update(CloseBottomSheetTransformer(userWalletId = userWallet.walletId))
viewModelScope.launch(dispatchers.main) {
val maybeFeeCurrencyStatus =
getFeePaidCryptoCurrencyStatusSyncUseCase(userWallet.walletId, cryptoCurrencyStatus).getOrNull()
when (val currency = cryptoCurrencyStatus.currency) {
is CryptoCurrency.Coin -> sendCoin(cryptoCurrencyStatus, userWallet, maybeFeeCurrencyStatus)
is CryptoCurrency.Token -> sendToken(
cryptoCurrency = currency,
cryptoCurrencyStatus = cryptoCurrencyStatus.value,
feeCurrencyStatus = maybeFeeCurrencyStatus,
userWallet = userWallet,
)
}
}
}
private fun sendCoin(
cryptoCurrencyStatus: CryptoCurrencyStatus,
userWallet: UserWallet,
feeCurrencyStatus: CryptoCurrencyStatus?,
) {
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendCoin(
userWallet = userWallet,
coinStatus = cryptoCurrencyStatus,
feeCurrencyStatus = feeCurrencyStatus,
),
val route = AppRoute.Send(
currency = cryptoCurrencyStatus.currency,
userWalletId = userWallet.walletId,
)
}
private fun sendToken(
cryptoCurrency: CryptoCurrency.Token,
cryptoCurrencyStatus: CryptoCurrencyStatus.Value,
feeCurrencyStatus: CryptoCurrencyStatus?,
userWallet: UserWallet,
) {
viewModelScope.launch(dispatchers.main) {
getNetworkCoinStatusUseCase(
userWalletId = userWallet.walletId,
networkId = cryptoCurrency.network.id,
derivationPath = cryptoCurrency.network.derivationPath,
isSingleWalletWithTokens = userWallet.scanResponse.cardTypesResolver.isSingleWalletWithToken(),
)
.take(count = 1)
.collectLatest {
it.onRight { coinStatus ->
reduxStateHolder.dispatch(
action = TradeCryptoAction.SendToken(
userWallet = userWallet,
tokenCurrency = cryptoCurrency,
tokenFiatRate = cryptoCurrencyStatus.fiatRate,
coinFiatRate = coinStatus.value.fiatRate,
feeCurrencyStatus = feeCurrencyStatus,
),
)
}
}
}
appRouter.push(route)
}
override fun onReceiveClick(cryptoCurrencyStatus: CryptoCurrencyStatus) {