Updated on 2026-08-14

This commit is contained in:
Tangem 2026-02-04 12:09:36 +03:00
parent 184c94d9d3
commit 2938fda36e
12 changed files with 83 additions and 67 deletions

View file

@ -285,5 +285,6 @@ sealed class AnalyticsParam {
const val ENS_ADDRESS = "ENS Address"
const val ACCOUNT_DERIVATION_FROM = "Account Derivation (from)"
const val FEE_TOKEN = "Fee Token"
const val ACCOUNT_DERIVATION = "Account Derivation"
}
}

View file

@ -5,6 +5,7 @@ import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.data.walletconnect.sign.SignStateConverter.toPreSign
import com.tangem.data.walletconnect.sign.SignStateConverter.toResult
import com.tangem.data.walletconnect.sign.SignStateConverter.toSigning
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.model.WcRequestError
import com.tangem.domain.walletconnect.model.WcRequestError.Companion.code
@ -71,6 +72,7 @@ internal class WcSignUseCaseDelegate<MiddleAction, SignModel>(
network = context.network,
errorCode = error.code(),
errorMessage = errorMessage,
accountDerivation = context.session.account?.derivationIndex?.value,
)
analytics.send(event)
}

View file

@ -185,4 +185,10 @@ sealed interface Account {
error("Not yet implemented")
}
}
}
}
val Account.derivationIndex: DerivationIndex?
get() = when (this) {
is Account.CryptoPortfolio -> derivationIndex
is Account.Payment -> TODO("[REDACTED_JIRA]")
}

View file

@ -34,8 +34,17 @@ sealed class WcAnalyticEvents(
),
)
class PairButtonConnect : WcAnalyticEvents(
class PairButtonConnect(
dAppName: String,
accountDerivation: Int?,
) : WcAnalyticEvents(
event = "Button - Connect",
params = buildMap {
put(AnalyticsParam.DAPP_NAME, dAppName)
accountDerivation?.let {
put(AnalyticsParam.ACCOUNT_DERIVATION, it.toString())
}
},
)
class PairRequested(
@ -114,6 +123,7 @@ sealed class WcAnalyticEvents(
rawRequest: WcSdkSessionRequest,
network: Network,
emulationStatus: EmulationStatus?,
accountDerivation: Int?,
securityStatus: CheckDAppResult,
) : WcAnalyticEvents(
event = "Signature Request Received",
@ -124,6 +134,7 @@ sealed class WcAnalyticEvents(
AnalyticsParam.BLOCKCHAIN to network.name,
AnalyticsParam.EMULATION_STATUS to emulationStatus?.status,
AnalyticsParam.TYPE to securityStatus.toAnalyticVerificationStatus(),
AnalyticsParam.ACCOUNT_DERIVATION to accountDerivation?.toString(),
).mapNotNullValues { it.value },
) {
enum class EmulationStatus(val status: String) {
@ -137,15 +148,19 @@ sealed class WcAnalyticEvents(
rawRequest: WcSdkSessionRequest,
network: Network,
securityStatus: CheckDAppResult,
accountDerivation: Int?,
) : WcAnalyticEvents(
event = "Signature Request Handled",
params = mapOf(
AnalyticsParam.DAPP_NAME to rawRequest.dAppMetaData.name,
AnalyticsParam.DAPP_URL to rawRequest.dAppMetaData.url,
AnalyticsParam.METHOD_NAME to rawRequest.request.method,
AnalyticsParam.BLOCKCHAIN to network.name,
AnalyticsParam.TYPE to securityStatus.toAnalyticVerificationStatus(),
),
params = buildMap {
put(AnalyticsParam.DAPP_NAME, rawRequest.dAppMetaData.name)
put(AnalyticsParam.DAPP_URL, rawRequest.dAppMetaData.url)
put(AnalyticsParam.METHOD_NAME, rawRequest.request.method)
put(AnalyticsParam.BLOCKCHAIN, network.name)
put(AnalyticsParam.TYPE, securityStatus.toAnalyticVerificationStatus())
accountDerivation?.let {
put(AnalyticsParam.ACCOUNT_DERIVATION, it.toString())
}
},
), AppsFlyerIncludedEvent
class SignatureRequestFailed(
@ -153,16 +168,18 @@ sealed class WcAnalyticEvents(
network: Network,
errorCode: String,
errorMessage: String,
accountDerivation: Int?,
) : WcAnalyticEvents(
event = "Signature Request Failed",
params = mapOf(
AnalyticsParam.DAPP_NAME to rawRequest.dAppMetaData.name,
AnalyticsParam.DAPP_URL to rawRequest.dAppMetaData.url,
AnalyticsParam.METHOD_NAME to rawRequest.request.method,
AnalyticsParam.BLOCKCHAIN to network.name,
AnalyticsParam.ERROR_CODE to errorCode,
AnalyticsParam.ERROR_DESCRIPTION to errorMessage,
),
params = buildMap {
put(AnalyticsParam.DAPP_NAME, rawRequest.dAppMetaData.name)
put(AnalyticsParam.DAPP_URL, rawRequest.dAppMetaData.url)
put(AnalyticsParam.METHOD_NAME, rawRequest.request.method)
put(AnalyticsParam.BLOCKCHAIN, network.name)
put(AnalyticsParam.ERROR_CODE, errorCode)
put(AnalyticsParam.ERROR_DESCRIPTION, errorMessage)
accountDerivation?.let { put(AnalyticsParam.ACCOUNT_DERIVATION, it.toString()) }
},
)
class SignatureRequestReceivedFailed(
@ -279,23 +296,4 @@ fun CheckDAppResult.toAnalyticVerificationStatus(): String = when (this) {
SAFE -> DAppVerificationStatus.Verified
UNSAFE -> DAppVerificationStatus.Risky
FAILED_TO_VERIFY -> DAppVerificationStatus.Unknown
}.status
sealed class WcAnalyticAccountEvents(
event: String,
params: Map<String, String> = emptyMap(),
) : AnalyticsEvent(category = WC_CATEGORY_ACCOUNT_NAME, event = event, params = params) {
data class PairButtonConnect(
private val accountDerivation: Int,
) : WcAnalyticAccountEvents(
event = "Button - Connect",
params = mapOf(
"Account Derivation" to accountDerivation.toString(),
),
)
companion object {
const val WC_CATEGORY_ACCOUNT_NAME = "WalletConnect / Account"
}
}
}.status

View file

@ -8,7 +8,7 @@ internal sealed class CustomTokenAnalyticsEvent(
event: String,
params: Map<String, String> = mapOf(),
) : AnalyticsEvent(
category = "Manage Tokens / Custom",
category = "Manage Tokens / Custom Token",
event = event,
params = params,
) {

View file

@ -22,16 +22,18 @@ internal sealed class SendWithSwapAnalyticEvents(
val feeType: AnalyticsParam.FeeType,
val fromToken: CryptoCurrency,
val toToken: CryptoCurrency,
val fromDerivationIndex: Int?,
) : SendWithSwapAnalyticEvents(
event = "Send With Swap In Progress Screen Opened",
params = mapOf(
PROVIDER to providerName,
FEE_TYPE to if (feeType is AnalyticsParam.FeeType.Normal) "Market" else "Fast",
SEND_TOKEN to fromToken.symbol,
RECEIVE_TOKEN to toToken.symbol,
SEND_BLOCKCHAIN to fromToken.network.name,
RECEIVE_BLOCKCHAIN to toToken.network.name,
),
params = buildMap {
put(PROVIDER, providerName)
put(FEE_TYPE, if (feeType is AnalyticsParam.FeeType.Normal) "Market" else "Fast")
put(SEND_TOKEN, fromToken.symbol)
put(RECEIVE_TOKEN, toToken.symbol)
put(SEND_BLOCKCHAIN, fromToken.network.name)
put(RECEIVE_BLOCKCHAIN, toToken.network.name)
if (fromDerivationIndex != null) put("Account Derivation (from)", fromDerivationIndex.toString())
},
), AppsFlyerIncludedEvent
data class NoticeCanNotSwapToken(

View file

@ -448,6 +448,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
val toCurrency = confirmData.toCryptoCurrencyStatus?.currency ?: return
val feeSelectorUM = uiState.value.feeSelectorUM as? FeeSelectorUM.Content ?: return
val feeType = feeSelectorUM.toAnalyticType()
val fromDerivationIndex = confirmData.fromAccount?.derivationIndex?.value
analyticsEventHandler.send(
SendWithSwapAnalyticEvents.TransactionScreenOpened(
@ -455,6 +456,7 @@ internal class SendWithSwapConfirmModel @Inject constructor(
feeType = feeType,
fromToken = fromCurrency,
toToken = toCurrency,
fromDerivationIndex = fromDerivationIndex,
),
)
analyticsEventHandler.send(

View file

@ -98,16 +98,17 @@ sealed class SwapEvents(
val toDerivationIndex: Int?,
) : SwapEvents(
event = "Swap in Progress Screen Opened",
params = mapOf(
"Provider" to provider.name,
"Commission" to if (commission == FeeType.NORMAL) "Market" else "Fast",
"Send Token" to sendToken,
"Receive Token" to receiveToken,
"Send Blockchain" to sendBlockchain,
"Receive Blockchain" to receiveBlockchain,
"Account Derivation From or To (optional)" to "$fromDerivationIndex, $toDerivationIndex",
FEE_TOKEN to feeToken,
),
params = buildMap {
put("Provider", provider.name)
put("Commission", if (commission == FeeType.NORMAL) "Market" else "Fast")
put("Send Token", sendToken)
put("Receive Token", receiveToken)
put("Send Blockchain", sendBlockchain)
put("Receive Blockchain", receiveBlockchain)
if (fromDerivationIndex != null) put("Account Derivation (from)", fromDerivationIndex.toString())
if (toDerivationIndex != null) put("Account Derivation (to)", toDerivationIndex.toString())
put(FEE_TOKEN, feeToken)
},
), AppsFlyerIncludedEvent
class ProviderClicked : SwapEvents("Provider Clicked")

View file

@ -27,12 +27,12 @@ import com.tangem.domain.account.supplier.SingleAccountListSupplier
import com.tangem.domain.account.usecase.IsAccountsModeEnabledUseCase
import com.tangem.domain.models.account.Account
import com.tangem.domain.models.account.AccountStatus
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
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.WcAnalyticAccountEvents
import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.model.WcPairError
import com.tangem.domain.walletconnect.model.WcPairError.Unknown
@ -324,15 +324,12 @@ internal class WcPairModel @Inject constructor(
val account = selectedPortfolio?.second?.account
modelScope.launch {
if (selectorController.isAccountModeSync() && account != null) {
val derivationIndex = when (account) {
is Account.CryptoPortfolio -> account.derivationIndex.value
is Account.Payment -> TODO("[REDACTED_JIRA]")
}
analytics.send(WcAnalyticAccountEvents.PairButtonConnect(derivationIndex))
} else {
analytics.send(WcAnalyticEvents.PairButtonConnect())
}
analytics.send(
WcAnalyticEvents.PairButtonConnect(
dAppName = sessionProposal.dAppMetaData.name,
accountDerivation = account?.derivationIndex?.value,
),
)
}
wcPairUseCase.approve(
WcSessionApprove(

View file

@ -11,6 +11,7 @@ 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.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.usecase.method.WcAddNetworkUseCase
@ -131,13 +132,13 @@ internal class WcAddNetworkModel @Inject constructor(
private fun sendSignatureReceivedAnalytics(useCase: WcAddNetworkUseCase) {
if (signatureReceivedAnalyticsSendState.value) return
analytics.send(
WcAnalyticEvents.SignatureRequestReceived(
rawRequest = useCase.rawSdkRequest,
network = useCase.network,
emulationStatus = null,
securityStatus = CheckDAppResult.FAILED_TO_VERIFY,
accountDerivation = useCase.session.account?.derivationIndex?.value,
),
)

View file

@ -23,6 +23,7 @@ import com.tangem.core.ui.components.bottomsheets.message.MessageBottomSheetUMV2
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.core.lce.Lce
import com.tangem.domain.models.account.derivationIndex
import com.tangem.domain.models.currency.CryptoCurrencyStatus
import com.tangem.domain.models.network.Network
import com.tangem.domain.models.wallet.UserWallet
@ -426,6 +427,7 @@ internal class WcSendTransactionModel @Inject constructor(
rawRequest = useCase.rawSdkRequest,
network = useCase.network,
securityStatus = securityStatusState.value.toCheckDAppResult(),
accountDerivation = useCase.session.account?.derivationIndex?.value,
)
analytics.send(event)
showSuccessSignMessage()
@ -465,6 +467,7 @@ internal class WcSendTransactionModel @Inject constructor(
network = useCase.network,
emulationStatus = emulationStatus,
securityStatus = securityCheck.toCheckDAppResult(),
accountDerivation = useCase.session.account?.derivationIndex?.value,
),
)

View file

@ -12,6 +12,7 @@ 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.models.account.derivationIndex
import com.tangem.domain.walletconnect.WcAnalyticEvents
import com.tangem.domain.walletconnect.WcRequestUseCaseFactory
import com.tangem.domain.walletconnect.model.WcEthMethod
@ -143,6 +144,7 @@ internal class WcSignTransactionModel @Inject constructor(
rawRequest = useCase.rawSdkRequest,
network = useCase.network,
securityStatus = CheckDAppResult.FAILED_TO_VERIFY,
accountDerivation = useCase.session.account?.derivationIndex?.value,
)
analytics.send(event)
showSuccessSignMessage()
@ -171,6 +173,7 @@ internal class WcSignTransactionModel @Inject constructor(
network = useCase.network,
emulationStatus = null,
securityStatus = CheckDAppResult.FAILED_TO_VERIFY,
accountDerivation = useCase.session.account?.derivationIndex?.value,
),
)