From 0257c23494baf8e46de0162cd6452a781b91f725 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Aug 2025 11:40:43 +0500 Subject: [PATCH 1/7] Updated on 2026-08-14 --- .../components/WcSelectNetworksComponent.kt | 40 ++++++------------- .../connections/entity/WcAppInfoUM.kt | 1 + .../connections/entity/WcSelectNetworksUM.kt | 2 +- .../connections/model/WcPairModel.kt | 29 +++++++++----- .../model/WcSelectNetworksModel.kt | 5 ++- .../transformers/WcAppInfoTransformer.kt | 13 +++++- .../WcAppInfoWalletChangedTransformer.kt | 13 +++++- .../WcConnectButtonAvailabilityConverter.kt | 22 ++++++++++ .../transformers/WcNetworksInfoConverter.kt | 33 ++++++++------- .../WcNetworksSelectedTransformer.kt | 14 ++++++- .../connections/ui/WcAppInfoBS.kt | 19 +++++++-- .../connections/ui/WcConnectionsContent.kt | 1 + 12 files changed, 128 insertions(+), 64 deletions(-) create mode 100644 features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectNetworksComponent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectNetworksComponent.kt index 633c8859bc..b5e00c8355 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectNetworksComponent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/components/WcSelectNetworksComponent.kt @@ -32,12 +32,13 @@ import com.tangem.core.ui.components.PrimaryButton import com.tangem.core.ui.components.TangemSwitch import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfigContent -import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheet import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTitle import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.decompose.ComposableBottomSheetComponent +import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.extensions.wrappedList import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview import com.tangem.domain.models.network.Network @@ -145,8 +146,11 @@ private fun MissingRequiredBlock(missingNetworks: ImmutableList( - containerColor = TangemTheme.colors.background.tertiary, - config = TangemBottomSheetConfig( - isShown = true, - onDismissRequest = {}, - content = TangemBottomSheetConfigContent.Empty, - ), - title = { - TangemModalBottomSheetTitle( - title = stringReference("Choose wallet"), - onEndClick = {}, - endIconRes = R.drawable.ic_close_24, - ) - }, - content = { - WcSelectNetworksContent( - modifier = Modifier - .background(TangemTheme.colors.background.tertiary) - .padding(horizontal = TangemTheme.dimens.spacing16), - state = state, - ) - }, - ) + WcSelectNetworksBS(state = state, onBack = {}, onDismiss = {}) } } @@ -328,7 +310,7 @@ private class WcSelectNetworksProvider : CollectionPreviewParameterProvider) : WcNetworksInfo() } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcSelectNetworksUM.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcSelectNetworksUM.kt index 26a00e9e6e..5c2ed43886 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcSelectNetworksUM.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/entity/WcSelectNetworksUM.kt @@ -8,5 +8,5 @@ internal data class WcSelectNetworksUM( val available: ImmutableList, val notAdded: ImmutableList, val onDone: () -> Unit, - val doneButtonEnabled: Boolean = true, + val doneButtonEnabled: Boolean, ) \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt index c745515dc4..bbac86dbfd 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcPairModel.kt @@ -1,7 +1,9 @@ package com.tangem.features.walletconnect.connections.model import androidx.compose.runtime.Stable -import com.arkivanov.decompose.router.stack.* +import com.arkivanov.decompose.router.stack.StackNavigation +import com.arkivanov.decompose.router.stack.pop +import com.arkivanov.decompose.router.stack.pushNew import com.domain.blockaid.models.dapp.CheckDAppResult import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped @@ -10,18 +12,16 @@ import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.extensions.stringReference +import com.tangem.core.ui.message.SnackbarMessage import com.tangem.core.ui.message.ToastMessage import com.tangem.domain.models.network.Network -import com.tangem.domain.walletconnect.WcAnalyticEvents -import com.tangem.domain.walletconnect.model.WcPairError -import com.tangem.domain.walletconnect.model.WcPairRequest -import com.tangem.domain.walletconnect.model.WcSessionApprove -import com.tangem.domain.walletconnect.model.WcSessionProposal -import com.tangem.domain.walletconnect.usecase.pair.WcPairState -import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.models.wallet.isLocked import com.tangem.domain.models.wallet.isMultiCurrency +import com.tangem.domain.walletconnect.WcAnalyticEvents +import com.tangem.domain.walletconnect.model.* +import com.tangem.domain.walletconnect.usecase.pair.WcPairState +import com.tangem.domain.walletconnect.usecase.pair.WcPairUseCase import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.walletconnect.connections.components.WcPairComponent import com.tangem.features.walletconnect.connections.components.WcSelectNetworksComponent @@ -91,7 +91,9 @@ internal class WcPairModel @Inject constructor( appInfoUiState.transformerUpdate( WcConnectButtonProgressTransformer(showProgress = false), ) - pairState.result.onLeft(::processError) + pairState.result + .onLeft(::processError) + .onRight(::processSuccessfullyConnected) router.pop() } is WcPairState.Error -> { @@ -196,6 +198,13 @@ internal class WcPairModel @Inject constructor( stackNavigation.pushNew(WcAppInfoRoutes.Alert(WcAppInfoRoutes.Alert.Type.Verified(appName))) } + private fun processSuccessfullyConnected(session: WcSession) { + // TODO: [REDACTED_JIRA] localization + messageSender.send( + SnackbarMessage(message = stringReference("Connected to ${session.sdkModel.appMetaData.name}")), + ) + } + private fun processError(error: WcPairError) { val alert = when (error) { is WcPairError.UnsupportedDApp -> { @@ -236,6 +245,8 @@ internal class WcPairModel @Inject constructor( WcNetworksSelectedTransformer( missingNetworks = proposalNetwork.missingRequired, requiredNetworks = proposalNetwork.required, + availableNetworks = proposalNetwork.available, + notAddedNetworks = proposalNetwork.notAdded, additionallyEnabledNetworks = additionallyEnabledNetworks, ), ) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectNetworksModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectNetworksModel.kt index 1def1766ce..06a987c536 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectNetworksModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/WcSelectNetworksModel.kt @@ -60,6 +60,9 @@ internal class WcSelectNetworksModel @Inject constructor( private fun getInitialState(): WcSelectNetworksUM { val editEnabled = params.missingRequiredNetworks.isEmpty() + val doneButtonEnabled = params.missingRequiredNetworks.isEmpty() && + (params.requiredNetworks.isNotEmpty() || params.availableNetworks.isNotEmpty()) + return WcSelectNetworksUM( missing = params.missingRequiredNetworks.map { network -> WcNetworkInfoItem.Required( @@ -98,7 +101,7 @@ internal class WcSelectNetworksModel @Inject constructor( ) }.toImmutableList(), onDone = ::onDone, - doneButtonEnabled = editEnabled, + doneButtonEnabled = doneButtonEnabled, ) } } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoTransformer.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoTransformer.kt index 4527b5e065..41dd25542e 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoTransformer.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoTransformer.kt @@ -2,8 +2,8 @@ package com.tangem.features.walletconnect.connections.model.transformers import com.domain.blockaid.models.dapp.CheckDAppResult import com.tangem.domain.models.network.Network -import com.tangem.domain.walletconnect.model.WcSessionProposal import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.walletconnect.model.WcSessionProposal import com.tangem.features.walletconnect.connections.entity.WcAppInfoSecurityNotification import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM import com.tangem.features.walletconnect.connections.entity.WcPrimaryButtonConfig @@ -37,13 +37,22 @@ internal class WcAppInfoTransformer( value = WcNetworksInfoConverter.Input( missingNetworks = proposalNetwork.missingRequired, requiredNetworks = proposalNetwork.required, + availableNetworks = proposalNetwork.available, + notAddedNetworks = proposalNetwork.notAdded, additionallyEnabledNetworks = additionallyEnabledNetworks, ), ), onNetworksClick = onNetworksClick, connectButtonConfig = WcPrimaryButtonConfig( showProgress = false, - enabled = proposalNetwork.missingRequired.isEmpty(), + enabled = WcConnectButtonAvailabilityConverter.convert( + WcConnectButtonAvailabilityConverter.Input( + missingNetworks = proposalNetwork.missingRequired, + requiredNetworks = proposalNetwork.required, + availableNetworks = proposalNetwork.available, + selectedNetworks = additionallyEnabledNetworks, + ), + ), onClick = { onConnect(dAppSession.securityStatus) }, ), onDismiss = onDismiss, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoWalletChangedTransformer.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoWalletChangedTransformer.kt index b57674f3f1..54d753bd72 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoWalletChangedTransformer.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcAppInfoWalletChangedTransformer.kt @@ -1,8 +1,8 @@ package com.tangem.features.walletconnect.connections.model.transformers import com.tangem.domain.models.network.Network -import com.tangem.domain.walletconnect.model.WcSessionProposal import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.walletconnect.model.WcSessionProposal import com.tangem.features.walletconnect.connections.entity.WcAppInfoUM import com.tangem.utils.transformer.Transformer @@ -19,11 +19,20 @@ internal class WcAppInfoWalletChangedTransformer( WcNetworksInfoConverter.Input( missingNetworks = proposalNetwork.missingRequired, requiredNetworks = proposalNetwork.required, + availableNetworks = proposalNetwork.available, + notAddedNetworks = proposalNetwork.notAdded, additionallyEnabledNetworks = additionallyEnabledNetworks, ), ), connectButtonConfig = prevState.connectButtonConfig.copy( - enabled = proposalNetwork.missingRequired.isEmpty(), + enabled = WcConnectButtonAvailabilityConverter.convert( + WcConnectButtonAvailabilityConverter.Input( + missingNetworks = proposalNetwork.missingRequired, + requiredNetworks = proposalNetwork.required, + availableNetworks = proposalNetwork.available, + selectedNetworks = additionallyEnabledNetworks, + ), + ), ), ) } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt new file mode 100644 index 0000000000..3e25e03e74 --- /dev/null +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt @@ -0,0 +1,22 @@ +package com.tangem.features.walletconnect.connections.model.transformers + +import com.tangem.domain.models.network.Network +import com.tangem.utils.converter.Converter + +@Suppress("DestructuringDeclarationWithTooManyEntries") +internal object WcConnectButtonAvailabilityConverter : Converter { + + override fun convert(value: Input): Boolean { + val (missingNetworks, requiredNetworks, availableNetworks, selectedNetworks) = value + + return missingNetworks.isEmpty() && + (requiredNetworks.isNotEmpty() || availableNetworks.isNotEmpty() || selectedNetworks.isNotEmpty()) + } + + data class Input( + val missingNetworks: Set, + val requiredNetworks: Set, + val availableNetworks: Set, + val selectedNetworks: Set, + ) +} \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt index 26934b08b7..96da1ebf09 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt @@ -7,31 +7,34 @@ import com.tangem.features.walletconnect.connections.entity.WcNetworksInfo import com.tangem.utils.converter.Converter import kotlinx.collections.immutable.toImmutableList +@Suppress("DestructuringDeclarationWithTooManyEntries") internal object WcNetworksInfoConverter : Converter { override fun convert(value: Input): WcNetworksInfo { - return if (value.missingNetworks.isNotEmpty()) { - WcNetworksInfo.MissingRequiredNetworkInfo( - networks = value.missingNetworks.joinToString { it.name }, - ) - } else { - WcNetworksInfo.ContainsAllRequiredNetworks( - items = (value.requiredNetworks + value.additionallyEnabledNetworks) - .map { + val (missing, required, available, notAdded, additionallyEnabled) = value + return when { + missing.isNotEmpty() -> WcNetworksInfo.MissingRequiredNetworkInfo(missing.joinToString { it.name }) + required.isEmpty() && available.isEmpty() && notAdded.isNotEmpty() -> WcNetworksInfo.NoneNetworksAdded + else -> { + val combinedNetworks = required + additionallyEnabled + WcNetworksInfo.ContainsAllRequiredNetworks( + items = combinedNetworks.map { network -> WcNetworkInfoItem.Required( - id = it.rawId, - icon = it.iconResId, - name = it.name, - symbol = it.currencySymbol, + id = network.rawId, + icon = network.iconResId, + name = network.name, + symbol = network.currencySymbol, ) - } - .toImmutableList(), - ) + }.toImmutableList(), + ) + } } } data class Input( val missingNetworks: Set, val requiredNetworks: Set, + val availableNetworks: Set, + val notAddedNetworks: Set, val additionallyEnabledNetworks: Set, ) } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksSelectedTransformer.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksSelectedTransformer.kt index ee953b6130..7c916d8acd 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksSelectedTransformer.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksSelectedTransformer.kt @@ -7,19 +7,29 @@ import com.tangem.utils.transformer.Transformer internal class WcNetworksSelectedTransformer( private val missingNetworks: Set, private val requiredNetworks: Set, + private val availableNetworks: Set, + private val notAddedNetworks: Set, private val additionallyEnabledNetworks: Set, ) : Transformer { override fun transform(prevState: WcAppInfoUM): WcAppInfoUM { val contentState = prevState as? WcAppInfoUM.Content ?: return prevState return contentState.copy( connectButtonConfig = contentState.connectButtonConfig.copy( - enabled = missingNetworks.isEmpty() && - (requiredNetworks.isNotEmpty() || additionallyEnabledNetworks.isNotEmpty()), + enabled = WcConnectButtonAvailabilityConverter.convert( + WcConnectButtonAvailabilityConverter.Input( + missingNetworks = missingNetworks, + requiredNetworks = requiredNetworks, + availableNetworks = availableNetworks, + selectedNetworks = additionallyEnabledNetworks, + ), + ), ), networksInfo = WcNetworksInfoConverter.convert( value = WcNetworksInfoConverter.Input( missingNetworks = missingNetworks, requiredNetworks = requiredNetworks, + availableNetworks = availableNetworks, + notAddedNetworks = notAddedNetworks, additionallyEnabledNetworks = additionallyEnabledNetworks, ), ), diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoBS.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoBS.kt index af9a95cdf2..27957362b7 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoBS.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcAppInfoBS.kt @@ -35,10 +35,7 @@ import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetTi import com.tangem.core.ui.components.bottomsheets.modal.TangemModalBottomSheetWithFooter import com.tangem.core.ui.components.notifications.Notification import com.tangem.core.ui.components.notifications.NotificationConfig -import com.tangem.core.ui.extensions.clickableSingle -import com.tangem.core.ui.extensions.resourceReference -import com.tangem.core.ui.extensions.stringResourceSafe -import com.tangem.core.ui.extensions.wrappedList +import com.tangem.core.ui.extensions.* import com.tangem.core.ui.res.TangemColorPalette import com.tangem.core.ui.res.TangemTheme import com.tangem.core.ui.res.TangemThemePreview @@ -284,6 +281,19 @@ private fun WcAppInfoSecondBlock(state: WcAppInfoUM.Content, modifier: Modifier ) when (state.networksInfo) { is WcNetworksInfo.ContainsAllRequiredNetworks -> Unit + is WcNetworksInfo.NoneNetworksAdded -> { + HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary) + Notification( + config = NotificationConfig( + iconResId = R.drawable.ic_alert_circle_24, + // TODO: [REDACTED_JIRA] localization + title = stringReference("Specify selected networks"), + subtitle = stringReference("At least one network is required for dApp connection"), + ), + iconTint = TangemTheme.colors.icon.attention, + containerColor = TangemTheme.colors.background.action, + ) + } is WcNetworksInfo.MissingRequiredNetworkInfo -> { HorizontalDivider(thickness = 1.dp, color = TangemTheme.colors.stroke.primary) Notification( @@ -370,6 +380,7 @@ private fun SelectNetworksBlock(networksInfo: WcNetworksInfo, modifier: Modifier when (networksInfo) { is WcNetworksInfo.ContainsAllRequiredNetworks -> NetworkIcons(items = networksInfo.items) is WcNetworksInfo.MissingRequiredNetworkInfo -> Unit + is WcNetworksInfo.NoneNetworksAdded -> Unit } Icon( modifier = Modifier.size(width = 18.dp, height = 24.dp), diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt index 0e9068267d..acceb4fc2d 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt @@ -192,6 +192,7 @@ private fun ConnectionItem(connection: WcConnectionsUM, modifier: Modifier = Mod private fun AppInfoItem(appInfo: WcConnectedAppInfo, modifier: Modifier = Modifier) { Row( modifier = modifier, + verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(TangemTheme.dimens.spacing12), ) { AsyncImage( From a2f10e35037e65c8a42bca9811ec6deaacf50702 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Aug 2025 12:34:05 +0500 Subject: [PATCH 2/7] Updated on 2026-08-14 --- .../core/analytics/models/AnalyticsParam.kt | 1 + .../sign/WcSignUseCaseDelegate.kt | 6 ---- .../domain/walletconnect/WcAnalyticEvents.kt | 25 +++++++++++++-- .../transaction/model/WcAddNetworkModel.kt | 13 +++++++- .../model/WcSendTransactionModel.kt | 32 +++++++++++++++++++ .../model/WcSignTransactionModel.kt | 14 +++++++- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt index 6667534f25..8eed0785bc 100644 --- a/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt +++ b/core/analytics/models/src/main/java/com/tangem/core/analytics/models/AnalyticsParam.kt @@ -223,5 +223,6 @@ sealed class AnalyticsParam { const val NONCE = "Nonce" const val STANDARD = "Standard" const val NO_COLLECTION = "No collection" + const val EMULATION_STATUS = "Emulation Status" } } \ No newline at end of file diff --git a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt index af4f00d088..73dc766bbb 100644 --- a/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt +++ b/data/wallet-connect/src/main/kotlin/com/tangem/data/walletconnect/sign/WcSignUseCaseDelegate.kt @@ -41,12 +41,6 @@ internal class WcSignUseCaseDelegate( operator fun invoke(initModel: SignModel) = channelFlow { val state = MutableStateFlow(WcSignState(initModel, WcSignStep.PreSign)) - analytics.send( - WcAnalyticEvents.SignatureRequestReceived( - rawRequest = context.rawSdkRequest, - network = context.network, - ), - ) state .onEach { newState -> channel.send(newState) } diff --git a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcAnalyticEvents.kt b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcAnalyticEvents.kt index fa4b050106..d4bff77def 100644 --- a/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcAnalyticEvents.kt +++ b/domain/wallet-connect/src/main/kotlin/com/tangem/domain/walletconnect/WcAnalyticEvents.kt @@ -87,11 +87,11 @@ sealed class WcAnalyticEvents( ), ) - class SignatureRequestReceived( + class TransactionDetailsOpened( rawRequest: WcSdkSessionRequest, network: Network, ) : WcAnalyticEvents( - event = "Signature Request Received", + event = "Transaction Details Opened", params = mapOf( AnalyticsParam.Key.DAPP_NAME to rawRequest.dAppMetaData.name, AnalyticsParam.Key.DAPP_URL to rawRequest.dAppMetaData.url, @@ -100,6 +100,27 @@ sealed class WcAnalyticEvents( ), ) + class SignatureRequestReceived( + rawRequest: WcSdkSessionRequest, + network: Network, + emulationStatus: EmulationStatus, + ) : WcAnalyticEvents( + event = "Signature Request Received", + params = mapOf( + AnalyticsParam.Key.DAPP_NAME to rawRequest.dAppMetaData.name, + AnalyticsParam.Key.DAPP_URL to rawRequest.dAppMetaData.url, + AnalyticsParam.Key.METHOD_NAME to rawRequest.request.method, + AnalyticsParam.Key.BLOCKCHAIN to network.name, + AnalyticsParam.Key.EMULATION_STATUS to emulationStatus.status, + ), + ) { + enum class EmulationStatus(val status: String) { + Emulated("Emulated"), + Error("Error"), + CanNotEmulate("Can't emulate"), + } + } + class SignatureRequestHandled( rawRequest: WcSdkSessionRequest, network: Network, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt index dc8aa4bc23..1684d836c3 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcAddNetworkModel.kt @@ -3,12 +3,14 @@ package com.tangem.features.walletconnect.transaction.model import androidx.compose.runtime.Stable import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pushNew +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager +import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase import com.tangem.features.walletconnect.transaction.components.common.WcTransactionModelParams @@ -24,6 +26,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject +import kotlin.properties.Delegates @Suppress("LongParameterList") @Stable @@ -34,6 +37,7 @@ internal class WcAddNetworkModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, private val clipboardManager: ClipboardManager, + private val analytics: AnalyticsEventHandler, private val useCaseFactory: WcRequestUseCaseFactory, private val wcAddEthereumChainUMConverter: WcAddEthereumChainUMConverter, ) : Model(), WcCommonTransactionModel { @@ -44,10 +48,11 @@ internal class WcAddNetworkModel @Inject constructor( val stackNavigation = StackNavigation() private val params = paramsContainer.require() + private var useCase by Delegates.notNull() init { modelScope.launch { - val useCase: WcAddNetworkUseCase = useCaseFactory.createUseCase(params.rawRequest) + useCase = useCaseFactory.createUseCase(params.rawRequest) .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } .getOrNull() ?: return@launch _uiState.emit( @@ -75,6 +80,12 @@ internal class WcAddNetworkModel @Inject constructor( } fun showTransactionRequest() { + analytics.send( + WcAnalyticEvents.TransactionDetailsOpened( + rawRequest = useCase.rawSdkRequest, + network = useCase.network, + ), + ) stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo) } diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index b86107b35c..1494a6161a 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -5,6 +5,7 @@ import arrow.core.Either import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.pushNew +import com.domain.blockaid.models.transaction.SimulationResult import com.domain.blockaid.models.transaction.ValidationResult import com.tangem.blockchain.common.TransactionData import com.tangem.blockchain.common.transaction.TransactionFee @@ -27,6 +28,7 @@ import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.transaction.error.GetFeeError import com.tangem.domain.transaction.usecase.GetFeeUseCase import com.tangem.domain.walletconnect.WcAnalyticEvents +import com.tangem.domain.walletconnect.WcAnalyticEvents.SignatureRequestReceived.EmulationStatus import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.model.WcRequestError import com.tangem.domain.walletconnect.model.WcRequestError.Companion.message @@ -121,6 +123,8 @@ internal class WcSendTransactionModel @Inject constructor( .collectLatest { (signState, securityCheck) -> if (signingIsDone(signState, useCase)) return@collectLatest + sendSignatureReceivedAnalytics(useCase, securityCheck) + this@WcSendTransactionModel.signState = signState val isSecurityCheckContent = securityCheck is Lce.Content val isApprovalMethod = isSecurityCheckContent && @@ -257,6 +261,12 @@ internal class WcSendTransactionModel @Inject constructor( } fun showTransactionRequest() { + analytics.send( + WcAnalyticEvents.TransactionDetailsOpened( + rawRequest = useCase.rawSdkRequest, + network = useCase.network, + ), + ) stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo) } @@ -358,4 +368,26 @@ internal class WcSendTransactionModel @Inject constructor( private fun copyData(text: String) { clipboardManager.setText(text = text, isSensitive = true) } + + private fun sendSignatureReceivedAnalytics( + useCase: WcSignUseCase<*>, + securityCheck: Lce, + ) { + val emulationStatus = when (securityCheck) { + is Lce.Content -> when (securityCheck.content.result.simulation) { + SimulationResult.FailedToSimulate -> EmulationStatus.CanNotEmulate + is SimulationResult.Success -> EmulationStatus.Emulated + } + is Lce.Error -> EmulationStatus.Error + is Lce.Loading -> return + } + + analytics.send( + WcAnalyticEvents.SignatureRequestReceived( + rawRequest = useCase.rawSdkRequest, + network = useCase.network, + emulationStatus = emulationStatus, + ), + ) + } } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt index cdcb80f9f4..1283f3e84f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSignTransactionModel.kt @@ -4,12 +4,14 @@ import androidx.compose.runtime.Stable import com.arkivanov.decompose.router.stack.StackNavigation import com.arkivanov.decompose.router.stack.pop import com.arkivanov.decompose.router.stack.pushNew +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model import com.tangem.core.decompose.model.ParamsContainer import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.ui.clipboard.ClipboardManager +import com.tangem.domain.walletconnect.WcAnalyticEvents import com.tangem.domain.walletconnect.WcRequestUseCaseFactory import com.tangem.domain.walletconnect.model.WcEthMethod import com.tangem.domain.walletconnect.model.WcSolanaMethod @@ -32,6 +34,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject +import kotlin.properties.Delegates @Suppress("LongParameterList") @Stable @@ -42,6 +45,7 @@ internal class WcSignTransactionModel @Inject constructor( override val dispatchers: CoroutineDispatcherProvider, private val router: Router, private val clipboardManager: ClipboardManager, + private val analytics: AnalyticsEventHandler, private val useCaseFactory: WcRequestUseCaseFactory, private val signTypedDataUMConverter: WcSignTypedDataUMConverter, private val signTransactionUMConverter: WcSignTransactionUMConverter, @@ -54,9 +58,11 @@ internal class WcSignTransactionModel @Inject constructor( val stackNavigation = StackNavigation() + private var useCase by Delegates.notNull() + init { modelScope.launch { - val useCase = useCaseFactory.createUseCase(params.rawRequest) + useCase = useCaseFactory.createUseCase(params.rawRequest) .onLeft { router.push(WcHandleMethodErrorConverter.convert(it)) } .getOrNull() ?: return@launch useCase.invoke() @@ -109,6 +115,12 @@ internal class WcSignTransactionModel @Inject constructor( } fun showTransactionRequest() { + analytics.send( + WcAnalyticEvents.TransactionDetailsOpened( + rawRequest = useCase.rawSdkRequest, + network = useCase.network, + ), + ) stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo) } From 5b2fb1b22c496d7d0c74c8575332b3907281a5b8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Aug 2025 14:50:59 +0500 Subject: [PATCH 3/7] Updated on 2026-08-14 --- .../transformers/WcConnectButtonAvailabilityConverter.kt | 8 +++++--- .../model/transformers/WcNetworksInfoConverter.kt | 6 +++++- .../transaction/model/WcSendTransactionModel.kt | 5 +++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt index 3e25e03e74..72042b2e79 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcConnectButtonAvailabilityConverter.kt @@ -7,10 +7,12 @@ import com.tangem.utils.converter.Converter internal object WcConnectButtonAvailabilityConverter : Converter { override fun convert(value: Input): Boolean { - val (missingNetworks, requiredNetworks, availableNetworks, selectedNetworks) = value + val missing = value.missingNetworks + val required = value.requiredNetworks + val available = value.availableNetworks + val selected = value.selectedNetworks - return missingNetworks.isEmpty() && - (requiredNetworks.isNotEmpty() || availableNetworks.isNotEmpty() || selectedNetworks.isNotEmpty()) + return missing.isEmpty() && (required.isNotEmpty() || available.isNotEmpty() || selected.isNotEmpty()) } data class Input( diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt index 96da1ebf09..4d690bc279 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/model/transformers/WcNetworksInfoConverter.kt @@ -10,7 +10,11 @@ import kotlinx.collections.immutable.toImmutableList @Suppress("DestructuringDeclarationWithTooManyEntries") internal object WcNetworksInfoConverter : Converter { override fun convert(value: Input): WcNetworksInfo { - val (missing, required, available, notAdded, additionallyEnabled) = value + val missing = value.missingNetworks + val required = value.requiredNetworks + val available = value.availableNetworks + val notAdded = value.notAddedNetworks + val additionallyEnabled = value.additionallyEnabledNetworks return when { missing.isNotEmpty() -> WcNetworksInfo.MissingRequiredNetworkInfo(missing.joinToString { it.name }) required.isEmpty() && available.isEmpty() && notAdded.isNotEmpty() -> WcNetworksInfo.NoneNetworksAdded diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt index 1494a6161a..623125db6f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/model/WcSendTransactionModel.kt @@ -90,6 +90,7 @@ internal class WcSendTransactionModel @Inject constructor( private var wcApproval: WcApproval? = null private var sign: () -> Unit = {} private val feeReloadState = MutableStateFlow(false) + private val signatureReceivedAnalyticsSendState = MutableStateFlow(false) init { @Suppress("UnusedPrivateMember") @@ -373,6 +374,8 @@ internal class WcSendTransactionModel @Inject constructor( useCase: WcSignUseCase<*>, securityCheck: Lce, ) { + if (signatureReceivedAnalyticsSendState.value) return + val emulationStatus = when (securityCheck) { is Lce.Content -> when (securityCheck.content.result.simulation) { SimulationResult.FailedToSimulate -> EmulationStatus.CanNotEmulate @@ -389,5 +392,7 @@ internal class WcSendTransactionModel @Inject constructor( emulationStatus = emulationStatus, ), ) + + signatureReceivedAnalyticsSendState.value = true } } \ No newline at end of file From ede97572e3f752295ceb17d42c2758d40c282893 Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 6 Aug 2025 12:39:16 +0500 Subject: [PATCH 4/7] Updated on 2026-08-14 --- .../walletconnect/connections/ui/InternalComponents.kt | 2 ++ .../walletconnect/connections/ui/WcConnectionsContent.kt | 3 +++ .../connections/ui/preview/WcConnectionsPreviewData.kt | 2 +- .../ui/send/WcSendTransactionModalBottomSheet.kt | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt index 3150cbc5f6..0096e3ef3c 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/InternalComponents.kt @@ -62,6 +62,8 @@ internal fun WcAppInfoItem( text = title, color = TangemTheme.colors.text.primary1, style = TangemTheme.typography.h3, + maxLines = 1, + overflow = TextOverflow.Ellipsis, ) if (verifiedDAppState is VerifiedDAppState.Verified) { Icon( diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt index acceb4fc2d..452502ee96 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/WcConnectionsContent.kt @@ -213,9 +213,12 @@ private fun AppInfoItem(appInfo: WcConnectedAppInfo, modifier: Modifier = Modifi verticalAlignment = Alignment.CenterVertically, ) { Text( + modifier = Modifier.weight(1f, fill = false), text = appInfo.name, color = TangemTheme.colors.text.primary1, style = TangemTheme.typography.subtitle2, + maxLines = 1, + overflow = TextOverflow.Ellipsis, ) if (appInfo.verifiedState is VerifiedDAppState.Verified) { Icon( diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/preview/WcConnectionsPreviewData.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/preview/WcConnectionsPreviewData.kt index 62530a542a..b478dee7cd 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/preview/WcConnectionsPreviewData.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/ui/preview/WcConnectionsPreviewData.kt @@ -41,7 +41,7 @@ internal object WcConnectionsPreviewData { walletName = "Bitcoin", connectedApps = persistentListOf( WcConnectedAppInfo( - name = "React app", + name = "React app React app React app React app React app", iconUrl = "$BASE_URL/LiteCoin.png", subtitle = "https://react-app.walletconnect.com/", verifiedState = VerifiedDAppState.Verified {}, diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt index 0a0a1f1eac..cf5f3fee9f 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/send/WcSendTransactionModalBottomSheet.kt @@ -185,9 +185,9 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide onDismiss = {}, onSend = {}, appInfo = WcTransactionAppInfoContentUM( - appName = "React App", + appName = "React App React App ReactApp ReactApp ReactApp", appIcon = "", - verifiedState = VerifiedDAppState.Verified {}, + verifiedState = VerifiedDAppState.Unknown, appSubtitle = "react-app.walletconnect.com", ), estimatedWalletChanges = WcSendReceiveTransactionCheckResultsUM( @@ -225,7 +225,7 @@ private class WcSendTransactionStateProvider : CollectionPreviewParameterProvide onDismiss = {}, onSend = {}, appInfo = WcTransactionAppInfoContentUM( - appName = "React App", + appName = "React App React App React App React App React App", appIcon = "", verifiedState = VerifiedDAppState.Verified {}, appSubtitle = "react-app.walletconnect.com", From 4c720113f9e37682a626927775349e30562791c3 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 5 Aug 2025 14:57:44 +0500 Subject: [PATCH 5/7] Updated on 2026-08-14 --- .../tap/di/domain/TokensDomainModule.kt | 6 +++++ .../tokens/GetAssetRequirementsUseCase.kt | 21 +++++++++++++++ .../tokens/actions/BaseActionsFactory.kt | 11 +++++++- .../tokens/actions/CommonActionsFactory.kt | 6 ++++- .../actions/OutdatedDataActionsFactory.kt | 8 ++++-- .../actions/UnreachableActionsFactory.kt | 8 ++++-- features/onramp/impl/build.gradle.kts | 1 + .../tokenlist/model/OnrampTokenListModel.kt | 26 ++++++++++++++----- features/swap/data/build.gradle.kts | 1 + .../feature/swap/DefaultSwapRepository.kt | 12 ++++++--- .../feature/swap/domain/SwapInteractorImpl.kt | 15 +++++++---- 11 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAssetRequirementsUseCase.kt diff --git a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt index eddbbc0fd4..819dab82ba 100644 --- a/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt +++ b/app/src/main/java/com/tangem/tap/di/domain/TokensDomainModule.kt @@ -484,4 +484,10 @@ internal object TokensDomainModule { dispatchers = dispatchers, ) } + + @Provides + @Singleton + fun provideGetAssetRequirementsUseCase(walletManagersFacade: WalletManagersFacade): GetAssetRequirementsUseCase { + return GetAssetRequirementsUseCase(walletManagersFacade) + } } \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAssetRequirementsUseCase.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAssetRequirementsUseCase.kt new file mode 100644 index 0000000000..06c27b8c64 --- /dev/null +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/GetAssetRequirementsUseCase.kt @@ -0,0 +1,21 @@ +package com.tangem.domain.tokens + +import arrow.core.Either +import com.tangem.domain.models.currency.CryptoCurrency +import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.transaction.models.AssetRequirementsCondition +import com.tangem.domain.walletmanager.WalletManagersFacade + +class GetAssetRequirementsUseCase( + private val walletManagersFacade: WalletManagersFacade, +) { + + suspend operator fun invoke( + userWalletId: UserWalletId, + currency: CryptoCurrency, + ): Either { + return Either.Companion.catch { + walletManagersFacade.getAssetRequirements(userWalletId, currency) + } + } +} \ No newline at end of file diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/BaseActionsFactory.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/BaseActionsFactory.kt index 9f6481cf9f..f8285e582d 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/BaseActionsFactory.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/BaseActionsFactory.kt @@ -56,15 +56,24 @@ internal open class BaseActionsFactory( * * @param userWallet the user's cold wallet * @param currency the cryptocurrency to check + * @param requirementsDeferred a deferred object containing the asset requirements condition */ protected suspend fun getOnrampUnavailabilityReason( userWallet: UserWallet, currency: CryptoCurrency, + requirementsDeferred: Deferred?, ): ScenarioUnavailabilityReason { - return rampStateManager.availableForBuy( + val onrampUnavailabilityReason = rampStateManager.availableForBuy( userWallet = userWallet, cryptoCurrency = currency, ) + val shouldCheckAssetRequirements = + onrampUnavailabilityReason == ScenarioUnavailabilityReason.None && requirementsDeferred != null + return if (shouldCheckAssetRequirements) { + getReceiveScenario(requirementsDeferred.await()) + } else { + onrampUnavailabilityReason + } } /** diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/CommonActionsFactory.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/CommonActionsFactory.kt index bd735df30c..47e33ba88b 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/CommonActionsFactory.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/CommonActionsFactory.kt @@ -52,7 +52,11 @@ internal class CommonActionsFactory( } val onrampUnavailabilityReasonDeferred = async { - getOnrampUnavailabilityReason(userWallet = userWallet, currency = cryptoCurrencyStatus.currency) + getOnrampUnavailabilityReason( + userWallet = userWallet, + currency = cryptoCurrencyStatus.currency, + requirementsDeferred = requirementsDeferred, + ) } val sendUnavailabilityReasonDeferred = async { diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/OutdatedDataActionsFactory.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/OutdatedDataActionsFactory.kt index f38522a4f7..288ef4398d 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/OutdatedDataActionsFactory.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/OutdatedDataActionsFactory.kt @@ -2,12 +2,12 @@ package com.tangem.domain.tokens.actions import com.tangem.domain.exchange.RampStateManager import com.tangem.domain.models.StatusSource +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.staking.model.StakingAvailability import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState.ActionState import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.models.wallet.UserWallet import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope @@ -50,7 +50,11 @@ internal class OutdatedDataActionsFactory( } val onrampUnavailabilityReasonDeferred = async { - getOnrampUnavailabilityReason(userWallet = userWallet, currency = cryptoCurrencyStatus.currency) + getOnrampUnavailabilityReason( + userWallet = userWallet, + currency = cryptoCurrencyStatus.currency, + requirementsDeferred = requirementsDeferred, + ) } val sendUnavailabilityReasonDeferred = if (sources.networkSource == StatusSource.ACTUAL) { diff --git a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/UnreachableActionsFactory.kt b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/UnreachableActionsFactory.kt index ded293f444..cd59aafb14 100644 --- a/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/UnreachableActionsFactory.kt +++ b/domain/tokens/src/main/kotlin/com/tangem/domain/tokens/actions/UnreachableActionsFactory.kt @@ -1,11 +1,11 @@ package com.tangem.domain.tokens.actions import com.tangem.domain.exchange.RampStateManager +import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenActionsState.ActionState import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.models.wallet.UserWallet import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope @@ -36,7 +36,11 @@ internal class UnreachableActionsFactory( } val onrampUnavailabilityReasonDeferred = async { - getOnrampUnavailabilityReason(userWallet = userWallet, currency = cryptoCurrencyStatus.currency) + getOnrampUnavailabilityReason( + userWallet = userWallet, + currency = cryptoCurrencyStatus.currency, + requirementsDeferred = requirementsDeferred, + ) } // endregion diff --git a/features/onramp/impl/build.gradle.kts b/features/onramp/impl/build.gradle.kts index b32858e319..efcd01bc52 100644 --- a/features/onramp/impl/build.gradle.kts +++ b/features/onramp/impl/build.gradle.kts @@ -45,6 +45,7 @@ dependencies { implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) implementation(projects.domain.settings) + implementation(projects.domain.transaction.models) /** DI */ implementation(deps.hilt.android) diff --git a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt index c9e0a59aee..8a3bd36ae7 100644 --- a/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt +++ b/features/onramp/impl/src/main/kotlin/com/tangem/features/onramp/tokenlist/model/OnrampTokenListModel.kt @@ -16,11 +16,13 @@ import com.tangem.domain.models.TotalFiatBalance import com.tangem.domain.models.wallet.requireColdWallet import com.tangem.domain.settings.usercountry.GetUserCountryUseCase import com.tangem.domain.settings.usercountry.models.UserCountry +import com.tangem.domain.tokens.GetAssetRequirementsUseCase import com.tangem.domain.tokens.GetTokenListUseCase import com.tangem.domain.tokens.error.TokenListError import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.domain.tokens.model.ScenarioUnavailabilityReason import com.tangem.domain.tokens.model.TokenList +import com.tangem.domain.transaction.models.AssetRequirementsCondition import com.tangem.domain.wallets.usecase.GetWalletsUseCase import com.tangem.features.onramp.impl.R import com.tangem.features.onramp.tokenlist.OnrampTokenListComponent @@ -54,6 +56,7 @@ internal class OnrampTokenListModel @Inject constructor( private val getWalletsUseCase: GetWalletsUseCase, private val rampStateManager: RampStateManager, private val getUserCountryUseCase: GetUserCountryUseCase, + private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase, ) : Model() { val state: StateFlow = tokenListUMController.state @@ -206,17 +209,28 @@ internal class OnrampTokenListModel @Inject constructor( return coroutineScope { map { status -> async { - val isAvailable = checkAvailabilityByOperation(status = status) + val isOperationAvailable = checkAvailabilityByOperation(status = status) val isNotMissedDerivation = status.value !is CryptoCurrencyStatus.MissedDerivation val isNotLoading = status.value !is CryptoCurrencyStatus.Loading + val requirements = getAssetRequirementsUseCase( + userWalletId = userWallet.walletId, + currency = status.currency, + ).getOrNull() - val isNotUnreachable = when (params.filterOperation) { - OnrampOperation.BUY -> true // unreachable state is available for Buy operation - OnrampOperation.SELL -> status.value !is CryptoCurrencyStatus.Unreachable - OnrampOperation.SWAP -> status.value !is CryptoCurrencyStatus.Unreachable + val isNotTrustlineRequired = requirements !is AssetRequirementsCondition.RequiredTrustline + val isNotUnreachable = status.value !is CryptoCurrencyStatus.Unreachable + + val isAvailable = when (params.filterOperation) { + OnrampOperation.BUY -> { + isNotTrustlineRequired + } // unreachable state is available for Buy operation + OnrampOperation.SELL -> isNotUnreachable + OnrampOperation.SWAP -> { + isNotUnreachable && isNotTrustlineRequired + } } - status to (isAvailable && isNotMissedDerivation && isNotLoading && isNotUnreachable) + status to (isOperationAvailable && isNotMissedDerivation && isNotLoading && isAvailable) } } .awaitAll() diff --git a/features/swap/data/build.gradle.kts b/features/swap/data/build.gradle.kts index 9c2a64eebe..5b0d422759 100644 --- a/features/swap/data/build.gradle.kts +++ b/features/swap/data/build.gradle.kts @@ -41,6 +41,7 @@ dependencies { implementation(projects.domain.models) implementation(projects.domain.wallets) implementation(projects.domain.wallets.models) + implementation(projects.domain.transaction.models) /** Data */ implementation(projects.data.common) diff --git a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt index 69f6fe5d7e..a23bc00f4b 100644 --- a/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt +++ b/features/swap/data/src/main/java/com/tangem/feature/swap/DefaultSwapRepository.kt @@ -26,10 +26,11 @@ import com.tangem.datasource.crypto.DataSignatureVerifier import com.tangem.datasource.exchangeservice.swap.ExpressUtils import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.domain.models.currency.CryptoCurrency -import com.tangem.domain.walletmanager.WalletManagersFacade -import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.domain.transaction.models.AssetRequirementsCondition +import com.tangem.domain.walletmanager.WalletManagersFacade +import com.tangem.domain.wallets.legacy.UserWalletsListManager import com.tangem.feature.swap.converters.* import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.ExpressDataError @@ -134,7 +135,12 @@ internal class DefaultSwapRepository( contractAddress = initialCurrency.contractAddress, network = initialCurrency.network, ) - val currenciesList = currencyList.map { leastTokenInfoConverter.convert(it) } + val currenciesList = currencyList + .filter { + val requirements = walletManagersFacade.getAssetRequirements(userWallet.walletId, it) + requirements !is AssetRequirementsCondition.RequiredTrustline + } + .map { leastTokenInfoConverter.convert(it) } val pairsDeferred = async { getPairsInternal( 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 f0fbc9fbcc..712d322bd4 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 @@ -20,6 +20,8 @@ import com.tangem.domain.demo.IsDemoCardUseCase import com.tangem.domain.models.currency.CryptoCurrency import com.tangem.domain.models.network.Network import com.tangem.domain.models.quote.QuoteStatus +import com.tangem.domain.models.wallet.UserWallet +import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.quotes.QuotesRepository import com.tangem.domain.quotes.multi.MultiQuoteStatusFetcher import com.tangem.domain.tokens.* @@ -29,10 +31,9 @@ import com.tangem.domain.tokens.model.warnings.CryptoCurrencyCheck import com.tangem.domain.tokens.repository.CurrenciesRepository import com.tangem.domain.tokens.repository.CurrencyChecksRepository import com.tangem.domain.transaction.error.GetFeeError +import com.tangem.domain.transaction.models.AssetRequirementsCondition import com.tangem.domain.transaction.usecase.* import com.tangem.domain.utils.convertToSdkAmount -import com.tangem.domain.models.wallet.UserWallet -import com.tangem.domain.models.wallet.UserWalletId import com.tangem.domain.wallets.usecase.GetUserWalletUseCase import com.tangem.feature.swap.domain.api.SwapRepository import com.tangem.feature.swap.domain.models.ExpressDataError @@ -79,6 +80,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( private val getEthSpecificFeeUseCase: GetEthSpecificFeeUseCase, private val getUserWalletUseCase: GetUserWalletUseCase, private val getCurrencyCheckUseCase: GetCurrencyCheckUseCase, + private val getAssetRequirementsUseCase: GetAssetRequirementsUseCase, private val amountFormatter: AmountFormatter, @Assisted private val userWalletId: UserWalletId, ) : SwapInteractor { @@ -139,7 +141,7 @@ internal class SwapInteractorImpl @AssistedInject constructor( ) } - private fun getToCurrenciesGroup( + private suspend fun getToCurrenciesGroup( currency: CryptoCurrency, leastPairs: List, cryptoCurrenciesList: List, @@ -171,15 +173,18 @@ internal class SwapInteractorImpl @AssistedInject constructor( ) } - private fun findProvidersForPair( + private suspend fun findProvidersForPair( cryptoCurrencyStatuses: CryptoCurrencyStatus, swapPairsLeastList: List, tokenInfoForAvailable: (SwapPairLeast) -> LeastTokenInfo, ): List? { + val requirements = getAssetRequirementsUseCase.invoke(userWalletId, cryptoCurrencyStatuses.currency).getOrNull() + return swapPairsLeastList.firstNotNullOfOrNull { val listTokenInfo = tokenInfoForAvailable(it) if (cryptoCurrencyStatuses.currency.network.backendId == listTokenInfo.network && - cryptoCurrencyStatuses.currency.getContractAddress() == listTokenInfo.contractAddress + cryptoCurrencyStatuses.currency.getContractAddress() == listTokenInfo.contractAddress && + requirements !is AssetRequirementsCondition.RequiredTrustline ) { it.providers } else { From af88b092a24fbab1b5daaf69724bbd3ae314fe07 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 4 Aug 2025 19:48:09 +0500 Subject: [PATCH 6/7] Updated on 2026-08-14 --- .../send/v2/api/entity/FeeSelectorUM.kt | 11 ++++-- ...eeSelectorCustomValueChangedTransformer.kt | 11 ++++++ .../FeeSelectorLoadedTransformer.kt | 1 + .../feeselector/ui/FeeSelectorBlockContent.kt | 2 ++ .../ui/FeeSelectorModalBottomSheet.kt | 5 ++- .../ethereum/EthereumEIPCustomFeeConverter.kt | 34 ++++++++++++++++--- ...firmationNotificationsTransformerV2Test.kt | 4 +++ .../TransformersComparisonTest.kt | 13 +++++++ .../success/ui/SendWithSwapSuccessContent.kt | 1 + 9 files changed, 73 insertions(+), 9 deletions(-) diff --git a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/entity/FeeSelectorUM.kt b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/entity/FeeSelectorUM.kt index bed3633556..6386d23721 100644 --- a/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/entity/FeeSelectorUM.kt +++ b/features/send-v2/api/src/main/java/com/tangem/features/send/v2/api/entity/FeeSelectorUM.kt @@ -13,11 +13,18 @@ import java.math.BigInteger @Immutable sealed class FeeSelectorUM { - data object Loading : FeeSelectorUM() + abstract val isPrimaryButtonEnabled: Boolean - data class Error(val error: GetFeeError) : FeeSelectorUM() + data object Loading : FeeSelectorUM() { + override val isPrimaryButtonEnabled = false + } + + data class Error(val error: GetFeeError) : FeeSelectorUM() { + override val isPrimaryButtonEnabled = false + } data class Content( + override val isPrimaryButtonEnabled: Boolean, val fees: TransactionFee, val feeItems: ImmutableList, val selectedFeeItem: FeeItem, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorCustomValueChangedTransformer.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorCustomValueChangedTransformer.kt index d1c3b9c9e0..54df9301fb 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorCustomValueChangedTransformer.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorCustomValueChangedTransformer.kt @@ -1,10 +1,12 @@ package com.tangem.features.send.v2.feeselector.model.transformers +import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus import com.tangem.features.send.v2.api.entity.FeeItem import com.tangem.features.send.v2.api.entity.FeeSelectorUM import com.tangem.features.send.v2.feeselector.model.FeeSelectorIntents +import com.tangem.utils.extensions.isZero import com.tangem.utils.transformer.Transformer import kotlinx.collections.immutable.toImmutableList @@ -30,7 +32,16 @@ internal class FeeSelectorCustomValueChangedTransformer( fee = customFeeConverter.convertBack(updatedCustomValues), customValues = updatedCustomValues, ) + + val customFeeValue = updatedCustomValues.firstOrNull() + val isNotEmptyCustom = if (customFeeValue != null) { + !customFeeValue.value.parseToBigDecimal(customFeeValue.decimals).isZero() + } else { + false + } + return state.copy( + isPrimaryButtonEnabled = isNotEmptyCustom, feeItems = state.feeItems.map { if (it is FeeItem.Custom) newCustomFee else it }.toImmutableList(), selectedFeeItem = newCustomFee, ) diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorLoadedTransformer.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorLoadedTransformer.kt index b2b45f8a90..e44f6cc4d0 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorLoadedTransformer.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/model/transformers/FeeSelectorLoadedTransformer.kt @@ -49,6 +49,7 @@ internal class FeeSelectorLoadedTransformer( val nonce = ((prevState as? FeeSelectorUM.Content)?.feeNonce as? FeeNonce.Nonce)?.nonce return FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, fees = fees, feeItems = feeItems, selectedFeeItem = selectedFee, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorBlockContent.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorBlockContent.kt index 6aee042366..b0f08978aa 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorBlockContent.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorBlockContent.kt @@ -203,6 +203,7 @@ private class FeeSelectorUMProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, feeItems = persistentListOf(lowFeeItem), selectedFeeItem = lowFeeItem, feeExtraInfo = FeeExtraInfo( @@ -218,6 +219,7 @@ private class FeeSelectorUMProvider : PreviewParameterProvider { fees = TransactionFee.Single(lowFeeItem.fee), ), FeeSelectorUM.Content( + isPrimaryButtonEnabled = false, feeItems = persistentListOf(maxFeeItem), selectedFeeItem = maxFeeItem, feeExtraInfo = FeeExtraInfo( diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorModalBottomSheet.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorModalBottomSheet.kt index 24445e46cf..f9f7905693 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorModalBottomSheet.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/feeselector/ui/FeeSelectorModalBottomSheet.kt @@ -87,6 +87,7 @@ internal fun FeeSelectorModalBottomSheet( modifier = Modifier .fillMaxWidth() .padding(16.dp), + enabled = state.isPrimaryButtonEnabled, text = stringResourceSafe(R.string.common_done), onClick = feeSelectorIntents::onDoneClick, ) @@ -484,6 +485,7 @@ private fun FeeSelectorBS_Preview( private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider( collection = listOf( FeeSelectorUM.Content( + isPrimaryButtonEnabled = false, feeItems = persistentListOf( FeeItem.Suggested( title = stringReference("Suggested by Tangem"), @@ -494,9 +496,6 @@ private class FeeSelectorUMContentProvider : CollectionPreviewParameterProvider< FeeItem.Fast(fee = Fee.Common(Amount(value = BigDecimal("0.03"), blockchain = Blockchain.Ethereum))), customFeeItem, ), - // selectedFeeItem = FeeItem.Market( - // amount = Amount(value = BigDecimal("0.02"), blockchain = Blockchain.Ethereum), - // ), selectedFeeItem = customFeeItem, feeExtraInfo = FeeExtraInfo( isFeeApproximate = true, diff --git a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt index 6a380e8e4c..929863fee3 100644 --- a/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt +++ b/features/send-v2/impl/src/main/java/com/tangem/features/send/v2/subcomponents/fee/model/converters/custom/ethereum/EthereumEIPCustomFeeConverter.kt @@ -11,6 +11,7 @@ import com.tangem.core.ui.utils.parseBigDecimal import com.tangem.core.ui.utils.parseToBigDecimal import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.model.CryptoCurrencyStatus +import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM import com.tangem.features.send.v2.impl.R import com.tangem.features.send.v2.subcomponents.fee.model.checkExceedBalance import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.ETHEREUM_GAS_UNIT @@ -18,7 +19,7 @@ import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.eth import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GAS_DECIMALS import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.ethereum.EthereumCustomFeeConverter.Companion.GIGA_DECIMALS import com.tangem.features.send.v2.subcomponents.fee.model.converters.custom.setEmpty -import com.tangem.features.send.v2.api.entity.CustomFeeFieldUM +import com.tangem.utils.extensions.isZero import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -91,7 +92,7 @@ internal class EthereumEIPCustomFeeConverter( val mutableCustomValues = customValues.toMutableList() return mutableCustomValues.apply { when (index) { - FEE_AMOUNT -> setOnAmountChange(value, index) + FEE_AMOUNT -> setOnAmountChange(feeValue, value, index) MAX_FEE -> setOnMaxFeeChange(value, index) GAS_LIMIT -> setOnGasLimitChange(value, index) else -> set(index, this[index].copy(value = value)) @@ -99,8 +100,12 @@ internal class EthereumEIPCustomFeeConverter( }.toImmutableList() } - private fun MutableList.setOnAmountChange(value: String, index: Int) { - val gasLimit = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) + private fun MutableList.setOnAmountChange( + feeValue: Fee.Ethereum.EIP1559, + value: String, + index: Int, + ) { + val gasLimitRaw = this[GAS_LIMIT].value.parseToBigDecimal(this[GAS_LIMIT].decimals) if (value.isBlank()) { setEmpty(FEE_AMOUNT) setEmpty(MAX_FEE) @@ -108,6 +113,27 @@ internal class EthereumEIPCustomFeeConverter( val newFeeAmountDecimal = value.parseToBigDecimal(this[FEE_AMOUNT].decimals) val newFeeAmount = newFeeAmountDecimal.movePointRight(GIGA_DECIMALS) // from ETH to GWEI + val gasLimit = if (gasLimitRaw.isZero()) { + val gasLimitTemp = feeValue.gasLimit.toBigDecimal() + set( + index = GAS_LIMIT, + element = this[GAS_LIMIT].copy(value = gasLimitTemp.parseBigDecimal(GIGA_DECIMALS)), + ) + gasLimitTemp + } else { + gasLimitRaw + } + + if (this[PRIORITY_FEE].value.isBlank()) { + set( + index = PRIORITY_FEE, + element = this[PRIORITY_FEE].copy( + value = feeValue.priorityFee.toBigDecimal().movePointLeft(GIGA_DECIMALS) + .parseBigDecimal(GIGA_DECIMALS), + ), + ) + } + val newMaxFee = newFeeAmount.divide(gasLimit, this[MAX_FEE].decimals, RoundingMode.HALF_UP) set( diff --git a/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformerV2Test.kt b/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformerV2Test.kt index 859eb4e9eb..873cfb305a 100644 --- a/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformerV2Test.kt +++ b/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/SendConfirmationNotificationsTransformerV2Test.kt @@ -242,6 +242,7 @@ class SendConfirmationNotificationsTransformerV2Test { ) val transactionFee = TransactionFee.Single(fee) return FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf(FeeItem.Market(fee)), selectedFeeItem = FeeItem.Market(fee), @@ -282,6 +283,7 @@ class SendConfirmationNotificationsTransformerV2Test { priority = priorityFee, ) return FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( @@ -364,6 +366,7 @@ class SendConfirmationNotificationsTransformerV2Test { priority = fee, ) return FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( @@ -434,6 +437,7 @@ class SendConfirmationNotificationsTransformerV2Test { priority = priorityFee, ) return FeeSelectorUM.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( diff --git a/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/TransformersComparisonTest.kt b/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/TransformersComparisonTest.kt index f197f57b08..79cba32b78 100644 --- a/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/TransformersComparisonTest.kt +++ b/features/send-v2/impl/src/test/java/com/tangem/features/send/v2/send/confirm/model/transformers/TransformersComparisonTest.kt @@ -72,6 +72,7 @@ class TransformersComparisonTest { val contentV1 = resultV1 as ConfirmUM.Content val contentV2 = resultV2 as ConfirmUM.Content + assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled) assertThat(contentV1.notifications.size).isEqualTo(contentV2.notifications.size) assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter) assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled) @@ -117,6 +118,8 @@ class TransformersComparisonTest { val contentV1 = resultV1 as ConfirmUM.Content val contentV2 = resultV2 as ConfirmUM.Content + assertThat(contentV1.isPrimaryButtonEnabled).isTrue() + assertThat(contentV2.isPrimaryButtonEnabled).isTrue() assertThat(contentV1.notifications).hasSize(1) assertThat(contentV2.notifications).hasSize(1) assertThat(contentV1.notifications.first()).isInstanceOf(NotificationUM.Warning.FeeTooLow::class.java) @@ -165,6 +168,8 @@ class TransformersComparisonTest { val contentV1 = resultV1 as ConfirmUM.Content val contentV2 = resultV2 as ConfirmUM.Content + assertThat(contentV1.isPrimaryButtonEnabled).isTrue() + assertThat(contentV2.isPrimaryButtonEnabled).isTrue() assertThat(contentV1.notifications).hasSize(1) assertThat(contentV2.notifications).hasSize(1) assertThat(contentV1.notifications.first()).isInstanceOf(NotificationUM.Warning.TooHigh::class.java) @@ -215,6 +220,8 @@ class TransformersComparisonTest { val contentV1 = resultV1 as ConfirmUM.Content val contentV2 = resultV2 as ConfirmUM.Content + assertThat(contentV1.isPrimaryButtonEnabled).isTrue() + assertThat(contentV2.isPrimaryButtonEnabled).isTrue() assertThat(contentV1.notifications).hasSize(2) assertThat(contentV2.notifications).hasSize(2) @@ -268,6 +275,7 @@ class TransformersComparisonTest { assertThat(contentV1.notifications).isEmpty() assertThat(contentV2.notifications).isEmpty() + assertThat(contentV1.isPrimaryButtonEnabled).isEqualTo(contentV2.isPrimaryButtonEnabled) assertThat(contentV1.sendingFooter).isEqualTo(contentV2.sendingFooter) } @@ -377,6 +385,7 @@ class TransformersComparisonTest { ) val transactionFee = TransactionFee.Single(fee) return FeeSelectorUMV2.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Market(fee), @@ -470,6 +479,7 @@ class TransformersComparisonTest { priority = fee, ) return FeeSelectorUMV2.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( @@ -605,6 +615,7 @@ class TransformersComparisonTest { priority = priorityFee, ) return FeeSelectorUMV2.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( @@ -740,6 +751,7 @@ class TransformersComparisonTest { priority = priorityFee, ) return FeeSelectorUMV2.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Custom( @@ -839,6 +851,7 @@ class TransformersComparisonTest { ) val transactionFee = TransactionFee.Single(fee) return FeeSelectorUMV2.Content( + isPrimaryButtonEnabled = true, fees = transactionFee, feeItems = persistentListOf( FeeItem.Market(fee), diff --git a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt index 4ea2e22fea..e730666446 100644 --- a/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt +++ b/features/swap-v2/impl/src/main/java/com/tangem/features/swap/v2/impl/sendviaswap/success/ui/SendWithSwapSuccessContent.kt @@ -379,6 +379,7 @@ private fun SendWithSwapSuccessContent_Preview() { ), feeFiatRateUM = null, feeNonce = FeeNonce.None, + isPrimaryButtonEnabled = false, ), confirmUM = ConfirmUM.Success( isPrimaryButtonEnabled = true, From 8ad45b2fe8e4e54088d835e84291f267c99d599a Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 6 Aug 2025 08:21:14 +0000 Subject: [PATCH 7/7] Updated on 2026-08-14 --- gradle/tangem_dependencies.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 7ab02a4628..78d485789e 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -5,9 +5,9 @@ # https://github.com/tangem/tangem-sdk-android/ # https://github.com/tangem/vico -tangemBlockchainSdk = "releases-5.27.0-1126" +tangemBlockchainSdk = "develop-1129" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.27.0-510" +tangemCardSdk = "develop-509" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^