Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analytics: track tx creations and safe views #2787

Merged
merged 15 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions src/components/dashboard/FeaturedApps/FeaturedApps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@ import { SafeAppsTag } from '@/config/constants'
import { useRemoteSafeApps } from '@/hooks/safe-apps/useRemoteSafeApps'
import SafeAppIconCard from '@/components/safe-apps/SafeAppIconCard'
import { WalletConnectContext } from '@/services/walletconnect/WalletConnectContext'

const isWalletConnectSafeApp = (app: SafeAppData): boolean => {
const WALLET_CONNECT = /wallet-connect/
return WALLET_CONNECT.test(app.url)
}
import { isWalletConnectSafeApp } from '@/services/walletconnect/utils'

const FeaturedAppCard = ({ app }: { app: SafeAppData }) => (
<Card>
Expand Down Expand Up @@ -62,7 +58,7 @@ export const FeaturedApps = ({ stackedLayout }: { stackedLayout: boolean }): Rea
>
{featuredApps?.map((app) => (
<Grid item xs md key={app.id}>
{isWalletConnectSafeApp(app) ? (
{isWalletConnectSafeApp(app.url) ? (
<a onClick={onWcWidgetClick} style={{ cursor: 'pointer' }}>
<FeaturedAppCard app={app} />
</a>
Expand Down
2 changes: 2 additions & 0 deletions src/components/tx-flow/flows/AddOwner/ReviewOwner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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 (
Expand Down
11 changes: 9 additions & 2 deletions src/components/tx-flow/flows/ConfirmBatch/index.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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
Expand All @@ -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 (
<SignOrExecuteForm onSubmit={onSubmit} isBatch>
<SignOrExecuteForm onSubmit={onTxSubmit} isBatch>
<BatchTxList txItems={batchTxs} />
</SignOrExecuteForm>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<SpendingLimitState>()
Expand Down Expand Up @@ -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
Expand Down
11 changes: 9 additions & 2 deletions src/components/tx-flow/flows/NftTransfer/ReviewNftBatch.tsx
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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
Expand Down Expand Up @@ -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 (
<SignOrExecuteForm onSubmit={onSubmit}>
<SignOrExecuteForm onSubmit={onTxSubmit}>
<Grid container gap={1} mb={2}>
<Grid item md>
<Typography variant="body2" color="text.secondary">
Expand Down
8 changes: 7 additions & 1 deletion src/components/tx-flow/flows/RejectTx/RejectTx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -19,7 +25,7 @@ const RejectTx = ({ txNonce }: RejectTxProps): ReactElement => {
}, [txNonce, setNonce, setSafeTx, setSafeTxError])

return (
<SignOrExecuteForm onSubmit={() => {}} isBatchable={false}>
<SignOrExecuteForm onSubmit={onSubmit} isBatchable={false}>
<Typography mb={2}>
To reject the transaction, a separate rejection transaction will be created to replace the original one.
</Typography>
Expand Down
10 changes: 6 additions & 4 deletions src/components/tx-flow/flows/RemoveGuard/ReviewRemoveGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -21,10 +27,6 @@ export const ReviewRemoveGuard = ({ params }: { params: RemoveGuardFlowProps })
}
}, [safeTxError])

const onFormSubmit = () => {
trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_GUARD)
}

return (
<SignOrExecuteForm onSubmit={onFormSubmit}>
<Typography sx={({ palette }) => ({ color: palette.primary.light })}>Transaction guard</Typography>
Expand Down
10 changes: 6 additions & 4 deletions src/components/tx-flow/flows/RemoveModule/ReviewRemoveModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -21,10 +27,6 @@ export const ReviewRemoveModule = ({ params }: { params: RemoveModuleFlowProps }
}
}, [safeTxError])

const onFormSubmit = () => {
trackEvent(SETTINGS_EVENTS.MODULES.REMOVE_MODULE)
}

return (
<SignOrExecuteForm onSubmit={onFormSubmit}>
<Grid container gap={1} alignItems="center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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 (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 (
<SignOrExecuteForm onSubmit={onFormSubmit}>
{token && (
Expand Down
18 changes: 17 additions & 1 deletion src/components/tx-flow/flows/SafeAppsTx/ReviewSafeAppsTx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@ import ApprovalEditor from '@/components/tx/ApprovalEditor'
import { getInteractionTitle, isTxValid } from '@/components/safe-apps/utils'
import ErrorMessage from '@/components/tx/ErrorMessage'
import { asError } from '@/services/exceptions/utils'
import { trackEvent } from '@/services/analytics'
import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions'
import { isWalletConnectSafeApp } from '@/services/walletconnect/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()
Expand Down Expand Up @@ -54,11 +59,22 @@ 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))
}

// Track tx creation
if (safeTx.signatures.size === 0) {
trackEvent({
...TX_EVENTS.CREATE,
label: isWalletConnectSafeApp(app?.url || '') ? TX_TYPES.walletconnect : TX_TYPES.safeapps,
})
}

onSubmit?.(txId, safeTxHash)
}

const origin = useMemo(() => getTxOrigin(app), [app])
Expand Down
10 changes: 8 additions & 2 deletions src/components/tx-flow/flows/SafeAppsTx/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ export type SafeAppsTxParams = {
params?: SendTransactionRequestParams
}

const SafeAppsTxFlow = ({ data }: { data: SafeAppsTxParams }) => {
const SafeAppsTxFlow = ({
Copy link
Member

@usame-algan usame-algan Nov 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why but I didn't see a Transaction created event when I created one via CSV Airdrop safe app. Only Propose Transaction and On-chain interaction. Do we need to add it to the App Frame?

data,
onSubmit,
}: {
data: SafeAppsTxParams
onSubmit?: (txId: string, safeTxHash: string) => void
}) => {
return (
<TxLayout
title="Confirm transaction"
subtitle={<AppTitle name={data.app?.name} logoUri={data.app?.iconUrl} />}
step={0}
>
<ReviewSafeAppsTx safeAppsTx={data} />
<ReviewSafeAppsTx safeAppsTx={data} onSubmit={onSubmit} />
</TxLayout>
)
}
Expand Down
19 changes: 11 additions & 8 deletions src/components/tx-flow/flows/SignMessage/SignMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ import InfoBox from '@/components/safe-messages/InfoBox'
import { DecodedMsg } from '@/components/safe-messages/DecodedMsg'
import TxCard from '@/components/tx-flow/common/TxCard'
import { dispatchPreparedSignature } from '@/services/safe-messages/safeMsgNotifications'
import { trackEvent } from '@/services/analytics'
import { TX_EVENTS, TX_TYPES } from '@/services/analytics/events/transactions'

const createSkeletonMessage = (confirmationsRequired: number): SafeMessage => {
return {
Expand Down Expand Up @@ -169,19 +171,14 @@ const SignMessage = ({ message, safeAppId, requestId }: ProposeProps | ConfirmPr
const { safe } = useSafeInfo()
const isOwner = useIsSafeOwner()
const wallet = useWallet()
useHighlightHiddenTab()

const { decodedMessage, safeMessageMessage, safeMessageHash } = useDecodedSafeMessage(message, safe)
const [safeMessage, setSafeMessage] = useSafeMessage(safeMessageHash)

useHighlightHiddenTab()

const decodedMessageAsString =
typeof decodedMessage === 'string' ? decodedMessage : JSON.stringify(decodedMessage, null, 2)

const isPlainTextMessage = typeof decodedMessage === 'string'
const decodedMessageAsString = isPlainTextMessage ? decodedMessage : JSON.stringify(decodedMessage, null, 2)
const hasSigned = !!safeMessage?.confirmations.some(({ owner }) => owner.value === wallet?.address)

const isFullySigned = !!safeMessage?.preparedSignature

const isDisabled = !isOwner || hasSigned

const { onSign, submitError } = useSyncSafeMessageSigner(
Expand All @@ -195,9 +192,15 @@ const SignMessage = ({ message, safeAppId, requestId }: ProposeProps | ConfirmPr

const handleSign = async () => {
const updatedMessage = await onSign()

if (updatedMessage) {
setSafeMessage(updatedMessage)
}

// Track first signature as creation
if (updatedMessage?.confirmations.length === 1) {
trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.typed_message })
}
}

const onContinue = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -98,6 +100,12 @@ const ReviewSignMessageOnChain = ({ message, method, requestId }: SignMessageOnC

const handleSubmit = async () => {
if (!safeTx || !onboard) return

// Track the creation of a typed message
if (isTypedMessage && safeTx.signatures.size === 1) {
trackEvent({ ...TX_EVENTS.CREATE, label: TX_TYPES.typed_message })
}

try {
await dispatchSafeAppsTx(safeTx, requestId, onboard, safe.chainId)
} catch (error) {
Expand Down
Loading
Loading