Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-04 12:34:05 +05:00
parent 0257c23494
commit a2f10e3503
6 changed files with 81 additions and 10 deletions

View file

@ -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"
}
}

View file

@ -41,12 +41,6 @@ internal class WcSignUseCaseDelegate<MiddleAction, SignModel>(
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) }

View file

@ -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,

View file

@ -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<WcTransactionRoutes>()
private val params = paramsContainer.require<WcTransactionModelParams>()
private var useCase by Delegates.notNull<WcAddNetworkUseCase>()
init {
modelScope.launch {
val useCase: WcAddNetworkUseCase = useCaseFactory.createUseCase<WcAddNetworkUseCase>(params.rawRequest)
useCase = useCaseFactory.createUseCase<WcAddNetworkUseCase>(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)
}

View file

@ -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<Throwable, BlockAidTransactionCheck.Result>,
) {
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,
),
)
}
}

View file

@ -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<WcTransactionRoutes>()
private var useCase by Delegates.notNull<WcMessageSignUseCase>()
init {
modelScope.launch {
val useCase = useCaseFactory.createUseCase<WcMessageSignUseCase>(params.rawRequest)
useCase = useCaseFactory.createUseCase<WcMessageSignUseCase>(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)
}