@lifi/widget 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/config/version.d.ts +1 -1
- package/dist/esm/config/version.js +1 -1
- package/dist/esm/config/version.js.map +1 -1
- package/dist/esm/hooks/useFilteredByTokenBalances.js +4 -1
- package/dist/esm/hooks/useFilteredByTokenBalances.js.map +1 -1
- package/dist/esm/types/widget.d.ts +1 -0
- package/dist/esm/types/widget.d.ts.map +1 -1
- package/dist/esm/types/widget.js.map +1 -1
- package/dist/esm/utils/token.js +38 -3
- package/dist/esm/utils/token.js.map +1 -1
- package/package.json +1 -1
- package/src/config/version.ts +1 -1
- package/src/hooks/useFilteredByTokenBalances.ts +7 -2
- package/src/types/widget.ts +1 -0
- package/src/utils/token.ts +71 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","names":[],"sources":["../../../src/config/version.ts"],"sourcesContent":["export const name = '@lifi/widget'\nexport const version = '4.
|
|
1
|
+
{"version":3,"file":"version.js","names":[],"sources":["../../../src/config/version.ts"],"sourcesContent":["export const name = '@lifi/widget'\nexport const version = '4.3.0'\n"],"mappings":";AAAA,MAAa,OAAO;AACpB,MAAa,UAAU"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getConfigItemSets, isFormItemAllowed } from "../utils/item.js";
|
|
2
2
|
import { useWidgetConfig } from "../providers/WidgetProvider/WidgetProvider.js";
|
|
3
3
|
import { useSDKClient } from "../providers/SDKClientProvider.js";
|
|
4
|
+
import { getVerifiedTokensSets } from "../utils/token.js";
|
|
4
5
|
import { isSupportedToken } from "../utils/tokenList.js";
|
|
5
6
|
import { ChainType, getWalletBalances } from "@lifi/sdk";
|
|
6
7
|
import { useMemo } from "react";
|
|
@@ -28,10 +29,12 @@ const useFilteredTokensByBalance = (accountsWithTokens, formType) => {
|
|
|
28
29
|
for (const [address, { tokens }] of Object.entries(accountsWithTokens)) result[address] = tokens;
|
|
29
30
|
return result;
|
|
30
31
|
}
|
|
32
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens);
|
|
31
33
|
for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {
|
|
32
34
|
result[address] = {};
|
|
33
35
|
for (const [chainIdStr, chainTokens] of Object.entries(tokens)) {
|
|
34
36
|
const chainId = Number(chainIdStr);
|
|
37
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId);
|
|
35
38
|
const balances = existingBalances?.[chainId];
|
|
36
39
|
if (!balances?.length) {
|
|
37
40
|
if (chainTokens.length) result[address][chainId] = chainTokens;
|
|
@@ -49,7 +52,7 @@ const useFilteredTokensByBalance = (accountsWithTokens, formType) => {
|
|
|
49
52
|
return !chainTokenSet.has(balanceKey) && isSupportedToken(balance) && isFormItemAllowed(balance, allowedAddressesConfig, formType, (t) => t.address.toLowerCase());
|
|
50
53
|
}).map((token) => ({
|
|
51
54
|
...token,
|
|
52
|
-
verified: false
|
|
55
|
+
verified: verifiedAddresses?.has(token.address.toLowerCase()) ?? false
|
|
53
56
|
}));
|
|
54
57
|
const allTokens = [...filteredTokens, ...additionalTokens];
|
|
55
58
|
if (allTokens.length) result[address][chainId] = allTokens;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFilteredByTokenBalances.js","names":[],"sources":["../../../src/hooks/useFilteredByTokenBalances.ts"],"sourcesContent":["import {\n type BaseToken,\n ChainType,\n getWalletBalances,\n type TokenExtended,\n type WalletTokenExtended,\n} from '@lifi/sdk'\nimport { useQuery } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { getConfigItemSets, isFormItemAllowed } from '../utils/item.js'\nimport { isSupportedToken } from '../utils/tokenList.js'\n\nexport const useFilteredTokensByBalance = (\n accountsWithTokens?: Record<\n string,\n { chainType: ChainType; tokens: Record<number, TokenExtended[]> }\n >,\n formType?: FormType\n): {\n data: Record<string, Record<number, TokenExtended[]>> | undefined\n isLoading: boolean\n} => {\n const { tokens: configTokens } = useWidgetConfig()\n const sdkClient = useSDKClient()\n\n const evmAddress = useMemo(() => {\n const evmAccount = Object.entries(accountsWithTokens ?? {}).find(\n ([_, { chainType }]) => chainType === ChainType.EVM\n )\n return evmAccount?.[0]\n }, [accountsWithTokens])\n\n const { data: existingBalances, isLoading } = useQuery({\n queryKey: ['existing-evm-balances', evmAddress],\n queryFn: () => getWalletBalances(sdkClient, evmAddress ?? ''),\n enabled: !!evmAddress,\n refetchInterval: 30_000, // 30 seconds\n staleTime: 30_000, // 30 seconds\n retry: false,\n })\n\n const accountsWithFilteredTokens = useMemo(() => {\n if (!accountsWithTokens) {\n return undefined\n }\n\n // Early return if no existing balances - return all tokens\n const result: Record<string, Record<number, TokenExtended[]>> = {}\n if (!existingBalances) {\n for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {\n result[address] = tokens\n }\n return result\n }\n\n for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {\n result[address] = {}\n\n for (const [chainIdStr, chainTokens] of Object.entries(tokens)) {\n const chainId = Number(chainIdStr)\n // Get balances for this specific chain\n const balances = existingBalances?.[chainId]\n // If no balances, RPC all tokens of the chain\n if (!balances?.length) {\n if (chainTokens.length) {\n result[address][chainId] = chainTokens\n }\n continue\n }\n\n // Optimize token matching with Set for O(1) lookup\n const balanceSet = new Set(\n balances.map((balance: WalletTokenExtended) =>\n balance.address.toLowerCase()\n )\n )\n\n // Get tokens that are in chainTokens and have balances\n const filteredTokens = chainTokens.filter((token) => {\n const tokenKey = token.address.toLowerCase()\n return balanceSet.has(tokenKey)\n })\n\n // Get tokens that are in balances but not in chainTokens\n const chainTokenSet = new Set(\n chainTokens.map((token) => token.address.toLowerCase())\n )\n\n // Get allowed addresses from config tokens\n const allowedAddressesConfig = getConfigItemSets(\n configTokens,\n (tokens: BaseToken[]) =>\n new Set(\n tokens\n .filter((t) => Number(t.chainId) === chainId)\n .map((t) => t.address.toLowerCase())\n ),\n formType\n )\n\n const additionalTokens = balances\n .filter((balance: WalletTokenExtended) => {\n const balanceKey = balance.address.toLowerCase()\n return (\n !chainTokenSet.has(balanceKey) &&\n isSupportedToken(balance) &&\n isFormItemAllowed(\n balance,\n allowedAddressesConfig,\n formType,\n (t) => t.address.toLowerCase()\n )\n )\n })\n // Mark tokens from wallet balances as unverified\n .map((token: WalletTokenExtended) => ({\n ...token,\n verified
|
|
1
|
+
{"version":3,"file":"useFilteredByTokenBalances.js","names":[],"sources":["../../../src/hooks/useFilteredByTokenBalances.ts"],"sourcesContent":["import {\n type BaseToken,\n ChainType,\n getWalletBalances,\n type TokenExtended,\n type WalletTokenExtended,\n} from '@lifi/sdk'\nimport { useQuery } from '@tanstack/react-query'\nimport { useMemo } from 'react'\nimport { useSDKClient } from '../providers/SDKClientProvider.js'\nimport { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'\nimport type { FormType } from '../stores/form/types.js'\nimport { getConfigItemSets, isFormItemAllowed } from '../utils/item.js'\nimport { getVerifiedTokensSets } from '../utils/token.js'\nimport { isSupportedToken } from '../utils/tokenList.js'\n\nexport const useFilteredTokensByBalance = (\n accountsWithTokens?: Record<\n string,\n { chainType: ChainType; tokens: Record<number, TokenExtended[]> }\n >,\n formType?: FormType\n): {\n data: Record<string, Record<number, TokenExtended[]>> | undefined\n isLoading: boolean\n} => {\n const { tokens: configTokens } = useWidgetConfig()\n const sdkClient = useSDKClient()\n\n const evmAddress = useMemo(() => {\n const evmAccount = Object.entries(accountsWithTokens ?? {}).find(\n ([_, { chainType }]) => chainType === ChainType.EVM\n )\n return evmAccount?.[0]\n }, [accountsWithTokens])\n\n const { data: existingBalances, isLoading } = useQuery({\n queryKey: ['existing-evm-balances', evmAddress],\n queryFn: () => getWalletBalances(sdkClient, evmAddress ?? ''),\n enabled: !!evmAddress,\n refetchInterval: 30_000, // 30 seconds\n staleTime: 30_000, // 30 seconds\n retry: false,\n })\n\n const accountsWithFilteredTokens = useMemo(() => {\n if (!accountsWithTokens) {\n return undefined\n }\n\n // Early return if no existing balances - return all tokens\n const result: Record<string, Record<number, TokenExtended[]>> = {}\n if (!existingBalances) {\n for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {\n result[address] = tokens\n }\n return result\n }\n\n const verifiedTokensSets = getVerifiedTokensSets(configTokens)\n\n for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {\n result[address] = {}\n\n for (const [chainIdStr, chainTokens] of Object.entries(tokens)) {\n const chainId = Number(chainIdStr)\n const verifiedAddresses = verifiedTokensSets?.get(chainId)\n // Get balances for this specific chain\n const balances = existingBalances?.[chainId]\n // If no balances, RPC all tokens of the chain\n if (!balances?.length) {\n if (chainTokens.length) {\n result[address][chainId] = chainTokens\n }\n continue\n }\n\n // Optimize token matching with Set for O(1) lookup\n const balanceSet = new Set(\n balances.map((balance: WalletTokenExtended) =>\n balance.address.toLowerCase()\n )\n )\n\n // Get tokens that are in chainTokens and have balances\n const filteredTokens = chainTokens.filter((token) => {\n const tokenKey = token.address.toLowerCase()\n return balanceSet.has(tokenKey)\n })\n\n // Get tokens that are in balances but not in chainTokens\n const chainTokenSet = new Set(\n chainTokens.map((token) => token.address.toLowerCase())\n )\n\n // Get allowed addresses from config tokens\n const allowedAddressesConfig = getConfigItemSets(\n configTokens,\n (tokens: BaseToken[]) =>\n new Set(\n tokens\n .filter((t) => Number(t.chainId) === chainId)\n .map((t) => t.address.toLowerCase())\n ),\n formType\n )\n\n const additionalTokens = balances\n .filter((balance: WalletTokenExtended) => {\n const balanceKey = balance.address.toLowerCase()\n return (\n !chainTokenSet.has(balanceKey) &&\n isSupportedToken(balance) &&\n isFormItemAllowed(\n balance,\n allowedAddressesConfig,\n formType,\n (t) => t.address.toLowerCase()\n )\n )\n })\n // Mark tokens from wallet balances as unverified unless allowlisted\n .map((token: WalletTokenExtended) => ({\n ...token,\n verified:\n verifiedAddresses?.has(token.address.toLowerCase()) ?? false,\n })) as TokenExtended[]\n\n // Combine both sets of tokens - convert WalletTokenExtended to TokenAmount\n const allTokens = [\n ...filteredTokens,\n ...additionalTokens,\n ] as TokenExtended[]\n\n if (allTokens.length) {\n result[address][chainId] = allTokens\n }\n }\n }\n\n return result\n }, [accountsWithTokens, existingBalances, configTokens, formType])\n\n return { data: accountsWithFilteredTokens, isLoading }\n}\n"],"mappings":";;;;;;;;;AAgBA,MAAa,8BACX,oBAIA,aAIG;CACH,MAAM,EAAE,QAAQ,iBAAiB,gBAAgB;CACjD,MAAM,YAAY,aAAa;CAE/B,MAAM,aAAa,cAAc;EAI/B,OAHmB,OAAO,QAAQ,sBAAsB,CAAC,CAAC,CAAC,CAAC,MACzD,CAAC,GAAG,EAAE,iBAAiB,cAAc,UAAU,GAElC,CAAC,GAAG;CACtB,GAAG,CAAC,kBAAkB,CAAC;CAEvB,MAAM,EAAE,MAAM,kBAAkB,cAAc,SAAS;EACrD,UAAU,CAAC,yBAAyB,UAAU;EAC9C,eAAe,kBAAkB,WAAW,cAAc,EAAE;EAC5D,SAAS,CAAC,CAAC;EACX,iBAAiB;EACjB,WAAW;EACX,OAAO;CACT,CAAC;CAoGD,OAAO;EAAE,MAlG0B,cAAc;GAC/C,IAAI,CAAC,oBACH;GAIF,MAAM,SAA0D,CAAC;GACjE,IAAI,CAAC,kBAAkB;IACrB,KAAK,MAAM,CAAC,SAAS,EAAE,aAAa,OAAO,QAAQ,kBAAkB,GACnE,OAAO,WAAW;IAEpB,OAAO;GACT;GAEA,MAAM,qBAAqB,sBAAsB,YAAY;GAE7D,KAAK,MAAM,CAAC,SAAS,EAAE,aAAa,OAAO,QAAQ,kBAAkB,GAAG;IACtE,OAAO,WAAW,CAAC;IAEnB,KAAK,MAAM,CAAC,YAAY,gBAAgB,OAAO,QAAQ,MAAM,GAAG;KAC9D,MAAM,UAAU,OAAO,UAAU;KACjC,MAAM,oBAAoB,oBAAoB,IAAI,OAAO;KAEzD,MAAM,WAAW,mBAAmB;KAEpC,IAAI,CAAC,UAAU,QAAQ;MACrB,IAAI,YAAY,QACd,OAAO,QAAQ,CAAC,WAAW;MAE7B;KACF;KAGA,MAAM,aAAa,IAAI,IACrB,SAAS,KAAK,YACZ,QAAQ,QAAQ,YAAY,CAC9B,CACF;KAGA,MAAM,iBAAiB,YAAY,QAAQ,UAAU;MACnD,MAAM,WAAW,MAAM,QAAQ,YAAY;MAC3C,OAAO,WAAW,IAAI,QAAQ;KAChC,CAAC;KAGD,MAAM,gBAAgB,IAAI,IACxB,YAAY,KAAK,UAAU,MAAM,QAAQ,YAAY,CAAC,CACxD;KAGA,MAAM,yBAAyB,kBAC7B,eACC,WACC,IAAI,IACF,OACG,QAAQ,MAAM,OAAO,EAAE,OAAO,MAAM,OAAO,CAAC,CAC5C,KAAK,MAAM,EAAE,QAAQ,YAAY,CAAC,CACvC,GACF,QACF;KAEA,MAAM,mBAAmB,SACtB,QAAQ,YAAiC;MACxC,MAAM,aAAa,QAAQ,QAAQ,YAAY;MAC/C,OACE,CAAC,cAAc,IAAI,UAAU,KAC7B,iBAAiB,OAAO,KACxB,kBACE,SACA,wBACA,WACC,MAAM,EAAE,QAAQ,YAAY,CAC/B;KAEJ,CAAC,CAAC,CAED,KAAK,WAAgC;MACpC,GAAG;MACH,UACE,mBAAmB,IAAI,MAAM,QAAQ,YAAY,CAAC,KAAK;KAC3D,EAAE;KAGJ,MAAM,YAAY,CAChB,GAAG,gBACH,GAAG,gBACL;KAEA,IAAI,UAAU,QACZ,OAAO,QAAQ,CAAC,WAAW;IAE/B;GACF;GAEA,OAAO;EACT,GAAG;GAAC;GAAoB;GAAkB;GAAc;EAAQ,CAExB;EAAG;CAAU;AACvD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.d.ts","names":[],"sources":["../../../src/types/widget.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"widget.d.ts","names":[],"sources":["../../../src/types/widget.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","names":[],"sources":["../../../src/types/widget.ts"],"sourcesContent":["import type {\n BaseToken,\n ChainType,\n ContractCall,\n ExecutionOptions,\n ExtendedChain,\n Order,\n Route,\n RouteOptions,\n SDKConfig,\n StaticToken,\n Token,\n} from '@lifi/sdk'\nimport type { WalletMenuOpenArgs } from '@lifi/wallet-management'\nimport type { WidgetProviderProps } from '@lifi/widget-provider'\nimport type {\n Components,\n PaletteMode,\n PaletteOptions,\n Shape,\n SxProps,\n Theme,\n} from '@mui/material'\nimport type { TypographyVariantsOptions } from '@mui/material/styles'\nimport type {\n CSSProperties,\n PropsWithChildren,\n ReactNode,\n RefObject,\n} from 'react'\nimport type {\n LanguageKey,\n LanguageResources,\n} from '../providers/I18nProvider/types.js'\nimport type { DefaultFieldValues } from '../stores/form/types.js'\n\nexport type WidgetVariant = 'compact' | 'wide' | 'drawer'\n\n/** @internal Not part of the public API. */\nexport type InternalWidgetMode = 'limit'\nexport type WidgetMode =\n | 'default'\n | 'split'\n | 'custom'\n | 'refuel'\n | InternalWidgetMode\nexport type SplitMode = 'bridge' | 'swap'\nexport type SplitModeOptions = {\n defaultTab: SplitMode\n}\nexport type CustomMode = 'checkout' | 'deposit'\nexport interface ModeOptions {\n /**\n * Configure split mode behavior:\n * - 'bridge' | 'swap': Single mode without tabs\n * - { defaultTab: 'bridge' | 'swap' }: Tabs mode with configurable default tab\n */\n split?: SplitMode | SplitModeOptions\n custom?: { type: CustomMode }\n}\n\n/**\n * Identity of a header navigation tab. Each key maps to a widget variant, mode and\n * (optionally) mode options; labels are resolved from the key.\n */\nexport type SplitNavigationTabKey = SplitMode\n/** @internal Not part of the public API. */\nexport type InternalNavigationTabKey =\n | 'default'\n | 'private'\n | 'refuel'\n | 'swap-advanced'\n | 'bridge-advanced'\n | 'limit'\nexport type NavigationTabKey = InternalNavigationTabKey | SplitNavigationTabKey\n\nexport type Appearance = PaletteMode | 'system'\nexport interface NavigationProps {\n /**\n * If given, uses a negative margin to counteract the padding on sides for navigation elements like icon buttons.\n * @default true\n */\n edge?: boolean\n}\nexport type WidgetThemeComponents = Partial<\n Pick<\n Components<Theme>,\n | 'MuiAppBar'\n | 'MuiAvatar'\n | 'MuiButton'\n | 'MuiCard'\n | 'MuiDrawer'\n | 'MuiIconButton'\n | 'MuiInputCard'\n | 'MuiNavigationTabs'\n | 'MuiNavigationTab'\n | 'MuiTabs'\n | 'MuiCheckbox'\n >\n>\n\nexport type WidgetTheme = {\n colorSchemes?: {\n light?: {\n palette: PaletteOptions\n }\n dark?: {\n palette: PaletteOptions\n }\n }\n shape?: Partial<Shape>\n typography?: TypographyVariantsOptions\n components?: WidgetThemeComponents\n container?: CSSProperties\n routesContainer?: CSSProperties\n chainSidebarContainer?: CSSProperties\n header?: CSSProperties\n navigation?: NavigationProps\n}\n\nexport interface DisabledUIConfig {\n fromAmount?: boolean\n fromToken?: boolean\n toAddress?: boolean\n toToken?: boolean\n}\n\nexport interface HiddenUIConfig {\n addressBookConnectedWallets?: boolean\n allNetworks?: boolean\n appearance?: boolean\n bridgesSettings?: boolean\n chainSelect?: boolean\n /**\n * Hide the chain sidebar in the `wide` variant. No effect in other variants.\n * @default false\n */\n chainSidebar?: boolean\n contactSupport?: boolean\n /**\n * Hide the drawer close button. Only meaningful when `variant === 'drawer'`.\n * @default false\n */\n drawerCloseButton?: boolean\n fromToken?: boolean\n gasRefuelMessage?: boolean\n hideSmallBalances?: boolean\n history?: boolean\n insufficientGasMessage?: boolean\n integratorStepDetails?: boolean\n language?: boolean\n /**\n * Hide the warning shown when sending to an address with low historical\n * on-chain activity (low transaction count or contract-like behavior).\n * @default false\n */\n lowAddressActivityConfirmation?: boolean\n poweredBy?: boolean\n reverseTokensButton?: boolean\n routeCardPriceImpact?: boolean\n routeTokenDescription?: boolean\n searchTokenInput?: boolean\n toAddress?: boolean\n toToken?: boolean\n walletMenu?: boolean\n}\n\nexport interface RequiredUIConfig {\n accountDeployedMessage?: boolean\n toAddress?: boolean\n}\n\nexport type DefaultUI = {\n transactionDetailsExpanded?: boolean\n navigationHeaderTitleNoWrap?: boolean\n /**\n * Layout for the main form.\n * - `'default'`: the chain/token selectors plus single amount input.\n * - `'cards'`: the redesigned card-based layout — stacked Send/Receive amount\n * cards (`AmountInputCardPair`) with inline token pill selectors and a swap\n * button.\n * @default 'default'\n */\n layout?: 'default' | 'cards'\n}\n\nexport interface WidgetWalletConfig {\n walletEcosystemsOrder?: Record<string, ChainType[]>\n onConnect?(args?: WalletMenuOpenArgs): void\n /**\n * Determines whether the widget should provide partial wallet management functionality.\n *\n * In partial mode, external wallet management will be used for \"opt-out\" providers,\n * while the internal management is applied for any remaining providers that do not opt out.\n * This allows a flexible balance between the integrator's custom wallet menu and the widget's native wallet menu.\n * @default false\n */\n usePartialWalletManagement?: boolean\n /**\n * This option forces the widget to always use internal wallet management ignoring external wallet management contexts\n * @default false\n */\n forceInternalWalletManagement?: boolean\n}\n\nexport interface WidgetSDKConfig\n extends Omit<\n SDKConfig,\n | 'apiKey'\n | 'disableVersionCheck'\n | 'integrator'\n | 'providers'\n | 'routeOptions'\n | 'widgetVersion'\n > {\n routeOptions?: Omit<\n RouteOptions,\n 'bridges' | 'exchanges' | 'fee' | 'referrer' | 'order' | 'slippage'\n >\n executionOptions?: Pick<ExecutionOptions, 'updateTransactionRequestHook'>\n}\n\nexport interface WidgetContractTool {\n name: string\n logoURI: string\n}\n\nexport interface CalculateFeeParams {\n fromChain: ExtendedChain\n toChain: ExtendedChain\n fromToken: Token\n toToken: Token\n fromAddress?: string\n toAddress?: string\n fromAmount?: bigint\n toAmount?: bigint\n slippage?: number\n}\n\nexport interface WidgetFeeConfig {\n name?: string\n logoURI?: string\n fee?: number\n /**\n * Whether to show the fee percentage in the fee details.\n * @default false\n */\n showFeePercentage?: boolean\n /**\n * Whether to show a tooltip with the fee details. Requires `name` or `feeTooltipComponent` to be set.\n * @default false\n */\n showFeeTooltip?: boolean\n /**\n * Custom tooltip component to show with the fee details.\n */\n feeTooltipComponent?: ReactNode\n /**\n * Function to calculate fees before fetching quotes.\n * If provided, this function will be used instead of the `fee` parameter.\n * Only one of `fee` or `calculateFee` should be used.\n *\n * @param params Object containing the fee calculation parameters\n * @returns A promise that resolves to the calculated fee as a number (e.g., 0.03 represents a 3% fee)\n */\n calculateFee?(params: CalculateFeeParams): Promise<number | undefined>\n}\n\nexport interface ToAddress {\n name?: string\n address: string\n chainType: ChainType\n logoURI?: string\n}\n\nexport interface AllowDeny<T> {\n allow?: T[]\n deny?: T[]\n}\n\nexport type AllowDenySetItem = string | number\nexport interface AllowDenySet {\n allow?: Set<AllowDenySetItem>\n deny?: Set<AllowDenySetItem>\n}\n\nexport type AllowDenySets = {\n from?: AllowDenySet\n to?: AllowDenySet\n} & AllowDenySet\n\nexport type AllowDenyItems<T> = {\n from?: AllowDeny<T>\n to?: AllowDeny<T>\n} & AllowDeny<T>\n\nexport type WidgetChains = {\n types?: AllowDeny<ChainType>\n} & AllowDenyItems<number>\n\nexport type WidgetTokens = {\n featured?: StaticToken[]\n include?: Token[]\n popular?: StaticToken[]\n} & AllowDenyItems<BaseToken>\n\nexport type WidgetLanguages = {\n default?: LanguageKey\n} & AllowDeny<LanguageKey>\n\nexport type PoweredByType = 'default' | 'jumper'\n\nexport interface RouteLabel {\n text: string\n sx?: SxProps<Theme>\n}\n\nexport interface RouteLabelRule {\n label: RouteLabel\n // Matching criteria\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n fromChainId?: number[]\n toChainId?: number[]\n fromTokenAddress?: string[]\n toTokenAddress?: string[]\n /**\n * Custom match function evaluated against the route. When provided, its\n * result is AND'd with the other matching criteria — all specified\n * conditions must pass for the label to apply. Use this for matching logic\n * that the built-in fields cannot express (gas costs, step count, route\n * tags, etc.).\n */\n match?: (route: Route) => boolean\n}\n\nexport type ExplorerUrl =\n | string\n | {\n url: string\n txPath?: string\n addressPath?: string\n }\n\nexport type WidgetProvider = (\n props: PropsWithChildren<WidgetProviderProps>\n) => ReactNode\n\nexport interface WidgetConfig {\n fromChain?: number\n toChain?: number\n fromToken?: string\n toToken?: string\n toAddress?: ToAddress\n toAddresses?: ToAddress[]\n fromAmount?: number | string\n minFromAmountUSD?: number\n toAmount?: number | string\n formUpdateKey?: string\n\n providers?: WidgetProvider[]\n\n contractCalls?: ContractCall[]\n contractComponent?: ReactNode\n contractSecondaryComponent?: ReactNode\n contractCompactComponent?: ReactNode\n contractTool?: WidgetContractTool\n integrator: string\n apiKey?: string\n feeConfig?: WidgetFeeConfig\n referrer?: string\n\n routePriority?: Order\n slippage?: number\n\n variant?: WidgetVariant\n mode?: WidgetMode\n modeOptions?: ModeOptions\n /**\n * Header navigation tabs, in order. When set, the widget renders a tab bar\n * and the active tab drives the displayed flow. Each entry is a tab key.\n *\n * @internal Not part of the public API.\n */\n _navigationTabs?: NavigationTabKey[]\n\n appearance?: Appearance\n theme?: WidgetTheme\n\n disabledUI?: DisabledUIConfig\n hiddenUI?: HiddenUIConfig\n requiredUI?: RequiredUIConfig\n defaultUI?: DefaultUI\n /**\n * When true, shows only the recommended route and hides the route\n * selector UI. Distinct from `routePriority`, which sets the SDK\n * ranking order across multiple displayed routes.\n * @default false\n */\n showSingleRoute?: boolean\n useRelayerRoutes?: boolean\n\n walletConfig?: WidgetWalletConfig\n sdkConfig?: WidgetSDKConfig\n\n buildUrl?: boolean\n keyPrefix?: string\n\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n chains?: WidgetChains\n tokens?: WidgetTokens\n languages?: WidgetLanguages\n languageResources?: LanguageResources\n explorerUrls?: Record<number, ExplorerUrl[]> &\n Partial<Record<'internal', ExplorerUrl[]>>\n poweredBy?: PoweredByType\n\n /**\n * Custom labels/badges to show on routes based on specified rules\n */\n routeLabels?: RouteLabelRule[]\n}\n\nexport interface FormFieldOptions {\n setUrlSearchParam: boolean\n}\n\nexport interface FieldValues\n extends Omit<DefaultFieldValues, 'fromAmount' | 'toAmount' | 'toAddress'> {\n fromAmount?: number | string\n toAmount?: number | string\n toAddress?: ToAddress | string\n}\n\nexport type FieldNames = keyof FieldValues\n\nexport type SetFieldValueFunction = <K extends FieldNames>(\n key: K,\n value: FieldValues[K],\n options?: FormFieldOptions\n) => void\n\nexport type FormState = {\n setFieldValue: SetFieldValueFunction\n}\n\nexport type FormRef = RefObject<FormState | null>\n\nexport interface FormRefProps {\n formRef?: FormRef\n}\n\nexport interface WidgetConfigProps extends FormRefProps {\n config: WidgetConfig\n}\n\nexport interface WidgetConfigPartialProps {\n config?: Partial<WidgetConfig>\n}\n\nexport type WidgetProps = WidgetDrawerProps &\n WidgetConfig &\n WidgetConfigPartialProps &\n FormRefProps\n\nexport interface WidgetDrawerProps extends WidgetConfigPartialProps {\n elementRef?: RefObject<HTMLDivElement>\n open?: boolean\n /**\n * Make sure to make the onClose callback stable (e.g. using useCallback) to avoid causing re-renders of the entire widget\n */\n onClose?(): void\n}\n\nexport enum ExpansionType {\n Routes = 'routes',\n FromChain = 'fromChain',\n ToChain = 'toChain',\n}\n"],"mappings":";AA2dA,IAAY,gBAAL,yBAAA,eAAA;CACL,cAAA,YAAA;CACA,cAAA,eAAA;CACA,cAAA,aAAA;;AACF,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"widget.js","names":[],"sources":["../../../src/types/widget.ts"],"sourcesContent":["import type {\n BaseToken,\n ChainType,\n ContractCall,\n ExecutionOptions,\n ExtendedChain,\n Order,\n Route,\n RouteOptions,\n SDKConfig,\n StaticToken,\n Token,\n} from '@lifi/sdk'\nimport type { WalletMenuOpenArgs } from '@lifi/wallet-management'\nimport type { WidgetProviderProps } from '@lifi/widget-provider'\nimport type {\n Components,\n PaletteMode,\n PaletteOptions,\n Shape,\n SxProps,\n Theme,\n} from '@mui/material'\nimport type { TypographyVariantsOptions } from '@mui/material/styles'\nimport type {\n CSSProperties,\n PropsWithChildren,\n ReactNode,\n RefObject,\n} from 'react'\nimport type {\n LanguageKey,\n LanguageResources,\n} from '../providers/I18nProvider/types.js'\nimport type { DefaultFieldValues } from '../stores/form/types.js'\n\nexport type WidgetVariant = 'compact' | 'wide' | 'drawer'\n\n/** @internal Not part of the public API. */\nexport type InternalWidgetMode = 'limit'\nexport type WidgetMode =\n | 'default'\n | 'split'\n | 'custom'\n | 'refuel'\n | InternalWidgetMode\nexport type SplitMode = 'bridge' | 'swap'\nexport type SplitModeOptions = {\n defaultTab: SplitMode\n}\nexport type CustomMode = 'checkout' | 'deposit'\nexport interface ModeOptions {\n /**\n * Configure split mode behavior:\n * - 'bridge' | 'swap': Single mode without tabs\n * - { defaultTab: 'bridge' | 'swap' }: Tabs mode with configurable default tab\n */\n split?: SplitMode | SplitModeOptions\n custom?: { type: CustomMode }\n}\n\n/**\n * Identity of a header navigation tab. Each key maps to a widget variant, mode and\n * (optionally) mode options; labels are resolved from the key.\n */\nexport type SplitNavigationTabKey = SplitMode\n/** @internal Not part of the public API. */\nexport type InternalNavigationTabKey =\n | 'default'\n | 'private'\n | 'refuel'\n | 'swap-advanced'\n | 'bridge-advanced'\n | 'limit'\nexport type NavigationTabKey = InternalNavigationTabKey | SplitNavigationTabKey\n\nexport type Appearance = PaletteMode | 'system'\nexport interface NavigationProps {\n /**\n * If given, uses a negative margin to counteract the padding on sides for navigation elements like icon buttons.\n * @default true\n */\n edge?: boolean\n}\nexport type WidgetThemeComponents = Partial<\n Pick<\n Components<Theme>,\n | 'MuiAppBar'\n | 'MuiAvatar'\n | 'MuiButton'\n | 'MuiCard'\n | 'MuiDrawer'\n | 'MuiIconButton'\n | 'MuiInputCard'\n | 'MuiNavigationTabs'\n | 'MuiNavigationTab'\n | 'MuiTabs'\n | 'MuiCheckbox'\n >\n>\n\nexport type WidgetTheme = {\n colorSchemes?: {\n light?: {\n palette: PaletteOptions\n }\n dark?: {\n palette: PaletteOptions\n }\n }\n shape?: Partial<Shape>\n typography?: TypographyVariantsOptions\n components?: WidgetThemeComponents\n container?: CSSProperties\n routesContainer?: CSSProperties\n chainSidebarContainer?: CSSProperties\n header?: CSSProperties\n navigation?: NavigationProps\n}\n\nexport interface DisabledUIConfig {\n fromAmount?: boolean\n fromToken?: boolean\n toAddress?: boolean\n toToken?: boolean\n}\n\nexport interface HiddenUIConfig {\n addressBookConnectedWallets?: boolean\n allNetworks?: boolean\n appearance?: boolean\n bridgesSettings?: boolean\n chainSelect?: boolean\n /**\n * Hide the chain sidebar in the `wide` variant. No effect in other variants.\n * @default false\n */\n chainSidebar?: boolean\n contactSupport?: boolean\n /**\n * Hide the drawer close button. Only meaningful when `variant === 'drawer'`.\n * @default false\n */\n drawerCloseButton?: boolean\n fromToken?: boolean\n gasRefuelMessage?: boolean\n hideSmallBalances?: boolean\n history?: boolean\n insufficientGasMessage?: boolean\n integratorStepDetails?: boolean\n language?: boolean\n /**\n * Hide the warning shown when sending to an address with low historical\n * on-chain activity (low transaction count or contract-like behavior).\n * @default false\n */\n lowAddressActivityConfirmation?: boolean\n poweredBy?: boolean\n reverseTokensButton?: boolean\n routeCardPriceImpact?: boolean\n routeTokenDescription?: boolean\n searchTokenInput?: boolean\n toAddress?: boolean\n toToken?: boolean\n walletMenu?: boolean\n}\n\nexport interface RequiredUIConfig {\n accountDeployedMessage?: boolean\n toAddress?: boolean\n}\n\nexport type DefaultUI = {\n transactionDetailsExpanded?: boolean\n navigationHeaderTitleNoWrap?: boolean\n /**\n * Layout for the main form.\n * - `'default'`: the chain/token selectors plus single amount input.\n * - `'cards'`: the redesigned card-based layout — stacked Send/Receive amount\n * cards (`AmountInputCardPair`) with inline token pill selectors and a swap\n * button.\n * @default 'default'\n */\n layout?: 'default' | 'cards'\n}\n\nexport interface WidgetWalletConfig {\n walletEcosystemsOrder?: Record<string, ChainType[]>\n onConnect?(args?: WalletMenuOpenArgs): void\n /**\n * Determines whether the widget should provide partial wallet management functionality.\n *\n * In partial mode, external wallet management will be used for \"opt-out\" providers,\n * while the internal management is applied for any remaining providers that do not opt out.\n * This allows a flexible balance between the integrator's custom wallet menu and the widget's native wallet menu.\n * @default false\n */\n usePartialWalletManagement?: boolean\n /**\n * This option forces the widget to always use internal wallet management ignoring external wallet management contexts\n * @default false\n */\n forceInternalWalletManagement?: boolean\n}\n\nexport interface WidgetSDKConfig\n extends Omit<\n SDKConfig,\n | 'apiKey'\n | 'disableVersionCheck'\n | 'integrator'\n | 'providers'\n | 'routeOptions'\n | 'widgetVersion'\n > {\n routeOptions?: Omit<\n RouteOptions,\n 'bridges' | 'exchanges' | 'fee' | 'referrer' | 'order' | 'slippage'\n >\n executionOptions?: Pick<ExecutionOptions, 'updateTransactionRequestHook'>\n}\n\nexport interface WidgetContractTool {\n name: string\n logoURI: string\n}\n\nexport interface CalculateFeeParams {\n fromChain: ExtendedChain\n toChain: ExtendedChain\n fromToken: Token\n toToken: Token\n fromAddress?: string\n toAddress?: string\n fromAmount?: bigint\n toAmount?: bigint\n slippage?: number\n}\n\nexport interface WidgetFeeConfig {\n name?: string\n logoURI?: string\n fee?: number\n /**\n * Whether to show the fee percentage in the fee details.\n * @default false\n */\n showFeePercentage?: boolean\n /**\n * Whether to show a tooltip with the fee details. Requires `name` or `feeTooltipComponent` to be set.\n * @default false\n */\n showFeeTooltip?: boolean\n /**\n * Custom tooltip component to show with the fee details.\n */\n feeTooltipComponent?: ReactNode\n /**\n * Function to calculate fees before fetching quotes.\n * If provided, this function will be used instead of the `fee` parameter.\n * Only one of `fee` or `calculateFee` should be used.\n *\n * @param params Object containing the fee calculation parameters\n * @returns A promise that resolves to the calculated fee as a number (e.g., 0.03 represents a 3% fee)\n */\n calculateFee?(params: CalculateFeeParams): Promise<number | undefined>\n}\n\nexport interface ToAddress {\n name?: string\n address: string\n chainType: ChainType\n logoURI?: string\n}\n\nexport interface AllowDeny<T> {\n allow?: T[]\n deny?: T[]\n}\n\nexport type AllowDenySetItem = string | number\nexport interface AllowDenySet {\n allow?: Set<AllowDenySetItem>\n deny?: Set<AllowDenySetItem>\n}\n\nexport type AllowDenySets = {\n from?: AllowDenySet\n to?: AllowDenySet\n} & AllowDenySet\n\nexport type AllowDenyItems<T> = {\n from?: AllowDeny<T>\n to?: AllowDeny<T>\n} & AllowDeny<T>\n\nexport type WidgetChains = {\n types?: AllowDeny<ChainType>\n} & AllowDenyItems<number>\n\nexport type WidgetTokens = {\n featured?: StaticToken[]\n include?: Token[]\n popular?: StaticToken[]\n verified?: BaseToken[]\n} & AllowDenyItems<BaseToken>\n\nexport type WidgetLanguages = {\n default?: LanguageKey\n} & AllowDeny<LanguageKey>\n\nexport type PoweredByType = 'default' | 'jumper'\n\nexport interface RouteLabel {\n text: string\n sx?: SxProps<Theme>\n}\n\nexport interface RouteLabelRule {\n label: RouteLabel\n // Matching criteria\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n fromChainId?: number[]\n toChainId?: number[]\n fromTokenAddress?: string[]\n toTokenAddress?: string[]\n /**\n * Custom match function evaluated against the route. When provided, its\n * result is AND'd with the other matching criteria — all specified\n * conditions must pass for the label to apply. Use this for matching logic\n * that the built-in fields cannot express (gas costs, step count, route\n * tags, etc.).\n */\n match?: (route: Route) => boolean\n}\n\nexport type ExplorerUrl =\n | string\n | {\n url: string\n txPath?: string\n addressPath?: string\n }\n\nexport type WidgetProvider = (\n props: PropsWithChildren<WidgetProviderProps>\n) => ReactNode\n\nexport interface WidgetConfig {\n fromChain?: number\n toChain?: number\n fromToken?: string\n toToken?: string\n toAddress?: ToAddress\n toAddresses?: ToAddress[]\n fromAmount?: number | string\n minFromAmountUSD?: number\n toAmount?: number | string\n formUpdateKey?: string\n\n providers?: WidgetProvider[]\n\n contractCalls?: ContractCall[]\n contractComponent?: ReactNode\n contractSecondaryComponent?: ReactNode\n contractCompactComponent?: ReactNode\n contractTool?: WidgetContractTool\n integrator: string\n apiKey?: string\n feeConfig?: WidgetFeeConfig\n referrer?: string\n\n routePriority?: Order\n slippage?: number\n\n variant?: WidgetVariant\n mode?: WidgetMode\n modeOptions?: ModeOptions\n /**\n * Header navigation tabs, in order. When set, the widget renders a tab bar\n * and the active tab drives the displayed flow. Each entry is a tab key.\n *\n * @internal Not part of the public API.\n */\n _navigationTabs?: NavigationTabKey[]\n\n appearance?: Appearance\n theme?: WidgetTheme\n\n disabledUI?: DisabledUIConfig\n hiddenUI?: HiddenUIConfig\n requiredUI?: RequiredUIConfig\n defaultUI?: DefaultUI\n /**\n * When true, shows only the recommended route and hides the route\n * selector UI. Distinct from `routePriority`, which sets the SDK\n * ranking order across multiple displayed routes.\n * @default false\n */\n showSingleRoute?: boolean\n useRelayerRoutes?: boolean\n\n walletConfig?: WidgetWalletConfig\n sdkConfig?: WidgetSDKConfig\n\n buildUrl?: boolean\n keyPrefix?: string\n\n bridges?: AllowDeny<string>\n exchanges?: AllowDeny<string>\n chains?: WidgetChains\n tokens?: WidgetTokens\n languages?: WidgetLanguages\n languageResources?: LanguageResources\n explorerUrls?: Record<number, ExplorerUrl[]> &\n Partial<Record<'internal', ExplorerUrl[]>>\n poweredBy?: PoweredByType\n\n /**\n * Custom labels/badges to show on routes based on specified rules\n */\n routeLabels?: RouteLabelRule[]\n}\n\nexport interface FormFieldOptions {\n setUrlSearchParam: boolean\n}\n\nexport interface FieldValues\n extends Omit<DefaultFieldValues, 'fromAmount' | 'toAmount' | 'toAddress'> {\n fromAmount?: number | string\n toAmount?: number | string\n toAddress?: ToAddress | string\n}\n\nexport type FieldNames = keyof FieldValues\n\nexport type SetFieldValueFunction = <K extends FieldNames>(\n key: K,\n value: FieldValues[K],\n options?: FormFieldOptions\n) => void\n\nexport type FormState = {\n setFieldValue: SetFieldValueFunction\n}\n\nexport type FormRef = RefObject<FormState | null>\n\nexport interface FormRefProps {\n formRef?: FormRef\n}\n\nexport interface WidgetConfigProps extends FormRefProps {\n config: WidgetConfig\n}\n\nexport interface WidgetConfigPartialProps {\n config?: Partial<WidgetConfig>\n}\n\nexport type WidgetProps = WidgetDrawerProps &\n WidgetConfig &\n WidgetConfigPartialProps &\n FormRefProps\n\nexport interface WidgetDrawerProps extends WidgetConfigPartialProps {\n elementRef?: RefObject<HTMLDivElement>\n open?: boolean\n /**\n * Make sure to make the onClose callback stable (e.g. using useCallback) to avoid causing re-renders of the entire widget\n */\n onClose?(): void\n}\n\nexport enum ExpansionType {\n Routes = 'routes',\n FromChain = 'fromChain',\n ToChain = 'toChain',\n}\n"],"mappings":";AA4dA,IAAY,gBAAL,yBAAA,eAAA;CACL,cAAA,YAAA;CACA,cAAA,eAAA;CACA,cAAA,aAAA;;AACF,EAAA,CAAA,CAAA"}
|
package/dist/esm/utils/token.js
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { getConfigItemSets, isFormItemAllowed } from "./item.js";
|
|
2
2
|
//#region src/utils/token.ts
|
|
3
3
|
/**
|
|
4
|
+
* Builds per-chain sets of lowercase token addresses from the
|
|
5
|
+
* `tokens.verified` config allowlist.
|
|
6
|
+
*/
|
|
7
|
+
const getVerifiedTokensSets = (configTokens) => {
|
|
8
|
+
if (!configTokens?.verified?.length) return;
|
|
9
|
+
const sets = /* @__PURE__ */ new Map();
|
|
10
|
+
for (const token of configTokens.verified) {
|
|
11
|
+
const chainId = Number(token.chainId);
|
|
12
|
+
let addresses = sets.get(chainId);
|
|
13
|
+
if (!addresses) {
|
|
14
|
+
addresses = /* @__PURE__ */ new Set();
|
|
15
|
+
sets.set(chainId, addresses);
|
|
16
|
+
}
|
|
17
|
+
addresses.add(token.address.toLowerCase());
|
|
18
|
+
}
|
|
19
|
+
return sets;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
4
22
|
* Merges verified tokens with search tokens.
|
|
5
23
|
* Verified tokens take priority - search tokens are only added if they don't already exist.
|
|
6
24
|
*/
|
|
@@ -41,11 +59,28 @@ const filterAllowedTokens = (dataTokens, configTokens, chainsConfig, formType) =
|
|
|
41
59
|
const allChainIds = Array.from(/* @__PURE__ */ new Set([...includedTokens.map((t) => t.chainId), ...Object.keys(dataTokens)])).map((chainId) => Number(chainId));
|
|
42
60
|
const configChainIdsSet = getConfigItemSets(chainsConfig, (chainIds) => new Set(chainIds), formType);
|
|
43
61
|
const allowedChainIds = configChainIdsSet ? allChainIds.filter((chainId) => isFormItemAllowed(chainId, configChainIdsSet, formType)) : allChainIds;
|
|
62
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens);
|
|
44
63
|
const allowedTokensByChain = {};
|
|
45
64
|
for (const chainId of allowedChainIds) {
|
|
46
|
-
const
|
|
65
|
+
const chainIncludedTokens = includedTokens.filter((t) => Number(t.chainId) === chainId);
|
|
66
|
+
const includedAddresses = new Set(chainIncludedTokens.map((t) => t.address.toLowerCase()));
|
|
47
67
|
const allowedAddresses = getConfigItemSets(configTokens, (tokens) => new Set(tokens.filter((t) => Number(t.chainId) === chainId).map((t) => t.address.toLowerCase())), formType);
|
|
48
|
-
|
|
68
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId);
|
|
69
|
+
const chainTokens = [...dataTokens[chainId] ?? [], ...chainIncludedTokens];
|
|
70
|
+
const filtered = [];
|
|
71
|
+
const seenAddresses = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const token of chainTokens) {
|
|
73
|
+
const address = token.address.toLowerCase();
|
|
74
|
+
if (seenAddresses.has(address)) continue;
|
|
75
|
+
seenAddresses.add(address);
|
|
76
|
+
if (!isFormItemAllowed(token, allowedAddresses, formType, (t) => t.address.toLowerCase())) continue;
|
|
77
|
+
if (!token.verified && (includedAddresses.has(address) || verifiedAddresses?.has(address))) filtered.push({
|
|
78
|
+
...token,
|
|
79
|
+
verified: true
|
|
80
|
+
});
|
|
81
|
+
else filtered.push(token);
|
|
82
|
+
}
|
|
83
|
+
allowedTokensByChain[chainId] = filtered;
|
|
49
84
|
}
|
|
50
85
|
return allowedTokensByChain;
|
|
51
86
|
};
|
|
@@ -54,6 +89,6 @@ const getExecutionToToken = (route) => ({
|
|
|
54
89
|
amount: BigInt(route.steps.at(-1)?.execution?.toAmount ?? route.steps.at(-1)?.estimate.toAmount ?? route.toAmount)
|
|
55
90
|
});
|
|
56
91
|
//#endregion
|
|
57
|
-
export { filterAllowedTokens, getExecutionToToken, mergeVerifiedWithSearchTokens, updateTokenInCache };
|
|
92
|
+
export { filterAllowedTokens, getExecutionToToken, getVerifiedTokensSets, mergeVerifiedWithSearchTokens, updateTokenInCache };
|
|
58
93
|
|
|
59
94
|
//# sourceMappingURL=token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","names":[],"sources":["../../../src/utils/token.ts"],"sourcesContent":["import type {
|
|
1
|
+
{"version":3,"file":"token.js","names":[],"sources":["../../../src/utils/token.ts"],"sourcesContent":["import type { BaseToken, RouteExtended, Token, TokenAmount } from '@lifi/sdk'\nimport type { FormType } from '../stores/form/types.js'\nimport type { TokensByChain, TokenWithVerified } from '../types/token.js'\nimport type { WidgetChains, WidgetTokens } from '../types/widget.js'\nimport { getConfigItemSets, isFormItemAllowed } from './item.js'\n\n/**\n * Builds per-chain sets of lowercase token addresses from the\n * `tokens.verified` config allowlist.\n */\nexport const getVerifiedTokensSets = (\n configTokens?: WidgetTokens\n): Map<number, Set<string>> | undefined => {\n if (!configTokens?.verified?.length) {\n return undefined\n }\n const sets = new Map<number, Set<string>>()\n for (const token of configTokens.verified) {\n const chainId = Number(token.chainId)\n let addresses = sets.get(chainId)\n if (!addresses) {\n addresses = new Set()\n sets.set(chainId, addresses)\n }\n addresses.add(token.address.toLowerCase())\n }\n return sets\n}\n\n/**\n * Merges verified tokens with search tokens.\n * Verified tokens take priority - search tokens are only added if they don't already exist.\n */\nexport const mergeVerifiedWithSearchTokens = (\n verifiedTokens?: TokensByChain,\n searchTokens?: TokensByChain\n): TokensByChain | undefined => {\n if (!verifiedTokens) {\n return searchTokens\n }\n if (!searchTokens) {\n return verifiedTokens\n }\n\n const result = { ...verifiedTokens }\n\n for (const [chainId, tokens] of Object.entries(searchTokens)) {\n const chainIdNum = Number(chainId)\n const existingTokens = result[chainIdNum] || []\n const existingAddresses = new Set(\n existingTokens.map((t) => t.address.toLowerCase())\n )\n\n const newTokens = tokens.filter(\n (t) => !existingAddresses.has(t.address.toLowerCase())\n )\n\n if (newTokens.length) {\n result[chainIdNum] = [...existingTokens, ...newTokens]\n }\n }\n\n return result\n}\n\n/**\n * Updates a token in the cache by chainId and address.\n * Returns a new cache object with the token updated, or the original if not found.\n */\nexport const updateTokenInCache = (\n data: TokensByChain | undefined,\n token: Token\n): TokensByChain | undefined => {\n if (!data) {\n return data\n }\n const chainTokens = data[token.chainId]\n if (!chainTokens) {\n return data\n }\n const index = chainTokens.findIndex((t) => t.address === token.address)\n if (index < 0) {\n return data\n }\n return {\n ...data,\n [token.chainId]: chainTokens.map((t, i) =>\n i === index ? { ...t, ...token } : t\n ),\n }\n}\n\nexport const filterAllowedTokens = (\n dataTokens: TokensByChain | undefined,\n configTokens?: WidgetTokens,\n chainsConfig?: WidgetChains,\n formType?: FormType\n): TokensByChain | undefined => {\n if (!dataTokens) {\n return\n }\n\n const includedTokens = configTokens?.include || []\n const allChainIds = Array.from(\n new Set([\n ...includedTokens.map((t) => t.chainId),\n ...Object.keys(dataTokens),\n ])\n ).map((chainId) => Number(chainId))\n\n const configChainIdsSet = getConfigItemSets(\n chainsConfig,\n (chainIds: number[]) => new Set(chainIds),\n formType\n )\n\n const allowedChainIds = configChainIdsSet\n ? allChainIds.filter((chainId) =>\n isFormItemAllowed(chainId, configChainIdsSet, formType)\n )\n : allChainIds\n\n const verifiedTokensSets = getVerifiedTokensSets(configTokens)\n\n const allowedTokensByChain: TokensByChain = {}\n for (const chainId of allowedChainIds) {\n const chainIncludedTokens = includedTokens.filter(\n (t) => Number(t.chainId) === chainId\n )\n const includedAddresses = new Set(\n chainIncludedTokens.map((t) => t.address.toLowerCase())\n )\n\n const allowedAddresses = getConfigItemSets(\n configTokens,\n (tokens: BaseToken[]) =>\n new Set(\n tokens\n .filter((t) => Number(t.chainId) === chainId)\n .map((t) => t.address.toLowerCase())\n ),\n formType\n )\n\n const verifiedAddresses = verifiedTokensSets?.get(chainId)\n\n const chainTokens: TokenWithVerified[] = [\n ...(dataTokens[chainId] ?? []),\n ...chainIncludedTokens,\n ]\n\n const filtered: TokenWithVerified[] = []\n const seenAddresses = new Set<string>()\n for (const token of chainTokens) {\n const address = token.address.toLowerCase()\n // Data tokens come first and win over include duplicates,\n // keeping their extended data\n if (seenAddresses.has(address)) {\n continue\n }\n seenAddresses.add(address)\n if (\n !isFormItemAllowed(token, allowedAddresses, formType, (t) =>\n t.address.toLowerCase()\n )\n ) {\n continue\n }\n // Include and verified-allowlist tokens are explicitly set by the\n // integrator, mark them as verified\n if (\n !token.verified &&\n (includedAddresses.has(address) || verifiedAddresses?.has(address))\n ) {\n filtered.push({ ...token, verified: true })\n } else {\n filtered.push(token)\n }\n }\n\n allowedTokensByChain[chainId] = filtered\n }\n\n return allowedTokensByChain\n}\n\nexport const getExecutionToToken = (route: RouteExtended): TokenAmount => ({\n ...(route.steps.at(-1)?.execution?.toToken ?? route.toToken),\n amount: BigInt(\n route.steps.at(-1)?.execution?.toAmount ??\n route.steps.at(-1)?.estimate.toAmount ??\n route.toAmount\n ),\n})\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifi/widget",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "LI.FI Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/esm/index.js",
|
package/src/config/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const name = '@lifi/widget'
|
|
2
|
-
export const version = '4.
|
|
2
|
+
export const version = '4.3.0'
|
|
@@ -11,6 +11,7 @@ import { useSDKClient } from '../providers/SDKClientProvider.js'
|
|
|
11
11
|
import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
|
|
12
12
|
import type { FormType } from '../stores/form/types.js'
|
|
13
13
|
import { getConfigItemSets, isFormItemAllowed } from '../utils/item.js'
|
|
14
|
+
import { getVerifiedTokensSets } from '../utils/token.js'
|
|
14
15
|
import { isSupportedToken } from '../utils/tokenList.js'
|
|
15
16
|
|
|
16
17
|
export const useFilteredTokensByBalance = (
|
|
@@ -56,11 +57,14 @@ export const useFilteredTokensByBalance = (
|
|
|
56
57
|
return result
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens)
|
|
61
|
+
|
|
59
62
|
for (const [address, { tokens }] of Object.entries(accountsWithTokens)) {
|
|
60
63
|
result[address] = {}
|
|
61
64
|
|
|
62
65
|
for (const [chainIdStr, chainTokens] of Object.entries(tokens)) {
|
|
63
66
|
const chainId = Number(chainIdStr)
|
|
67
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId)
|
|
64
68
|
// Get balances for this specific chain
|
|
65
69
|
const balances = existingBalances?.[chainId]
|
|
66
70
|
// If no balances, RPC all tokens of the chain
|
|
@@ -115,10 +119,11 @@ export const useFilteredTokensByBalance = (
|
|
|
115
119
|
)
|
|
116
120
|
)
|
|
117
121
|
})
|
|
118
|
-
// Mark tokens from wallet balances as unverified
|
|
122
|
+
// Mark tokens from wallet balances as unverified unless allowlisted
|
|
119
123
|
.map((token: WalletTokenExtended) => ({
|
|
120
124
|
...token,
|
|
121
|
-
verified:
|
|
125
|
+
verified:
|
|
126
|
+
verifiedAddresses?.has(token.address.toLowerCase()) ?? false,
|
|
122
127
|
})) as TokenExtended[]
|
|
123
128
|
|
|
124
129
|
// Combine both sets of tokens - convert WalletTokenExtended to TokenAmount
|
package/src/types/widget.ts
CHANGED
package/src/utils/token.ts
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
BaseToken,
|
|
3
|
-
RouteExtended,
|
|
4
|
-
Token,
|
|
5
|
-
TokenAmount,
|
|
6
|
-
TokenExtended,
|
|
7
|
-
} from '@lifi/sdk'
|
|
1
|
+
import type { BaseToken, RouteExtended, Token, TokenAmount } from '@lifi/sdk'
|
|
8
2
|
import type { FormType } from '../stores/form/types.js'
|
|
9
|
-
import type { TokensByChain } from '../types/token.js'
|
|
3
|
+
import type { TokensByChain, TokenWithVerified } from '../types/token.js'
|
|
10
4
|
import type { WidgetChains, WidgetTokens } from '../types/widget.js'
|
|
11
5
|
import { getConfigItemSets, isFormItemAllowed } from './item.js'
|
|
12
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Builds per-chain sets of lowercase token addresses from the
|
|
9
|
+
* `tokens.verified` config allowlist.
|
|
10
|
+
*/
|
|
11
|
+
export const getVerifiedTokensSets = (
|
|
12
|
+
configTokens?: WidgetTokens
|
|
13
|
+
): Map<number, Set<string>> | undefined => {
|
|
14
|
+
if (!configTokens?.verified?.length) {
|
|
15
|
+
return undefined
|
|
16
|
+
}
|
|
17
|
+
const sets = new Map<number, Set<string>>()
|
|
18
|
+
for (const token of configTokens.verified) {
|
|
19
|
+
const chainId = Number(token.chainId)
|
|
20
|
+
let addresses = sets.get(chainId)
|
|
21
|
+
if (!addresses) {
|
|
22
|
+
addresses = new Set()
|
|
23
|
+
sets.set(chainId, addresses)
|
|
24
|
+
}
|
|
25
|
+
addresses.add(token.address.toLowerCase())
|
|
26
|
+
}
|
|
27
|
+
return sets
|
|
28
|
+
}
|
|
29
|
+
|
|
13
30
|
/**
|
|
14
31
|
* Merges verified tokens with search tokens.
|
|
15
32
|
* Verified tokens take priority - search tokens are only added if they don't already exist.
|
|
@@ -74,11 +91,11 @@ export const updateTokenInCache = (
|
|
|
74
91
|
}
|
|
75
92
|
|
|
76
93
|
export const filterAllowedTokens = (
|
|
77
|
-
dataTokens:
|
|
94
|
+
dataTokens: TokensByChain | undefined,
|
|
78
95
|
configTokens?: WidgetTokens,
|
|
79
96
|
chainsConfig?: WidgetChains,
|
|
80
97
|
formType?: FormType
|
|
81
|
-
):
|
|
98
|
+
): TokensByChain | undefined => {
|
|
82
99
|
if (!dataTokens) {
|
|
83
100
|
return
|
|
84
101
|
}
|
|
@@ -103,12 +120,16 @@ export const filterAllowedTokens = (
|
|
|
103
120
|
)
|
|
104
121
|
: allChainIds
|
|
105
122
|
|
|
106
|
-
const
|
|
123
|
+
const verifiedTokensSets = getVerifiedTokensSets(configTokens)
|
|
124
|
+
|
|
125
|
+
const allowedTokensByChain: TokensByChain = {}
|
|
107
126
|
for (const chainId of allowedChainIds) {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
127
|
+
const chainIncludedTokens = includedTokens.filter(
|
|
128
|
+
(t) => Number(t.chainId) === chainId
|
|
129
|
+
)
|
|
130
|
+
const includedAddresses = new Set(
|
|
131
|
+
chainIncludedTokens.map((t) => t.address.toLowerCase())
|
|
132
|
+
)
|
|
112
133
|
|
|
113
134
|
const allowedAddresses = getConfigItemSets(
|
|
114
135
|
configTokens,
|
|
@@ -121,11 +142,41 @@ export const filterAllowedTokens = (
|
|
|
121
142
|
formType
|
|
122
143
|
)
|
|
123
144
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
)
|
|
128
|
-
|
|
145
|
+
const verifiedAddresses = verifiedTokensSets?.get(chainId)
|
|
146
|
+
|
|
147
|
+
const chainTokens: TokenWithVerified[] = [
|
|
148
|
+
...(dataTokens[chainId] ?? []),
|
|
149
|
+
...chainIncludedTokens,
|
|
150
|
+
]
|
|
151
|
+
|
|
152
|
+
const filtered: TokenWithVerified[] = []
|
|
153
|
+
const seenAddresses = new Set<string>()
|
|
154
|
+
for (const token of chainTokens) {
|
|
155
|
+
const address = token.address.toLowerCase()
|
|
156
|
+
// Data tokens come first and win over include duplicates,
|
|
157
|
+
// keeping their extended data
|
|
158
|
+
if (seenAddresses.has(address)) {
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
seenAddresses.add(address)
|
|
162
|
+
if (
|
|
163
|
+
!isFormItemAllowed(token, allowedAddresses, formType, (t) =>
|
|
164
|
+
t.address.toLowerCase()
|
|
165
|
+
)
|
|
166
|
+
) {
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
169
|
+
// Include and verified-allowlist tokens are explicitly set by the
|
|
170
|
+
// integrator, mark them as verified
|
|
171
|
+
if (
|
|
172
|
+
!token.verified &&
|
|
173
|
+
(includedAddresses.has(address) || verifiedAddresses?.has(address))
|
|
174
|
+
) {
|
|
175
|
+
filtered.push({ ...token, verified: true })
|
|
176
|
+
} else {
|
|
177
|
+
filtered.push(token)
|
|
178
|
+
}
|
|
179
|
+
}
|
|
129
180
|
|
|
130
181
|
allowedTokensByChain[chainId] = filtered
|
|
131
182
|
}
|