Skip to content
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
5 changes: 5 additions & 0 deletions src/background/Wallet/GlobalPreferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getRemoteConfigValue } from 'src/modules/remote-config';
import { removeEmptyValues } from 'src/shared/removeEmptyValues';
import { equal } from 'src/modules/fast-deep-equal';
import { difference } from 'src/shared/difference';
import { PLATFORM } from 'src/env/config';
import type { WalletNameFlag } from './model/WalletNameFlag';

const HALF_DAY = 1000 * 60 * 60 * 12;
Expand All @@ -26,6 +27,7 @@ export interface State {
recognizableConnectButtons?: boolean;
providerInjection?: ProviderInjection;
autoLockTimeout?: number | 'none';
analyticsEnabled?: boolean | null;
walletNameFlags?: Record<string, WalletNameFlag[] | undefined>;
}

Expand Down Expand Up @@ -58,6 +60,9 @@ export class GlobalPreferences extends PersistentStore<State> {
recognizableConnectButtons: true,
providerInjection: {},
walletNameFlags: {},
// Disable analytics by default for Firefox users
// And show first blocking screen during onboarding to set the initial value
analyticsEnabled: PLATFORM === 'firefox' ? null : true,
autoLockTimeout: HALF_DAY,
};

Expand Down
175 changes: 142 additions & 33 deletions src/shared/analytics/analytics.background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import { LoginActivity, type Account } from 'src/background/account/Account';
import { emitter } from 'src/background/events';
import { INTERNAL_SYMBOL_CONTEXT } from 'src/background/Wallet/Wallet';
import { INTERNAL_ORIGIN } from 'src/background/constants';
import { getWalletNameFlagsChange } from 'src/background/Wallet/GlobalPreferences';
import {
getWalletNameFlagsChange,
globalPreferences,
} from 'src/background/Wallet/GlobalPreferences';
import { dnaServiceEmitter } from 'src/modules/dna-service/dna.background';
import { estimateSessionExpiry } from 'src/background/user-activity';
import {
Expand Down Expand Up @@ -99,23 +102,34 @@ function trackAppEvents({ account }: { account: Account }) {
return createBaseParams(params);
};

emitter.on('requestAccountsResolved', ({ origin, address, explicitly }) => {
if (!explicitly) {
return;
emitter.on(
'requestAccountsResolved',
async ({ origin, address, explicitly }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
if (!explicitly) {
return;
}
Comment on lines +112 to +114
Copy link
Member

Choose a reason for hiding this comment

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

should this condition come first?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, this is fair. My only logic was to place this settings check as same as possible everywhere to simplify the usage

const params = createParams({
request_name: 'dapp_connection',
dapp_domain: origin,
wallet_address: address,
ecosystem: toEcosystemProperty(getAddressType(address)),
eip6963_supported: eip6963Dapps.has(origin),
});
sendToMetabase('dapp_connection', params);
const mixpanelParams = omit(params, ['request_name', 'wallet_address']);
mixpanelTrack('DApp: DApp Connection', mixpanelParams);
}
const params = createParams({
request_name: 'dapp_connection',
dapp_domain: origin,
wallet_address: address,
ecosystem: toEcosystemProperty(getAddressType(address)),
eip6963_supported: eip6963Dapps.has(origin),
});
sendToMetabase('dapp_connection', params);
const mixpanelParams = omit(params, ['request_name', 'wallet_address']);
mixpanelTrack('DApp: DApp Connection', mixpanelParams);
});
);

emitter.on('unlockedAppOpened', async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
await waitForAnalyticsIdSet();
const params = createParams({ request_name: 'unlocked_app_opened' });
/**
Expand All @@ -131,6 +145,10 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('screenView', async (data) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
await waitForAnalyticsIdSet();
const params = createParams({
request_name: 'screen_view',
Expand All @@ -150,6 +168,10 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('screenView', async (params) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
await waitForAnalyticsIdSet();
const gaParams = await prepareGaParams({
page_title: params.title,
Expand All @@ -158,7 +180,11 @@ function trackAppEvents({ account }: { account: Account }) {
gaCollect('page_view', gaParams);
});

emitter.on('buttonClicked', (data) => {
emitter.on('buttonClicked', async (data) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const { buttonName, buttonScope, pathname, walletAddress } = data;
const params = createParams({
request_name: 'button_clicked',
Expand All @@ -171,7 +197,11 @@ function trackAppEvents({ account }: { account: Account }) {
mixpanelTrack(event_name, mixpanelParams);
});

emitter.on('bannerClicked', (data) => {
emitter.on('bannerClicked', async (data) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const { bannerName, pathname, walletAddress } = data;
const params = createParams({
request_name: 'banner_clicked',
Expand All @@ -185,6 +215,10 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('assetClicked', async (data) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const { assetId, pathname, section } = data;

const assetData = await queryFungibleInfo({
Expand All @@ -204,7 +238,11 @@ function trackAppEvents({ account }: { account: Account }) {
mixpanelTrack(event_name, mixpanelParams);
});

emitter.on('daylightAction', ({ event_name, ...data }) => {
emitter.on('daylightAction', async ({ event_name, ...data }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
Comment on lines +242 to +245
Copy link
Member

Choose a reason for hiding this comment

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

This check is repeated over and over. Do you think we can create a helper that abstracts this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Discussed and decided to keep it this way for now

const params = createParams({
request_name: 'daylight_action',
wallet_address: data.address,
Expand All @@ -214,7 +252,11 @@ function trackAppEvents({ account }: { account: Account }) {
sendToMetabase('daylight_action', params);
});

emitter.on('globalError', ({ name, message }) => {
emitter.on('globalError', async ({ name, message }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const params = createParams({
request_name: 'client_error',
type: name,
Expand Down Expand Up @@ -313,15 +355,27 @@ function trackAppEvents({ account }: { account: Account }) {
statsigTrack('Transaction: Signed Transaction', mixpanelParams);
};

emitter.on('transactionSent', (result, context) =>
trackTransactionSign({ status: 'success', result, context })
);
emitter.on('transactionSent', async (result, context) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
trackTransactionSign({ status: 'success', result, context });
});

emitter.on('transactionFailed', (errorMessage, context) =>
trackTransactionSign({ status: 'failed', errorMessage, context })
);
emitter.on('transactionFailed', async (errorMessage, context) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
trackTransactionSign({ status: 'failed', errorMessage, context });
});

emitter.on('transactionFormed', async (context) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const {
formState,
quote,
Expand Down Expand Up @@ -457,15 +511,27 @@ function trackAppEvents({ account }: { account: Account }) {
mixpanelTrack('Transaction: Signed Message', mixpanelParams);
}

emitter.on('typedDataSigned', ({ typedData, ...rest }) => {
emitter.on('typedDataSigned', async ({ typedData, ...rest }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
handleSign({ type: 'typedDataSigned', ...rest });
});
emitter.on('messageSigned', ({ message, ...rest }) => {
emitter.on('messageSigned', async ({ message, ...rest }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
handleSign({ type: 'messageSigned', ...rest });
});

// TODO: add networks-related analytics
emitter.on('addEthereumChain', ({ values: [chainConfig], origin }) => {
emitter.on('addEthereumChain', async ({ values: [chainConfig], origin }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const wallet_address = getCurrentAddress();
const params = createParams({
request_name: 'custom_evm_network_created',
Expand All @@ -481,7 +547,11 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('globalPreferencesChange', (state, prevState) => {
onIdle(() => {
onIdle(async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const { enabled: newlyEnabled, disabled: newlyDisabled } =
getWalletNameFlagsChange(state, prevState);

Expand All @@ -504,7 +574,11 @@ function trackAppEvents({ account }: { account: Account }) {
});
});

emitter.on('holdToSignPreferenceChange', (active) => {
emitter.on('holdToSignPreferenceChange', async (active) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const params = createParams({
request_name: 'hold_to_sign_prerefence',
active,
Expand All @@ -513,7 +587,11 @@ function trackAppEvents({ account }: { account: Account }) {
mixpanelTrack('Experiments: Hold Sign Button', mixpanelParams);
});

emitter.on('walletCreated', ({ walletContainer, origin }) => {
emitter.on('walletCreated', async ({ walletContainer, origin }) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
for (const wallet of walletContainer.wallets) {
const type =
origin === WalletOrigin.extension
Expand Down Expand Up @@ -541,6 +619,10 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('firstScreenView', async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
await waitForAnalyticsIdSet();
statsigTrack('General: Launch first time');
mixpanelTrack('General: Launch first time', {});
Expand All @@ -553,6 +635,10 @@ function trackAppEvents({ account }: { account: Account }) {
});

emitter.on('backgroundScriptInitialized', async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
// We want to check whether background script got restarted in a way
// that has led to an unexpected logout.
// The browser restart is considered an expected logout.
Expand Down Expand Up @@ -598,14 +684,22 @@ function trackAppEvents({ account }: { account: Account }) {
});

dnaServiceEmitter.on('registerError', async (error, action) => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const request_name = 'client_error';
const message = getError(error).message;
const type = 'dna action';
const params = createParams({ request_name, type, message, action });
sendToMetabase(request_name, params);
});

emitter.on('cloudflareChallengeIssued', () => {
emitter.on('cloudflareChallengeIssued', async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
const params = createParams({
request_name: 'cloudflare_challenge_issued',
});
Expand All @@ -621,10 +715,25 @@ export function initialize({ account }: { account: Account }) {
initializeApiV4Analytics({
willSendRequest: createAddProviderHook({ getWalletProvider }),
});
const handleUserId = () => mixpanelIdentify(account);
const handleUserId = async () => {
const preferences = await globalPreferences.getPreferences();
if (!preferences.analyticsEnabled) {
return;
}
mixpanelIdentify(account);
};
account.on('authenticated', () => handleUserId());
if (account.getUser()) {
handleUserId();
}
globalPreferences.on('change', (state, prevState) => {
if (
state.analyticsEnabled &&
!prevState.analyticsEnabled &&
account.getUser()
) {
handleUserId();
}
});
return trackAppEvents({ account });
}
Loading