Skip to content

Commit

Permalink
swap search fixes (#1732)
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-schrammel authored Oct 21, 2024
1 parent 055e774 commit 4c3e583
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 211 deletions.
16 changes: 9 additions & 7 deletions src/core/resources/search/tokenDiscovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@ const tokenSearchDiscoveryHttp = createHttpClient({
timeout: 30000,
});

type TokenDiscoveryArgs = {
chainId: ChainId;
};

const tokenDiscoveryQueryKey = ({ chainId }: TokenDiscoveryArgs) =>
const tokenDiscoveryQueryKey = ({ chainId }: { chainId: ChainId }) =>
createQueryKey('TokenDiscovery', { chainId }, { persisterVersion: 1 });

async function tokenSearchQueryFunction({
Expand All @@ -36,12 +32,18 @@ async function tokenSearchQueryFunction({
}
}

export function useTokenDiscovery({ chainId }: TokenDiscoveryArgs) {
export function useTokenDiscovery<T = SearchAsset[]>({
chainId,
select,
}: {
chainId: ChainId;
select?: (data: SearchAsset[]) => T;
}) {
return useQuery({
queryKey: tokenDiscoveryQueryKey({ chainId }),
queryFn: tokenSearchQueryFunction,
staleTime: 15 * 60 * 1000, // 15 min
gcTime: 24 * 60 * 60 * 1000, // 1 day
select: (data) => data.slice(0, 3),
select,
});
}
39 changes: 6 additions & 33 deletions src/core/resources/search/tokenSearch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { isAddress } from '@ethersproject/address';
import { useQueries, useQuery } from '@tanstack/react-query';
import qs from 'qs';

Expand Down Expand Up @@ -27,9 +26,7 @@ import { parseTokenSearch } from './parseTokenSearch';
export type TokenSearchArgs = {
chainId: ChainId;
fromChainId?: ChainId | '';
keys: TokenSearchAssetKey[];
list: TokenSearchListId;
threshold: TokenSearchThreshold;
query: string;
};

Expand All @@ -46,14 +43,12 @@ export type TokenSearchAllNetworksArgs = {
const tokenSearchQueryKey = ({
chainId,
fromChainId,
keys,
list,
threshold,
query,
}: TokenSearchArgs) =>
createQueryKey(
'TokenSearch',
{ chainId, fromChainId, keys, list, threshold, query },
{ chainId, fromChainId, list, query },
{ persisterVersion: 2 },
);

Expand All @@ -63,26 +58,19 @@ type TokenSearchQueryKey = ReturnType<typeof tokenSearchQueryKey>;
// Query Function

async function tokenSearchQueryFunction({
queryKey: [{ chainId, fromChainId, keys, list, threshold, query }],
queryKey: [{ chainId, fromChainId, list, query }],
}: QueryFunctionArgs<typeof tokenSearchQueryKey>) {
const queryParams: {
keys: string;
list: TokenSearchListId;
threshold: TokenSearchThreshold;
query?: string;
fromChainId?: number;
} = {
keys: keys.join(','),
list,
threshold,
query,
};
if (fromChainId) {
queryParams.fromChainId = fromChainId;
}
if (isAddress(query)) {
queryParams.keys = `networks.${chainId}.address`;
}
const url = `/${chainId}/?${qs.stringify(queryParams)}`;
try {
const tokenSearch = await tokenSearchHttp.get<{ data: SearchAsset[] }>(url);
Expand All @@ -100,7 +88,7 @@ type TokenSearchResult = QueryFunctionResult<typeof tokenSearchQueryFunction>;
// Query Fetcher

export async function fetchTokenSearch(
{ chainId, fromChainId, keys, list, threshold, query }: TokenSearchArgs,
{ chainId, fromChainId, list, query }: TokenSearchArgs,
config: QueryConfig<
TokenSearchResult,
Error,
Expand All @@ -112,9 +100,7 @@ export async function fetchTokenSearch(
queryKey: tokenSearchQueryKey({
chainId,
fromChainId,
keys,
list,
threshold,
query,
}),
queryFn: tokenSearchQueryFunction,
Expand All @@ -126,7 +112,7 @@ export async function fetchTokenSearch(
// Query Hook

export function useTokenSearch(
{ chainId, fromChainId, keys, list, threshold, query }: TokenSearchArgs,
{ chainId, fromChainId, list, query }: TokenSearchArgs,
config: QueryConfig<
TokenSearchResult,
Error,
Expand All @@ -138,9 +124,7 @@ export function useTokenSearch(
queryKey: tokenSearchQueryKey({
chainId,
fromChainId,
keys,
list,
threshold,
query,
}),
queryFn: tokenSearchQueryFunction,
Expand All @@ -152,12 +136,7 @@ export function useTokenSearch(
// Query Hook

export function useTokenSearchAllNetworks(
{
keys,
list,
threshold,
query,
}: Omit<TokenSearchArgs, 'chainId' | 'fromChainId'>,
{ list, query }: Omit<TokenSearchArgs, 'chainId' | 'fromChainId'>,
config: QueryConfig<
TokenSearchResult,
Error,
Expand All @@ -172,13 +151,7 @@ export function useTokenSearchAllNetworks(
const queries = useQueries({
queries: rainbowSupportedChains.map(({ id: chainId }) => {
return {
queryKey: tokenSearchQueryKey({
chainId,
keys,
list,
threshold,
query,
}),
queryKey: tokenSearchQueryKey({ chainId, list, query }),
queryFn: tokenSearchQueryFunction,
refetchOnWindowFocus: false,
...config,
Expand Down
20 changes: 0 additions & 20 deletions src/entries/popup/components/CommandK/useSearchableTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { useHideSmallBalancesStore } from '~/core/state/currentSettings/hideSmal
import { useTestnetModeStore } from '~/core/state/currentSettings/testnetMode';
import { useHiddenAssetStore } from '~/core/state/hiddenAssets/hiddenAssets';
import { ParsedUserAsset } from '~/core/types/assets';
import { TokenSearchAssetKey, TokenSearchThreshold } from '~/core/types/search';
import { isENSAddressFormat } from '~/core/utils/ethereum';
import { isLowerCaseMatch } from '~/core/utils/strings';

Expand Down Expand Up @@ -70,21 +69,6 @@ export const useSearchableTokens = ({
!isENSAddressFormat(debouncedSearchQuery) &&
!testnetMode;

const queryIsAddress = useMemo(
() => isAddress(debouncedSearchQuery),
[debouncedSearchQuery],
);

const keys: TokenSearchAssetKey[] = useMemo(
() => (queryIsAddress ? ['address'] : ['name', 'symbol']),
[queryIsAddress],
);

const threshold: TokenSearchThreshold = useMemo(
() => (queryIsAddress ? 'CASE_SENSITIVE_EQUAL' : 'CONTAINS'),
[queryIsAddress],
);

const enableSearchChainAssets = isAddress(query) && !testnetMode;

// All on chain searched assets from all user chains
Expand All @@ -111,8 +95,6 @@ export const useSearchableTokens = ({
} = useTokenSearchAllNetworks(
{
list: 'verifiedAssets',
keys,
threshold,
query: debouncedSearchQuery,
},
{
Expand All @@ -131,8 +113,6 @@ export const useSearchableTokens = ({
} = useTokenSearchAllNetworks(
{
list: 'highLiquidityAssets',
keys,
threshold,
query: debouncedSearchQuery,
},
{
Expand Down
113 changes: 32 additions & 81 deletions src/entries/popup/hooks/useFavoriteAssets.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,42 @@
import { isAddress } from 'ethers/lib/utils';
import { useCallback, useEffect, useState } from 'react';
import { keepPreviousData, useQuery } from '@tanstack/react-query';

import { createQueryKey } from '~/core/react-query';
import { fetchTokenSearch } from '~/core/resources/search/tokenSearch';
import { useFavoritesStore } from '~/core/state/favorites';
import { ParsedAsset } from '~/core/types/assets';
import { AddressOrEth } from '~/core/types/assets';
import { ChainId } from '~/core/types/chains';
import { SearchAsset } from '~/core/types/search';

type FavoriteAssets = Record<number, SearchAsset[]>;
const FAVORITES_EMPTY_STATE = {
[ChainId.mainnet]: [],
[ChainId.optimism]: [],
[ChainId.bsc]: [],
[ChainId.polygon]: [],
[ChainId.arbitrum]: [],
[ChainId.base]: [],
[ChainId.zora]: [],
[ChainId.avalanche]: [],
[ChainId.hardhat]: [],
[ChainId.hardhatOptimism]: [],
};
async function fetchFavoriteToken(address: AddressOrEth, chain: ChainId) {
const results = await fetchTokenSearch({
chainId: chain,
list: 'verifiedAssets',
query: address.toLowerCase(),
});
if (results?.[0]) return results[0];

// expensive hook, only use in top level parent components
export function useFavoriteAssets() {
const { favorites } = useFavoritesStore();
const [favoritesData, setFavoritesData] = useState<FavoriteAssets>(
FAVORITES_EMPTY_STATE,
);

const setFavoriteAssetsData = useCallback(async () => {
const chainIds = Object.keys(favorites)
.filter((k) => favorites?.[parseInt(k)])
.map((c) => +c);
const searches: Promise<void>[] = [];
const newSearchData = {} as Record<ChainId, SearchAsset[]>;
for (const chain of chainIds) {
const addressesByChain = favorites[chain];
addressesByChain?.forEach((address) => {
const searchAddress = async (add: string) => {
const query = add.toLocaleLowerCase();
const queryIsAddress = isAddress(query);
const keys = (
queryIsAddress ? ['address'] : ['name', 'symbol']
) as (keyof ParsedAsset)[];
const threshold = queryIsAddress
? 'CASE_SENSITIVE_EQUAL'
: 'CONTAINS';
const results = await fetchTokenSearch({
chainId: chain,
keys,
list: 'verifiedAssets',
threshold,
query,
});
const unverifiedSearchResults = await fetchTokenSearch({
chainId: chain,
list: 'highLiquidityAssets',
query: address.toLowerCase(),
});
if (!unverifiedSearchResults?.[0]) return unverifiedSearchResults[0];
}

const currentFavoritesData = newSearchData[chain] || [];
if (results?.[0]) {
newSearchData[chain] = [...currentFavoritesData, results[0]];
} else {
const unverifiedSearchResults = await fetchTokenSearch({
chainId: chain,
keys,
list: 'highLiquidityAssets',
threshold,
query,
});
if (unverifiedSearchResults?.[0]) {
// eslint-disable-next-line require-atomic-updates
newSearchData[chain] = [
...currentFavoritesData,
unverifiedSearchResults[0],
];
}
}
};
searches.push(searchAddress(address));
});
}
await Promise.all(searches);
setFavoritesData(newSearchData);
}, [favorites]);
export function useFavoriteAssets(chainId: ChainId) {
const favorites = useFavoritesStore((s) => s.favorites[chainId]);

useEffect(() => {
setFavoriteAssetsData();
}, [setFavoriteAssetsData]);
const { data = [] } = useQuery({
queryKey: createQueryKey('favorites assets', { chainId, favorites }),
queryFn: async () => {
if (!favorites) throw new Error('No chain favorites');
return (
await Promise.all(
favorites.map((address) => fetchFavoriteToken(address, chainId)),
)
).filter(Boolean);
},
placeholderData: keepPreviousData,
});

return {
favorites: favoritesData,
};
return { favorites: data };
}
Loading

0 comments on commit 4c3e583

Please sign in to comment.