@lifi/widget 1.11.4 → 1.13.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.
Files changed (93) hide show
  1. package/AppDrawer.style.d.ts +1 -1
  2. package/AppDrawer.style.js +6 -2
  3. package/AppProvider.d.ts +4 -0
  4. package/AppProvider.js +5 -2
  5. package/components/Header/Header.js +1 -0
  6. package/components/Initializer.js +1 -1
  7. package/components/NotFound.js +2 -1
  8. package/components/PoweredBy/PoweredBy.js +3 -2
  9. package/components/ReverseTokensButton/ReverseTokensButton.style.d.ts +1 -1
  10. package/components/Step/CircularProgress.d.ts +0 -1
  11. package/components/Step/Step.js +4 -1
  12. package/components/Step/StepProcess.style.d.ts +1 -1
  13. package/components/StepActions/StepActions.js +4 -2
  14. package/components/SwapButton/ButtonTooltip.d.ts +0 -1
  15. package/components/SwapButton/SwapButton.js +7 -4
  16. package/components/SwapButton/SwapButton.style.d.ts +1 -1
  17. package/components/SwapInput/FormPriceHelperText.js +2 -2
  18. package/components/SwapInput/SwapInput.style.d.ts +1 -1
  19. package/components/SwapInput/SwapInputAdornment.d.ts +0 -1
  20. package/components/SwapInput/SwapInputAdornment.js +2 -2
  21. package/components/SwapInput/SwapInputAdornment.style.d.ts +1 -1
  22. package/components/SwapRouteCard/SwapRouteCard.style.js +4 -1
  23. package/components/TokenAvatar/TokenAvatar.js +3 -2
  24. package/components/TokenList/TokenList.js +25 -42
  25. package/components/TokenList/TokenList.style.d.ts +2 -2
  26. package/components/TokenList/TokenList.style.js +5 -2
  27. package/components/TokenList/TokenListItem.d.ts +2 -2
  28. package/components/TokenList/TokenListItem.js +7 -10
  29. package/components/TokenList/TokenNotFound.d.ts +2 -0
  30. package/components/TokenList/TokenNotFound.js +15 -0
  31. package/components/TokenList/VirtualizedTokenList.d.ts +3 -0
  32. package/components/TokenList/VirtualizedTokenList.js +53 -0
  33. package/components/TokenList/types.d.ts +16 -1
  34. package/config/lifi.d.ts +1 -1
  35. package/config/lifi.js +2 -8
  36. package/config/sentry.d.ts +1 -1
  37. package/config/sentry.js +33 -18
  38. package/config/theme.js +14 -11
  39. package/config/version.d.ts +1 -1
  40. package/config/version.js +1 -1
  41. package/hooks/index.d.ts +3 -0
  42. package/hooks/index.js +3 -0
  43. package/hooks/useFeaturedTokens.d.ts +1 -0
  44. package/hooks/useFeaturedTokens.js +6 -0
  45. package/hooks/useGasSufficiency.js +11 -4
  46. package/hooks/useRouteExecution.js +31 -17
  47. package/hooks/useSwapRoutes.js +2 -2
  48. package/hooks/useToken.d.ts +2 -1
  49. package/hooks/useToken.js +2 -1
  50. package/hooks/useTokenBalance.d.ts +2 -4
  51. package/hooks/useTokenBalance.js +11 -42
  52. package/hooks/useTokenBalances.d.ts +6 -3
  53. package/hooks/useTokenBalances.js +46 -22
  54. package/hooks/useTokenSearch.d.ts +7 -0
  55. package/hooks/useTokenSearch.js +37 -0
  56. package/hooks/useTokens.d.ts +2 -1
  57. package/hooks/useTokens.js +12 -4
  58. package/i18n/en/translation.json +5 -2
  59. package/i18n/index.d.ts +3 -0
  60. package/package.json +14 -15
  61. package/pages/MainPage/SwapRoutes.style.d.ts +1 -1
  62. package/pages/SelectTokenPage/ChainSelect.d.ts +0 -1
  63. package/pages/SelectTokenPage/ChainSelect.js +8 -5
  64. package/pages/SelectTokenPage/SearchTokenInput.d.ts +0 -1
  65. package/pages/SelectTokenPage/SearchTokenInput.js +2 -2
  66. package/pages/SelectWalletPage/SelectWalletPage.d.ts +0 -1
  67. package/pages/SelectWalletPage/SelectWalletPage.style.d.ts +2 -2
  68. package/pages/SettingsPage/AdvancedPreferences.d.ts +0 -1
  69. package/pages/SettingsPage/ColorSchemeButtonGroup.style.d.ts +1 -1
  70. package/pages/SettingsPage/GasPriceSelect.d.ts +0 -1
  71. package/pages/SettingsPage/SettingsPage.d.ts +0 -1
  72. package/pages/SettingsPage/SlippageInput.d.ts +0 -1
  73. package/pages/SwapHistoryPage/SwapHistoryPage.js +19 -3
  74. package/pages/SwapPage/StatusBottomSheet.js +2 -2
  75. package/pages/SwapRoutesPage/SwapRoutesPage.style.d.ts +1 -1
  76. package/providers/SwapFormProvider/SwapFormProvider.d.ts +1 -1
  77. package/providers/SwapFormProvider/SwapFormProvider.js +22 -5
  78. package/providers/SwapFormProvider/types.d.ts +2 -3
  79. package/providers/SwapFormProvider/types.js +1 -2
  80. package/providers/WalletProvider/WalletProvider.d.ts +11 -1
  81. package/providers/WalletProvider/WalletProvider.js +24 -33
  82. package/providers/WidgetProvider/WidgetProvider.js +24 -12
  83. package/stores/route/types.d.ts +1 -0
  84. package/stores/route/useRouteStore.js +3 -12
  85. package/types/index.d.ts +1 -0
  86. package/types/index.js +1 -0
  87. package/types/token.d.ts +4 -0
  88. package/types/token.js +1 -0
  89. package/types/widget.d.ts +4 -3
  90. package/utils/colors.d.ts +1 -0
  91. package/utils/colors.js +5 -0
  92. package/components/TokenList/utils.d.ts +0 -15
  93. package/components/TokenList/utils.js +0 -10
package/config/lifi.js CHANGED
@@ -1,11 +1,5 @@
1
1
  import LIFI from '@lifi/sdk';
2
- const defaultConfig = {
3
- // apiUrl: env.LIFI_API_URL,
4
- // defaultRouteOptions: {
5
- // integrator: 'li.fi',
6
- // },
7
- };
8
- export const LiFi = new LIFI(defaultConfig);
2
+ export const LiFi = new LIFI();
9
3
  export const updateLiFiConfig = (configUpdate) => {
10
- LiFi.setConfig(Object.assign(Object.assign({}, defaultConfig), configUpdate));
4
+ LiFi.setConfig(configUpdate);
11
5
  };
@@ -1 +1 @@
1
- export declare const initSentry: (enabled?: boolean) => void;
1
+ export declare const initSentry: (enabled?: boolean) => Promise<void>;
package/config/sentry.js CHANGED
@@ -1,20 +1,35 @@
1
- import { CaptureConsole } from '@sentry/integrations';
2
- import * as Sentry from '@sentry/react';
3
- import { BrowserTracing } from '@sentry/tracing';
4
- import { version } from './version';
5
- export const initSentry = (enabled) => {
6
- Sentry.init({
7
- dsn: 'https://bc1312161bf948db9b9c82618035ec22@o1302189.ingest.sentry.io/6539228',
8
- integrations: [
9
- new BrowserTracing(),
10
- new CaptureConsole({
11
- levels: ['error'],
12
- }),
13
- ],
14
- sampleRate: 1,
15
- tracesSampleRate: 0.2,
16
- enabled,
17
- environment: process.env.NODE_ENV,
18
- release: version,
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
19
8
  });
20
9
  };
10
+ import { version } from './version';
11
+ let sentryLoaded = false;
12
+ export const initSentry = (enabled) => __awaiter(void 0, void 0, void 0, function* () {
13
+ if (enabled || sentryLoaded) {
14
+ const [Sentry, { CaptureConsole }, { BrowserTracing }] = yield Promise.all([
15
+ import('@sentry/react'),
16
+ import('@sentry/integrations'),
17
+ import('@sentry/tracing'),
18
+ ]);
19
+ Sentry.init({
20
+ dsn: 'https://bc1312161bf948db9b9c82618035ec22@o1302189.ingest.sentry.io/6539228',
21
+ integrations: [
22
+ new BrowserTracing(),
23
+ new CaptureConsole({
24
+ levels: ['error'],
25
+ }),
26
+ ],
27
+ sampleRate: 1,
28
+ tracesSampleRate: 0.2,
29
+ enabled,
30
+ environment: process.env.NODE_ENV,
31
+ release: version,
32
+ });
33
+ sentryLoaded = true;
34
+ }
35
+ });
package/config/theme.js CHANGED
@@ -31,12 +31,15 @@ const shape = {
31
31
  };
32
32
  export const createTheme = (mode, theme = {}) => {
33
33
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
34
+ const primaryMainColor = (_c = (_b = (_a = theme.palette) === null || _a === void 0 ? void 0 : _a.primary) === null || _b === void 0 ? void 0 : _b.main) !== null && _c !== void 0 ? _c : palette.primary.main;
35
+ const primaryLightColor = lighten((_f = (_e = (_d = theme.palette) === null || _d === void 0 ? void 0 : _d.primary) === null || _e === void 0 ? void 0 : _e.main) !== null && _f !== void 0 ? _f : palette.primary.main, 0.5);
36
+ const primaryDarkColor = darken((_j = (_h = (_g = theme.palette) === null || _g === void 0 ? void 0 : _g.primary) === null || _h === void 0 ? void 0 : _h.main) !== null && _j !== void 0 ? _j : palette.primary.main, 0.2);
34
37
  return createMuiTheme({
35
38
  typography: Object.assign({ fontFamily: 'Inter var, Inter, sans-serif' }, theme.typography),
36
39
  palette: Object.assign(Object.assign(Object.assign({ mode }, palette), { primary: {
37
- main: (_c = (_b = (_a = theme.palette) === null || _a === void 0 ? void 0 : _a.primary) === null || _b === void 0 ? void 0 : _b.main) !== null && _c !== void 0 ? _c : palette.primary.main,
38
- light: lighten((_f = (_e = (_d = theme.palette) === null || _d === void 0 ? void 0 : _d.primary) === null || _e === void 0 ? void 0 : _e.main) !== null && _f !== void 0 ? _f : palette.primary.main, 0.5),
39
- dark: darken((_j = (_h = (_g = theme.palette) === null || _g === void 0 ? void 0 : _g.primary) === null || _h === void 0 ? void 0 : _h.main) !== null && _j !== void 0 ? _j : palette.primary.main, 0.2),
40
+ main: primaryMainColor,
41
+ light: primaryLightColor,
42
+ dark: primaryDarkColor,
40
43
  }, secondary: {
41
44
  main: (_m = (_l = (_k = theme.palette) === null || _k === void 0 ? void 0 : _k.secondary) === null || _l === void 0 ? void 0 : _l.main) !== null && _m !== void 0 ? _m : palette.secondary.main,
42
45
  light: lighten((_q = (_p = (_o = theme.palette) === null || _o === void 0 ? void 0 : _o.secondary) === null || _p === void 0 ? void 0 : _p.main) !== null && _q !== void 0 ? _q : palette.secondary.main, 0.5),
@@ -85,18 +88,18 @@ export const createTheme = (mode, theme = {}) => {
85
88
  styleOverrides: Object.assign(Object.assign({}, (mode === 'dark'
86
89
  ? {
87
90
  outlined: {
88
- color: palette.primary.light,
89
- borderColor: palette.primary.light,
91
+ color: primaryLightColor,
92
+ borderColor: primaryLightColor,
90
93
  '&:hover': {
91
- backgroundColor: alpha(palette.primary.light, 0.08),
92
- borderColor: palette.primary.light,
94
+ backgroundColor: alpha(primaryLightColor, 0.08),
95
+ borderColor: primaryLightColor,
93
96
  },
94
97
  },
95
98
  text: {
96
- color: palette.primary.light,
99
+ color: primaryLightColor,
97
100
  '&:hover': {
98
- backgroundColor: alpha(palette.primary.light, 0.08),
99
- borderColor: palette.primary.light,
101
+ backgroundColor: alpha(primaryLightColor, 0.08),
102
+ borderColor: primaryLightColor,
100
103
  },
101
104
  },
102
105
  }
@@ -117,7 +120,7 @@ export const createTheme = (mode, theme = {}) => {
117
120
  },
118
121
  }, contained: {
119
122
  '&:hover': {
120
- color: getContrastRatio(palette.primary.main, dark.text.primary) >= 3
123
+ color: getContrastRatio(dark.text.primary, primaryMainColor) >= 3
121
124
  ? dark.text.primary
122
125
  : light.text.primary,
123
126
  },
@@ -1,2 +1,2 @@
1
1
  export declare const name = "@lifi/widget";
2
- export declare const version = "1.11.4";
2
+ export declare const version = "1.13.0";
package/config/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  export const name = '@lifi/widget';
2
- export const version = '1.11.4';
2
+ export const version = '1.13.0';
package/hooks/index.d.ts CHANGED
@@ -2,7 +2,9 @@ export * from './useChain';
2
2
  export * from './useChains';
3
3
  export * from './useContentHeight';
4
4
  export * from './useDebouncedWatch';
5
+ export * from './useFeaturedTokens';
5
6
  export * from './useGasSufficiency';
7
+ export * from './useInitializer';
6
8
  export * from './useRouteExecution';
7
9
  export * from './useScrollableContainer';
8
10
  export * from './useSwapRoutes';
@@ -11,4 +13,5 @@ export * from './useToken';
11
13
  export * from './useTokenBalance';
12
14
  export * from './useTokenBalances';
13
15
  export * from './useTokens';
16
+ export * from './useTokenSearch';
14
17
  export * from './useTools';
package/hooks/index.js CHANGED
@@ -2,7 +2,9 @@ export * from './useChain';
2
2
  export * from './useChains';
3
3
  export * from './useContentHeight';
4
4
  export * from './useDebouncedWatch';
5
+ export * from './useFeaturedTokens';
5
6
  export * from './useGasSufficiency';
7
+ export * from './useInitializer';
6
8
  export * from './useRouteExecution';
7
9
  export * from './useScrollableContainer';
8
10
  export * from './useSwapRoutes';
@@ -11,4 +13,5 @@ export * from './useToken';
11
13
  export * from './useTokenBalance';
12
14
  export * from './useTokenBalances';
13
15
  export * from './useTokens';
16
+ export * from './useTokenSearch';
14
17
  export * from './useTools';
@@ -0,0 +1 @@
1
+ export declare const useFeaturedTokens: (selectedChainId: number) => import("@lifi/types").Token[] | undefined;
@@ -0,0 +1,6 @@
1
+ import { useMemo } from 'react';
2
+ import { useWidgetConfig } from '../providers/WidgetProvider';
3
+ export const useFeaturedTokens = (selectedChainId) => {
4
+ const { featuredTokens } = useWidgetConfig();
5
+ return useMemo(() => featuredTokens === null || featuredTokens === void 0 ? void 0 : featuredTokens.filter((token) => token.chainId === selectedChainId), [featuredTokens, selectedChainId]);
6
+ };
@@ -15,12 +15,16 @@ export const useGasSufficiency = (route) => {
15
15
  ],
16
16
  });
17
17
  const fromAmount = useDebouncedWatch(SwapFormKey.FromAmount, 250);
18
- const { tokens: fromChainTokenBalances } = useTokenBalances(fromChainId);
19
- const { tokens: toChainTokenBalances } = useTokenBalances(toChainId);
20
18
  const { getChainById } = useChains();
19
+ const { tokensWithBalance: fromChainTokenBalances } = useTokenBalances(fromChainId);
20
+ const { tokensWithBalance: toChainTokenBalances } = useTokenBalances(toChainId);
21
21
  const insufficientGas = useMemo(() => {
22
22
  var _a;
23
- if (!account.isActive || !route || !fromAmount) {
23
+ if (!account.isActive ||
24
+ !route ||
25
+ !fromAmount ||
26
+ !fromChainTokenBalances ||
27
+ !toChainTokenBalances) {
24
28
  return [];
25
29
  }
26
30
  const tokenBalancesByChain = {
@@ -78,7 +82,10 @@ export const useGasSufficiency = (route) => {
78
82
  ]);
79
83
  const insufficientFunds = useMemo(() => {
80
84
  var _a, _b;
81
- if (!account.isActive || !fromToken || !fromAmount) {
85
+ if (!account.isActive ||
86
+ !fromToken ||
87
+ !fromAmount ||
88
+ !fromChainTokenBalances) {
82
89
  return false;
83
90
  }
84
91
  const balance = Big((_b = (_a = fromChainTokenBalances === null || fromChainTokenBalances === void 0 ? void 0 : fromChainTokenBalances.find((t) => t.address === fromToken)) === null || _a === void 0 ? void 0 : _a.amount) !== null && _b !== void 0 ? _b : 0);
@@ -20,21 +20,23 @@ export const useRouteExecution = (routeId) => {
20
20
  const routeExecution = useRouteStore((state) => state.routes[routeId]);
21
21
  const [updateRoute, restartRoute, deleteRoute] = useRouteStore((state) => [state.updateRoute, state.restartRoute, state.deleteRoute], shallow);
22
22
  const updateCallback = (updatedRoute) => {
23
- console.log('Route updated.', updatedRoute);
24
- updateRoute(deepClone(updatedRoute));
23
+ const clonedUpdatedRoute = deepClone(updatedRoute);
24
+ console.log('Route updated.', clonedUpdatedRoute);
25
+ updateRoute(clonedUpdatedRoute);
25
26
  };
26
- const switchChainHook = useCallback((requiredChainId) => __awaiter(void 0, void 0, void 0, function* () {
27
+ const switchChainHook = (requiredChainId) => __awaiter(void 0, void 0, void 0, function* () {
27
28
  if (!account.isActive || !account.signer) {
28
29
  return account.signer;
29
30
  }
30
- if ((yield account.signer.getChainId()) !== requiredChainId) {
31
+ const currentChainId = yield account.signer.getChainId();
32
+ if (currentChainId !== requiredChainId) {
31
33
  const switched = yield switchChain(requiredChainId);
32
34
  if (!switched) {
33
35
  throw new Error('Chain was not switched.');
34
36
  }
35
37
  }
36
38
  return account.signer;
37
- }), [account.isActive, account.signer, switchChain]);
39
+ });
38
40
  const executeRouteMutation = useMutation(() => {
39
41
  if (!account.signer) {
40
42
  throw Error('Account signer not found.');
@@ -112,26 +114,29 @@ export const useRouteExecution = (routeId) => {
112
114
  deleteRoute(routeId);
113
115
  // eslint-disable-next-line react-hooks/exhaustive-deps
114
116
  }, [routeId]);
117
+ // Resume route execution after page reload
115
118
  useEffect(() => {
116
- // check if route is eligible for automatic resuming
117
- const isDone = routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.route.steps.every((step) => { var _a; return ((_a = step.execution) === null || _a === void 0 ? void 0 : _a.status) === 'DONE'; });
118
- const isFailed = routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.route.steps.some((step) => { var _a; return ((_a = step.execution) === null || _a === void 0 ? void 0 : _a.status) === 'FAILED'; });
119
- const alreadyStarted = routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.route.steps.some((step) => step.execution);
120
- if (!isDone &&
121
- !isFailed &&
122
- alreadyStarted &&
123
- account.signer &&
119
+ // Check if route is eligible for automatic resuming
120
+ if (isActiveRoute(routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.route) &&
121
+ account.isActive &&
124
122
  !resumedAfterMount.current) {
125
123
  resumedAfterMount.current = true;
126
124
  resumeRoute();
127
125
  }
126
+ // eslint-disable-next-line react-hooks/exhaustive-deps
127
+ }, [account.isActive]);
128
+ useEffect(() => {
128
129
  return () => {
129
- if (routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.route) {
130
- LiFi.moveExecutionToBackground(routeExecution.route);
130
+ var _a;
131
+ const route = (_a = useRouteStore.getState().routes[routeId]) === null || _a === void 0 ? void 0 : _a.route;
132
+ if (!route || !isActiveRoute(route)) {
133
+ return;
131
134
  }
135
+ LiFi.moveExecutionToBackground(route);
136
+ console.log('Move route execution to background.', routeId);
137
+ resumedAfterMount.current = false;
132
138
  };
133
- // eslint-disable-next-line react-hooks/exhaustive-deps
134
- }, [account.signer]);
139
+ }, [routeId]);
135
140
  return {
136
141
  executeRoute,
137
142
  restartRoute: restartRouteMutation,
@@ -140,3 +145,12 @@ export const useRouteExecution = (routeId) => {
140
145
  status: routeExecution === null || routeExecution === void 0 ? void 0 : routeExecution.status,
141
146
  };
142
147
  };
148
+ const isActiveRoute = (route) => {
149
+ if (!route) {
150
+ return false;
151
+ }
152
+ const allDone = route.steps.every((step) => { var _a; return ((_a = step.execution) === null || _a === void 0 ? void 0 : _a.status) === 'DONE'; });
153
+ const isFailed = route.steps.some((step) => { var _a; return ((_a = step.execution) === null || _a === void 0 ? void 0 : _a.status) === 'FAILED'; });
154
+ const alreadyStarted = route.steps.some((step) => step.execution);
155
+ return !allDone && !isFailed && alreadyStarted;
156
+ };
@@ -40,7 +40,7 @@ export const useSwapRoutes = () => {
40
40
  // Boolean(account.address) &&
41
41
  !isNaN(fromChainId) &&
42
42
  !isNaN(toChainId) &&
43
- Boolean(fromTokenAddress) &&
43
+ Boolean(token === null || token === void 0 ? void 0 : token.address) &&
44
44
  Boolean(toTokenAddress) &&
45
45
  !isNaN(fromTokenAmount) &&
46
46
  Number(fromTokenAmount) > 0 &&
@@ -49,7 +49,7 @@ export const useSwapRoutes = () => {
49
49
  'routes',
50
50
  account.address,
51
51
  fromChainId,
52
- fromTokenAddress,
52
+ token === null || token === void 0 ? void 0 : token.address,
53
53
  fromTokenAmount,
54
54
  toChainId,
55
55
  toTokenAddress,
@@ -1,4 +1,5 @@
1
1
  export declare const useToken: (chainId: number, tokenAddress: string) => {
2
- token: import("@lifi/types").Token | undefined;
2
+ token: import("..").Token | undefined;
3
3
  isLoading: boolean;
4
+ isFetching: boolean;
4
5
  };
package/hooks/useToken.js CHANGED
@@ -8,6 +8,7 @@ export const useToken = (chainId, tokenAddress) => {
8
8
  }, [chainId, tokenAddress, tokens]);
9
9
  return {
10
10
  token,
11
- isLoading: isLoading && isFetching,
11
+ isLoading,
12
+ isFetching,
12
13
  };
13
14
  };
@@ -1,7 +1,5 @@
1
- import { TokenAmount } from '@lifi/sdk';
2
1
  export declare const useTokenBalance: (chainId: number, tokenAddress: string) => {
3
- token: TokenAmount | undefined;
2
+ token: import("..").Token | undefined;
4
3
  isLoading: boolean;
5
- isFetching: boolean;
6
- refetchBalance: (chainId?: number, tokenAddress?: string) => Promise<void>;
4
+ refetch: <TPageData>(options?: (import("@tanstack/query-core").RefetchOptions & import("@tanstack/query-core").RefetchQueryFilters<TPageData>) | undefined) => Promise<import("@tanstack/query-core").QueryObserverResult<import("..").Token[] | undefined, unknown>>;
7
5
  };
@@ -1,46 +1,15 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { useQuery, useQueryClient } from '@tanstack/react-query';
11
- import { useCallback } from 'react';
12
- import { LiFi } from '../config/lifi';
13
- import { useWallet } from '../providers/WalletProvider';
14
- import { formatTokenAmount } from '../utils';
15
- import { useToken } from './useToken';
1
+ import { useMemo } from 'react';
2
+ import { useTokenBalances } from './useTokenBalances';
16
3
  export const useTokenBalance = (chainId, tokenAddress) => {
17
- const { account } = useWallet();
18
- const queryClient = useQueryClient();
19
- const { token } = useToken(chainId, tokenAddress);
20
- const { data: tokenWithBalance, isLoading, isFetching, refetch, } = useQuery(['token', account.address, chainId, tokenAddress], ({ queryKey: [, address] }) => __awaiter(void 0, void 0, void 0, function* () {
21
- if (!address || !token) {
22
- return null;
23
- }
24
- const tokenBalance = yield LiFi.getTokenBalance(address, token);
25
- return Object.assign(Object.assign(Object.assign({}, token), tokenBalance), { amount: formatTokenAmount(tokenBalance === null || tokenBalance === void 0 ? void 0 : tokenBalance.amount) });
26
- }), {
27
- enabled: Boolean(account.address) && Boolean(token),
28
- refetchIntervalInBackground: true,
29
- refetchInterval: 30000,
30
- staleTime: 30000,
31
- cacheTime: 30000,
32
- });
33
- const refetchBalance = useCallback((chainId, tokenAddress) => __awaiter(void 0, void 0, void 0, function* () {
34
- if (!chainId && !tokenAddress) {
35
- refetch();
36
- return;
37
- }
38
- yield queryClient.invalidateQueries(['token', account.address, chainId, tokenAddress], { type: 'all', exact: true });
39
- }), [account.address, queryClient, refetch]);
4
+ const { tokens, tokensWithBalance, isBalanceLoading, refetch } = useTokenBalances(chainId);
5
+ const token = useMemo(() => {
6
+ var _a;
7
+ const token = (_a = (tokensWithBalance !== null && tokensWithBalance !== void 0 ? tokensWithBalance : tokens)) === null || _a === void 0 ? void 0 : _a.find((token) => token.address === tokenAddress && token.chainId === chainId);
8
+ return token;
9
+ }, [chainId, tokenAddress, tokens, tokensWithBalance]);
40
10
  return {
41
- token: tokenWithBalance !== null && tokenWithBalance !== void 0 ? tokenWithBalance : token,
42
- isLoading,
43
- isFetching,
44
- refetchBalance,
11
+ token,
12
+ isLoading: isBalanceLoading,
13
+ refetch,
45
14
  };
46
15
  };
@@ -1,7 +1,10 @@
1
- import { TokenAmount } from '@lifi/sdk';
1
+ import { Token } from '../types';
2
2
  export declare const useTokenBalances: (selectedChainId: number) => {
3
- tokens: TokenAmount[] | undefined;
3
+ tokens: Token[] | undefined;
4
+ tokensWithBalance: Token[] | undefined;
5
+ featuredTokens: import("@lifi/types").Token[] | undefined;
4
6
  isLoading: boolean;
5
7
  isBalanceLoading: boolean;
6
- updateBalances: <TPageData>(options?: (import("@tanstack/react-query").RefetchOptions & import("@tanstack/react-query").RefetchQueryFilters<TPageData>) | undefined) => Promise<import("@tanstack/react-query").QueryObserverResult<TokenAmount[], unknown>>;
8
+ isBalanceFetched: boolean;
9
+ refetch: <TPageData>(options?: (import("@tanstack/react-query").RefetchOptions & import("@tanstack/react-query").RefetchQueryFilters<TPageData>) | undefined) => Promise<import("@tanstack/react-query").QueryObserverResult<Token[] | undefined, unknown>>;
7
10
  };
@@ -7,46 +7,70 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
+ /* eslint-disable consistent-return */
10
11
  import { useQuery } from '@tanstack/react-query';
12
+ import { useState } from 'react';
11
13
  import { LiFi } from '../config/lifi';
12
14
  import { useWallet } from '../providers/WalletProvider';
13
15
  import { formatTokenAmount } from '../utils';
14
- import { useChains } from './useChains';
16
+ import { useFeaturedTokens } from './useFeaturedTokens';
15
17
  import { useTokens } from './useTokens';
18
+ const defaultRefetchInterval = 60000;
19
+ const minRefetchInterval = 1000;
16
20
  export const useTokenBalances = (selectedChainId) => {
17
21
  const { account } = useWallet();
18
- const { chains, isLoading: isChainsLoading } = useChains();
22
+ const featuredTokens = useFeaturedTokens(selectedChainId);
19
23
  const { tokens, isLoading } = useTokens(selectedChainId);
20
- const isBalanceLoadingEnabled = Boolean(account.address) && Boolean(tokens) && Boolean(chains);
21
- const { data: tokensWithBalance, isLoading: isBalanceLoading, refetch, } = useQuery(['token-balances', selectedChainId, account.address], ({ queryKey: [_, chainId, account] }) => __awaiter(void 0, void 0, void 0, function* () {
22
- if (!account || !tokens) {
23
- return [];
24
+ const [refetchInterval, setRefetchInterval] = useState(defaultRefetchInterval);
25
+ const isBalanceLoadingEnabled = Boolean(account.address) && Boolean(tokens === null || tokens === void 0 ? void 0 : tokens.length);
26
+ const { data: tokensWithBalance, isLoading: isBalanceLoading, isFetched: isBalanceFetched, refetch, } = useQuery(['token-balances', account.address, selectedChainId, tokens === null || tokens === void 0 ? void 0 : tokens.length], ({ queryKey: [, accountAddress] }) => __awaiter(void 0, void 0, void 0, function* () {
27
+ if (!accountAddress || !tokens) {
28
+ return;
24
29
  }
25
- const tokenBalances = yield LiFi.getTokenBalances(account, tokens);
26
- const formatedTokens = (tokenBalances.length === 0 ? tokens : tokenBalances).map((token) => {
30
+ const tokenBalances = yield LiFi.getTokenBalances(accountAddress, tokens);
31
+ if (!(tokenBalances === null || tokenBalances === void 0 ? void 0 : tokenBalances.length)) {
32
+ // Sometimes RPCs (e.g. Arbitrum) don't return balances on first call
33
+ // TODO: fix and remove backplane
34
+ setRefetchInterval((interval) => interval === defaultRefetchInterval
35
+ ? minRefetchInterval
36
+ : interval * 2);
37
+ return;
38
+ }
39
+ const featuredTokenAddresses = new Set(featuredTokens === null || featuredTokens === void 0 ? void 0 : featuredTokens.map((token) => token.address));
40
+ const sortFn = (a, b) => {
41
+ var _a, _b, _c, _d;
42
+ return parseFloat((_a = b.amount) !== null && _a !== void 0 ? _a : '0') * parseFloat((_b = b.priceUSD) !== null && _b !== void 0 ? _b : '0') -
43
+ parseFloat((_c = a.amount) !== null && _c !== void 0 ? _c : '0') * parseFloat((_d = a.priceUSD) !== null && _d !== void 0 ? _d : '0');
44
+ };
45
+ const formattedTokens = (tokenBalances.length === 0 ? tokens : tokenBalances).map((token) => {
27
46
  token.amount = formatTokenAmount(token.amount);
28
47
  return token;
29
48
  });
30
- return [
31
- ...formatedTokens
32
- .filter((token) => token.amount !== '0')
33
- .sort((a, b) => {
34
- var _a, _b, _c, _d;
35
- return parseFloat((_a = b.amount) !== null && _a !== void 0 ? _a : '0') * parseFloat((_b = b.priceUSD) !== null && _b !== void 0 ? _b : '0') -
36
- parseFloat((_c = a.amount) !== null && _c !== void 0 ? _c : '0') * parseFloat((_d = a.priceUSD) !== null && _d !== void 0 ? _d : '0');
37
- }),
38
- ...formatedTokens.filter((token) => token.amount === '0'),
49
+ const result = [
50
+ ...formattedTokens
51
+ .filter((token) => token.amount !== '0' && featuredTokenAddresses.has(token.address))
52
+ .sort(sortFn),
53
+ ...formattedTokens.filter((token) => token.amount === '0' && featuredTokenAddresses.has(token.address)),
54
+ ...formattedTokens
55
+ .filter((token) => token.amount !== '0' &&
56
+ !featuredTokenAddresses.has(token.address))
57
+ .sort(sortFn),
58
+ ...formattedTokens.filter((token) => token.amount === '0' && !featuredTokenAddresses.has(token.address)),
39
59
  ];
60
+ return result;
40
61
  }), {
41
62
  enabled: isBalanceLoadingEnabled,
42
63
  refetchIntervalInBackground: true,
43
- refetchInterval: 60000,
44
- staleTime: 60000,
64
+ refetchInterval,
65
+ staleTime: refetchInterval,
45
66
  });
46
67
  return {
47
- tokens: tokensWithBalance !== null && tokensWithBalance !== void 0 ? tokensWithBalance : tokens,
48
- isLoading: isLoading || isChainsLoading,
68
+ tokens,
69
+ tokensWithBalance,
70
+ featuredTokens,
71
+ isLoading,
49
72
  isBalanceLoading: isBalanceLoading && isBalanceLoadingEnabled,
50
- updateBalances: refetch,
73
+ isBalanceFetched,
74
+ refetch,
51
75
  };
52
76
  };
@@ -0,0 +1,7 @@
1
+ import { Token } from '../types';
2
+ export declare const useTokenSearch: (token: string, chainId: number, enabled?: boolean) => {
3
+ token: Token | undefined;
4
+ isLoading: boolean;
5
+ isFetching: boolean;
6
+ isFetched: boolean;
7
+ };
@@ -0,0 +1,37 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
11
+ import { LiFi } from '../config/lifi';
12
+ export const useTokenSearch = (token, chainId, enabled) => {
13
+ const queryClient = useQueryClient();
14
+ const { data, isLoading, isFetching, isFetched } = useQuery(['token-search', chainId, token], ({ queryKey: [, chainId, token], signal }) => __awaiter(void 0, void 0, void 0, function* () {
15
+ const data = yield LiFi.getToken(chainId, token, {
16
+ signal,
17
+ });
18
+ if (data) {
19
+ queryClient.setQueriesData(['tokens', chainId], (tokens) => {
20
+ if (!(tokens === null || tokens === void 0 ? void 0 : tokens.some((token) => token.address === data.address))) {
21
+ tokens === null || tokens === void 0 ? void 0 : tokens.push(data);
22
+ }
23
+ return tokens;
24
+ });
25
+ }
26
+ return data;
27
+ }), {
28
+ enabled,
29
+ retry: false,
30
+ });
31
+ return {
32
+ token: data,
33
+ isLoading,
34
+ isFetching,
35
+ isFetched,
36
+ };
37
+ };
@@ -1,5 +1,6 @@
1
+ import { Token } from '../types';
1
2
  export declare const useTokens: (selectedChainId: number) => {
2
- tokens: import("@lifi/types").Token[] | undefined;
3
+ tokens: Token[] | undefined;
3
4
  isLoading: boolean;
4
5
  isFetching: boolean;
5
6
  };
@@ -9,12 +9,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { useQuery } from '@tanstack/react-query';
11
11
  import { LiFi } from '../config/lifi';
12
+ import { useFeaturedTokens } from './useFeaturedTokens';
12
13
  export const useTokens = (selectedChainId) => {
13
- const { data: tokens, isLoading, isFetching, } = useQuery(['tokens', selectedChainId], () => __awaiter(void 0, void 0, void 0, function* () {
14
- var _a;
14
+ const featuredTokens = useFeaturedTokens(selectedChainId);
15
+ const { data: tokens, isLoading, isFetching, } = useQuery(['tokens', selectedChainId, featuredTokens === null || featuredTokens === void 0 ? void 0 : featuredTokens.length], () => __awaiter(void 0, void 0, void 0, function* () {
16
+ var _a, _b, _c;
15
17
  const data = yield LiFi.getTokens({ chains: [selectedChainId] });
16
- return (_a = data.tokens) === null || _a === void 0 ? void 0 : _a[selectedChainId];
17
- // .sort((a, b) => (a.symbol > b.symbol ? 1 : -1));
18
+ const featuredTokenAddresses = new Set(featuredTokens === null || featuredTokens === void 0 ? void 0 : featuredTokens.map((token) => token.address));
19
+ return [
20
+ ...((_a = featuredTokens === null || featuredTokens === void 0 ? void 0 : featuredTokens.map((token) => {
21
+ token.featured = true;
22
+ return token;
23
+ })) !== null && _a !== void 0 ? _a : []),
24
+ ...((_c = (_b = data.tokens) === null || _b === void 0 ? void 0 : _b[selectedChainId].filter((token) => !featuredTokenAddresses.has(token.address))) !== null && _c !== void 0 ? _c : []),
25
+ ];
18
26
  }));
19
27
  return {
20
28
  tokens,
@@ -50,6 +50,8 @@
50
50
  "selectChain": "Chain",
51
51
  "selectToken": "Token",
52
52
  "selectChainAndToken": "Select chain and token",
53
+ "featuredTokens": "Featured tokens",
54
+ "otherTokens": "Other tokens",
53
55
  "inProgress": "In progress",
54
56
  "couldntFindTokens": "We couldn't find tokens on this chain or you don't have any.",
55
57
  "stepSwap": "Swap",
@@ -90,7 +92,8 @@
90
92
  "warning": {
91
93
  "title": {
92
94
  "insufficientGas": "Insufficient gas",
93
- "deleteSwap": "Delete this swap?"
95
+ "deleteSwap": "Delete this swap?",
96
+ "deleteSwapHistory": "Delete swap history?"
94
97
  },
95
98
  "message": {
96
99
  "insufficientFunds": "You don't have enough funds to execute the swap.",
@@ -164,7 +167,7 @@
164
167
  },
165
168
  "tooltip": {
166
169
  "notFound": {
167
- "title": "Sorry 🥲",
170
+ "title": "404",
168
171
  "text": "We couldn't find this page."
169
172
  },
170
173
  "progressToNextUpdate": "Displayed data will auto-refresh after {{value}} seconds. Click this circle to update manually."