Skip to content

Commit

Permalink
feat: tracking for MPC wallet
Browse files Browse the repository at this point in the history
  • Loading branch information
schmanu committed Oct 12, 2023
1 parent cc7398b commit 5c8e807
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 66 deletions.
67 changes: 37 additions & 30 deletions src/components/common/ConnectWallet/MPCLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import GoogleLogo from '@/public/images/welcome/logo-google.svg'

import css from './styles.module.css'
import useWallet from '@/hooks/wallets/useWallet'
import Track from '../Track'
import { CREATE_SAFE_EVENTS } from '@/services/analytics'
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'

const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => {
const { triggerLogin, userInfo, walletState, recoverFactorWithPassword } = useContext(MpcWalletContext)
Expand Down Expand Up @@ -34,44 +37,48 @@ const MPCLogin = ({ onLogin }: { onLogin?: () => void }) => {
<>
{wallet && userInfo ? (
<>
<Track {...CREATE_SAFE_EVENTS.CONTINUE_TO_CREATION} label={wallet.label}>
<Button
variant="outlined"
sx={{ px: 2, py: 1, borderWidth: '1px !important' }}
onClick={onLogin}
size="small"
disabled={loginPending}
fullWidth
>
<Box width="100%" display="flex" flexDirection="row" alignItems="center" gap={1}>
<img
src={userInfo.profileImage}
className={css.profileImg}
alt="Profile Image"
referrerPolicy="no-referrer"
/>
<div className={css.profileData}>
<Typography variant="subtitle2" fontWeight={700}>
Continue as {userInfo.name}
</Typography>
<Typography variant="body2">{userInfo.email}</Typography>
</div>
<SvgIcon component={GoogleLogo} inheritViewBox fontSize="medium" sx={{ marginLeft: 'auto' }} />
</Box>
</Button>
</Track>
</>
) : (
<Track {...MPC_WALLET_EVENTS.CONNECT_GOOGLE}>
<Button
variant="outlined"
sx={{ px: 2, py: 1, borderWidth: '1px !important' }}
onClick={onLogin}
onClick={login}
size="small"
disabled={loginPending}
fullWidth
sx={{ borderWidth: '1px !important' }}
>
<Box width="100%" display="flex" flexDirection="row" alignItems="center" gap={1}>
<img
src={userInfo.profileImage}
className={css.profileImg}
alt="Profile Image"
referrerPolicy="no-referrer"
/>
<div className={css.profileData}>
<Typography variant="subtitle2" fontWeight={700}>
Continue as {userInfo.name}
</Typography>
<Typography variant="body2">{userInfo.email}</Typography>
</div>
<SvgIcon component={GoogleLogo} inheritViewBox fontSize="medium" sx={{ marginLeft: 'auto' }} />
<Box display="flex" flexDirection="row" alignItems="center" gap={1}>
<SvgIcon component={GoogleLogo} inheritViewBox fontSize="medium" /> Continue with Google
</Box>
</Button>
</>
) : (
<Button
variant="outlined"
onClick={login}
size="small"
disabled={loginPending}
fullWidth
sx={{ borderWidth: '1px !important' }}
>
<Box display="flex" flexDirection="row" alignItems="center" gap={1}>
<SvgIcon component={GoogleLogo} inheritViewBox fontSize="medium" /> Continue with Google
</Box>
</Button>
</Track>
)}

{walletState === MPCWalletState.MANUAL_RECOVERY && (
Expand Down
14 changes: 10 additions & 4 deletions src/components/common/ConnectWallet/PasswordRecovery.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'
import { VisibilityOff, Visibility } from '@mui/icons-material'
import {
DialogContent,
Expand All @@ -11,6 +12,7 @@ import {
} from '@mui/material'
import { useState } from 'react'
import ModalDialog from '../ModalDialog'
import Track from '../Track'

export const PasswordRecovery = ({
recoverFactorWithPassword,
Expand Down Expand Up @@ -52,10 +54,14 @@ export const PasswordRecovery = ({
control={<Checkbox checked={storeDeviceFactor} onClick={() => setStoreDeviceFactor((prev) => !prev)} />}
label="Do not ask again on this device"
/>

<Button variant="contained" onClick={() => recoverFactorWithPassword(recoveryPassword, storeDeviceFactor)}>
Submit
</Button>
<Track {...MPC_WALLET_EVENTS.RECOVER_PASSWORD}>
<Button
variant="contained"
onClick={() => recoverFactorWithPassword(recoveryPassword, storeDeviceFactor)}
>
Submit
</Button>
</Track>
</Box>
</Box>
</DialogContent>
Expand Down
19 changes: 11 additions & 8 deletions src/components/settings/SignerAccountMFA/PasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Track from '@/components/common/Track'
import { SecurityQuestionRecovery } from '@/hooks/wallets/mpc/recovery/SecurityQuestionRecovery'
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'
import { Typography, TextField, Button, Box } from '@mui/material'
import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
import { useState, useMemo } from 'react'
Expand Down Expand Up @@ -92,14 +94,15 @@ export const PasswordForm = ({ mpcCoreKit }: { mpcCoreKit: Web3AuthMPCCoreKit })
},
})}
/>

<Button
sx={{ justifySelf: 'flex-start' }}
disabled={!formMethods.formState.isValid || enablingMFA}
type="submit"
>
Change
</Button>
<Track {...MPC_WALLET_EVENTS.UPSERT_PASSWORD}>
<Button
sx={{ justifySelf: 'flex-start' }}
disabled={!formMethods.formState.isValid || enablingMFA}
type="submit"
>
Change
</Button>
</Track>
</Box>
</form>
)
Expand Down
3 changes: 3 additions & 0 deletions src/components/settings/SignerAccountMFA/helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { SecurityQuestionRecovery } from '@/hooks/wallets/mpc/recovery/SecurityQuestionRecovery'
import { trackEvent } from '@/services/analytics'
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'
import { logError } from '@/services/exceptions'
import ErrorCodes from '@/services/exceptions/ErrorCodes'
import { asError } from '@/services/exceptions/utils'
Expand Down Expand Up @@ -35,6 +37,7 @@ export const enableMFA = async (
}

if (!isMFAEnabled(mpcCoreKit)) {
trackEvent(MPC_WALLET_EVENTS.ENABLE_MFA)
// 2. enable MFA in mpcCoreKit
await mpcCoreKit.enableMFA({}, false)
}
Expand Down
51 changes: 32 additions & 19 deletions src/components/welcome/WelcomeLogin/WalletLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import useConnectWallet from '@/components/common/ConnectWallet/useConnectWallet'
import Track from '@/components/common/Track'
import useWallet from '@/hooks/wallets/useWallet'
import { CREATE_SAFE_EVENTS } from '@/services/analytics'
import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/module'
import { Box, Button, Typography } from '@mui/material'
import { EthHashInfo } from '@safe-global/safe-react-components'
Expand All @@ -9,30 +11,41 @@ const WalletLogin = ({ onLogin }: { onLogin: () => void }) => {
const connectWallet = useConnectWallet()

const login = async () => {
await connectWallet()
onLogin()
const walletState = await connectWallet()
if (walletState) {
onLogin()
}
}

if (wallet !== null && wallet?.label !== ONBOARD_MPC_MODULE_LABEL) {
return (
<Button variant="contained" sx={{ padding: '8px 16px' }} fullWidth onClick={onLogin}>
<Box width="100%" justifyContent="space-between" display="flex" flexDirection="row" alignItems="center" gap={1}>
<Box display="flex" flexDirection="column" alignItems="flex-start">
<Typography variant="subtitle2" fontWeight={700}>
Continue with {wallet.label}
</Typography>
{wallet.address && <EthHashInfo address={wallet.address} shortAddress avatarSize={16} />}
<Track {...CREATE_SAFE_EVENTS.CONTINUE_TO_CREATION} label={wallet.label}>
<Button variant="contained" sx={{ padding: '8px 16px' }} fullWidth onClick={onLogin}>
<Box
width="100%"
justifyContent="space-between"
display="flex"
flexDirection="row"
alignItems="center"
gap={1}
>
<Box display="flex" flexDirection="column" alignItems="flex-start">
<Typography variant="subtitle2" fontWeight={700}>
Continue with {wallet.label}
</Typography>
{wallet.address && <EthHashInfo address={wallet.address} shortAddress avatarSize={16} />}
</Box>
{wallet.icon && (
<img
width="24px"
height="24px"
src={`data:image/svg+xml;utf8,${encodeURIComponent(wallet.icon)}`}
alt="icon"
/>
)}
</Box>
{wallet.icon && (
<img
width="24px"
height="24px"
src={`data:image/svg+xml;utf8,${encodeURIComponent(wallet.icon)}`}
alt="icon"
/>
)}
</Box>
</Button>
</Button>
</Track>
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('WalletLogin', () => {
const mockOnLogin = jest.fn()
const walletAddress = hexZeroPad('0x1', 20)
const mockUseWallet = jest.spyOn(useWallet, 'default').mockReturnValue(null)
jest.spyOn(useConnectWallet, 'default').mockReturnValue(jest.fn())
jest.spyOn(useConnectWallet, 'default').mockReturnValue(jest.fn().mockReturnValue([{}]))

const result = render(<WalletLogin onLogin={mockOnLogin} />)

Expand Down
4 changes: 1 addition & 3 deletions src/components/welcome/WelcomeLogin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@ import SafeLogo from '@/public/images/logo-text.svg'
import css from './styles.module.css'
import { useRouter } from 'next/router'
import WalletLogin from './WalletLogin'
import { CREATE_SAFE_EVENTS, LOAD_SAFE_EVENTS } from '@/services/analytics/events/createLoadSafe'
import { LOAD_SAFE_EVENTS } from '@/services/analytics/events/createLoadSafe'
import Track from '@/components/common/Track'
import { trackEvent } from '@/services/analytics'

const WelcomeLogin = () => {
const router = useRouter()

const continueToCreation = () => {
trackEvent(CREATE_SAFE_EVENTS.CREATE_BUTTON)
router.push(AppRoutes.newSafe.create)
}

Expand Down
5 changes: 4 additions & 1 deletion src/hooks/wallets/mpc/useMPCWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import useOnboard, { connectWallet } from '../useOnboard'
import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/module'
import { SecurityQuestionRecovery } from './recovery/SecurityQuestionRecovery'
import { DeviceShareRecovery } from './recovery/DeviceShareRecovery'
import { trackEvent } from '@/services/analytics'
import { MPC_WALLET_EVENTS } from '@/services/analytics/events/mpcWallet'

export enum MPCWalletState {
NOT_INITIALIZED,
Expand All @@ -33,7 +35,7 @@ export const useMPCWallet = (): MPCWalletHook => {
// This is a critical function that should only be used for testing purposes
// Resetting your account means clearing all the metadata associated with it from the metadata server
// The key details will be deleted from our server and you will not be able to recover your account
if (!mpcCoreKit || !mpcCoreKit.metadataKey) {
if (!mpcCoreKit?.metadataKey) {
throw new Error('MPC Core Kit is not initialized or the user is not logged in')
}

Expand Down Expand Up @@ -73,6 +75,7 @@ export const useMPCWallet = (): MPCWalletHook => {
// Check password recovery
const securityQuestions = new SecurityQuestionRecovery(mpcCoreKit)
if (securityQuestions.isEnabled()) {
trackEvent(MPC_WALLET_EVENTS.MANUAL_RECOVERY)
setWalletState(MPCWalletState.MANUAL_RECOVERY)
return false
}
Expand Down
5 changes: 5 additions & 0 deletions src/services/analytics/events/createLoadSafe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { EventType } from '@/services/analytics/types'
export const CREATE_SAFE_CATEGORY = 'create-safe'

export const CREATE_SAFE_EVENTS = {
CONTINUE_TO_CREATION: {
action: 'Continue to creation',
category: CREATE_SAFE_CATEGORY,
event: EventType.META,
},
CREATE_BUTTON: {
action: 'Open stepper',
category: CREATE_SAFE_CATEGORY,
Expand Down
31 changes: 31 additions & 0 deletions src/services/analytics/events/mpcWallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { EventType } from '@/services/analytics/types'

const MPC_WALLET_CATEGORY = 'mpc-wallet'

export const MPC_WALLET_EVENTS = {
CONNECT_GOOGLE: {
event: EventType.CLICK,
action: 'Continue with Google button',
category: MPC_WALLET_CATEGORY,
},
MANUAL_RECOVERY: {
event: EventType.META,
action: 'Account recovery started',
category: MPC_WALLET_CATEGORY,
},
RECOVER_PASSWORD: {
event: EventType.CLICK,
action: 'Recover account using password',
category: MPC_WALLET_CATEGORY,
},
UPSERT_PASSWORD: {
event: EventType.CLICK,
action: 'Set or change password',
category: MPC_WALLET_CATEGORY,
},
ENABLE_MFA: {
event: EventType.META,
action: 'Enable MFA for account',
category: MPC_WALLET_CATEGORY,
},
}

0 comments on commit 5c8e807

Please sign in to comment.