From aa52b659ce3bc86a169857681d6e5e9f43df4451 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 16 May 2024 21:31:23 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../walletconnect/WalletConnectSdkHelper.kt | 33 ++++++++++++++----- .../data/DefaultWalletConnectRepository.kt | 12 ++++--- .../domain/WalletConnectInteractor.kt | 18 +++++++--- .../domain/WalletConnectRepository.kt | 2 +- .../domain/WcSessionRequestConverter.kt | 18 ++++++---- .../domain/models/WalletConnectError.kt | 12 ++++--- .../walletconnect/WalletConnectMiddleware.kt | 13 ++++++++ 7 files changed, 79 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt index cd502dc24e..2dfd015a7e 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectSdkHelper.kt @@ -48,19 +48,30 @@ class WalletConnectSdkHelper { } @Suppress("MagicNumber") - suspend fun prepareTransactionData(data: EthTransactionData): WcTransactionData? { + suspend fun prepareTransactionData(data: EthTransactionData): WcTransactionData { val transaction = data.transaction - val blockchain = Blockchain.fromNetworkId(data.networkId) ?: return null - val walletManager = getWalletManager(blockchain, data.rawDerivationPath) ?: return null + val blockchain = requireNotNull(Blockchain.fromNetworkId(data.networkId)) { + "Blockchain not found" + } + val walletManager = requireNotNull(getWalletManager(blockchain, data.rawDerivationPath)) { + "WalletManager not found" + } walletManager.safeUpdate(isDemoCard()) val wallet = walletManager.wallet - val balance = wallet.amounts[AmountType.Coin]?.value ?: return null + val balance = requireNotNull(wallet.amounts[AmountType.Coin]?.value) { + "Coin balance not found" + } val decimals = wallet.blockchain.decimals() - val value = (transaction.value ?: "0").hexToBigDecimal() - .movePointLeft(decimals) ?: return null + val value = (transaction.value ?: "0") + .hexToBigDecimal() + .movePointLeft(decimals) + + requireNotNull(value) { + "Transaction amount is null" + } val gasLimit = getGasLimitFromTx(value, walletManager, transaction) @@ -69,20 +80,23 @@ class WalletConnectSdkHelper { is Result.Success -> result.data.toBigDecimal() is Result.Failure -> { (result.error as? Throwable)?.let { Timber.e(it, "getGasPrice failed") } - return null + + error("Unable to get gas price: ${result.error}") } - null -> return null + null -> error("Gas price is null") } val fee = (gasLimit * gasPrice).movePointLeft(decimals) val total = value + fee + val destinationAddress = requireNotNull(transaction.to) { "Destination address is null" } + val transactionData = TransactionData( amount = Amount(value, wallet.blockchain), // TODO refactoring fee = Fee.Common(Amount(fee, wallet.blockchain)), sourceAddress = transaction.from, - destinationAddress = transaction.to!!, + destinationAddress = destinationAddress, extras = EthereumTransactionExtras( data = transaction.data.removePrefix(HEX_PREFIX).hexToBytes(), gasLimit = gasLimit.toBigInteger(), @@ -102,6 +116,7 @@ class WalletConnectSdkHelper { id = data.id, type = data.type, ) + return WcTransactionData( type = data.type, transaction = transactionData, diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultWalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultWalletConnectRepository.kt index a4c78ad4b9..df6ad4d1af 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultWalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/DefaultWalletConnectRepository.kt @@ -374,6 +374,7 @@ internal class DefaultWalletConnectRepository( override fun rejectRequest(requestData: RequestData, error: WalletConnectError) { val session = currentSessions.find { it.topic == requestData.topic } + analyticsHandler.send( WalletConnect.RequestHandled( WalletConnect.RequestHandledParams( @@ -385,17 +386,18 @@ internal class DefaultWalletConnectRepository( ), ), ) - cancelRequest(requestData.topic, requestData.requestId) + + cancelRequest(requestData.topic, requestData.requestId, error.error) } - override fun cancelRequest(topic: String, id: Long) { + override fun cancelRequest(topic: String, id: Long, message: String) { Web3Wallet.respondSessionRequest( params = Wallet.Params.SessionRequestResponse( sessionTopic = topic, jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcError( id = id, code = 0, - message = "", + message = message, ), ), onSuccess = {}, @@ -406,8 +408,8 @@ internal class DefaultWalletConnectRepository( override fun reject() { Web3Wallet.rejectSession( params = Wallet.Params.SessionReject( - sessionProposal?.proposerPublicKey ?: "", - "", + proposerPublicKey = sessionProposal?.proposerPublicKey ?: "", + reason = "", ), onSuccess = { Timber.d("Rejected successfully: $it") diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt index e2e43d4975..187f705e63 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectInteractor.kt @@ -260,10 +260,18 @@ class WalletConnectInteractor( ) else -> { currentRequest = sessionRequest - val data = prepareRequestData(sessionRequest) - if (data != null) { - handler.onSessionRequest(data) + + val data = prepareRequestData(sessionRequest).getOrElse { e -> + val wrappedError = e as? WalletConnectError ?: WalletConnectError.UnknownError( + message = e.localizedMessage ?: "Unknown error", + ) + + walletConnectRepository.rejectRequest(requestData, wrappedError) + handler.onSessionRejected(wrappedError) + return } + + handler.onSessionRequest(data) } } } @@ -353,7 +361,9 @@ class WalletConnectInteractor( } } - private suspend fun prepareRequestData(sessionRequest: WalletConnectEvents.SessionRequest): WcPreparedRequest? { + private suspend fun prepareRequestData( + sessionRequest: WalletConnectEvents.SessionRequest, + ): Result { return sessionRequestConverter.prepareRequest(sessionRequest, userWalletId) } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectRepository.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectRepository.kt index 33d62fca22..23e7f0bc82 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WalletConnectRepository.kt @@ -27,5 +27,5 @@ interface WalletConnectRepository { fun rejectRequest(requestData: RequestData, error: WalletConnectError) - fun cancelRequest(topic: String, id: Long) + fun cancelRequest(topic: String, id: Long, message: String = "") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt index 12085cad12..e02d7cc679 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/WcSessionRequestConverter.kt @@ -4,6 +4,7 @@ import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper import com.tangem.tap.domain.walletconnect2.domain.mapper.mapToTransaction import com.tangem.tap.domain.walletconnect2.domain.models.BnbData import com.tangem.tap.domain.walletconnect2.domain.models.EthTransactionData +import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectError import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents import com.tangem.tap.features.details.redux.walletconnect.WcEthTransactionType @@ -17,15 +18,18 @@ internal class WcSessionRequestConverter( suspend fun prepareRequest( sessionRequest: WalletConnectEvents.SessionRequest, userWalletId: String, - ): WcPreparedRequest? { - val networkId = blockchainHelper.chainIdToNetworkIdOrNull(sessionRequest.chainId ?: "") ?: return null + ): Result = runCatching { + val networkId = requireNotNull(blockchainHelper.chainIdToNetworkIdOrNull(sessionRequest.chainId.orEmpty())) { + "Failed to get network ID for chain ID: ${sessionRequest.chainId}" + } val derivationPath = getDerivationPath( sessionsRepository = sessionsRepository, sessionRequest = sessionRequest, userWalletId = userWalletId, walletAddress = getWalletAddress(sessionRequest.request), ) - return when (val request = sessionRequest.request) { + + when (val request = sessionRequest.request) { is WcRequest.EthSendTransaction -> { val data = sdkHelper.prepareTransactionData( EthTransactionData( @@ -38,7 +42,8 @@ internal class WcSessionRequestConverter( metaName = sessionRequest.metaName, metaUrl = sessionRequest.metaUrl, ), - ) ?: return null + ) + WcPreparedRequest.EthTransaction( preparedRequestData = data, topic = sessionRequest.topic, @@ -58,7 +63,8 @@ internal class WcSessionRequestConverter( metaName = sessionRequest.metaName, metaUrl = sessionRequest.metaUrl, ), - ) ?: return null + ) + WcPreparedRequest.EthTransaction( preparedRequestData = data, topic = sessionRequest.topic, @@ -122,7 +128,7 @@ internal class WcSessionRequestConverter( derivationPath = derivationPath, ) } - else -> null + else -> throw WalletConnectError.UnsupportedMethod } } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt index 7d6504d923..40d82cdb51 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectError.kt @@ -20,8 +20,12 @@ sealed class WalletConnectError(val error: String) : Exception() { override val message: String?, ) : WalletConnectError("ExternalApprovalError") - object WrongUserWallet : WalletConnectError("WrongUserWallet") - object UnsupportedMethod : WalletConnectError("UnsupportedMethod") - object SigningError : WalletConnectError("SigningError") - object ValidationError : WalletConnectError("ValidationError") + data class UnknownError( + override val message: String, + ) : WalletConnectError(message) + + data object WrongUserWallet : WalletConnectError("WrongUserWallet") + data object UnsupportedMethod : WalletConnectError("UnsupportedMethod") + data object SigningError : WalletConnectError("SigningError") + data object ValidationError : WalletConnectError("ValidationError") } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt index b480ea809c..7b34183f53 100644 --- a/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt +++ b/app/src/main/java/com/tangem/tap/features/details/redux/walletconnect/WalletConnectMiddleware.kt @@ -9,6 +9,7 @@ import com.tangem.domain.qrscanning.models.SourceType import com.tangem.feature.qrscanning.QrScanningRouter import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.extensions.inject +import com.tangem.tap.common.redux.AppDialog import com.tangem.tap.common.redux.AppState import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.walletconnect2.domain.WalletConnectInteractor @@ -20,6 +21,7 @@ import com.tangem.tap.features.demo.DemoHelper import com.tangem.tap.proxy.redux.DaggerGraphState import com.tangem.tap.scope import com.tangem.tap.store +import com.tangem.wallet.R import kotlinx.coroutines.launch import org.rekotlin.Action import org.rekotlin.Middleware @@ -135,6 +137,17 @@ class WalletConnectMiddleware { ), ) } + is WalletConnectError.UnknownError -> { + store.dispatchOnMain( + GlobalAction.ShowDialog( + AppDialog.SimpleOkDialogRes( + headerId = R.string.wallet_connect_title, + messageId = R.string.wallet_connect_error_with_framework_message, + args = listOf(action.error.message), + ), + ), + ) + } is WalletConnectError.ExternalApprovalError -> { Timber.e(action.error, "ExternalApprovalError ${action.error.message}") // do not show dialog on this event