Skip to content

Commit

Permalink
Add analytics (#5805)
Browse files Browse the repository at this point in the history
* add analytics

* clean up analytics and add bridging and native values

* add native values and cleanup

* fix lint

* fix cast

* code review changes
  • Loading branch information
walmat authored Jun 11, 2024
1 parent 0619c71 commit ae62ef9
Show file tree
Hide file tree
Showing 12 changed files with 204 additions and 46 deletions.
11 changes: 9 additions & 2 deletions src/__swaps__/screens/Swap/components/FlipButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,27 @@ import { AnimatedBlurView } from '@/__swaps__/screens/Swap/components/AnimatedBl
import { useSwapContext } from '@/__swaps__/screens/Swap/providers/swap-provider';
import { TIMING_CONFIGS } from '@/components/animations/animationConfigs';
import { SwapAssetType } from '@/__swaps__/types/swap';
import { analyticsV2 } from '@/analytics';

export const FlipButton = () => {
const { isDarkMode } = useColorMode();

const { AnimatedSwapStyles, internalSelectedInputAsset, internalSelectedOutputAsset, setAsset } = useSwapContext();
const { AnimatedSwapStyles, internalSelectedInputAsset, internalSelectedOutputAsset, setAsset, SwapInputController } = useSwapContext();

const handleSwapAssets = useCallback(() => {
if (internalSelectedInputAsset.value && internalSelectedOutputAsset.value) {
const assetTypeToSet = SwapAssetType.outputAsset;
const assetToSet = internalSelectedInputAsset.value;

analyticsV2.track(analyticsV2.event.swapsFlippedAssets, {
inputAmount: SwapInputController.inputValues.value.inputAmount,
previousInputAsset: internalSelectedInputAsset.value,
previousOutputAsset: internalSelectedOutputAsset.value,
});

setAsset({ type: assetTypeToSet, asset: assetToSet });
}
}, [internalSelectedInputAsset, internalSelectedOutputAsset, /* lastTypedInput, */ setAsset]);
}, [SwapInputController.inputValues, internalSelectedInputAsset, internalSelectedOutputAsset, setAsset]);

const flipButtonInnerStyles = useAnimatedStyle(() => {
return {
Expand Down
28 changes: 16 additions & 12 deletions src/__swaps__/screens/Swap/components/GasButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ChainId } from '@/__swaps__/types/chains';
import { weiToGwei } from '@/__swaps__/utils/ethereum';
import { OnPressMenuItemEventObject } from 'react-native-ios-context-menu';
import { getCachedCurrentBaseFee, useMeteorologySuggestions } from '@/__swaps__/utils/meteorology';
import { add } from '@/__swaps__/utils/numbers';
import { ContextMenu } from '@/components/context-menu';
Expand All @@ -8,15 +9,16 @@ import ContextMenuButton from '@/components/native-context-menu/contextMenu';
import { Box, Inline, Text, TextIcon, useColorMode, useForegroundColor } from '@/design-system';
import { IS_ANDROID } from '@/env';
import * as i18n from '@/languages';
import { useSwapsStore } from '@/state/swaps/swapsStore';
import { swapsStore } from '@/state/swaps/swapsStore';
import { gasUtils } from '@/utils';
import React, { ReactNode, useCallback, useMemo } from 'react';
import { StyleSheet } from 'react-native';
import { runOnJS, runOnUI } from 'react-native-reanimated';
import { ETH_COLOR, ETH_COLOR_DARK, THICK_BORDER_WIDTH } from '../constants';
import { formatNumber } from '../hooks/formatNumber';
import { GasSettings, useCustomGasSettings } from '../hooks/useCustomGas';
import { GasSpeed, setSelectedGasSpeed, useSelectedGas, useSelectedGasSpeed } from '../hooks/useSelectedGas';
import { GasSpeed } from '@/__swaps__/types/gas';
import { setSelectedGasSpeed, useSelectedGas, useSelectedGasSpeed } from '../hooks/useSelectedGas';
import { useSwapContext } from '../providers/swap-provider';
import { EstimatedSwapGasFee } from './EstimatedSwapGasFee';
import { GestureHandlerV1Button } from './GestureHandlerV1Button';
Expand All @@ -26,7 +28,7 @@ const { GAS_ICONS } = gasUtils;
const GAS_BUTTON_HIT_SLOP = 16;

function EstimatedGasFee() {
const chainId = useSwapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const chainId = swapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const gasSettings = useSelectedGas(chainId);

return (
Expand All @@ -40,7 +42,7 @@ function EstimatedGasFee() {
}

function SelectedGas() {
const chainId = useSwapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const chainId = swapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const selectedGasSpeed = useSelectedGasSpeed(chainId);

return (
Expand Down Expand Up @@ -83,30 +85,32 @@ function keys<const T extends string>(obj: Record<T, any> | undefined) {
const GasMenu = ({ backToReview = false, children }: { backToReview?: boolean; children: ReactNode }) => {
const { SwapNavigation } = useSwapContext();

const chainId = useSwapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const chainId = swapsStore(s => s.inputAsset?.chainId || ChainId.mainnet);
const metereologySuggestions = useMeteorologySuggestions({ chainId });
const customGasSettings = useCustomGasSettings(chainId);

const menuOptions = useMemo(() => [...keys(metereologySuggestions.data), 'custom'] as const, [metereologySuggestions.data]);
const menuOptions = useMemo(() => [...keys(metereologySuggestions.data), GasSpeed.CUSTOM] as GasSpeed[], [metereologySuggestions.data]);

const handlePressSpeedOption = useCallback(
(selectedGasSpeed: GasSpeed) => {
setSelectedGasSpeed(chainId, selectedGasSpeed);

if (selectedGasSpeed === 'custom') {
if (selectedGasSpeed === GasSpeed.CUSTOM) {
runOnUI(SwapNavigation.handleShowGas)({ backToReview });
}
},
[SwapNavigation.handleShowGas, backToReview, chainId]
);

const handlePressMenuItem = useCallback(
({ nativeEvent: { actionKey } }: any) => handlePressSpeedOption(actionKey),
({ nativeEvent: { actionKey } }: OnPressMenuItemEventObject) => handlePressSpeedOption(actionKey as GasSpeed),
[handlePressSpeedOption]
);

const handlePressActionSheet = useCallback(
(buttonIndex: number) => handlePressSpeedOption(menuOptions[buttonIndex]),
(buttonIndex: number) => {
if (buttonIndex < 0) return;
handlePressSpeedOption(menuOptions[buttonIndex]);
},
[handlePressSpeedOption, menuOptions]
);

Expand All @@ -115,7 +119,7 @@ const GasMenu = ({ backToReview = false, children }: { backToReview?: boolean; c
if (IS_ANDROID) return gasOption;

const currentBaseFee = getCachedCurrentBaseFee(chainId);
const gasSettings = gasOption === 'custom' ? customGasSettings : metereologySuggestions.data?.[gasOption];
const gasSettings = gasOption === GasSpeed.CUSTOM ? customGasSettings : metereologySuggestions.data?.[gasOption];
const subtitle = getEstimatedFeeRangeInGwei(gasSettings, currentBaseFee);

return {
Expand Down Expand Up @@ -176,7 +180,7 @@ export function ReviewGasButton() {
const handleShowCustomGas = () => {
'worklet';

runOnJS(setSelectedGasSpeed)(internalSelectedInputAsset.value?.chainId || ChainId.mainnet, 'custom');
runOnJS(setSelectedGasSpeed)(internalSelectedInputAsset.value?.chainId || ChainId.mainnet, GasSpeed.CUSTOM);
SwapNavigation.handleShowGas({ backToReview: true });
};

Expand Down
5 changes: 3 additions & 2 deletions src/__swaps__/screens/Swap/components/GasPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { formatNumber } from '../hooks/formatNumber';
import { GasSettings, getCustomGasSettings, setCustomGasSettings, useCustomGasStore } from '../hooks/useCustomGas';
import { setSelectedGasSpeed, useSelectedGasSpeed } from '../hooks/useSelectedGas';
import { EstimatedSwapGasFee } from './EstimatedSwapGasFee';
import { GasSpeed } from '@/__swaps__/types/gas';

const { GAS_TRENDS } = gasUtils;

Expand Down Expand Up @@ -334,12 +335,12 @@ function saveCustomGasSettings() {
const { inputAsset } = useSwapsStore.getState();
const chainId = inputAsset?.chainId || ChainId.mainnet;
if (!unsaved) {
if (getCustomGasSettings(chainId)) setSelectedGasSpeed(chainId, 'custom');
if (getCustomGasSettings(chainId)) setSelectedGasSpeed(chainId, GasSpeed.CUSTOM);
return;
}

setCustomGasSettings(chainId, unsaved);
setSelectedGasSpeed(chainId, 'custom');
setSelectedGasSpeed(chainId, GasSpeed.CUSTOM);
useGasPanelStore.setState(undefined);
}

Expand Down
22 changes: 8 additions & 14 deletions src/__swaps__/screens/Swap/components/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,21 +77,15 @@ export const SearchInput = ({
};
});

const onInputSearchQueryChange = useDebouncedCallback(
(text: string) => {
userAssetsStore.getState().setSearchQuery(text);
},
50,
{ leading: true, trailing: true }
);
const onInputSearchQueryChange = useDebouncedCallback((text: string) => userAssetsStore.getState().setSearchQuery(text), 50, {
leading: true,
trailing: true,
});

const onOutputSearchQueryChange = useDebouncedCallback(
(text: string) => {
useSwapsStore.setState({ outputSearchQuery: text });
},
100,
{ leading: false, trailing: true }
);
const onOutputSearchQueryChange = useDebouncedCallback((text: string) => useSwapsStore.setState({ outputSearchQuery: text }), 100, {
leading: false,
trailing: true,
});

const isSearchFocused = useDerivedValue(
() =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { OnPressMenuItemEventObject } from 'react-native-ios-context-menu';
import { userAssetsStore } from '@/state/assets/userAssets';
import { useSharedValueState } from '@/hooks/reanimated/useSharedValueState';
import { chainNameForChainIdWithMainnetSubstitution } from '@/__swaps__/utils/chains';
import { analyticsV2 } from '@/analytics';
import { swapsStore } from '@/state/swaps/swapsStore';

type ChainSelectionProps = {
allText?: string;
Expand Down Expand Up @@ -50,6 +52,12 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:

const handleSelectChain = useCallback(
({ nativeEvent: { actionKey } }: Omit<OnPressMenuItemEventObject, 'isUsingActionSheetFallback'>) => {
analyticsV2.track(analyticsV2.event.swapsChangedChainId, {
inputAsset: swapsStore.getState().inputAsset,
type: output ? 'output' : 'input',
chainId: Number(actionKey) as ChainId,
});

if (output) {
setSelectedOutputChainId(Number(actionKey) as ChainId);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { userAssetsStore } from '@/state/assets/userAssets';
import { EXPANDED_INPUT_HEIGHT } from '../../constants';
import { DEVICE_WIDTH } from '@/utils/deviceUtils';
import { getStandardizedUniqueIdWorklet } from '@/__swaps__/utils/swaps';
import { swapsStore } from '@/state/swaps/swapsStore';
import { analyticsV2 } from '@/analytics';

interface SectionProp {
color: TextStyle['color'];
Expand Down Expand Up @@ -95,6 +97,16 @@ export const TokenToBuySection = ({ section }: { section: AssetToBuySection }) =
type: SwapAssetType.outputAsset,
asset: parsedAsset,
});

const { outputSearchQuery } = swapsStore.getState();

// track what search query the user had prior to selecting an asset
if (outputSearchQuery.trim().length) {
analyticsV2.track(analyticsV2.event.swapsSearchedForToken, {
query: outputSearchQuery,
type: 'output',
});
}
},
[internalSelectedInputAsset, internalSelectedOutputAsset, isFetching, isQuoteStale, setAsset]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { EXPANDED_INPUT_HEIGHT } from '../../constants';
import { DEVICE_WIDTH } from '@/utils/deviceUtils';
import { getStandardizedUniqueIdWorklet } from '@/__swaps__/utils/swaps';
import { useDelayedMount } from '@/hooks/useDelayedMount';
import { swapsStore } from '@/state/swaps/swapsStore';
import { analyticsV2 } from '@/analytics';

export const TokenToSellList = () => {
const shouldMount = useDelayedMount();
Expand Down Expand Up @@ -43,6 +45,16 @@ const TokenToSellListComponent = () => {
type: SwapAssetType.inputAsset,
asset: token,
});

const { inputSearchQuery } = userAssetsStore.getState();

// track what search query the user had prior to selecting an asset
if (inputSearchQuery.trim().length) {
analyticsV2.track(analyticsV2.event.swapsSearchedForToken, {
query: inputSearchQuery,
type: 'input',
});
}
},
[internalSelectedInputAsset, internalSelectedOutputAsset, isFetching, isQuoteStale, setAsset]
);
Expand Down
16 changes: 8 additions & 8 deletions src/__swaps__/screens/Swap/hooks/useSelectedGas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ import { getCachedGasSuggestions, useMeteorologySuggestions } from '@/__swaps__/
import { createRainbowStore } from '@/state/internal/createRainbowStore';
import { useMemo } from 'react';
import { getCustomGasSettings, useCustomGasSettings } from './useCustomGas';
import { GasSpeed } from '@/__swaps__/types/gas';

export type GasSpeed = 'custom' | 'urgent' | 'fast' | 'normal';
const useSelectedGasSpeedStore = createRainbowStore<{ [c in ChainId]?: GasSpeed }>(() => ({}), {
version: 0,
storageKey: 'preferred gas speed',
});
export const useSelectedGasSpeed = (chainId: ChainId) =>
useSelectedGasSpeedStore(s => {
const speed = s[chainId] || 'fast';
if (speed === 'custom' && getCustomGasSettings(chainId) === undefined) return 'fast';
const speed = s[chainId] || GasSpeed.FAST;
if (speed === GasSpeed.CUSTOM && getCustomGasSettings(chainId) === undefined) return GasSpeed.FAST;
return speed;
});
export const setSelectedGasSpeed = (chainId: ChainId, speed: GasSpeed) => useSelectedGasSpeedStore.setState({ [chainId]: speed });
export const getSelectedGasSpeed = (chainId: ChainId) => useSelectedGasSpeedStore.getState()[chainId] || 'fast';
export const getSelectedGasSpeed = (chainId: ChainId) => useSelectedGasSpeedStore.getState()[chainId] || GasSpeed.FAST;

export function useGasSettings(chainId: ChainId, speed: GasSpeed) {
const userCustomGasSettings = useCustomGasSettings(chainId);
const { data: metereologySuggestions } = useMeteorologySuggestions({
chainId,
enabled: speed !== 'custom',
enabled: speed !== GasSpeed.CUSTOM,
});

return useMemo(() => {
if (speed === 'custom') return userCustomGasSettings;
if (speed === GasSpeed.CUSTOM) return userCustomGasSettings;
return metereologySuggestions?.[speed];
}, [speed, userCustomGasSettings, metereologySuggestions]);
}
Expand All @@ -45,11 +45,11 @@ export function getGasSettingsBySpeed(chainId: ChainId) {
}

export function getGasSettings(speed: GasSpeed, chainId: ChainId) {
if (speed === 'custom') return getCustomGasSettings(chainId);
if (speed === GasSpeed.CUSTOM) return getCustomGasSettings(chainId);
return getCachedGasSuggestions(chainId)?.[speed];
}

export function getSelectedGas(chainId: ChainId) {
const selectedGasSpeed = useSelectedGasSpeedStore.getState()[chainId] || 'fast';
const selectedGasSpeed = useSelectedGasSpeedStore.getState()[chainId] || GasSpeed.FAST;
return getGasSettings(selectedGasSpeed, chainId);
}
8 changes: 8 additions & 0 deletions src/__swaps__/screens/Swap/hooks/useSwapInputsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import {
} from '@/resources/assets/externalAssetsQuery';
import { ethereumUtils } from '@/utils';
import { queryClient } from '@/react-query';
import { userAssetsStore } from '@/state/assets/userAssets';
import { analyticsV2 } from '@/analytics';
import { divWorklet, equalWorklet, greaterThanWorklet, mulWorklet, toFixedWorklet } from '@/__swaps__/safe-math/SafeMath';

function getInitialInputValues(initialSelectedInputAsset: ExtendedAnimatedAssetWithColors | null) {
Expand Down Expand Up @@ -498,6 +500,12 @@ export function useSwapInputsController({
)
: undefined;

analyticsV2.track(analyticsV2.event.swapsReceivedQuote, {
inputAsset: internalSelectedInputAsset.value,
outputAsset: internalSelectedOutputAsset.value,
quote: quoteResponse,
});

runOnUI(() => {
setQuote({
data: quoteResponse,
Expand Down
Loading

0 comments on commit ae62ef9

Please sign in to comment.