diff --git a/mock/futa-token-list.json b/mock/futa-token-list.json new file mode 100644 index 0000000000..5e3fd333c6 --- /dev/null +++ b/mock/futa-token-list.json @@ -0,0 +1,72 @@ +{ + "futa-token-list": { + "name": "Futa Token List", + "logoURI": "https://ambient.finance/icons/ambient_icon_x180.png", + "timestamp": "2024-07-05T15:02:53.363Z", + "version": { + "major": 1, + "minor": 0, + "patch": 0 + }, + "tags": {}, + "keywords": ["futa", "default"], + "tokens": [ + { + "name": "new token11", + "address": "0x50bBA138A74C5e7326885De5090700626950d509", + "chainId": 11155111, + "decimals": 6, + "logoURI": "", + "symbol": "NEW11" + }, + { + "name": "new token", + "address": "0x40bBA138A74C5e7326885De5090700626950d509", + "chainId": 11155111, + "decimals": 6, + "logoURI": "", + "symbol": "NEW9" + }, + { + "name": "Wrapped BTC", + "address": "0xCA97CC9c1a1dfA54A252DaAFE9b5Cd1E16C81328", + "chainId": 11155111, + "decimals": 8, + "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png", + "symbol": "WBTC" + }, + { + "name": "PEPE", + "address": "0x1230000000000000000000000000000000000000", + "symbol": "PEPE", + "decimals": 18, + "chainId": 11155111, + "logoURI": "" + }, + { + "name": "JUNIOR", + "address": "0x2340000000000000000000000000000000000000", + "symbol": "JUNIOR", + "decimals": 18, + "chainId": 11155111, + "logoURI": "" + }, + { + "name": "HELLO😊", + "address": "0x3450000000000000000000000000000000000000", + "symbol": "HELLO😊", + "decimals": 18, + "chainId": 11155111, + "logoURI": "" + }, + { + "name": "EMILY", + "address": "0x4560000000000000000000000000000000000000", + "symbol": "EMILY", + "decimals": 18, + "chainId": 11155111, + "logoURI": "" + } + ] + } +} diff --git a/package.json b/package.json index 27ea440f68..c217ca069b 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,8 @@ "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc", "prepare": "husky", - "postbuild": "node generateManifest.js" + "postbuild": "node generateManifest.js", + "serve:token-list": "json-server mock/futa-token-list.json --port 3002" }, "lint-staged": { "*.{js,jsx,ts,tsx,json}": [ @@ -90,6 +91,7 @@ "eslint-plugin-react": "^7.35.0", "eslint-plugin-react-hooks": "^5.1.0", "husky": "^9.1.7", + "json-server": "^1.0.0-beta.3", "lint-staged": "^15.2.11", "playwright": "^1.49.1", "prettier": "^3.3.3", diff --git a/public/futa-token-list.json b/public/futa-token-list.json deleted file mode 100644 index c22bab12fc..0000000000 --- a/public/futa-token-list.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "name": "Futa Token List", - "logoURI": "https://ambient.finance/icons/ambient_icon_x180.png", - "timestamp": "2024-07-05T15:02:53.363Z", - "version": { - "major": 1, - "minor": 0, - "patch": 0 - }, - "tags": {}, - "keywords": ["futa", "default"], - "tokens": [ - { - "name": "Native Ether", - "address": "0x0000000000000000000000000000000000000000", - "symbol": "ETH", - "decimals": 18, - "chainId": 11155111, - "logoURI": "https://ethereum-optimism.github.io/data/ETH/logo.svg" - }, - { - "name": "USDC", - "address": "0x60bBA138A74C5e7326885De5090700626950d509", - "chainId": 11155111, - "decimals": 6, - "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png", - "symbol": "USDC" - }, - { - "name": "Wrapped BTC", - "address": "0xCA97CC9c1a1dfA54A252DaAFE9b5Cd1E16C81328", - "chainId": 11155111, - "decimals": 8, - "logoURI": "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png", - "symbol": "WBTC" - }, - { - "name": "PEPE", - "address": "0x1230000000000000000000000000000000000000", - "symbol": "PEPE", - "decimals": 18, - "chainId": 11155111, - "logoURI": "" - }, - { - "name": "JUNIOR", - "address": "0x2340000000000000000000000000000000000000", - "symbol": "JUNIOR", - "decimals": 18, - "chainId": 11155111, - "logoURI": "" - }, - { - "name": "HELLO😊", - "address": "0x3450000000000000000000000000000000000000", - "symbol": "HELLO😊", - "decimals": 18, - "chainId": 11155111, - "logoURI": "" - }, - { - "name": "EMILY", - "address": "0x4560000000000000000000000000000000000000", - "symbol": "EMILY", - "decimals": 18, - "chainId": 11155111, - "logoURI": "" - } - ] -} diff --git a/src/App/hooks/useTokens.ts b/src/App/hooks/useTokens.ts index bcb33307bb..ab48c83a47 100644 --- a/src/App/hooks/useTokens.ts +++ b/src/App/hooks/useTokens.ts @@ -1,9 +1,13 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { defaultTokens, + defaultTokensFUTA, hiddenTokens, + tokenListEndpointStrings, tokenListURIs, } from '../../ambient-utils/constants'; +import ambientTokenList from '../../ambient-utils/constants/ambient-token-list.json'; +import testnetTokenList from '../../ambient-utils/constants/testnet-token-list.json'; import { chainNumToString, serializeBigInt, @@ -19,6 +23,7 @@ export interface tokenMethodsIF { tokenUniv: TokenIF[]; getTokenByAddress: (addr: string) => TokenIF | undefined; getTokensFromList: (uri: string) => TokenIF[]; + getFutaTokens: () => TokenIF[]; getTokensByNameOrSymbol: ( input: string, chn: string, @@ -55,11 +60,12 @@ function getTokenEntryFromLS(key: string) { return []; } +// fn to retrieve and parse token lists from local storage function getTokenListsFromLS(): TokenListIF[] { return getTokenEntryFromLS(localStorageKeys.tokenLists) as TokenListIF[]; } -// fn to retrieve and parse token lists from local storage +// fn to retrieve and parse list of acknowledged tokens from local storage function getAckTokensFromLS(): TokenIF[] { return getTokenEntryFromLS(localStorageKeys.ackTokens) as TokenIF[]; } @@ -80,6 +86,24 @@ export const useTokens = ( // User acknowledge tokens const [ackTokens, setAckTokens] = useState(INIT_ACK); + function checkDefault(t: TokenIF, list: TokenIF[]): boolean { + return list.some( + (listedToken: TokenIF) => + listedToken.address.toLowerCase() === t.address.toLowerCase(), + ); + } + + function findDefaultPlatforms(t: TokenIF): ('ambient' | 'futa')[] { + const defaultPlatforms: ('ambient' | 'futa')[] = []; + if (checkDefault(t, defaultTokens)) { + defaultPlatforms.push('ambient'); + } + if (checkDefault(t, defaultTokensFUTA)) { + defaultPlatforms.push('futa'); + } + return defaultPlatforms; + } + // Universe of tokens within the given chain. Combines both tokens from // lists and user-acknowledge tokens const tokenMap = useMemo>(() => { @@ -108,6 +132,14 @@ export const useTokens = ( const tknFromMap: TokenIF | undefined = retMap.get( t.address.toLowerCase(), ); + const defaultForPlatforms: ('ambient' | 'futa')[] = []; + if (checkDefault(deepToken, defaultTokens)) { + defaultForPlatforms.push('ambient'); + } + if (checkDefault(deepToken, defaultTokensFUTA)) { + defaultForPlatforms.push('futa'); + } + deepToken.defaultPlatforms = findDefaultPlatforms(deepToken); // if token is listed, update the array of originating URIs if (tknFromMap?.listedBy) { deepToken.listedBy = deepToken.listedBy?.concat( @@ -181,9 +213,13 @@ export const useTokens = ( excluded.chainId === t.chainId, ); }) - .map((tkn: TokenIF) => - deepCopyToken(tkn, tkn.fromList ?? tokenListURIs.ambient), - ); + .map((tkn: TokenIF) => { + const copiedToken = deepCopyToken( + tkn, + tkn.fromList ?? tokenListURIs.ambient, + ); + return copiedToken; + }); } }, [tokenMap, tokenBalances]); @@ -213,38 +249,83 @@ export const useTokens = ( [chainId, tokenUniv.length], ); - // Load token lists from local storage for fast load, but asynchronously - // fetch tokens from external URLs and update with latest values - useEffect(() => { - const fetchAndFormatList = async ( - uri: string, - ): Promise => { - // convert URI to an array of queryable endpoints - const endpoints: string[] = uriToHttp(uri, 'retry'); - // logic to query endpoints until a query is successful - let rawData; - for (let i = 0; i < endpoints.length; i++) { - const response = await fetch(endpoints[i]); + // fn to fetch a token list from an endpoint and decorate + async function fetchAndFormatList( + uri: tokenListEndpointStrings, + ): Promise { + // convert URI to an array of queryable endpoints + const endpoints: string[] = uriToHttp(uri, 'retry'); + // logic to query endpoints until a query is successful + let rawData; + // process all endpoints + for (let i = 0; i < endpoints.length; i++) { + // isolate current endpoint from list + const endpoint = endpoints[i]; + // special handling for the ambient token list (exists locally) + if (endpoint === tokenListURIs.ambient) { + rawData = ambientTokenList; + } + // special handling for the testnet token list (exists locally) + else if (endpoint === tokenListURIs.testnet) { + rawData = testnetTokenList; + } + // handling for all non-local token lists + else { + const response = await fetch(endpoint); if (response.ok) { rawData = await response.json(); break; } } - // cease funcationality if no endpoint returned a valid response - if (!rawData) return; - // format the raw data returned with values used in the Ambient app - const output: TokenListIF = { - ...rawData, - uri, - dateRetrieved: new Date().toISOString(), - userImported: false, - tokens: rawData.tokens.map((tkn: TokenIF) => { - return { ...tkn, fromList: uri }; - }), - }; - // return formatted token list - return output; + } + // format the raw data returned with values used in the Ambient app + const output: TokenListIF = { + ...rawData, + uri, + dateRetrieved: new Date().toISOString(), + userImported: false, + tokens: rawData.tokens.map((tkn: TokenIF) => { + return { ...tkn, fromList: uri }; + }), }; + // return formatted token list + return output; + } + + // fn to patch the a single updated token list into the array + async function patchTokenList( + uri: tokenListEndpointStrings, + ): Promise { + // fresh list retrieved from endpoint + const list: TokenListIF | undefined = await fetchAndFormatList(uri); + // cease processes if the fetch fails + if (!list) return; + // array of token lists with the new one patched in + const updatedLists: TokenListIF[] = tokenLists.map( + (oldList: TokenListIF) => (oldList.uri === uri ? list : oldList), + ); + // send updated array of token lists to local state + setTokenLists(updatedLists); + localStorage.setItem( + localStorageKeys.tokenLists, + JSON.stringify(updatedLists), + ); + } + + // logic to update the FUTA token list + // having trouble getting multiple lists to update in parallel + useEffect(() => { + // time interval between updates + const TIME = 120000; + // endpoint (will use a centralized endpoing later) + const FUTA_LIST_URI = 'http://localhost:3002/futa-token-list'; + // set interval to patch token list after a timeout + setInterval(() => patchTokenList(FUTA_LIST_URI), TIME); + }, []); + + // Load token lists from local storage for fast load, but asynchronously + // fetch tokens from external URLs and update with latest values + useEffect(() => { // array of promises for fetched token lists const tokenListPromises: Promise[] = Object.values(tokenListURIs).map((uri: string) => @@ -342,6 +423,32 @@ export const useTokens = ( [chainId, tokenUniv], ); + // fn to get all FUTA tokens + const getFutaTokens = useCallback((): TokenIF[] => { + // filter token universe for FUTA tokens + const found: TokenIF[] = tokenUniv.filter( + (tkn: TokenIF) => + tkn.listedBy?.includes( + 'http://localhost:3002/futa-token-list', + ) || tkn.defaultPlatforms?.includes('futa'), + ); + // patch in FUTA tokens from the default list + // TODO: make chain-specific + defaultTokensFUTA.forEach((dtf: TokenIF) => { + const alreadyFound: boolean = found.some( + (foundToken: TokenIF) => + foundToken.address.toLowerCase() === + dtf.address.toLowerCase(), + ); + alreadyFound || + found.push({ + ...dtf, + defaultPlatforms: findDefaultPlatforms(dtf), + }); + }); + return found; + }, [tokenUniv]); + // fn to return all tokens where name or symbol matches search input // can return just exact matches or exact + partial matches const getTokensByNameOrSymbol = useCallback( @@ -417,6 +524,7 @@ export const useTokens = ( tokenUniv: tokenUniv, getTokenByAddress: getTokenByAddress, getTokensFromList: getTokensFromList, + getFutaTokens: getFutaTokens, getTokensByNameOrSymbol: getTokensByNameOrSymbol, }), [tokenUniv, chainId], diff --git a/src/ambient-utils/api/fetchTokenList.ts b/src/ambient-utils/api/fetchTokenList.ts deleted file mode 100644 index c005912c7a..0000000000 --- a/src/ambient-utils/api/fetchTokenList.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -import ambientTokenList from '../constants/ambient-token-list.json'; -import testnetTokenList from '../constants/testnet-token-list.json'; -import { uriToHttp } from '../dataLayer/functions/uriToHttp'; -import { TokenListIF } from '../types/token/TokenListIF'; - -// !important: abstraction is at this point largely unnecessary, but at -// !important: ... some point in the future we'll likely support users -// !important: ... important custom lists of tokens to the platform - -// fn to fetch a token list asynchronously... this function creates and -// ... returns a promise but allows the parent file to determine how to -// ... best resolve it (multiple fetches may be dispatched in parallel) -export default async function fetchTokenList( - uri: string, - isUserImported = false, -): Promise { - function isRunningOnLocalhost(): boolean { - const hostname = window.location.hostname; - return ( - hostname === 'localhost' || - hostname === '127.0.0.1' || - hostname.startsWith('192.168') || - hostname === '[::1]' - ); - } - - // Handle manual lists - const tokenListMap = new Map([ - ['ambient-token-list.json', ambientTokenList], - ['testnet-token-list.json', testnetTokenList], - ]); - - if (uri.startsWith('/') && isRunningOnLocalhost()) { - for (const [key, value] of tokenListMap) { - if (uri.includes(key)) { - return Promise.resolve({ - ...value, - uri, - dateRetrieved: new Date().toISOString(), - isUserImported, - }); - } - } - throw Error(`Can not access ${uri} token list if deployed locally`); - } - - return fetch(uriToHttp(uri)) - .then((response) => response.json()) - .then((response) => ({ - ...response, - uri, - dateRetrieved: new Date().toISOString(), - isUserImported, - })); -} diff --git a/src/ambient-utils/api/fetchTokenUniverse.ts b/src/ambient-utils/api/fetchTokenUniverse.ts deleted file mode 100644 index 175e1ee480..0000000000 --- a/src/ambient-utils/api/fetchTokenUniverse.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { tokenListURIs } from '../constants'; -import { TokenIF } from '../types'; -import fetchTokenList from './fetchTokenList'; -const tokenUniverses = new Map(); - -function processTokenList( - tokenList: TokenIF[], - universe: Map>, -) { - for (const token of tokenList) { - const strChainId = '0x' + token.chainId.toString(16); - if (!universe.has(strChainId)) { - universe.set(strChainId, new Map()); - } - const currentTokens = universe.get(strChainId); - if (currentTokens && !currentTokens.has(token.address)) { - currentTokens.set(token.address, token); - } - } -} - -export async function downloadAllTokenUniverses(): Promise< - Map -> { - if (tokenUniverses.size > 0) return tokenUniverses; - const universes = new Map>(); - for (const uri of Object.values(tokenListURIs)) { - try { - const tokenList = await fetchTokenList(uri, false); - processTokenList(tokenList.tokens, universes); - } catch (error) { - console.warn( - `Log: Could not load token list from URI: ${uri}`, - error, - ); - } - } - universes.forEach((tokens, chainId) => { - tokenUniverses.set(chainId, Array.from(tokens.values())); - }); - return tokenUniverses; -} - -export async function fetchTokenUniverse(chainId: string): Promise { - const tokenUniverse = await downloadAllTokenUniverses(); - return tokenUniverse.get(chainId) || ([] as TokenIF[]); -} diff --git a/src/ambient-utils/api/index.ts b/src/ambient-utils/api/index.ts index 137b1dfed5..8dfa811348 100644 --- a/src/ambient-utils/api/index.ts +++ b/src/ambient-utils/api/index.ts @@ -11,11 +11,9 @@ export * from './fetchPoolList'; export * from './fetchPoolRecentChanges'; export * from './fetchTimeout'; export * from './fetchTokenBalances'; -export * from './fetchTokenList'; export * from './fetchTokenPrice'; export * from './fetchUserRecentChanges'; export * from './fetchWithFallbacks'; export * from './fetchUserPositions'; export * from './fetchBlockNumber'; -export * from './fetchTokenUniverse'; export * from './fetchXp'; diff --git a/src/ambient-utils/constants/defaultTokens.ts b/src/ambient-utils/constants/defaultTokens.ts index 2bc2b83f97..130f6fe777 100644 --- a/src/ambient-utils/constants/defaultTokens.ts +++ b/src/ambient-utils/constants/defaultTokens.ts @@ -3,9 +3,24 @@ import { TokenIF } from '../types/token/TokenIF'; // Use `defaultTokens` directly as the registry export const defaultTokens: TokenIF[] = []; +export const defaultTokensAmbient: TokenIF[] = []; +export const defaultTokensFUTA: TokenIF[] = []; + +type platforms = 'ambient' | 'futa'; + // Helper to register tokens -function registerToken(token: TokenIF): TokenIF { +function registerToken( + token: TokenIF, + additionalPlatforms?: platforms[], +): TokenIF { defaultTokens.push(token); + if (additionalPlatforms) { + additionalPlatforms.includes('futa') && defaultTokensFUTA.push(token); + additionalPlatforms.includes('ambient') && + defaultTokensAmbient.push(token); + } else { + defaultTokensAmbient.push(token); + } return token; } @@ -417,14 +432,17 @@ export const blastSepoliaUSDB: TokenIF = registerToken({ symbol: 'USDB', }); -export const sepoliaETH: TokenIF = registerToken({ - name: 'Native Ether', - address: '0x0000000000000000000000000000000000000000', - symbol: 'ETH', - decimals: 18, - chainId: 11155111, - logoURI: 'https://ethereum-optimism.github.io/data/ETH/logo.svg', -}); +export const sepoliaETH: TokenIF = registerToken( + { + name: 'Native Ether', + address: '0x0000000000000000000000000000000000000000', + symbol: 'ETH', + decimals: 18, + chainId: 11155111, + logoURI: 'https://ethereum-optimism.github.io/data/ETH/logo.svg', + }, + ['futa'], +); export const sepoliaUSDC: TokenIF = registerToken({ name: 'USDC', @@ -436,15 +454,18 @@ export const sepoliaUSDC: TokenIF = registerToken({ 'https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png', }); -export const sepoliaWBTC: TokenIF = registerToken({ - name: 'Wrapped BTC', - address: '0xCA97CC9c1a1dfA54A252DaAFE9b5Cd1E16C81328', - symbol: 'WBTC', - decimals: 8, - chainId: 11155111, - logoURI: - 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png', -}); +export const sepoliaWBTC: TokenIF = registerToken( + { + name: 'Wrapped BTC', + address: '0xCA97CC9c1a1dfA54A252DaAFE9b5Cd1E16C81328', + symbol: 'WBTC', + decimals: 8, + chainId: 11155111, + logoURI: + 'https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599/logo.png', + }, + ['futa'], +); export const scrollSepoliaWBTC: TokenIF = registerToken({ name: 'Wrapped BTC', diff --git a/src/ambient-utils/constants/tokenListURIs.ts b/src/ambient-utils/constants/tokenListURIs.ts index 0f2e64f6c6..2a3fab6db3 100644 --- a/src/ambient-utils/constants/tokenListURIs.ts +++ b/src/ambient-utils/constants/tokenListURIs.ts @@ -11,8 +11,24 @@ export const tokenListURIs = { scrollTech: 'https://raw.githubusercontent.com/scroll-tech/token-list/main/scroll.tokenlist.json', // uniswap: 'https://tokens.uniswap.org', - futa: '/futa-token-list.json', + futa: 'http://localhost:3002/futa-token-list', baseCoingecko: 'https://tokens.coingecko.com/base/all.json', }; +// string union of all keys in the `tokenListURIs` obj export type TokenListURITypes = keyof typeof tokenListURIs; + +// string union of all values in the `tokenListURIs` obj +export type tokenListEndpointStrings = + (typeof tokenListURIs)[TokenListURITypes]; + +// type definition for the refresh intervals object +// keys: subset of keys in the `tokenListURIs` obj +// values: refresh time in seconds (arbitrary number) +export type refreshTime = [TokenListURITypes, number]; + +// times to refresh individual token lists +// export const refreshTimes: refreshTime[] = [ +// ['scrollTech', 6], +// ['futa', 15], +// ]; diff --git a/src/ambient-utils/dataLayer/functions/uriToHttp.ts b/src/ambient-utils/dataLayer/functions/uriToHttp.ts index c99541a7ed..c4f225e197 100644 --- a/src/ambient-utils/dataLayer/functions/uriToHttp.ts +++ b/src/ambient-utils/dataLayer/functions/uriToHttp.ts @@ -62,7 +62,7 @@ export function uriToHttp(uri: string, retry?: string): string | string[] { // handle http URIs case 'http': // create an https version of the URI - outputURLs.push('https' + uri.slice(4)); + // outputURLs.push('https' + uri.slice(4)); // create a backup URI using the unaltered http form outputURLs.push(uri); break; diff --git a/src/ambient-utils/types/token/TokenIF.ts b/src/ambient-utils/types/token/TokenIF.ts index 98b1be1d7d..44c71d1e0a 100644 --- a/src/ambient-utils/types/token/TokenIF.ts +++ b/src/ambient-utils/types/token/TokenIF.ts @@ -24,4 +24,5 @@ export interface TokenIF extends ServerTokenIF { walletBalance?: string; dexBalance?: string; totalSupply?: bigint; + defaultPlatforms?: ('ambient' | 'futa')[]; } diff --git a/src/components/Global/TokenSelectContainer/SoloTokenSelectModal.tsx b/src/components/Global/TokenSelectContainer/SoloTokenSelectModal.tsx index 39a2e633fb..11d01fcd5a 100644 --- a/src/components/Global/TokenSelectContainer/SoloTokenSelectModal.tsx +++ b/src/components/Global/TokenSelectContainer/SoloTokenSelectModal.tsx @@ -325,9 +325,9 @@ export const SoloTokenSelectModal = (props: propsIF) => { )}
-
- {platform !== 'futa' && - isWrappedNativeToken(validatedInput) && ( + {platform !== 'futa' && + isWrappedNativeToken(validatedInput) && ( +
{ } /> - )} -
+
+ )} {platform === 'ambient' && ( <> {isWrappedNativeToken(validatedInput) && @@ -400,7 +400,7 @@ export const SoloTokenSelectModal = (props: propsIF) => { )} {platform === 'futa' && tokens - .getTokensFromList('/futa-token-list.json') + .getFutaTokens() .filter((tk: TokenIF) => { // fn to compare name and symbol to search input function matchSymbolOrName( @@ -449,6 +449,22 @@ export const SoloTokenSelectModal = (props: propsIF) => { ? checkForMatches() : true; }) + .sort((tickerA: TokenIF, tickerB: TokenIF) => { + function rankTicker(t: TokenIF): number { + let rank: number; + if ( + t.address.toLowerCase() === ZERO_ADDRESS + ) { + rank = 1; + } else { + rank = 2; + } + return rank; + } + const rankA: number = rankTicker(tickerA); + const rankB: number = rankTicker(tickerB); + return rankA - rankB; + }) .map((ticker: TokenIF) => ( { activeNetwork: { chainId }, } = useContext(AppStateContext); const { tokenBalances } = useContext(TokenBalanceContext); + const tokens: tokenMethodsIF = useTokens(chainId, tokenBalances); const { addRecentToken, getRecentTokens } = useRecentTokens(chainId); diff --git a/yarn.lock b/yarn.lock index 651c3a9703..04ab691e12 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1944,6 +1944,11 @@ "@parcel/watcher-win32-ia32" "2.4.1" "@parcel/watcher-win32-x64" "2.4.1" +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.28" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" + integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== + "@popperjs/core@^2.11.8": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" @@ -2211,6 +2216,143 @@ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd" integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ== +"@tinyhttp/accepts@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/accepts/-/accepts-2.2.3.tgz#be7601206eeda8bd8350ad82a2307808efcb7831" + integrity sha512-9pQN6pJAJOU3McmdJWTcyq7LLFW8Lj5q+DadyKcvp+sxMkEpktKX5sbfJgJuOvjk6+1xWl7pe0YL1US1vaO/1w== + dependencies: + mime "4.0.4" + negotiator "^0.6.3" + +"@tinyhttp/app@^2.4.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/app/-/app-2.5.0.tgz#fab0ee613a9ab21938c861940bec12d4abe20def" + integrity sha512-mwVY6RhTqF/s49tqNqpkRWbXAC7OmfpxR6YI6atp9xDauUOv3n1hv38AKy89Ga8HC8G2p1KR9vPD66VmF6VMnw== + dependencies: + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/proxy-addr" "2.2.0" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/res" "2.2.4" + "@tinyhttp/router" "2.2.3" + header-range-parser "1.1.3" + regexparam "^2.0.2" + +"@tinyhttp/content-disposition@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-disposition/-/content-disposition-2.2.2.tgz#1207d18bdd59e1cd38ecf2493ee187f4f592ebe7" + integrity sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g== + +"@tinyhttp/content-type@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/content-type/-/content-type-0.1.4.tgz#112bce3b564213e0ed43fa76fccca4237be3a634" + integrity sha512-dl6f3SHIJPYbhsW1oXdrqOmLSQF/Ctlv3JnNfXAE22kIP7FosqJHxkz/qj2gv465prG8ODKH5KEyhBkvwrueKQ== + +"@tinyhttp/cookie-signature@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie-signature/-/cookie-signature-2.1.1.tgz#ae2caad6aec4ec51d42e7d852ae34a04196d5138" + integrity sha512-VDsSMY5OJfQJIAtUgeQYhqMPSZptehFSfvEEtxr+4nldPA8IImlp3QVcOVuK985g4AFR4Hl1sCbWCXoqBnVWnw== + +"@tinyhttp/cookie@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cookie/-/cookie-2.1.1.tgz#50ad664f732357a466a14cdc888e88e80dc3440e" + integrity sha512-h/kL9jY0e0Dvad+/QU3efKZww0aTvZJslaHj3JTPmIPC9Oan9+kYqmh3M6L5JUQRuTJYFK2nzgL2iJtH2S+6dA== + +"@tinyhttp/cors@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/cors/-/cors-2.0.1.tgz#7f5ff7bd47b8e48172d8e43818b8d61eaa84037b" + integrity sha512-qrmo6WJuaiCzKWagv2yA/kw6hIISfF/hOqPWwmI6w0o8apeTMmRN3DoCFvQ/wNVuWVdU5J4KU7OX8aaSOEq51A== + dependencies: + "@tinyhttp/vary" "^0.1.3" + +"@tinyhttp/encode-url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/encode-url/-/encode-url-2.1.1.tgz#a52bdbd75f541455190d1a16b0a81374c8dc587d" + integrity sha512-AhY+JqdZ56qV77tzrBm0qThXORbsVjs/IOPgGCS7x/wWnsa/Bx30zDUU/jPAUcSzNOzt860x9fhdGpzdqbUeUw== + +"@tinyhttp/etag@2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@tinyhttp/etag/-/etag-2.1.2.tgz#34fc91933bd1acce3cda3a64e5352ce5514abe4e" + integrity sha512-j80fPKimGqdmMh6962y+BtQsnYPVCzZfJw0HXjyH70VaJBHLKGF+iYhcKqzI3yef6QBNa8DKIPsbEYpuwApXTw== + +"@tinyhttp/forwarded@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/forwarded/-/forwarded-2.1.1.tgz#dbf2cae75a1737b88b71c2a2d1931e5e9ced73c3" + integrity sha512-nO3kq0R1LRl2+CAMlnggm22zE6sT8gfvGbNvSitV6F9eaUSurHP0A8YZFMihSkugHxK+uIegh1TKrqgD8+lyGQ== + +"@tinyhttp/logger@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/logger/-/logger-2.0.0.tgz#64c0e53497abc82765c17289a05cd75edbd4c04a" + integrity sha512-8DfLQjGDIaIJeivYamVrrpmwmsGwS8wt2DGvzlcY5HEBagdiI4QJy/veAFcUHuaJqufn4wLwmn4q5VUkW8BCpQ== + dependencies: + colorette "^2.0.20" + dayjs "^1.11.10" + http-status-emojis "^2.2.0" + +"@tinyhttp/proxy-addr@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@tinyhttp/proxy-addr/-/proxy-addr-2.2.0.tgz#82487f25af4d320d79e613bbecac17c7ad69c8f2" + integrity sha512-WM/PPL9xNvrs7/8Om5nhKbke5FHrP3EfjOOR+wBnjgESfibqn0K7wdUTnzSLp1lBmemr88os1XvzwymSgaibyA== + dependencies: + "@tinyhttp/forwarded" "2.1.1" + ipaddr.js "^2.2.0" + +"@tinyhttp/req@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/req/-/req-2.2.4.tgz#c9dfc40e3a3b3cc1eb48bdc137b5d0cd71501057" + integrity sha512-lQAZIAo0NOeghxFOZS57tQzxpHSPPLs9T68Krq2BncEBImKwqaDKUt7M9Y5Kb+rvC/GwIL3LeErhkg7f5iG4IQ== + dependencies: + "@tinyhttp/accepts" "2.2.3" + "@tinyhttp/type-is" "2.2.4" + "@tinyhttp/url" "2.1.1" + header-range-parser "^1.1.3" + +"@tinyhttp/res@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/res/-/res-2.2.4.tgz#ed79d511f21d6ef226ae907bdecc26f69c93583c" + integrity sha512-ETBRShnO19oJyIg2XQHQoofXPWeTXPAuwnIVYkU8WaftvXd/Vz4y5+WFQDHUzKlmdGOw5fAFnrEU7pIVMeFeVA== + dependencies: + "@tinyhttp/content-disposition" "2.2.2" + "@tinyhttp/cookie" "2.1.1" + "@tinyhttp/cookie-signature" "2.1.1" + "@tinyhttp/encode-url" "2.1.1" + "@tinyhttp/req" "2.2.4" + "@tinyhttp/send" "2.2.3" + "@tinyhttp/vary" "^0.1.3" + es-escape-html "^0.1.1" + mime "4.0.4" + +"@tinyhttp/router@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/router/-/router-2.2.3.tgz#a29a33da89ae7365f5897aed20f44663509273a4" + integrity sha512-O0MQqWV3Vpg/uXsMYg19XsIgOhwjyhTYWh51Qng7bxqXixxx2PEvZWnFjP7c84K7kU/nUX41KpkEBTLnznk9/Q== + +"@tinyhttp/send@2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/send/-/send-2.2.3.tgz#726c400af76c62963bd71fe92e6e6838f35a7996" + integrity sha512-o4cVHHGQ8WjVBS8UT0EE/2WnjoybrfXikHwsRoNlG1pfrC/Sd01u1N4Te8cOd/9aNGLr4mGxWb5qTm2RRtEi7g== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + "@tinyhttp/etag" "2.1.2" + mime "4.0.4" + +"@tinyhttp/type-is@2.2.4": + version "2.2.4" + resolved "https://registry.yarnpkg.com/@tinyhttp/type-is/-/type-is-2.2.4.tgz#8f5a30bb3cdc93dd02f399e152d88b815b0efc99" + integrity sha512-7F328NheridwjIfefBB2j1PEcKKABpADgv7aCJaE8x8EON77ZFrAkI3Rir7pGjopV7V9MBmW88xUQigBEX2rmQ== + dependencies: + "@tinyhttp/content-type" "^0.1.4" + mime "4.0.4" + +"@tinyhttp/url@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@tinyhttp/url/-/url-2.1.1.tgz#77fa8963f5b698bacbdc6912407f946d32c793e1" + integrity sha512-POJeq2GQ5jI7Zrdmj22JqOijB5/GeX+LEX7DUdml1hUnGbJOTWDx7zf2b5cCERj7RoXL67zTgyzVblBJC+NJWg== + +"@tinyhttp/vary@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@tinyhttp/vary/-/vary-0.1.3.tgz#f5bea4769f380c43a158832a8daad8e8b186757c" + integrity sha512-SoL83sQXAGiHN1jm2VwLUWQSQeDAAl1ywOm6T0b0Cg1CZhVsjoiZadmjhxF6FHCCY7OHHVaLnTgSMxTPIDLxMg== + "@types/adm-zip@^0.5.7": version "0.5.7" resolved "https://registry.yarnpkg.com/@types/adm-zip/-/adm-zip-0.5.7.tgz#eec10b6f717d3948beb64aca0abebc4b344ac7e9" @@ -3596,6 +3738,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.4.1.tgz#1b48bf0963ec158dce2aacf69c093ae2dd2092d8" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + chalk@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" @@ -3621,6 +3768,13 @@ chokidar@^3.5.1, chokidar@^3.6.0: optionalDependencies: fsevents "~2.3.2" +chokidar@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + citty@^0.1.5, citty@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.6.tgz#0f7904da1ed4625e1a9ea7e0fa780981aab7c5e4" @@ -4151,6 +4305,11 @@ dayjs@1.11.10: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== +dayjs@^1.11.10: + version "1.11.13" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" + integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4311,6 +4470,13 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +dot-prop@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-9.0.0.tgz#bae5982fe6dc6b8fddb92efef4f2ddff26779e92" + integrity sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ== + dependencies: + type-fest "^4.18.2" + dotenv@^16.4.7: version "16.4.7" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.7.tgz#0e20c5b82950140aa99be360a8a5f52335f53c26" @@ -4452,6 +4618,11 @@ es-errors@^1.2.1, es-errors@^1.3.0: resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-escape-html@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/es-escape-html/-/es-escape-html-0.1.1.tgz#9a582d49754ec6204524952c76a383fe5f03c1c0" + integrity sha512-yUx1o+8RsG7UlszmYPtks+dm6Lho2m8lgHMOsLJQsFI0R8XwUJwiMhM1M4E/S8QLeGyf6MkDV/pWgjQ0tdTSyQ== + es-get-iterator@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" @@ -4820,6 +4991,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eta@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eta/-/eta-3.5.0.tgz#b728b2d4aa3cbce9d08db638719a60b31d2b0ccf" + integrity sha512-e3x3FBvGzeCIHhF+zhK8FZA2vC5uFn6b4HJjegUbIWrDb4mJ7JjTGMJY9VGIbRVpmSwHopNiaJibhjIr+HfLug== + ethers@^6.13.4: version "6.13.4" resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" @@ -5248,6 +5424,11 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +header-range-parser@1.1.3, header-range-parser@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/header-range-parser/-/header-range-parser-1.1.3.tgz#6414b5b12e3b645d29d85225a58fd207d66d30ef" + integrity sha512-B9zCFt3jH8g09LR1vHL4pcAn8yMEtlSlOUdQemzHMRKMImNIhhszdeosYFfNW0WXKQtXIlWB+O4owHJKvEJYaA== + hexoid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-2.0.0.tgz#fb36c740ebbf364403fa1ec0c7efd268460ec5b9" @@ -5270,6 +5451,11 @@ http-shutdown@^1.2.2: resolved "https://registry.yarnpkg.com/http-shutdown/-/http-shutdown-1.2.2.tgz#41bc78fc767637c4c95179bc492f312c0ae64c5f" integrity sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw== +http-status-emojis@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/http-status-emojis/-/http-status-emojis-2.2.0.tgz#2cf3316f0c1610c4fc94c6fccdada35aa70f992a" + integrity sha512-ompKtgwpx8ff0hsbpIB7oE4ax1LXoHmftsHHStMELX56ivG3GhofTX8ZHWlUaFKfGjcGjw6G3rPk7dJRXMmbbg== + human-signals@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" @@ -5325,6 +5511,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +inflection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-3.0.0.tgz#6a956fa90d72a27d22e6b32ec1064877593ee23b" + integrity sha512-1zEJU1l19SgJlmwqsEyFTbScw/tkMHFenUo//Y0i+XEP83gDFdMvPizAD/WGcE+l1ku12PcTVHQhO6g5E0UCMw== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -5362,6 +5553,11 @@ intro.js@^7.0.0: resolved "https://registry.yarnpkg.com/intro.js/-/intro.js-7.2.0.tgz#e58e8fee4f6b43d6e0fcb264c9ca8a0f0565026d" integrity sha512-qbMfaB70rOXVBceIWNYnYTpVTiZsvQh/MIkfdQbpA9di9VBfj1GigUPfcCv3aOfsbrtPcri8vTLTA4FcEDcHSQ== +ipaddr.js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== + iron-webcrypto@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f" @@ -5696,6 +5892,25 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== +json-server@^1.0.0-beta.3: + version "1.0.0-beta.3" + resolved "https://registry.yarnpkg.com/json-server/-/json-server-1.0.0-beta.3.tgz#dfbbc2cd3fd9faea419586ae045c00a8fd6084ca" + integrity sha512-DwE69Ep5ccwIJZBUIWEENC30Yj8bwr4Ax9W9VoIWAYnB8Sj4ReptscO8/DRHv/nXwVlmb3Bk73Ls86+VZdYkkA== + dependencies: + "@tinyhttp/app" "^2.4.0" + "@tinyhttp/cors" "^2.0.1" + "@tinyhttp/logger" "^2.0.0" + chalk "^5.3.0" + chokidar "^4.0.1" + dot-prop "^9.0.0" + eta "^3.5.0" + inflection "^3.0.0" + json5 "^2.2.3" + lowdb "^7.0.1" + milliparsec "^4.0.0" + sirv "^2.0.4" + sort-on "^6.1.0" + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -6003,6 +6218,13 @@ loupe@^3.1.0, loupe@^3.1.2: resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.2.tgz#c86e0696804a02218f2206124c45d8b15291a240" integrity sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg== +lowdb@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/lowdb/-/lowdb-7.0.1.tgz#7354a684547d76206b1c730b9434604235b125e5" + integrity sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw== + dependencies: + steno "^4.0.2" + lru-cache@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -6068,6 +6290,11 @@ micromatch@^4.0.4, micromatch@^4.0.5, micromatch@~4.0.8: braces "^3.0.3" picomatch "^2.3.1" +milliparsec@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/milliparsec/-/milliparsec-4.0.0.tgz#ba5169aaa4922587c92f22878df9c85730a0d893" + integrity sha512-/wk9d4Z6/9ZvoEH/6BI4TrTCgmkpZPuSRN/6fI9aUHOfXdNTuj/VhLS7d+NqG26bi6L9YmGXutVYvWC8zQ0qtA== + mime-db@1.52.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" @@ -6085,6 +6312,11 @@ mime@2.6.0: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== +mime@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-4.0.4.tgz#9f851b0fc3c289d063b20a7a8055b3014b25664b" + integrity sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ== + mime@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" @@ -6156,6 +6388,11 @@ mri@^1.2.0: resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== +mrmime@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -6186,6 +6423,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +negotiator@^0.6.3: + version "0.6.4" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7" + integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w== + node-addon-api@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" @@ -6800,6 +7042,11 @@ readable-stream@^3.1.1, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a" + integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA== + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -6859,6 +7106,11 @@ regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.2" +regexparam@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.2.tgz#a0f6aa057c67b1c9c09508c45823c0755b1f6e58" + integrity sha512-A1PeDEYMrkLrfyOwv2jwihXbo9qxdGD3atBYQA9JJgreAx8/7rC6IUkWOw2NQlOxLp2wL0ifQbh1HuidDfYA6w== + regexpp@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" @@ -7138,6 +7390,15 @@ signal-exit@^4.1.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== +sirv@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" + integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -7180,6 +7441,13 @@ sonic-boom@^2.2.1: dependencies: atomic-sleep "^1.0.0" +sort-on@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/sort-on/-/sort-on-6.1.0.tgz#96899b3536e4b2694090842f2e766ba11ccc7459" + integrity sha512-WTECP0nYNWO1n2g5bpsV0yZN9cBmZsF8ThHFbOqVN0HBFRoaQZLLEMvMmJlKHNPYQeVngeI5+jJzIfFqOIo1OA== + dependencies: + dot-prop "^9.0.0" + source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" @@ -7230,6 +7498,11 @@ std-env@^3.8.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== +steno@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/steno/-/steno-4.0.2.tgz#9bd9b0ffc226a1f9436f29132c8b8e7199d22c50" + integrity sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A== + stop-iteration-iterator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" @@ -7517,6 +7790,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -7576,6 +7854,11 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +type-fest@^4.18.2: + version "4.31.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.31.0.tgz#a3de630c96eb77c281b6ba2affa5dae5fb3c326c" + integrity sha512-yCxltHW07Nkhv/1F6wWBr8kz+5BGMfP+RbRSYFnegVb0qV/UMT0G0ElBloPVerqn4M2ZV80Ir1FtCcYv1cT6vQ== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3"