Skip to content

Commit

Permalink
Optimize backendNetworks store (#6409)
Browse files Browse the repository at this point in the history
* Optimize backendNetworks store, remove worklet functions

* Restore defaultSimplehashNetwork chain list

* Clean up store methods, improve memoization

* Avoid repeated store access in swap buy list info icons

* Migrate to createQueryStore, remove sync components

Not sure why there were two instances of <BackendNetworks />

* staleTime: 15 minutes → 10 minutes
  • Loading branch information
christianbaroni authored Jan 23, 2025
1 parent 9c916f5 commit 2015cf9
Show file tree
Hide file tree
Showing 14 changed files with 397 additions and 723 deletions.
2 changes: 0 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import { IS_ANDROID, IS_DEV } from '@/env';
import { prefetchDefaultFavorites } from '@/resources/favorites';
import Routes from '@/navigation/Routes';
import { BackupsSync } from '@/state/sync/BackupsSync';
import { BackendNetworks } from '@/components/BackendNetworks';
import { AbsolutePortalRoot } from './components/AbsolutePortal';
import { getAndroidBottomInset } from './utils/deviceUtils';

Expand Down Expand Up @@ -85,7 +84,6 @@ function App({ walletReady }: AppProps) {
<NotificationsHandler walletReady={walletReady} />
<DeeplinkHandler initialRoute={initialRoute} walletReady={walletReady} />
<BackupsSync />
<BackendNetworks />
<AbsolutePortalRoot />
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import React, { useMemo } from 'react';
import { Image, StyleSheet, View } from 'react-native';
import { Image, View } from 'react-native';
import { getChainBadgeStyles } from '@/components/coin-icon/ChainImage';
import { globalColors, useColorMode } from '@/design-system';
import { useColorMode } from '@/design-system';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { ChainId } from '@/state/backendNetworks/types';
import { useSwapsStore } from '@/state/swaps/swapsStore';
Expand Down Expand Up @@ -41,16 +41,3 @@ export function AnimatedChainImage({
</View>
);
}

const sx = StyleSheet.create({
badge: {
position: 'absolute',
shadowColor: globalColors.grey100,
shadowOffset: {
height: 4,
width: 0,
},
shadowOpacity: 0.2,
shadowRadius: 6,
},
});
23 changes: 5 additions & 18 deletions src/__swaps__/screens/Swap/components/AnimatedChainImage.ios.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useMemo } from 'react';
import { StyleSheet, View } from 'react-native';
import { View } from 'react-native';
import { useAnimatedProps, useDerivedValue } from 'react-native-reanimated';
import { AnimatedFasterImage } from '@/components/AnimatedComponents/AnimatedFasterImage';
import { BLANK_BASE64_PIXEL } from '@/components/DappBrowser/constants';
import { getChainBadgeStyles } from '@/components/coin-icon/ChainImage';
import { DEFAULT_FASTER_IMAGE_CONFIG } from '@/components/images/ImgixImage';
import { globalColors, useColorMode } from '@/design-system';
import { getChainsBadgeWorklet, useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { useColorMode } from '@/design-system';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { ChainId } from '@/state/backendNetworks/types';
import { useSwapContext } from '../providers/swap-provider';

Expand All @@ -20,15 +20,15 @@ export function AnimatedChainImage({
size?: number;
}) {
const { internalSelectedInputAsset, internalSelectedOutputAsset } = useSwapContext();
const backendNetworks = useBackendNetworksStore(state => state.backendNetworksSharedValue);
const networkBadges = useBackendNetworksStore(state => state.getChainsBadge());

const url = useDerivedValue(() => {
const asset = assetType === 'input' ? internalSelectedInputAsset : internalSelectedOutputAsset;
const chainId = asset?.value?.chainId;

let url = 'eth';
if (chainId !== undefined && !(!showMainnetBadge && chainId === ChainId.mainnet)) {
url = getChainsBadgeWorklet(backendNetworks)[chainId];
url = networkBadges[chainId];
}
return url;
});
Expand All @@ -55,16 +55,3 @@ export function AnimatedChainImage({
</View>
);
}

const sx = StyleSheet.create({
badge: {
position: 'absolute',
shadowColor: globalColors.grey100,
shadowOffset: {
height: 4,
width: 0,
},
shadowOpacity: 0.2,
shadowRadius: 6,
},
});
98 changes: 51 additions & 47 deletions src/__swaps__/screens/Swap/components/CoinRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import React, { useCallback, useMemo } from 'react';
import { GestureResponderEvent } from 'react-native';
import { OnPressMenuItemEventObject } from 'react-native-ios-context-menu';
import RainbowCoinIcon from '@/components/coin-icon/RainbowCoinIcon';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';

export const COIN_ROW_WITH_PADDING_HEIGHT = 56;

Expand All @@ -41,6 +40,7 @@ function determineFavoriteAddressAndChain(address: AddressOrEth, mainnetAddress:
interface InputCoinRowProps {
isFavorite?: boolean;
isTrending?: boolean;
isSupportedChain?: never;
nativePriceChange?: string;
onPress: (asset: ParsedSearchAsset | null) => void;
output?: false | undefined;
Expand All @@ -56,12 +56,13 @@ interface OutputCoinRowProps extends PartialAsset {
output: true;
nativePriceChange?: string;
isTrending?: boolean;
isSupportedChain: boolean;
testID?: string;
}

type CoinRowProps = InputCoinRowProps | OutputCoinRowProps;

export function CoinRow({ isFavorite, onPress, output, uniqueId, testID, ...assetProps }: CoinRowProps) {
export function CoinRow({ isFavorite, isSupportedChain, onPress, output, uniqueId, testID, ...assetProps }: CoinRowProps) {
const inputAsset = useUserAssetsStore(state => (output ? undefined : state.getUserAsset(uniqueId)));
const outputAsset = output ? (assetProps as PartialAsset) : undefined;

Expand Down Expand Up @@ -165,7 +166,7 @@ export function CoinRow({ isFavorite, onPress, output, uniqueId, testID, ...asse
<Column width="content">
<Box paddingLeft="12px" paddingRight="20px">
<Inline space="10px">
<InfoButton address={address} chainId={chainId} />
<InfoButton address={address} chainId={chainId} isSupportedChain={isSupportedChain} />
<CoinRowButton color={favoritesIconColor} onPress={handleToggleFavorite} icon="􀋃" weight="black" />
</Inline>
</Box>
Expand All @@ -176,75 +177,78 @@ export function CoinRow({ isFavorite, onPress, output, uniqueId, testID, ...asse
);
}

const InfoButton = ({ address, chainId }: { address: string; chainId: ChainId }) => {
const getSupportedChainIds = useBackendNetworksStore(state => state.getSupportedChainIds);
const supportedChain = getSupportedChainIds().includes(chainId);

const InfoButton = ({ address, chainId, isSupportedChain }: { address: string; chainId: ChainId; isSupportedChain: boolean }) => {
const handleCopy = useCallback(() => {
haptics.selection();
setClipboard(address);
}, [address]);

const options = {
copy: {
title: i18n.t(i18n.l.exchange.coin_row.copy_contract_address),
action: handleCopy,
},
...(supportedChain
? {
blockExplorer: {
title: i18n.t(i18n.l.exchange.coin_row.view_on, { blockExplorerName: startCase(ethereumUtils.getBlockExplorer({ chainId })) }),
action: () => ethereumUtils.openAddressInBlockExplorer({ address, chainId }),
},
}
: {}),
};
const { options, menuConfig } = useMemo(() => {
const options = {
copy: {
title: i18n.t(i18n.l.exchange.coin_row.copy_contract_address),
action: handleCopy,
},
...(isSupportedChain
? {
blockExplorer: {
title: i18n.t(i18n.l.exchange.coin_row.view_on, {
blockExplorerName: startCase(ethereumUtils.getBlockExplorer({ chainId })),
}),
action: () => ethereumUtils.openAddressInBlockExplorer({ address, chainId }),
},
}
: {}),
};

const menuConfig = {
menuItems: [
{
actionKey: 'copyAddress',
actionTitle: options.copy.title,
icon: {
iconType: 'SYSTEM',
iconValue: 'doc.on.doc',
const menuConfig = {
menuItems: [
{
actionKey: 'copyAddress',
actionTitle: options.copy.title,
icon: {
iconType: 'SYSTEM',
iconValue: 'doc.on.doc',
},
},
},
...(supportedChain
? [
{
actionKey: 'blockExplorer',
actionTitle: options.blockExplorer?.title,
icon: {
iconType: 'SYSTEM',
iconValue: 'link',
...(isSupportedChain
? [
{
actionKey: 'blockExplorer',
actionTitle: options.blockExplorer?.title,
icon: {
iconType: 'SYSTEM',
iconValue: 'link',
},
},
},
]
: []),
],
menuTitle: '',
};
]
: []),
],
menuTitle: '',
};

return { options, menuConfig };
}, [isSupportedChain, handleCopy, chainId, address]);

const handlePressMenuItem = async ({ nativeEvent: { actionKey } }: OnPressMenuItemEventObject) => {
if (actionKey === 'copyAddress') {
options.copy.action();
} else if (actionKey === 'blockExplorer' && supportedChain) {
} else if (actionKey === 'blockExplorer' && isSupportedChain) {
options.blockExplorer?.action();
}
};

const onPressAndroid = () =>
showActionSheetWithOptions(
{
options: [options.copy.title, ...(supportedChain ? [options.blockExplorer?.title] : [])],
options: [options.copy.title, ...(isSupportedChain ? [options.blockExplorer?.title] : [])],
showSeparators: true,
},
(idx: number) => {
if (idx === 0) {
options.copy.action();
}
if (idx === 1 && supportedChain) {
if (idx === 1 && isSupportedChain) {
options.blockExplorer?.action();
}
}
Expand Down
8 changes: 3 additions & 5 deletions src/__swaps__/screens/Swap/components/ReviewPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { useSelectedGasSpeed } from '../hooks/useSelectedGas';
import { NavigationSteps, useSwapContext } from '../providers/swap-provider';
import { EstimatedSwapGasFee, EstimatedSwapGasFeeSlot } from './EstimatedSwapGasFee';
import { UnmountOnAnimatedReaction } from './UnmountOnAnimatedReaction';
import { getChainsLabelWorklet, useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { ChainId } from '@/state/backendNetworks/types';

const UNKNOWN_LABEL = i18n.t(i18n.l.swap.unknown);
Expand Down Expand Up @@ -245,17 +245,15 @@ export const SlippageRow = () => {
export function ReviewPanel() {
const { navigate } = useNavigation();
const { isDarkMode } = useColorMode();
const backendNetworks = useBackendNetworksStore(state => state.backendNetworksSharedValue);
const { configProgress, lastTypedInput, internalSelectedInputAsset, internalSelectedOutputAsset, quote } = useSwapContext();
const chainLabels = useBackendNetworksStore(state => state.getChainsLabel());

const labelTertiary = useForegroundColor('labelTertiary');
const separator = useForegroundColor('separator');

const unknown = i18n.t(i18n.l.swap.unknown);

const chainName = useDerivedValue(
() => getChainsLabelWorklet(backendNetworks)[internalSelectedInputAsset.value?.chainId ?? ChainId.mainnet]
);
const chainName = useDerivedValue(() => chainLabels[internalSelectedInputAsset.value?.chainId ?? ChainId.mainnet]);

const minReceivedOrMaxSoldLabel = useDerivedValue(() => {
const isInputBasedTrade = lastTypedInput.value === 'inputAmount' || lastTypedInput.value === 'inputNativeValue';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useAccountAccentColor } from '@/hooks';
import { useSharedValueState } from '@/hooks/reanimated/useSharedValueState';
import { userAssetsStore, useUserAssetsStore } from '@/state/assets/userAssets';
import { swapsStore } from '@/state/swaps/swapsStore';
import { getChainsBadgeWorklet, getChainsLabelWorklet, useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';
import { DropdownMenu, MenuItem } from '@/components/DropdownMenu';

type ChainSelectionProps = {
Expand All @@ -27,7 +27,9 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
const { isDarkMode } = useColorMode();
const { accentColor: accountColor } = useAccountAccentColor();
const { selectedOutputChainId, setSelectedOutputChainId } = useSwapContext();
const backendNetworks = useBackendNetworksStore(state => state.backendNetworksSharedValue);

const chainLabels = useBackendNetworksStore(state => state.getChainsLabel());
const networkBadges = useBackendNetworksStore(state => state.getChainsBadge());

// chains sorted by balance on output, chains without balance hidden on input
const balanceSortedChainList = useUserAssetsStore(state => (output ? state.getBalanceSortedChainList() : state.getChainsWithBalance()));
Expand All @@ -45,8 +47,6 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
}, [accountColor, isDarkMode]);

const chainName = useDerivedValue(() => {
const chainLabels = getChainsLabelWorklet(backendNetworks);

return output
? chainLabels[selectedOutputChainId.value]
: inputListFilter.value === 'all'
Expand Down Expand Up @@ -79,11 +79,11 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
supportedChains = balanceSortedChainList.map(chainId => {
return {
actionKey: `${chainId}`,
actionTitle: getChainsLabelWorklet(backendNetworks)[chainId],
actionTitle: chainLabels[chainId],
icon: {
iconType: 'REMOTE',
iconValue: {
uri: getChainsBadgeWorklet(backendNetworks)[chainId],
uri: networkBadges[chainId],
},
},
};
Expand All @@ -103,7 +103,7 @@ export const ChainSelection = memo(function ChainSelection({ allText, output }:
return {
menuItems: supportedChains,
};
}, [backendNetworks, balanceSortedChainList, output]);
}, [balanceSortedChainList, chainLabels, networkBadges, output]);

return (
<Box as={Animated.View} paddingBottom={output ? '8px' : { custom: 14 }} paddingHorizontal="20px" paddingTop="20px">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ import * as i18n from '@/languages';
import { userAssetsStore } from '@/state/assets/userAssets';
import { swapsStore } from '@/state/swaps/swapsStore';
import { DEVICE_WIDTH } from '@/utils/deviceUtils';
import React, { memo, useCallback, useMemo } from 'react';
import React, { memo, useCallback, useMemo, useState } from 'react';
import Animated, { runOnUI, useAnimatedProps, useAnimatedStyle, withTiming } from 'react-native-reanimated';
import { EXPANDED_INPUT_HEIGHT, FOCUSED_INPUT_HEIGHT } from '../../constants';
import { ChainSelection } from './ChainSelection';
import { useBackendNetworksStore } from '@/state/backendNetworks/backendNetworks';

export const BUY_LIST_HEADER_HEIGHT = 20 + 10 + 8; // paddingTop + height + paddingBottom

Expand Down Expand Up @@ -97,6 +98,13 @@ export const TokenToBuyList = () => {
const { internalSelectedInputAsset, internalSelectedOutputAsset, isFetching, isQuoteStale, outputProgress, setAsset } = useSwapContext();
const { results: sections, isLoading } = useSearchCurrencyLists();

const [supportedChainsBooleanMap] = useState(
useBackendNetworksStore
.getState()
.getSupportedChainIds()
.reduce((acc, chainId) => ({ ...acc, [chainId]: true }), {} as Record<ChainId, boolean>)
);

const handleSelectToken = useCallback(
(token: SearchAsset) => {
runOnUI(() => {
Expand Down Expand Up @@ -174,6 +182,7 @@ export const TokenToBuyList = () => {
icon_url={item.icon_url}
// @ts-expect-error item.favorite does not exist - it does for favorites, need to fix the type
isFavorite={item.favorite}
isSupportedChain={supportedChainsBooleanMap[item.chainId] ?? false}
mainnetAddress={item.mainnetAddress}
name={item.name}
onPress={() => handleSelectToken(item)}
Expand Down
Loading

0 comments on commit 2015cf9

Please sign in to comment.