From ab2f0f58bb1a670858159ca17c5beeeedbbc2ed2 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 23 Jun 2025 13:58:27 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../connections/utils/WcAlertsFactory.kt | 43 ++++++++++++++++--- .../model/WcSendTransactionModel.kt | 43 +++++++++++++++++-- .../transaction/routes/WcTransactionRoutes.kt | 3 +- .../blockaid/WcEstimatedWalletChangesItem.kt | 8 +++- 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcAlertsFactory.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcAlertsFactory.kt index 723b7046bf..75e7d6143e 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcAlertsFactory.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/connections/utils/WcAlertsFactory.kt @@ -10,11 +10,16 @@ import com.tangem.features.walletconnect.transaction.routes.WcTransactionRoutes internal object WcAlertsFactory { fun createCommonTransactionAppInfoAlertUM(alertType: WcTransactionRoutes.Alert.Type) = when (alertType) { - is WcTransactionRoutes.Alert.Type.Verified -> createVerifiedDomainAlert(alertType.appName) - is WcTransactionRoutes.Alert.Type.UnknownDomain -> createUnknownDomainAlert() - is WcTransactionRoutes.Alert.Type.UnsafeDomain -> createUnsafeDomainAlert() - is WcTransactionRoutes.Alert.Type.MaliciousDApp -> + is WcTransactionRoutes.Alert.Type.Verified -> + createVerifiedDomainAlert(alertType.appName) + is WcTransactionRoutes.Alert.Type.UnknownDomain -> + createUnknownDomainAlert() + is WcTransactionRoutes.Alert.Type.UnsafeDomain -> + createUnsafeDomainAlert() + is WcTransactionRoutes.Alert.Type.MaliciousInfo -> createMaliciousDAppAlert(alertType.description, alertType.onClick) + is WcTransactionRoutes.Alert.Type.UnknownError -> + createUnknownErrorAlert(alertType.errorMessage, alertType.onDismiss) } fun createUnknownDomainAlert(activeButtonOnClick: (() -> Unit)? = null): MessageBottomSheetUMV2 { @@ -69,8 +74,32 @@ internal object WcAlertsFactory { } } + private fun createUnknownErrorAlert(errorMessage: String?, onDismiss: () -> Unit): MessageBottomSheetUMV2 { + return messageBottomSheetUM { + infoBlock { + icon(R.drawable.img_attention_20) { + type = MessageBottomSheetUMV2.Icon.Type.Warning + backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.SameAsTint + } + title = resourceReference(R.string.wc_alert_unknown_error_title) + body = if (errorMessage.isNullOrEmpty()) { + resourceReference(R.string.wc_alert_unknown_error_description_no_error_code) + } else { + resourceReference( + R.string.wc_alert_unknown_error_description, + wrappedList(errorMessage), + ) + } + } + secondaryButton { + text = resourceReference(R.string.balance_hidden_got_it_button) + onClick { onDismiss() } + } + } + } + private fun createMaliciousDAppAlert( - description: String, + description: String?, activeButtonOnClick: (() -> Unit), ): MessageBottomSheetUMV2 { return messageBottomSheetUM { @@ -80,7 +109,9 @@ internal object WcAlertsFactory { backgroundType = MessageBottomSheetUMV2.Icon.BackgroundType.SameAsTint } title = resourceReference(R.string.security_alert_title) - body = TextReference.Str(description) + if (!description.isNullOrEmpty()) { + body = TextReference.Str(description) + } } primaryButton { text = resourceReference(R.string.common_cancel) 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 4d8311c79c..3e745c13f9 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 @@ -1,8 +1,11 @@ package com.tangem.features.walletconnect.transaction.model import androidx.compose.runtime.Stable +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.ValidationResult import com.tangem.blockchain.common.TransactionData import com.tangem.core.decompose.di.ModelScoped import com.tangem.core.decompose.model.Model @@ -48,6 +51,7 @@ internal class WcSendTransactionModel @Inject constructor( val stackNavigation = StackNavigation() private var wcApproval: WcApproval? = null + private var sign: () -> Unit = {} init { @Suppress("UnusedPrivateMember") @@ -66,7 +70,7 @@ internal class WcSendTransactionModel @Inject constructor( .distinctUntilChanged() .collectLatest { val (signState, securityCheck) = it - if (signingIsDone(signState)) return@collectLatest + if (signingIsDone(signState, useCase)) return@collectLatest val signModel: Any = signState.signModel val isMutableFee = useCase is WcMutableFee val dAppFee = if (isMutableFee) useCase.dAppFee() else null @@ -81,6 +85,7 @@ internal class WcSendTransactionModel @Inject constructor( var isApprovalMethod = isSecurityCheckContent && securityCheck.content is BlockAidTransactionCheck.Result.Approval wcApproval = useCase as? WcApproval + sign = { useCase.sign() } buildUiState(securityCheck, useCase, signState) } else -> unknownMethodRunnable() @@ -107,7 +112,7 @@ internal class WcSendTransactionModel @Inject constructor( actions = WcTransactionActionsUM( onShowVerifiedAlert = ::showVerifiedAlert, onDismiss = { cancel(useCase) }, - onSign = useCase::sign, + onSign = { onSign(securityCheck.getOrNull()) }, onCopy = { copyData(useCase.rawSdkRequest.request.params) }, ), ), @@ -127,6 +132,14 @@ internal class WcSendTransactionModel @Inject constructor( stackNavigation.pushNew(WcTransactionRoutes.TransactionRequestInfo) } + private fun onSign(securityCheck: BlockAidTransactionCheck.Result?) { + if (securityCheck?.result?.validation == ValidationResult.UNSAFE) { + showMaliciousAlert(securityCheck.result.description) + } else { + sign() + } + } + fun onClickDoneCustomAllowance(value: BigDecimal, isUnlimited: Boolean) { val maxValue = if (isUnlimited) Double.MAX_VALUE.toBigDecimal() else value wcApproval?.getAmount()?.let { currentAmount -> @@ -142,14 +155,36 @@ internal class WcSendTransactionModel @Inject constructor( stackNavigation.pushNew(WcTransactionRoutes.Alert(WcTransactionRoutes.Alert.Type.Verified(appName))) } - private fun signingIsDone(signState: WcSignState<*>): Boolean { + private fun showMaliciousAlert(description: String?) { + val type = WcTransactionRoutes.Alert.Type.MaliciousInfo(description = description, onClick = ::signFromAlert) + stackNavigation.pushNew(WcTransactionRoutes.Alert(type)) + } + + private fun signFromAlert() { + stackNavigation.pop() + sign() + } + + private fun signingIsDone(signState: WcSignState<*>, useCase: WcSignUseCase<*>): Boolean { (signState.domainStep as? WcSignStep.Result)?.result?.let { - router.pop() + handleSigningError(it, useCase) return true } return false } + private fun handleSigningError(result: Either, useCase: WcSignUseCase<*>) { + if (result.isLeft()) { + val error = WcTransactionRoutes.Alert.Type.UnknownError( + errorMessage = result.leftOrNull()?.message, + onDismiss = { cancel(useCase) }, + ) + stackNavigation.pushNew(WcTransactionRoutes.Alert(error)) + } else { + router.pop() + } + } + private fun cancel(useCase: WcSignUseCase<*>) { useCase.cancel() router.pop() diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/routes/WcTransactionRoutes.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/routes/WcTransactionRoutes.kt index b08fafc300..066a19eebc 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/routes/WcTransactionRoutes.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/routes/WcTransactionRoutes.kt @@ -24,7 +24,8 @@ internal sealed class WcTransactionRoutes : TangemBottomSheetConfigContent, Rout data class Verified(val appName: String) : Type() data object UnknownDomain : Type() data object UnsafeDomain : Type() - data class MaliciousDApp(val description: String, val onClick: () -> Unit) : Type() + data class MaliciousInfo(val description: String?, val onClick: () -> Unit) : Type() + data class UnknownError(val errorMessage: String?, val onDismiss: () -> Unit) : Type() } } } \ No newline at end of file diff --git a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesItem.kt b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesItem.kt index fb730d52bb..25e8b53eba 100644 --- a/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesItem.kt +++ b/features/walletconnect/impl/src/main/kotlin/com/tangem/features/walletconnect/transaction/ui/blockaid/WcEstimatedWalletChangesItem.kt @@ -4,6 +4,7 @@ import android.content.res.Configuration import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Icon @@ -68,9 +69,14 @@ internal fun WcEstimatedWalletChangesItem(item: WcEstimatedWalletChangesUM, modi } if (item.items.size > MAX_CHANGES_SIZE) { + val interactionSource = remember { MutableInteractionSource() } Row( modifier = Modifier - .clickable { isExpanded = !isExpanded } + .clickable( + interactionSource = interactionSource, + indication = null, + onClick = { isExpanded = !isExpanded }, + ) .padding(bottom = 12.dp, start = 12.dp), verticalAlignment = Alignment.CenterVertically, ) {