Skip to content

Commit

Permalink
Merge b5bc8b0 into 9d3be8a
Browse files Browse the repository at this point in the history
  • Loading branch information
walmat authored Oct 4, 2024
2 parents 9d3be8a + b5bc8b0 commit 27b2f7e
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 46 deletions.
52 changes: 33 additions & 19 deletions src/__swaps__/screens/Swap/providers/swap-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ export const SwapProvider = ({ children }: SwapProviderProps) => {

const isBridge = swapsStore.getState().inputAsset?.mainnetAddress === swapsStore.getState().outputAsset?.mainnetAddress;
const isDegenModeEnabled = swapsStore.getState().degenMode;
const slippage = swapsStore.getState().slippage;
const isSwappingToPopularAsset = swapsStore.getState().outputAsset?.sectionId === 'popular';

const selectedGas = getSelectedGas(parameters.chainId);
Expand Down Expand Up @@ -244,7 +243,6 @@ export const SwapProvider = ({ children }: SwapProviderProps) => {
}

const gasFeeParamsBySpeed = getGasSettingsBySpeed(parameters.chainId);
const selectedGasSpeed = getSelectedGasSpeed(parameters.chainId);

let gasParams: TransactionGasParamAmounts | LegacyTransactionGasParamAmounts = {} as
| TransactionGasParamAmounts
Expand Down Expand Up @@ -282,18 +280,26 @@ export const SwapProvider = ({ children }: SwapProviderProps) => {
SwapInputController.quoteFetchingInterval.start();

analyticsV2.track(analyticsV2.event.swapsFailed, {
createdAt: Date.now(),
type,
parameters,
selectedGas,
selectedGasSpeed,
slippage,
bridge: isBridge,
errorMessage,
inputNativeValue: SwapInputController.inputValues.value.inputNativeValue,
outputNativeValue: SwapInputController.inputValues.value.outputNativeValue,
isBridge: isBridge,
inputAssetSymbol: internalSelectedInputAsset.value?.symbol || '',
inputAssetName: internalSelectedInputAsset.value?.name || '',
inputAssetAddress: internalSelectedInputAsset.value?.address as AddressOrEth,
inputAssetChainId: internalSelectedInputAsset.value?.chainId || ChainId.mainnet,
inputAssetAmount: parameters.quote.sellAmount as number,
outputAssetSymbol: internalSelectedOutputAsset.value?.symbol || '',
outputAssetName: internalSelectedOutputAsset.value?.name || '',
outputAssetAddress: internalSelectedOutputAsset.value?.address as AddressOrEth,
outputAssetChainId: internalSelectedOutputAsset.value?.chainId || ChainId.mainnet,
outputAssetAmount: parameters.quote.buyAmount as number,
mainnetAddress: (parameters.assetToBuy.chainId === ChainId.mainnet
? parameters.assetToBuy.address
: parameters.assetToSell.mainnetAddress) as AddressOrEth,
flashbots: parameters.flashbots ?? false,
tradeAmountUSD: parameters.quote.tradeAmountUSD,
degenMode: isDegenModeEnabled,
isSwappingToPopularAsset,
errorMessage,
});

if (errorMessage !== 'handled') {
Expand Down Expand Up @@ -333,15 +339,23 @@ export const SwapProvider = ({ children }: SwapProviderProps) => {
})(Routes.PROFILE_SCREEN, {});

analyticsV2.track(analyticsV2.event.swapsSubmitted, {
createdAt: Date.now(),
type,
parameters,
selectedGas,
selectedGasSpeed,
slippage,
bridge: isBridge,
inputNativeValue: SwapInputController.inputValues.value.inputNativeValue,
outputNativeValue: SwapInputController.inputValues.value.outputNativeValue,
isBridge: isBridge,
inputAssetSymbol: internalSelectedInputAsset.value?.symbol || '',
inputAssetName: internalSelectedInputAsset.value?.name || '',
inputAssetAddress: internalSelectedInputAsset.value?.address as AddressOrEth,
inputAssetChainId: internalSelectedInputAsset.value?.chainId || ChainId.mainnet,
inputAssetAmount: parameters.quote.sellAmount as number,
outputAssetSymbol: internalSelectedOutputAsset.value?.symbol || '',
outputAssetName: internalSelectedOutputAsset.value?.name || '',
outputAssetAddress: internalSelectedOutputAsset.value?.address as AddressOrEth,
outputAssetChainId: internalSelectedOutputAsset.value?.chainId || ChainId.mainnet,
outputAssetAmount: parameters.quote.buyAmount as number,
mainnetAddress: (parameters.assetToBuy.chainId === ChainId.mainnet
? parameters.assetToBuy.address
: parameters.assetToSell.mainnetAddress) as AddressOrEth,
flashbots: parameters.flashbots ?? false,
tradeAmountUSD: parameters.quote.tradeAmountUSD,
degenMode: isDegenModeEnabled,
isSwappingToPopularAsset,
});
Expand Down
48 changes: 36 additions & 12 deletions src/analytics/event.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { GasSettings } from '@/__swaps__/screens/Swap/hooks/useCustomGas';
import { ExtendedAnimatedAssetWithColors, ParsedSearchAsset } from '@/__swaps__/types/assets';
import { AddressOrEth, ExtendedAnimatedAssetWithColors, ParsedSearchAsset } from '@/__swaps__/types/assets';
import { ChainId, Network } from '@/chains/types';
import { GasSpeed } from '@/__swaps__/types/gas';
import { SwapAssetType } from '@/__swaps__/types/swap';
import { UnlockableAppIconKey } from '@/appIcons/appIcons';
import { CardType } from '@/components/cards/GenericCard';
import { LearnCategory } from '@/components/cards/utils/types';
import { FiatProviderName } from '@/entities/f2c';
import { RapSwapActionParameters } from '@/raps/references';
import { RequestSource } from '@/utils/requestNavigationHandlers';
import { CrosschainQuote, Quote, QuoteError } from '@rainbow-me/swaps';
import { AnyPerformanceLog, Screen } from '../state/performance/operations';
Expand Down Expand Up @@ -149,18 +146,28 @@ export const event = {

performanceTimeToSign: 'performance.time_to_sign',
performanceTimeToSignOperation: 'performance.time_to_sign.operation',

addFavoriteToken: 'add_favorite_token',
watchWallet: 'watch_wallet',
watchedWalletCohort: 'watched_wallet_cohort',
} as const;

type SwapEventParameters<T extends 'swap' | 'crosschainSwap'> = {
createdAt: number;
type: T;
bridge: boolean;
inputNativeValue: string | number;
outputNativeValue: string | number;
parameters: Omit<RapSwapActionParameters<T>, 'gasParams' | 'gasFeeParamsBySpeed' | 'selectedGasFee'>;
selectedGas: GasSettings;
selectedGasSpeed: GasSpeed;
slippage: string;
isBridge: boolean;
inputAssetSymbol: string;
inputAssetName: string;
inputAssetAddress: AddressOrEth;
inputAssetChainId: ChainId;
inputAssetAmount: number;
outputAssetSymbol: string;
outputAssetName: string;
outputAssetAddress: AddressOrEth;
outputAssetChainId: ChainId;
outputAssetAmount: number;
mainnetAddress: string;
flashbots: boolean;
tradeAmountUSD: number;
degenMode: boolean;
isSwappingToPopularAsset: boolean;
};
Expand Down Expand Up @@ -571,4 +578,21 @@ export type EventProperties = {
};

[event.performanceTimeToSignOperation]: AnyPerformanceLog;

[event.addFavoriteToken]: {
address: AddressOrEth;
chainId: ChainId;
name: string;
symbol: string;
};

[event.watchWallet]: {
addressOrEnsName: string;
address: string;
};

[event.watchedWalletCohort]: {
numWatchedWallets: number;
watchedWalletsAddresses: string[];
};
};
29 changes: 29 additions & 0 deletions src/helpers/runWatchedWalletCohort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useWallets } from '@/hooks';
import walletTypes from './walletTypes';
import { useEffect } from 'react';
import { analyticsV2 } from '@/analytics';
import * as ls from '@/storage';

const WATCHED_WALLET_COHORT_INTERVAL = 1000 * 60 * 60 * 24; // 1 day between cohort reports

export function useRunWatchedWalletCohort() {
const { wallets } = useWallets();

useEffect(() => {
const watchedWallets = Object.values(wallets || {}).filter(wallet => wallet.type === walletTypes.readOnly);
if (!watchedWallets.length) {
return;
}

const lastReported = ls.watchedWalletCohort.get(['lastReported']);
if (lastReported && Date.now() - lastReported < WATCHED_WALLET_COHORT_INTERVAL) {
return;
}

ls.watchedWalletCohort.set(['lastReported'], Date.now());
analyticsV2.track(analyticsV2.event.watchedWalletCohort, {
numWatchedWallets: watchedWallets.length,
watchedWalletsAddresses: watchedWallets.flatMap(wallet => wallet.addresses.map(acc => acc.address)),
});
}, [wallets]);
}
3 changes: 3 additions & 0 deletions src/hooks/useApplicationSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@ import { initListeners as initWalletConnectListeners, initWalletConnectPushNotif
import isTestFlight from '@/helpers/isTestFlight';
import { PerformanceTracking } from '@/performance/tracking';
import { PerformanceMetrics } from '@/performance/tracking/types/PerformanceMetrics';
import { useRunWatchedWalletCohort } from '@/helpers/runWatchedWalletCohort';

export function useApplicationSetup() {
const [initialRoute, setInitialRoute] = useState<InitialRoute>(null);

useRunWatchedWalletCohort();

const identifyFlow = useCallback(async () => {
const address = await loadAddress();
if (address) {
Expand Down
69 changes: 58 additions & 11 deletions src/hooks/useImportingWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import usePrevious from './usePrevious';
import useWalletENSAvatar from './useWalletENSAvatar';
import useWallets from './useWallets';
import { WrappedAlert as Alert } from '@/helpers/alert';
import { analytics } from '@/analytics';
import { analytics, analyticsV2 } from '@/analytics';
import { PROFILES, useExperimentalFlag } from '@/config';
import { fetchReverseRecord } from '@/handlers/ens';
import { getProvider, isValidBluetoothDeviceId, resolveUnstoppableDomain } from '@/handlers/web3';
Expand Down Expand Up @@ -110,7 +110,19 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
);

const handlePressImportButton = useCallback(
async (forceColor: any, forceAddress: any, forceEmoji: any = null, avatarUrl: any) => {
async ({
forceColor,
forceAddress = '',
forceEmoji,
avatarUrl,
type = 'import',
}: {
forceColor?: string | number;
forceAddress?: string;
forceEmoji?: string;
avatarUrl?: string;
type?: 'import' | 'watch';
} = {}) => {
setBusy(true);
analytics.track('Tapped "Import" button');
// guard against pressEvent coming in as forceColor if
Expand All @@ -135,9 +147,17 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
}
setResolvedAddress(address);
name = forceEmoji ? `${forceEmoji} ${input}` : input;
avatarUrl = avatarUrl || (avatar && avatar?.imageUrl);
const finalAvatarUrl = avatarUrl || (avatar && avatar?.imageUrl);
setBusy(false);
startImportProfile(name, guardedForceColor, address, avatarUrl);

if (type === 'watch') {
analyticsV2.track(analyticsV2.event.watchWallet, {
addressOrEnsName: input, // ENS name
address,
});
}

startImportProfile(name, guardedForceColor, address, finalAvatarUrl);
analytics.track('Show wallet profile modal for ENS address', {
address,
input,
Expand All @@ -159,6 +179,14 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
setResolvedAddress(address);
name = forceEmoji ? `${forceEmoji} ${input}` : input;
setBusy(false);

if (type === 'watch') {
analyticsV2.track(analyticsV2.event.watchWallet, {
addressOrEnsName: input, // unstoppable domain name
address,
});
}

// @ts-expect-error ts-migrate(2554) FIXME: Expected 4 arguments, but got 3.
startImportProfile(name, guardedForceColor, address);
analytics.track('Show wallet profile modal for Unstoppable address', {
Expand All @@ -171,15 +199,18 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
return;
}
} else if (isValidAddress(input)) {
let finalAvatarUrl: string | null | undefined = avatarUrl;
let ens = input;
try {
const ens = await fetchReverseRecord(input);
ens = await fetchReverseRecord(input);
if (ens && ens !== input) {
name = forceEmoji ? `${forceEmoji} ${ens}` : ens;
if (!avatarUrl && profilesEnabled) {
const avatar = await fetchENSAvatar(name, { swallowError: true });
avatarUrl = avatar?.imageUrl;
finalAvatarUrl = avatar?.imageUrl;
}
}

analytics.track('Show wallet profile modal for read only wallet', {
ens,
input,
Expand All @@ -188,8 +219,15 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
logger.error(new RainbowError(`[useImportingWallet]: Error resolving ENS during wallet import: ${e}`));
}
setBusy(false);
// @ts-expect-error ts-migrate(2554) FIXME: Expected 4 arguments, but got 3.
startImportProfile(name, guardedForceColor, input);

if (type === 'watch') {
analyticsV2.track(analyticsV2.event.watchWallet, {
addressOrEnsName: ens,
address: input,
});
}

startImportProfile(name, guardedForceColor, input, finalAvatarUrl);
} else {
try {
setTimeout(async () => {
Expand All @@ -200,17 +238,26 @@ export default function useImportingWallet({ showImportModal = true } = {}) {
return null;
}
const ens = await fetchReverseRecord(walletResult.address);
let finalAvatarUrl: string | null | undefined = avatarUrl;
if (ens && ens !== input) {
name = forceEmoji ? `${forceEmoji} ${ens}` : ens;
if (!avatarUrl && profilesEnabled) {
if (!finalAvatarUrl && profilesEnabled) {
const avatar = await fetchENSAvatar(name, {
swallowError: true,
});
avatarUrl = avatar?.imageUrl;
finalAvatarUrl = avatar?.imageUrl;
}
}
setBusy(false);
startImportProfile(name, guardedForceColor, walletResult.address, avatarUrl);

if (type === 'watch') {
analyticsV2.track(analyticsV2.event.watchWallet, {
addressOrEnsName: ens,
address: input,
});
}

startImportProfile(name, guardedForceColor, walletResult.address, finalAvatarUrl);
analytics.track('Show wallet profile modal for imported wallet', {
address: walletResult.address,
type: walletResult.type,
Expand Down
8 changes: 8 additions & 0 deletions src/resources/favorites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useQuery } from '@tanstack/react-query';
import { omit } from 'lodash';
import { externalTokenQueryKey, fetchExternalToken } from './assets/externalAssetsQuery';
import { chainsIdByName, chainsName } from '@/chains';
import { analyticsV2 } from '@/analytics';

export const favoritesQueryKey = createQueryKey('favorites', {}, { persisterVersion: 4 });

Expand Down Expand Up @@ -123,6 +124,13 @@ export async function toggleFavorite(address: string, chainId = ChainId.mainnet)
queryClient.setQueryData(favoritesQueryKey, omit(favorites, uniqueId));
} else {
const metadata = await fetchMetadata([lowercasedAddress], chainId);
analyticsV2.track(analyticsV2.event.addFavoriteToken, {
address: lowercasedAddress,
chainId,
name: metadata[uniqueId].name,
symbol: metadata[uniqueId].symbol,
});

queryClient.setQueryData(favoritesQueryKey, { ...favorites, ...metadata });
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/AddWalletSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const AddWalletSheet = () => {
};

const onPressWatch = () => {
analytics.track('Tapped "Add an existing wallet"');
analytics.track('Tapped "Watch an Ethereum Address"');
analyticsV2.track(analyticsV2.event.addWalletFlowStarted, {
isFirstWallet,
type: 'watch',
Expand Down
3 changes: 1 addition & 2 deletions src/screens/ImportOrWatchWalletSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ export const ImportOrWatchWalletSheet = () => {
multiline
numberOfLines={3}
onSubmitEditing={() => {
// @ts-expect-error callback needs refactor
if (isSecretValid) handlePressImportButton();
if (isSecretValid) handlePressImportButton({ type });
}}
placeholder={i18n.t(TRANSLATIONS[type].placeholder)}
placeholderTextColor={labelTertiary}
Expand Down
4 changes: 3 additions & 1 deletion src/storage/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MMKV } from 'react-native-mmkv';

import { Account, Cards, Campaigns, Device, Review } from '@/storage/schema';
import { Account, Cards, Campaigns, Device, Review, WatchedWalletCohort } from '@/storage/schema';
import { EthereumAddress, RainbowTransaction } from '@/entities';
import { SecureStorage } from '@coinbase/mobile-wallet-protocol-host';
import { ChainId } from '@/chains/types';
Expand Down Expand Up @@ -135,3 +135,5 @@ export const mwp: SecureStorage = {
mwpStorage.remove([key]);
},
};

export const watchedWalletCohort = new Storage<[], WatchedWalletCohort>({ id: 'watchedWalletCohort' });
4 changes: 4 additions & 0 deletions src/storage/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ export type Campaigns = CampaignKeys & CampaignMetadata;
export type Cards = {
[cardKey: string]: boolean;
};

export type WatchedWalletCohort = {
lastReported: ReturnType<typeof Date.now>;
};

0 comments on commit 27b2f7e

Please sign in to comment.