diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt index 28744c2332..e5e4c697a6 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/AnalyticsParam.kt @@ -157,6 +157,9 @@ sealed class AnalyticsParam { const val ERROR_KEY = "Error Key" const val CREATION_TYPE = "Creation type" const val DAPP_NAME = "DApp Name" + const val DAPP_URL = "DApp Url" + const val METHOD_NAME = "Method Name" + const val VALIDATION = "Validation" const val BLOCKCHAIN_EXCEPTION_HOST = "exception_host" const val BLOCKCHAIN_SELECTED_HOST = "selected_host" } diff --git a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt index 49c49b912a..13c04ec76f 100644 --- a/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt +++ b/app/src/main/java/com/tangem/tap/common/analytics/events/WalletConnect.kt @@ -1,6 +1,7 @@ package com.tangem.tap.common.analytics.events import com.tangem.core.analytics.models.AnalyticsEvent +import com.tangem.tap.common.extensions.filterNotNull /** [REDACTED_AUTHOR] @@ -12,16 +13,51 @@ sealed class WalletConnect( ) : AnalyticsEvent("Wallet Connect", event, params, error) { class ScreenOpened : WalletConnect(event = "WC Screen Opened") - class NewSessionEstablished(dAppName: String) : WalletConnect( + class NewSessionEstablished(dAppName: String, dAppUrl: String) : WalletConnect( event = "New Session Established", params = mapOf( AnalyticsParam.DAPP_NAME to dAppName, + AnalyticsParam.DAPP_URL to dAppUrl, ), ) - class SessionDisconnected : WalletConnect("Session Disconnected") - class RequestSigned : WalletConnect("Request Signed") + class SessionDisconnected(dAppName: String, dAppUrl: String) : WalletConnect( + event = "Session Disconnected", + params = mapOf( + AnalyticsParam.DAPP_NAME to dAppName, + AnalyticsParam.DAPP_URL to dAppUrl, + ), + ) - class SignError(error: Throwable) : WalletConnect("Sign", error = error) - class TransactionError(error: Throwable) : WalletConnect("Transaction", error = error) + class RequestHandled( + params: RequestHandledParams, + ) : WalletConnect( + event = "Request Handled", + params = params.toParamsMap(), + ) + + data class RequestHandledParams( + val dAppName: String, + val dAppUrl: String, + val methodName: String, + val blockchain: String, + val errorCode: String? = null, + ) { + fun toParamsMap(): Map { + val validation = if (errorCode == null) Validation.SUCCESS.param else Validation.FAIL.param + return mapOf( + AnalyticsParam.DAPP_NAME to dAppName, + AnalyticsParam.DAPP_URL to dAppUrl, + AnalyticsParam.METHOD_NAME to methodName, + AnalyticsParam.BLOCKCHAIN to blockchain, + AnalyticsParam.VALIDATION to validation, + if (errorCode != null) AnalyticsParam.ERROR_CODE to errorCode else null to null, + ).filterNotNull() + } + } + + enum class Validation(val param: String) { + SUCCESS("Success"), + FAIL("Fail"), + } } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt index a86a86719a..a4bda602c0 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect/WalletConnectManager.kt @@ -3,11 +3,9 @@ package com.tangem.tap.domain.walletconnect import com.tangem.blockchain.common.Blockchain import com.tangem.common.card.EllipticCurve import com.tangem.common.extensions.guard -import com.tangem.core.analytics.Analytics import com.tangem.datasource.api.common.createNetworkLoggingInterceptor import com.tangem.domain.common.extensions.toNetworkId import com.tangem.domain.models.scan.ScanResponse -import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.extensions.dispatchOnMain import com.tangem.tap.common.redux.global.GlobalAction import com.tangem.tap.domain.TapError @@ -227,7 +225,6 @@ class WalletConnectManager { } private fun onSessionClosed(session: WCSession) { - Analytics.send(WalletConnect.SessionDisconnected()) sessions.remove(session.topic) walletConnectRepository.removeSession(session) store.dispatchOnMain(WalletConnectAction.RemoveSession(session)) @@ -395,7 +392,6 @@ class WalletConnectManager { ), ) } - Analytics.send(WalletConnect.NewSessionEstablished("")) } } } 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 03f8cf7d40..f84ad537dd 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 @@ -12,7 +12,6 @@ import com.tangem.blockchain.extensions.SimpleResult import com.tangem.blockchain.extensions.hexToBigDecimal import com.tangem.blockchain.extensions.isAscii import com.tangem.common.CompletionResult -import com.tangem.common.core.TangemSdkError import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toDecompressedPublicKey import com.tangem.common.extensions.toHexString @@ -23,7 +22,6 @@ import com.tangem.operations.sign.SignHashCommand import com.tangem.tap.common.analytics.events.AnalyticsParam import com.tangem.tap.common.analytics.events.Basic import com.tangem.tap.common.analytics.events.Basic.TransactionSent.MemoType -import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.extensions.safeUpdate import com.tangem.tap.common.extensions.toFormattedString import com.tangem.tap.domain.walletconnect.BnbHelper.toWCBinanceTradeOrder @@ -175,7 +173,6 @@ class WalletConnectSdkHelper { HEX_PREFIX + data.walletManager.wallet.recentTransactions.last().hash } is SimpleResult.Failure -> { - (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) } Timber.e(result.error as BlockchainSdkError) null } @@ -205,7 +202,6 @@ class WalletConnectSdkHelper { ).toHexString() } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) } Timber.e(result.error.customMessage) null } @@ -244,7 +240,6 @@ class WalletConnectSdkHelper { ) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.TransactionError(it)) } Timber.e(result.error.customMessage) null } @@ -338,7 +333,6 @@ class WalletConnectSdkHelper { ) } is CompletionResult.Failure -> { - (result.error as? TangemSdkError)?.let { Analytics.send(WalletConnect.SignError(it)) } Timber.e(result.error.customMessage) null } diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt index 9890f9863f..3304faa535 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/data/WalletConnectRepositoryImpl.kt @@ -2,9 +2,10 @@ package com.tangem.tap.domain.walletconnect2.data import android.app.Application import arrow.core.flatten -import com.tangem.core.analytics.Analytics +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.domain.walletconnect2.domain.WalletConnectRepository +import com.tangem.tap.domain.walletconnect2.domain.WcJrpcMethods import com.tangem.tap.domain.walletconnect2.domain.WcJrpcRequestsDeserializer import com.tangem.tap.domain.walletconnect2.domain.WcRequest import com.tangem.tap.domain.walletconnect2.domain.models.* @@ -25,6 +26,7 @@ import javax.inject.Inject class WalletConnectRepositoryImpl @Inject constructor( private val application: Application, private val wcRequestDeserializer: WcJrpcRequestsDeserializer, + private val analyticsHandler: AnalyticsEventHandler, ) : WalletConnectRepository { private var sessionProposal: Wallet.Model.SessionProposal? = null @@ -37,6 +39,8 @@ class WalletConnectRepositoryImpl @Inject constructor( private val _activeSessions: MutableSharedFlow> = MutableSharedFlow() override val activeSessions: Flow> = _activeSessions + private var currentSessions: List = emptyList() + /** * @param projectId Project ID at https://cloud.walletconnect.com/ */ @@ -127,8 +131,12 @@ class WalletConnectRepositoryImpl @Inject constructor( // we can send approval automatically, because in WC 2.0 the list of chains is approved when // initial connection is established sendRequest( - topic = sessionRequest.topic, - id = sessionRequest.request.id, + RequestData( + topic = sessionRequest.topic, + requestId = sessionRequest.request.id, + blockchain = sessionRequest.chainId.toString(), + method = WcJrpcMethods.WALLET_ADD_ETHEREUM_CHAIN.code, + ), result = "", ) } @@ -142,6 +150,7 @@ class WalletConnectRepositoryImpl @Inject constructor( id = sessionRequest.request.id, metaUrl = sessionRequest.peerMetaData?.url ?: "", metaName = sessionRequest.peerMetaData?.name ?: "", + method = sessionRequest.request.method, ), ) } @@ -263,7 +272,12 @@ class WalletConnectRepositoryImpl @Inject constructor( params = sessionApproval, onSuccess = { Timber.d("Approved successfully: $it") - Analytics.send(WalletConnect.NewSessionEstablished(sessionProposal.name)) + analyticsHandler.send( + WalletConnect.NewSessionEstablished( + dAppName = sessionProposal.name, + dAppUrl = sessionProposal.url, + ), + ) }, onError = { Timber.d("Error while approving: $it") @@ -278,23 +292,56 @@ class WalletConnectRepositoryImpl @Inject constructor( ) } - override fun sendRequest(topic: String, id: Long, result: String) { + override fun sendRequest(requestData: RequestData, result: String) { + val session = currentSessions.find { it.topic == requestData.topic } + analyticsHandler.send( + WalletConnect.RequestHandled( + WalletConnect.RequestHandledParams( + dAppName = session?.name ?: "", + dAppUrl = session?.url ?: "", + methodName = requestData.method, + blockchain = requestData.blockchain, + ), + ), + ) Web3Wallet.respondSessionRequest( params = Wallet.Params.SessionRequestResponse( - sessionTopic = topic, + sessionTopic = requestData.topic, jsonRpcResponse = Wallet.Model.JsonRpcResponse.JsonRpcResult( - id = id, + id = requestData.requestId, result = result, ), ), onSuccess = {}, onError = { - Analytics.send(WalletConnect.TransactionError(it.throwable)) + WalletConnect.RequestHandledParams( + dAppName = session?.name ?: "", + dAppUrl = session?.url ?: "", + methodName = requestData.method, + blockchain = requestData.blockchain, + errorCode = WalletConnectError.ValidationError.toString(), + ) }, ) } - override fun rejectRequest(topic: String, id: Long) { + override fun rejectRequest(requestData: RequestData, error: WalletConnectError) { + val session = currentSessions.find { it.topic == requestData.topic } + analyticsHandler.send( + WalletConnect.RequestHandled( + WalletConnect.RequestHandledParams( + dAppName = session?.name ?: "", + dAppUrl = session?.url ?: "", + methodName = requestData.method, + blockchain = requestData.blockchain, + errorCode = error.toString(), + ), + ), + ) + cancelRequest(requestData.topic, requestData.requestId) + } + + override fun cancelRequest(topic: String, id: Long) { Web3Wallet.respondSessionRequest( params = Wallet.Params.SessionRequestResponse( sessionTopic = topic, @@ -325,10 +372,16 @@ class WalletConnectRepositoryImpl @Inject constructor( } override fun disconnect(topic: String) { + val session = currentSessions.find { it.topic == topic } Web3Wallet.disconnectSession( params = Wallet.Params.SessionDisconnect(topic), onSuccess = { - Analytics.send(WalletConnect.SessionDisconnected()) + analyticsHandler.send( + WalletConnect.SessionDisconnected( + dAppName = session?.name ?: "", + dAppUrl = session?.url ?: "", + ), + ) updateSessions() Timber.d("Disconnected successfully: $it") }, @@ -364,6 +417,7 @@ class WalletConnectRepositoryImpl @Inject constructor( ) } Timber.d("Available sessions: $availableSessions") + currentSessions = availableSessions _activeSessions.emit(availableSessions) } } 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 e37d7c2949..9f5ce79361 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 @@ -1,7 +1,5 @@ package com.tangem.tap.domain.walletconnect2.domain -import com.tangem.core.analytics.Analytics -import com.tangem.tap.common.analytics.events.WalletConnect import com.tangem.tap.common.extensions.filterNotNull import com.tangem.tap.domain.walletconnect.WalletConnectSdkHelper import com.tangem.tap.domain.walletconnect2.domain.models.* @@ -148,8 +146,8 @@ class WalletConnectInteractor( walletConnectRepository.disconnect(topic) } - fun rejectRequest(topic: String, id: Long) { - walletConnectRepository.rejectRequest(topic, id) + fun cancelRequest(topic: String, id: Long) { + walletConnectRepository.cancelRequest(topic, id) } private suspend fun handleRequest(sessionRequest: WalletConnectEvents.SessionRequest) { @@ -164,16 +162,23 @@ class WalletConnectInteractor( null } } + val networkId = sessionRequest.chainId?.let { blockchainHelper.chainIdToNetworkIdOrNull(it) } ?: "" + val requestData = RequestData( + topic = sessionRequest.topic, + requestId = sessionRequest.id, + blockchain = networkId, + method = sessionRequest.method, + ) + if (error != null) { - walletConnectRepository.rejectRequest(sessionRequest.topic, sessionRequest.id) + walletConnectRepository.rejectRequest(requestData, error) return } when (sessionRequest.request) { is WcRequest.BnbCancel -> Unit is WcRequest.BnbTxConfirm -> walletConnectRepository.sendRequest( - topic = sessionRequest.topic, - id = sessionRequest.id, + requestData = requestData, result = "", ) else -> { @@ -212,16 +217,18 @@ class WalletConnectInteractor( Timber.d("Signed hash: $signedHash") + val requestData = RequestData( + topic = request.topic, + requestId = request.requestId, + blockchain = networkId, + method = currentRequest.method, + ) + if (signedHash == null) { - walletConnectRepository.rejectRequest( - topic = request.topic, - id = request.requestId, - ) + walletConnectRepository.rejectRequest(requestData, WalletConnectError.SigningError) } else { - Analytics.send(WalletConnect.RequestSigned()) walletConnectRepository.sendRequest( - topic = request.topic, - id = request.requestId, + requestData = requestData, result = signedHash, ) } 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 4069a56fa8..93e772b0d2 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 @@ -1,9 +1,6 @@ package com.tangem.tap.domain.walletconnect2.domain -import com.tangem.tap.domain.walletconnect2.domain.models.Account -import com.tangem.tap.domain.walletconnect2.domain.models.NetworkNamespace -import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectEvents -import com.tangem.tap.domain.walletconnect2.domain.models.WalletConnectSession +import com.tangem.tap.domain.walletconnect2.domain.models.* import kotlinx.coroutines.flow.Flow interface WalletConnectRepository { @@ -24,7 +21,9 @@ interface WalletConnectRepository { fun reject() - fun sendRequest(topic: String, id: Long, result: String) + fun sendRequest(requestData: RequestData, result: String) - fun rejectRequest(topic: String, id: Long) + fun rejectRequest(requestData: RequestData, error: WalletConnectError) + + fun cancelRequest(topic: String, id: Long) } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/RequestData.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/RequestData.kt new file mode 100644 index 0000000000..38cd19ca97 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/RequestData.kt @@ -0,0 +1,8 @@ +package com.tangem.tap.domain.walletconnect2.domain.models + +data class RequestData( + val topic: String, + val requestId: Long, + val method: String, + val blockchain: String, +) \ No newline at end of file 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 35da4b88f8..ca01b701a7 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 @@ -7,4 +7,6 @@ sealed class WalletConnectError : Exception() { data class ExternalApprovalError(override val message: String?) : WalletConnectError() object WrongUserWallet : WalletConnectError() object UnsupportedMethod : WalletConnectError() + object SigningError : WalletConnectError() + object ValidationError : WalletConnectError() } \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectEvents.kt b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectEvents.kt index e481daa22d..d47c296a42 100644 --- a/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectEvents.kt +++ b/app/src/main/java/com/tangem/tap/domain/walletconnect2/domain/models/WalletConnectEvents.kt @@ -24,5 +24,6 @@ sealed interface WalletConnectEvents { val id: Long, val metaName: String, val metaUrl: String, + val method: String, ) : WalletConnectEvents } \ 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 b3b5057a76..c2276c9065 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 @@ -182,7 +182,7 @@ class WalletConnectMiddleware { } is WalletConnectAction.RejectRequest -> { walletConnectManager.rejectRequest(action.topic, action.id) - walletConnectInteractor.rejectRequest(action.topic, action.id) + walletConnectInteractor.cancelRequest(action.topic, action.id) } is WalletConnectAction.SendTransaction -> { walletConnectManager.completeTransaction(action.topic)