Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize backendNetworks store #6409

Merged
merged 6 commits into from
Jan 23, 2025
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
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(
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason not to use useRef here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it's mostly a semantic choice, seems a bit cleaner to use useState since you can omit the setter, making it closer to naturally read only, and with useState you don't need to deal with .current.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds reasonable to me. Was just curious!

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
Loading