From bd2844b749357167c5b1e6f947dbca2b841bcf59 Mon Sep 17 00:00:00 2001 From: katspaugh Date: Thu, 9 Nov 2023 17:32:58 +0100 Subject: [PATCH] Feat: track tx creations and safe views --- .../tx-flow/flows/AddOwner/ReviewOwner.tsx | 2 + .../ChangeThreshold/ReviewChangeThreshold.tsx | 2 + .../tx-flow/flows/ConfirmBatch/index.tsx | 11 +++++- .../NewSpendingLimit/ReviewSpendingLimit.tsx | 3 ++ .../flows/NftTransfer/ReviewNftBatch.tsx | 11 +++++- .../tx-flow/flows/RejectTx/RejectTx.tsx | 8 +++- .../flows/RemoveGuard/ReviewRemoveGuard.tsx | 10 +++-- .../flows/RemoveModule/ReviewRemoveModule.tsx | 10 +++-- .../flows/RemoveOwner/ReviewRemoveOwner.tsx | 2 + .../RemoveSpendingLimit.tsx | 10 +++-- .../flows/SafeAppsTx/ReviewSafeAppsTx.tsx | 7 +++- .../tx-flow/flows/SafeAppsTx/index.tsx | 10 ++++- .../ReviewSignMessageOnChain.tsx | 5 +++ .../flows/TokenTransfer/ReviewTokenTx.tsx | 18 +++++++-- .../flows/UpdateSafe/UpdateSafeReview.tsx | 8 +++- src/hooks/messages/useSafeMsgTracking.ts | 5 +++ src/services/analytics/events/overview.ts | 4 ++ src/services/analytics/events/transactions.ts | 38 +++++++++++++++++++ src/services/analytics/useGtm.ts | 6 +++ .../useSafeWalletProvider.tsx | 23 +++++------ src/services/tx/tx-sender/dispatch.ts | 3 +- 21 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 src/services/analytics/events/transactions.ts diff --git a/src/components/tx-flow/flows/AddOwner/ReviewOwner.tsx b/src/components/tx-flow/flows/AddOwner/ReviewOwner.tsx index d2c18301b3..ba1aa23212 100644 --- a/src/components/tx-flow/flows/AddOwner/ReviewOwner.tsx +++ b/src/components/tx-flow/flows/AddOwner/ReviewOwner.tsx @@ -14,6 +14,7 @@ import PlusIcon from '@/public/images/common/plus.svg' import MinusIcon from '@/public/images/common/minus.svg' import EthHashInfo from '@/components/common/EthHashInfo' import commonCss from '@/components/tx-flow/common/styles.module.css' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' export const ReviewOwner = ({ params }: { params: AddOwnerFlowProps | ReplaceOwnerFlowProps }) => { const dispatch = useAppDispatch() @@ -49,6 +50,7 @@ export const ReviewOwner = ({ params }: { params: AddOwnerFlowProps | ReplaceOwn trackEvent({ ...SETTINGS_EVENTS.SETUP.THRESHOLD, label: safe.threshold }) trackEvent({ ...SETTINGS_EVENTS.SETUP.OWNERS, label: safe.owners.length }) + trackEvent({ ...TX_EVENTS.CREATE, label: params.removedOwner ? TX_TYPES.owner_swap : TX_TYPES.owner_add }) } return ( diff --git a/src/components/tx-flow/flows/ChangeThreshold/ReviewChangeThreshold.tsx b/src/components/tx-flow/flows/ChangeThreshold/ReviewChangeThreshold.tsx index 6c1aa11d61..e9e7068a25 100644 --- a/src/components/tx-flow/flows/ChangeThreshold/ReviewChangeThreshold.tsx +++ b/src/components/tx-flow/flows/ChangeThreshold/ReviewChangeThreshold.tsx @@ -8,6 +8,7 @@ import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' import { SafeTxContext } from '@/components/tx-flow/SafeTxProvider' import { ChangeThresholdFlowFieldNames } from '@/components/tx-flow/flows/ChangeThreshold' import type { ChangeThresholdFlowProps } from '@/components/tx-flow/flows/ChangeThreshold' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' import commonCss from '@/components/tx-flow/common/styles.module.css' @@ -24,6 +25,7 @@ const ReviewChangeThreshold = ({ params }: { params: ChangeThresholdFlowProps }) const onChangeThreshold = () => { trackEvent({ ...SETTINGS_EVENTS.SETUP.OWNERS, label: safe.owners.length }) trackEvent({ ...SETTINGS_EVENTS.SETUP.THRESHOLD, label: newThreshold }) + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.owner_threshold_change }) } return ( diff --git a/src/components/tx-flow/flows/ConfirmBatch/index.tsx b/src/components/tx-flow/flows/ConfirmBatch/index.tsx index 27e53d211f..daf1ae5580 100644 --- a/src/components/tx-flow/flows/ConfirmBatch/index.tsx +++ b/src/components/tx-flow/flows/ConfirmBatch/index.tsx @@ -1,4 +1,4 @@ -import { type ReactElement, useContext, useEffect } from 'react' +import { type ReactElement, useContext, useEffect, useCallback } from 'react' import { type TransactionDetails } from '@safe-global/safe-gateway-typescript-sdk' import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' import { createMultiSendCallOnlyTx } from '@/services/tx/tx-sender' @@ -9,6 +9,8 @@ import TxLayout from '../../common/TxLayout' import BatchIcon from '@/public/images/common/batch.svg' import { useDraftBatch } from '@/hooks/useDraftBatch' import BatchTxList from '@/components/batch/BatchSidebar/BatchTxList' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' +import { trackEvent } from '@/services/analytics' type ConfirmBatchProps = { onSubmit: () => void @@ -32,8 +34,13 @@ const ConfirmBatch = ({ onSubmit }: ConfirmBatchProps): ReactElement => { createMultiSendCallOnlyTx(calls).then(setSafeTx).catch(setSafeTxError) }, [batchTxs, setSafeTx, setSafeTxError]) + const onTxSubmit = useCallback(() => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.batch }) + onSubmit() + }, [onSubmit]) + return ( - + ) diff --git a/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx b/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx index 5ab7d1a2a2..15cb0b27e0 100644 --- a/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx +++ b/src/components/tx-flow/flows/NewSpendingLimit/ReviewSpendingLimit.tsx @@ -17,6 +17,7 @@ import type { SpendingLimitState } from '@/store/spendingLimitsSlice' import type { NewSpendingLimitFlowProps } from '.' import EthHashInfo from '@/components/common/EthHashInfo' import { SafeTxContext } from '../../SafeTxProvider' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' export const ReviewSpendingLimit = ({ params }: { params: NewSpendingLimitFlowProps }) => { const [existingSpendingLimit, setExistingSpendingLimit] = useState() @@ -53,6 +54,8 @@ export const ReviewSpendingLimit = ({ params }: { params: NewSpendingLimitFlowPr ...SETTINGS_EVENTS.SPENDING_LIMIT.RESET_PERIOD, label: resetTime, }) + + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.spending_limit_add }) } const existingAmount = existingSpendingLimit diff --git a/src/components/tx-flow/flows/NftTransfer/ReviewNftBatch.tsx b/src/components/tx-flow/flows/NftTransfer/ReviewNftBatch.tsx index c9024eb02f..baa97927fb 100644 --- a/src/components/tx-flow/flows/NftTransfer/ReviewNftBatch.tsx +++ b/src/components/tx-flow/flows/NftTransfer/ReviewNftBatch.tsx @@ -1,4 +1,4 @@ -import { type ReactElement, useEffect, useContext } from 'react' +import { type ReactElement, useEffect, useContext, useCallback } from 'react' import { Grid, Typography } from '@mui/material' import SendToBlock from '@/components/tx-flow/flows/TokenTransfer/SendToBlock' import { createNftTransferParams } from '@/services/tx/tokenTransferParams' @@ -8,6 +8,8 @@ import { createMultiSendCallOnlyTx, createTx } from '@/services/tx/tx-sender' import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' import { SafeTxContext } from '../../SafeTxProvider' import { NftItems } from '@/components/tx-flow/flows/NftTransfer/SendNftBatch' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' +import { trackEvent } from '@/services/analytics' type ReviewNftBatchProps = { params: NftTransferParams @@ -38,8 +40,13 @@ const ReviewNftBatch = ({ params, onSubmit, txNonce }: ReviewNftBatchProps): Rea promise.then(setSafeTx).catch(setSafeTxError) }, [safeAddress, params, setSafeTx, setSafeTxError]) + const onTxSubmit = useCallback(() => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.transfer_nft }) + onSubmit() + }, [onSubmit]) + return ( - + diff --git a/src/components/tx-flow/flows/RejectTx/RejectTx.tsx b/src/components/tx-flow/flows/RejectTx/RejectTx.tsx index 91db5ae55f..24b2f66251 100644 --- a/src/components/tx-flow/flows/RejectTx/RejectTx.tsx +++ b/src/components/tx-flow/flows/RejectTx/RejectTx.tsx @@ -4,11 +4,17 @@ import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' import { createRejectTx } from '@/services/tx/tx-sender' import { useContext, useEffect } from 'react' import { SafeTxContext } from '../../SafeTxProvider' +import { trackEvent } from '@/services/analytics' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' type RejectTxProps = { txNonce: number } +const onSubmit = () => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.rejection }) +} + const RejectTx = ({ txNonce }: RejectTxProps): ReactElement => { const { setSafeTx, setSafeTxError, setNonce } = useContext(SafeTxContext) @@ -19,7 +25,7 @@ const RejectTx = ({ txNonce }: RejectTxProps): ReactElement => { }, [txNonce, setNonce, setSafeTx, setSafeTxError]) return ( - {}} isBatchable={false}> + To reject the transaction, a separate rejection transaction will be created to replace the original one. diff --git a/src/components/tx-flow/flows/RemoveGuard/ReviewRemoveGuard.tsx b/src/components/tx-flow/flows/RemoveGuard/ReviewRemoveGuard.tsx index e2155eb66e..6ac5920984 100644 --- a/src/components/tx-flow/flows/RemoveGuard/ReviewRemoveGuard.tsx +++ b/src/components/tx-flow/flows/RemoveGuard/ReviewRemoveGuard.tsx @@ -7,6 +7,12 @@ import { trackEvent, SETTINGS_EVENTS } from '@/services/analytics' import { createRemoveGuardTx } from '@/services/tx/tx-sender' import { type RemoveGuardFlowProps } from '.' import { SafeTxContext } from '@/components/tx-flow/SafeTxProvider' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' + +const onFormSubmit = () => { + trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_GUARD) + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.guard_remove }) +} export const ReviewRemoveGuard = ({ params }: { params: RemoveGuardFlowProps }) => { const { setSafeTx, safeTxError, setSafeTxError } = useContext(SafeTxContext) @@ -21,10 +27,6 @@ export const ReviewRemoveGuard = ({ params }: { params: RemoveGuardFlowProps }) } }, [safeTxError]) - const onFormSubmit = () => { - trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_GUARD) - } - return ( ({ color: palette.primary.light })}>Transaction guard diff --git a/src/components/tx-flow/flows/RemoveModule/ReviewRemoveModule.tsx b/src/components/tx-flow/flows/RemoveModule/ReviewRemoveModule.tsx index 01a11b223d..d6fb40da21 100644 --- a/src/components/tx-flow/flows/RemoveModule/ReviewRemoveModule.tsx +++ b/src/components/tx-flow/flows/RemoveModule/ReviewRemoveModule.tsx @@ -7,6 +7,12 @@ import { createRemoveModuleTx } from '@/services/tx/tx-sender' import { SafeTxContext } from '@/components/tx-flow/SafeTxProvider' import { type RemoveModuleFlowProps } from '.' import EthHashInfo from '@/components/common/EthHashInfo' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' + +const onFormSubmit = () => { + trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_MODULE) + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.module_remove }) +} export const ReviewRemoveModule = ({ params }: { params: RemoveModuleFlowProps }) => { const { setSafeTx, safeTxError, setSafeTxError } = useContext(SafeTxContext) @@ -21,10 +27,6 @@ export const ReviewRemoveModule = ({ params }: { params: RemoveModuleFlowProps } } }, [safeTxError]) - const onFormSubmit = () => { - trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_MODULE) - } - return ( diff --git a/src/components/tx-flow/flows/RemoveOwner/ReviewRemoveOwner.tsx b/src/components/tx-flow/flows/RemoveOwner/ReviewRemoveOwner.tsx index 676a2b1561..59c5498744 100644 --- a/src/components/tx-flow/flows/RemoveOwner/ReviewRemoveOwner.tsx +++ b/src/components/tx-flow/flows/RemoveOwner/ReviewRemoveOwner.tsx @@ -11,6 +11,7 @@ import MinusIcon from '@/public/images/common/minus.svg' import { SafeTxContext } from '../../SafeTxProvider' import type { RemoveOwnerFlowProps } from '.' import EthHashInfo from '@/components/common/EthHashInfo' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' import commonCss from '@/components/tx-flow/common/styles.module.css' @@ -29,6 +30,7 @@ export const ReviewRemoveOwner = ({ params }: { params: RemoveOwnerFlowProps }): const onFormSubmit = () => { trackEvent({ ...SETTINGS_EVENTS.SETUP.THRESHOLD, label: safe.threshold }) trackEvent({ ...SETTINGS_EVENTS.SETUP.OWNERS, label: safe.owners.length }) + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.owner_remove }) } return ( diff --git a/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx b/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx index df046f6cc6..087cf68705 100644 --- a/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx +++ b/src/components/tx-flow/flows/RemoveSpendingLimit/RemoveSpendingLimit.tsx @@ -13,6 +13,12 @@ import SendAmountBlock from '@/components/tx-flow/flows/TokenTransfer/SendAmount import { safeFormatUnits } from '@/utils/formatters' import SpendingLimitLabel from '@/components/common/SpendingLimitLabel' import { createTx } from '@/services/tx/tx-sender' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' + +const onFormSubmit = () => { + trackEvent(SETTINGS_EVENTS.SPENDING_LIMIT.LIMIT_REMOVED) + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.spending_limit_remove }) +} export const RemoveSpendingLimit = ({ params }: { params: SpendingLimitState }) => { const { setSafeTx, setSafeTxError } = useContext(SafeTxContext) @@ -42,10 +48,6 @@ export const RemoveSpendingLimit = ({ params }: { params: SpendingLimitState }) createTx(txParams).then(setSafeTx).catch(setSafeTxError) }, [chainId, params.beneficiary, params.token, setSafeTx, setSafeTxError]) - const onFormSubmit = () => { - trackEvent(SETTINGS_EVENTS.SPENDING_LIMIT.LIMIT_REMOVED) - } - return ( {token && ( diff --git a/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx b/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx index 4580b6021f..efc96834a3 100644 --- a/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx +++ b/src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx @@ -20,10 +20,12 @@ import { asError } from '@/services/exceptions/utils' type ReviewSafeAppsTxProps = { safeAppsTx: SafeAppsTxParams + onSubmit?: (txId: string, safeTxHash: string) => void } const ReviewSafeAppsTx = ({ safeAppsTx: { txs, requestId, params, appId, app }, + onSubmit, }: ReviewSafeAppsTxProps): ReactElement => { const { safe } = useSafeInfo() const onboard = useOnboard() @@ -54,11 +56,14 @@ const ReviewSafeAppsTx = ({ if (!safeTx || !onboard) return trackSafeAppTxCount(Number(appId)) + let safeTxHash = '' try { - await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId, txId) + safeTxHash = await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId, txId) } catch (error) { setSafeTxError(asError(error)) } + + onSubmit?.(txId, safeTxHash) } const origin = useMemo(() => getTxOrigin(app), [app]) diff --git a/src/components/tx-flow/flows/SafeAppsTx/index.tsx b/src/components/tx-flow/flows/SafeAppsTx/index.tsx index a5f6bdf329..297d13f569 100644 --- a/src/components/tx-flow/flows/SafeAppsTx/index.tsx +++ b/src/components/tx-flow/flows/SafeAppsTx/index.tsx @@ -12,14 +12,20 @@ export type SafeAppsTxParams = { params?: SendTransactionRequestParams } -const SafeAppsTxFlow = ({ data }: { data: SafeAppsTxParams }) => { +const SafeAppsTxFlow = ({ + data, + onSubmit, +}: { + data: SafeAppsTxParams + onSubmit?: (txId: string, safeTxHash: string) => void +}) => { return ( } step={0} > - + ) } diff --git a/src/components/tx-flow/flows/SignMessageOnChain/ReviewSignMessageOnChain.tsx b/src/components/tx-flow/flows/SignMessageOnChain/ReviewSignMessageOnChain.tsx index ab535b7ede..378b296979 100644 --- a/src/components/tx-flow/flows/SignMessageOnChain/ReviewSignMessageOnChain.tsx +++ b/src/components/tx-flow/flows/SignMessageOnChain/ReviewSignMessageOnChain.tsx @@ -25,6 +25,8 @@ import useHighlightHiddenTab from '@/hooks/useHighlightHiddenTab' import { type SafeAppData } from '@safe-global/safe-gateway-typescript-sdk' import { SafeTxContext } from '@/components/tx-flow/SafeTxProvider' import { asError } from '@/services/exceptions/utils' +import { trackEvent } from '@/services/analytics' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' export type SignMessageOnChainProps = { app?: SafeAppData @@ -98,6 +100,9 @@ const ReviewSignMessageOnChain = ({ message, method, requestId }: SignMessageOnC const handleSubmit = async () => { if (!safeTx || !onboard) return + + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.message }) + try { await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId) } catch (error) { diff --git a/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx b/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx index 98e2535f31..4b13a65cc3 100644 --- a/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx +++ b/src/components/tx-flow/flows/TokenTransfer/ReviewTokenTx.tsx @@ -1,7 +1,9 @@ -import { type ReactElement } from 'react' +import { useCallback, type ReactElement } from 'react' import { type TokenTransferParams, TokenTransferType } from '@/components/tx-flow/flows/TokenTransfer/index' import ReviewTokenTransfer from '@/components/tx-flow/flows/TokenTransfer/ReviewTokenTransfer' import ReviewSpendingLimitTx from '@/components/tx-flow/flows/TokenTransfer/ReviewSpendingLimitTx' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' +import { trackEvent } from '@/services/analytics' // TODO: Split this into separate flows const ReviewTokenTx = ({ @@ -15,10 +17,20 @@ const ReviewTokenTx = ({ }): ReactElement => { const isSpendingLimitTx = params.type === TokenTransferType.spendingLimit + const onTxSubmit = useCallback(() => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.transfer_token }) + onSubmit() + }, [onSubmit]) + + const onSpendingLimitTxSubmit = useCallback(() => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.spending_limit_transfer }) + onSubmit() + }, [onSubmit]) + return isSpendingLimitTx ? ( - + ) : ( - + ) } diff --git a/src/components/tx-flow/flows/UpdateSafe/UpdateSafeReview.tsx b/src/components/tx-flow/flows/UpdateSafe/UpdateSafeReview.tsx index 62239c188f..8e3f7e7d7f 100644 --- a/src/components/tx-flow/flows/UpdateSafe/UpdateSafeReview.tsx +++ b/src/components/tx-flow/flows/UpdateSafe/UpdateSafeReview.tsx @@ -9,6 +9,12 @@ import { createUpdateSafeTxs } from '@/services/tx/safeUpdateParams' import { createMultiSendCallOnlyTx } from '@/services/tx/tx-sender' import { SafeTxContext } from '../../SafeTxProvider' import SignOrExecuteForm from '@/components/tx/SignOrExecuteForm' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' +import { trackEvent } from '@/services/analytics' + +const onSubmit = () => { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.safe_update }) +} export const UpdateSafeReview = () => { const { safe, safeLoaded } = useSafeInfo() @@ -25,7 +31,7 @@ export const UpdateSafeReview = () => { }, [chain, safe, safeLoaded, setNonce, setSafeTx, setSafeTxError]) return ( - null}> + Update now to take advantage of new features and the highest security standards available. diff --git a/src/hooks/messages/useSafeMsgTracking.ts b/src/hooks/messages/useSafeMsgTracking.ts index 45b3bf6fae..8e1131ccbf 100644 --- a/src/hooks/messages/useSafeMsgTracking.ts +++ b/src/hooks/messages/useSafeMsgTracking.ts @@ -2,6 +2,7 @@ import { useEffect } from 'react' import { trackEvent, WALLET_EVENTS } from '@/services/analytics' import { SafeMsgEvent, safeMsgSubscribe } from '@/services/safe-messages/safeMsgEvents' +import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions' const safeMsgEvents = { [SafeMsgEvent.PROPOSE]: WALLET_EVENTS.SIGN_MESSAGE, @@ -13,6 +14,10 @@ export const useSafeMsgTracking = (): void => { const unsubFns = Object.entries(safeMsgEvents).map(([safeMsgEvent, analyticsEvent]) => safeMsgSubscribe(safeMsgEvent as SafeMsgEvent, () => { trackEvent(analyticsEvent) + + if (analyticsEvent === WALLET_EVENTS.SIGN_MESSAGE) { + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.message }) + } }), ) diff --git a/src/services/analytics/events/overview.ts b/src/services/analytics/events/overview.ts index 369dad15eb..a1a408c469 100644 --- a/src/services/analytics/events/overview.ts +++ b/src/services/analytics/events/overview.ts @@ -96,4 +96,8 @@ export const OVERVIEW_EVENTS = { action: 'Click on SEP5 allocation button', category: OVERVIEW_CATEGORY, }, + SAFE_VIEWED: { + action: 'Safe viewed', + category: OVERVIEW_CATEGORY, + }, } diff --git a/src/services/analytics/events/transactions.ts b/src/services/analytics/events/transactions.ts new file mode 100644 index 0000000000..df6503e367 --- /dev/null +++ b/src/services/analytics/events/transactions.ts @@ -0,0 +1,38 @@ +export enum TX_TYPES { + // Owner txs + owner_add = 'owner_add', + owner_remove = 'owner_remove', + owner_swap = 'owner_swap', + owner_threshold_change = 'owner_threshold_change', + + // Module txs + guard_remove = 'guard_remove', + module_remove = 'module_remove', + spending_limit_remove = 'spending_limit_remove', + spending_limit_add = 'spending_limit_add', + spending_limit_transfer = 'spending_limit_transfer', + + // Safe txs + safe_update = 'safe_update', + + // Transfers + transfer_token = 'transfer_token', + transfer_nft = 'transfer_nft', + + // Other + batch = 'batch', + rejection = 'rejection', + message = 'message', + safeapps = 'safeapps', + walletconnect = 'walletconnect', +} + +const TX_CATEGORY = 'transactions' + +export const TX_EVENTS = { + CREATE: { + action: 'Create transaction', + category: TX_CATEGORY, + // label: TX_TYPES, + }, +} diff --git a/src/services/analytics/useGtm.ts b/src/services/analytics/useGtm.ts index f2fc484de3..6525867c60 100644 --- a/src/services/analytics/useGtm.ts +++ b/src/services/analytics/useGtm.ts @@ -14,6 +14,7 @@ import { gtmSetDeviceType, gtmSetSafeAddress, gtmSetUserProperty, + gtmTrack, } from '@/services/analytics/gtm' import { useAppSelector } from '@/store' import { CookieType, selectCookies } from '@/store/cookiesSlice' @@ -25,6 +26,7 @@ import { useMediaQuery } from '@mui/material' import { AnalyticsUserProperties, DeviceType } from './types' import useSafeAddress from '@/hooks/useSafeAddress' import useWallet from '@/hooks/wallets/useWallet' +import { OVERVIEW_EVENTS } from './events' const useGtm = () => { const chainId = useChainId() @@ -72,6 +74,10 @@ const useGtm = () => { // Set safe address for all GTM events useEffect(() => { gtmSetSafeAddress(safeAddress) + + if (safeAddress) { + gtmTrack(OVERVIEW_EVENTS.SAFE_VIEWED) + } }, [safeAddress]) // Track page views – anonymized by default. diff --git a/src/services/safe-wallet-provider/useSafeWalletProvider.tsx b/src/services/safe-wallet-provider/useSafeWalletProvider.tsx index ae04d26073..8573a958f0 100644 --- a/src/services/safe-wallet-provider/useSafeWalletProvider.tsx +++ b/src/services/safe-wallet-provider/useSafeWalletProvider.tsx @@ -23,6 +23,8 @@ import SignMessageOnChainFlow from '@/components/tx-flow/flows/SignMessageOnChai import { useAppSelector } from '@/store' import { selectOnChainSigning } from '@/store/settingsSlice' import { isOffchainEIP1271Supported } from '@/utils/safe-messages' +import { TX_EVENTS, TX_TYPES } from '../analytics/events/transactions' +import { trackEvent } from '../analytics' export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | undefined => { const { safe } = useSafeInfo() @@ -131,23 +133,15 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | code: RpcErrorCode.USER_REJECTED, message: 'User rejected transaction', }) - unsubscribe() } - const unsubscribeSignaturePrepared = txSubscribe( - TxEvent.SAFE_APPS_REQUEST, - async ({ safeAppRequestId, safeTxHash, txId }) => { - if (safeAppRequestId === id) { - const txHash = txId ? pendingTxs.current[txId] : undefined - resolve({ safeTxHash, txHash }) - unsubscribe() - } - }, - ) - - const unsubscribe = () => { + const onSubmit = (txId: string, safeTxHash: string) => { + const txHash = pendingTxs.current[txId] onClose = () => {} - unsubscribeSignaturePrepared() + + trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.walletconnect }) + + resolve({ safeTxHash, txHash }) } setTxFlow( @@ -159,6 +153,7 @@ export const _useTxFlowApi = (chainId: string, safeAddress: string): WalletSDK | txs: transactions, params: params.params, }} + onSubmit={onSubmit} />, onClose, ) diff --git a/src/services/tx/tx-sender/dispatch.ts b/src/services/tx/tx-sender/dispatch.ts index 570aa0e0ea..2013ecc84f 100644 --- a/src/services/tx/tx-sender/dispatch.ts +++ b/src/services/tx/tx-sender/dispatch.ts @@ -312,10 +312,11 @@ export const dispatchSafeAppsTx = async ( onboard: OnboardAPI, chainId: SafeInfo['chainId'], txId?: string, -) => { +): Promise => { const sdk = await getSafeSDKWithSigner(onboard, chainId) const safeTxHash = await sdk.getTransactionHash(safeTx) txDispatch(TxEvent.SAFE_APPS_REQUEST, { safeAppRequestId, safeTxHash, txId }) + return safeTxHash } export const dispatchTxRelay = async (