@lifi/widget 3.21.3 → 3.22.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 (135) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/esm/AppProvider.js +2 -3
  3. package/dist/esm/AppProvider.js.map +1 -1
  4. package/dist/esm/components/AppContainer.js +23 -22
  5. package/dist/esm/components/AppContainer.js.map +1 -1
  6. package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.js +12 -7
  7. package/dist/esm/components/BaseTransactionButton/BaseTransactionButton.js.map +1 -1
  8. package/dist/esm/components/BaseTransactionButton/types.d.ts +2 -0
  9. package/dist/esm/components/ChainSelect/ChainSelect.js +3 -1
  10. package/dist/esm/components/ChainSelect/ChainSelect.js.map +1 -1
  11. package/dist/esm/components/ChainSelect/ChainSelect.style.d.ts +3 -1
  12. package/dist/esm/components/ChainSelect/ChainSelect.style.js +23 -9
  13. package/dist/esm/components/ChainSelect/ChainSelect.style.js.map +1 -1
  14. package/dist/esm/components/Messages/MissingRouteRequiredAccountMessage.d.ts +8 -0
  15. package/dist/esm/components/Messages/MissingRouteRequiredAccountMessage.js +20 -0
  16. package/dist/esm/components/Messages/MissingRouteRequiredAccountMessage.js.map +1 -0
  17. package/dist/esm/components/Messages/WarningMessages.js +3 -0
  18. package/dist/esm/components/Messages/WarningMessages.js.map +1 -1
  19. package/dist/esm/components/Messages/useMessageQueue.js +15 -4
  20. package/dist/esm/components/Messages/useMessageQueue.js.map +1 -1
  21. package/dist/esm/components/RouteCard/RouteCard.js +3 -3
  22. package/dist/esm/components/RouteCard/RouteCard.js.map +1 -1
  23. package/dist/esm/components/TokenList/TokenListItem.js +2 -2
  24. package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
  25. package/dist/esm/config/version.d.ts +1 -1
  26. package/dist/esm/config/version.js +1 -1
  27. package/dist/esm/hooks/useAvailableChains.js +3 -2
  28. package/dist/esm/hooks/useAvailableChains.js.map +1 -1
  29. package/dist/esm/hooks/useExplorer.d.ts +0 -1
  30. package/dist/esm/hooks/useExplorer.js +26 -31
  31. package/dist/esm/hooks/useExplorer.js.map +1 -1
  32. package/dist/esm/hooks/useFromTokenSufficiency.js +4 -1
  33. package/dist/esm/hooks/useFromTokenSufficiency.js.map +1 -1
  34. package/dist/esm/hooks/useGasRecommendation.js +9 -1
  35. package/dist/esm/hooks/useGasRecommendation.js.map +1 -1
  36. package/dist/esm/hooks/useGasSufficiency.js +50 -16
  37. package/dist/esm/hooks/useGasSufficiency.js.map +1 -1
  38. package/dist/esm/hooks/useIsBatchingSupported.js +8 -1
  39. package/dist/esm/hooks/useIsBatchingSupported.js.map +1 -1
  40. package/dist/esm/hooks/useIsContractAddress.js +1 -1
  41. package/dist/esm/hooks/useIsContractAddress.js.map +1 -1
  42. package/dist/esm/hooks/useRouteExecution.js +10 -4
  43. package/dist/esm/hooks/useRouteExecution.js.map +1 -1
  44. package/dist/esm/hooks/useRouteRequiredAccountConnection.d.ts +10 -0
  45. package/dist/esm/hooks/useRouteRequiredAccountConnection.js +45 -0
  46. package/dist/esm/hooks/useRouteRequiredAccountConnection.js.map +1 -0
  47. package/dist/esm/hooks/useRoutes.d.ts +1 -1
  48. package/dist/esm/hooks/useRoutes.js +13 -4
  49. package/dist/esm/hooks/useRoutes.js.map +1 -1
  50. package/dist/esm/hooks/useToAddressRequirements.d.ts +1 -1
  51. package/dist/esm/hooks/useToAddressRequirements.js +6 -5
  52. package/dist/esm/hooks/useToAddressRequirements.js.map +1 -1
  53. package/dist/esm/hooks/useTokenBalance.js +12 -3
  54. package/dist/esm/hooks/useTokenBalance.js.map +1 -1
  55. package/dist/esm/hooks/useTokenBalances.js +4 -1
  56. package/dist/esm/hooks/useTokenBalances.js.map +1 -1
  57. package/dist/esm/hooks/useTokenSearch.js +5 -2
  58. package/dist/esm/hooks/useTokenSearch.js.map +1 -1
  59. package/dist/esm/hooks/useTokens.js +3 -2
  60. package/dist/esm/hooks/useTokens.js.map +1 -1
  61. package/dist/esm/hooks/useTools.js +3 -2
  62. package/dist/esm/hooks/useTools.js.map +1 -1
  63. package/dist/esm/hooks/useTransactionDetails.js +9 -4
  64. package/dist/esm/hooks/useTransactionDetails.js.map +1 -1
  65. package/dist/esm/hooks/useTransactionHistory.js +7 -1
  66. package/dist/esm/hooks/useTransactionHistory.js.map +1 -1
  67. package/dist/esm/i18n/en.json +6 -4
  68. package/dist/esm/pages/MainPage/ReviewButton.js +1 -1
  69. package/dist/esm/pages/MainPage/ReviewButton.js.map +1 -1
  70. package/dist/esm/pages/TransactionPage/StartTransactionButton.js +1 -1
  71. package/dist/esm/pages/TransactionPage/StartTransactionButton.js.map +1 -1
  72. package/dist/esm/pages/TransactionPage/StatusBottomSheet.js +26 -43
  73. package/dist/esm/pages/TransactionPage/StatusBottomSheet.js.map +1 -1
  74. package/dist/esm/pages/TransactionPage/StatusBottomSheet.style.d.ts +0 -1
  75. package/dist/esm/pages/TransactionPage/StatusBottomSheet.style.js +4 -11
  76. package/dist/esm/pages/TransactionPage/StatusBottomSheet.style.js.map +1 -1
  77. package/dist/esm/providers/QueryClientProvider.d.ts +2 -0
  78. package/dist/esm/providers/QueryClientProvider.js +9 -0
  79. package/dist/esm/providers/QueryClientProvider.js.map +1 -0
  80. package/dist/esm/providers/WalletProvider/SuiBaseProvider.js +3 -8
  81. package/dist/esm/providers/WalletProvider/SuiBaseProvider.js.map +1 -1
  82. package/dist/esm/stores/form/FormStore.js +5 -12
  83. package/dist/esm/stores/form/FormStore.js.map +1 -1
  84. package/dist/esm/stores/form/useFormRef.js +1 -7
  85. package/dist/esm/stores/form/useFormRef.js.map +1 -1
  86. package/dist/esm/types/widget.d.ts +6 -1
  87. package/dist/esm/utils/queries.d.ts +1 -0
  88. package/dist/esm/utils/queries.js +2 -0
  89. package/dist/esm/utils/queries.js.map +1 -0
  90. package/dist/esm/utils/timer.js +8 -1
  91. package/dist/esm/utils/timer.js.map +1 -1
  92. package/package.json +11 -11
  93. package/package.json.tmp +10 -10
  94. package/src/AppProvider.tsx +2 -3
  95. package/src/components/AppContainer.tsx +24 -23
  96. package/src/components/BaseTransactionButton/BaseTransactionButton.tsx +15 -6
  97. package/src/components/BaseTransactionButton/types.ts +3 -0
  98. package/src/components/ChainSelect/ChainSelect.style.tsx +25 -9
  99. package/src/components/ChainSelect/ChainSelect.tsx +4 -1
  100. package/src/components/Messages/MissingRouteRequiredAccountMessage.tsx +44 -0
  101. package/src/components/Messages/WarningMessages.tsx +9 -0
  102. package/src/components/Messages/useMessageQueue.ts +17 -4
  103. package/src/components/RouteCard/RouteCard.tsx +3 -3
  104. package/src/components/TokenList/TokenListItem.tsx +2 -2
  105. package/src/config/version.ts +1 -1
  106. package/src/hooks/useAvailableChains.ts +4 -2
  107. package/src/hooks/useExplorer.ts +35 -36
  108. package/src/hooks/useFromTokenSufficiency.ts +4 -1
  109. package/src/hooks/useGasRecommendation.ts +9 -1
  110. package/src/hooks/useGasSufficiency.ts +76 -22
  111. package/src/hooks/useIsBatchingSupported.ts +9 -1
  112. package/src/hooks/useIsContractAddress.ts +1 -1
  113. package/src/hooks/useRouteExecution.ts +10 -4
  114. package/src/hooks/useRouteRequiredAccountConnection.ts +58 -0
  115. package/src/hooks/useRoutes.ts +13 -7
  116. package/src/hooks/useToAddressRequirements.ts +6 -5
  117. package/src/hooks/useTokenBalance.ts +12 -3
  118. package/src/hooks/useTokenBalances.ts +4 -1
  119. package/src/hooks/useTokenSearch.ts +5 -2
  120. package/src/hooks/useTokens.ts +3 -2
  121. package/src/hooks/useTools.ts +3 -2
  122. package/src/hooks/useTransactionDetails.ts +13 -4
  123. package/src/hooks/useTransactionHistory.ts +7 -1
  124. package/src/i18n/en.json +6 -4
  125. package/src/pages/MainPage/ReviewButton.tsx +1 -0
  126. package/src/pages/TransactionPage/StartTransactionButton.tsx +1 -0
  127. package/src/pages/TransactionPage/StatusBottomSheet.style.tsx +4 -12
  128. package/src/pages/TransactionPage/StatusBottomSheet.tsx +47 -77
  129. package/src/providers/QueryClientProvider.tsx +20 -0
  130. package/src/providers/WalletProvider/SuiBaseProvider.tsx +3 -9
  131. package/src/stores/form/FormStore.tsx +4 -15
  132. package/src/stores/form/useFormRef.ts +1 -8
  133. package/src/types/widget.ts +10 -2
  134. package/src/utils/queries.ts +2 -0
  135. package/src/utils/timer.ts +8 -1
@@ -1,7 +1,10 @@
1
- import type { EVMChain, RouteExtended, Token } from '@lifi/sdk'
2
- import { isRelayerStep } from '@lifi/sdk'
1
+ import type { EVMChain, RouteExtended, Token, TokenAmount } from '@lifi/sdk'
2
+ import { ChainType, isRelayerStep } from '@lifi/sdk'
3
3
  import { useAccount } from '@lifi/wallet-management'
4
4
  import { useQuery } from '@tanstack/react-query'
5
+ import { useMemo } from 'react'
6
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
7
+ import { getQueryKey } from '../utils/queries.js'
5
8
  import { useAvailableChains } from './useAvailableChains.js'
6
9
  import { useIsContractAddress } from './useIsContractAddress.js'
7
10
  import { getTokenBalancesWithRetry } from './useTokenBalance.js'
@@ -19,30 +22,64 @@ const refetchInterval = 30_000
19
22
 
20
23
  export const useGasSufficiency = (route?: RouteExtended) => {
21
24
  const { getChainById } = useAvailableChains()
22
- const { account } = useAccount({
23
- chainType: getChainById(route?.fromChainId)?.chainType,
25
+ const { account: EVMAccount, accounts } = useAccount({
26
+ chainType: ChainType.EVM,
24
27
  })
28
+ const { keyPrefix } = useWidgetConfig()
29
+
30
+ const { relevantAccounts, relevantAccountsQueryKey } = useMemo(() => {
31
+ const chainTypes = route?.steps.reduce((acc, step) => {
32
+ const chainType = getChainById(step.action.fromChainId)?.chainType
33
+ if (chainType) {
34
+ acc.add(chainType)
35
+ }
36
+ return acc
37
+ }, new Set<ChainType>())
38
+
39
+ const relevantAccounts = accounts.filter(
40
+ (account) =>
41
+ account.isConnected &&
42
+ account.address &&
43
+ chainTypes?.has(account.chainType)
44
+ )
45
+ return {
46
+ relevantAccounts,
47
+ relevantAccountsQueryKey: relevantAccounts
48
+ .map((account) => account.address)
49
+ .join(','),
50
+ }
51
+ }, [accounts, route?.steps, getChainById])
25
52
 
26
53
  const { isContractAddress, isLoading: isContractAddressLoading } =
27
- useIsContractAddress(account.address, route?.fromChainId, account.chainType)
54
+ useIsContractAddress(
55
+ EVMAccount.address,
56
+ route?.fromChainId,
57
+ EVMAccount.chainType
58
+ )
28
59
 
29
60
  const { data: insufficientGas, isLoading } = useQuery({
30
61
  queryKey: [
31
- 'gas-sufficiency-check',
32
- account.address,
62
+ getQueryKey('gas-sufficiency-check', keyPrefix),
63
+ relevantAccountsQueryKey,
33
64
  route?.id,
34
65
  isContractAddress,
35
66
  ] as const,
36
- queryFn: async ({ queryKey: [, accountAddress] }) => {
67
+ queryFn: async () => {
37
68
  if (!route) {
38
69
  return
39
70
  }
40
71
 
41
- // If we have a relayer step with a permit (EIP-2612) for the from token, we don't need to check for gas sufficiency
42
- if (
43
- isRelayerStep(route.steps[0]) &&
44
- route.steps[0].typedData.some((t) => t.primaryType === 'Permit')
45
- ) {
72
+ // Filter out steps that are relayer steps or have primaryType 'Permit' or 'Order'
73
+ const filteredSteps = route.steps.filter(
74
+ (step) =>
75
+ !isRelayerStep(step) &&
76
+ !step.typedData?.some(
77
+ (t) => t.primaryType === 'Permit' || t.primaryType === 'Order'
78
+ )
79
+ )
80
+
81
+ // If all steps are filtered out, we don't need to check for gas sufficiency
82
+ if (!filteredSteps.length) {
46
83
  return
47
84
  }
48
85
 
@@ -51,7 +88,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
51
88
  .flatMap((step) => step.includedSteps)
52
89
  .some((includedStep) => includedStep.tool === 'gasZip')
53
90
 
54
- const gasCosts = route.steps
91
+ const gasCosts = filteredSteps
55
92
  .filter((step) => !step.execution || step.execution.status !== 'DONE')
56
93
  .reduce(
57
94
  (groupedGasCosts, step) => {
@@ -70,6 +107,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
70
107
  ? groupedGasCosts[token.chainId].gasAmount + gasCostAmount
71
108
  : gasCostAmount,
72
109
  token,
110
+ chain: getChainById(token.chainId),
73
111
  }
74
112
  }
75
113
  // Add fees paid in native tokens to gas sufficiency check (included: false)
@@ -88,11 +126,12 @@ export const useGasSufficiency = (route?: RouteExtended) => {
88
126
  ? groupedGasCosts[token.chainId].gasAmount + feeCostAmount
89
127
  : feeCostAmount,
90
128
  token,
91
- } as any
129
+ chain: getChainById(token.chainId),
130
+ }
92
131
  }
93
132
  return groupedGasCosts
94
133
  },
95
- {} as Record<number, GasSufficiency>
134
+ {} as Record<string, GasSufficiency>
96
135
  )
97
136
 
98
137
  // Check whether we are sending a native token
@@ -104,15 +143,30 @@ export const useGasSufficiency = (route?: RouteExtended) => {
104
143
  gasCosts[route.fromChainId]?.gasAmount + BigInt(route.fromAmount)
105
144
  }
106
145
 
107
- const tokenBalances = await getTokenBalancesWithRetry(
108
- accountAddress!,
109
- Object.values(gasCosts).map((item) => item.token)
146
+ const gasCostsValues = Object.values(gasCosts)
147
+
148
+ const balanceChecks = await Promise.allSettled(
149
+ relevantAccounts.map((account) => {
150
+ const relevantTokens = gasCostsValues
151
+ .filter((gasCost) => gasCost.chain?.chainType === account.chainType)
152
+ .map((item) => item.token)
153
+
154
+ return getTokenBalancesWithRetry(account.address!, relevantTokens)
155
+ })
110
156
  )
111
157
 
158
+ const tokenBalances = balanceChecks
159
+ .filter(
160
+ (result): result is PromiseFulfilledResult<TokenAmount[]> =>
161
+ result.status === 'fulfilled' && Boolean(result.value)
162
+ )
163
+ .flatMap((result) => result.value)
164
+
112
165
  if (!tokenBalances?.length) {
113
166
  return
114
167
  }
115
- ;[route.fromChainId, route.toChainId].forEach((chainId) => {
168
+
169
+ Object.keys(gasCosts).forEach((chainId) => {
116
170
  if (gasCosts[chainId]) {
117
171
  const gasTokenBalance =
118
172
  tokenBalances?.find(
@@ -135,7 +189,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
135
189
  ...gasCosts[chainId],
136
190
  insufficient,
137
191
  insufficientAmount,
138
- chain: insufficient ? getChainById(chainId) : undefined,
192
+ chain: insufficient ? getChainById(Number(chainId)) : undefined,
139
193
  }
140
194
  }
141
195
  })
@@ -150,7 +204,7 @@ export const useGasSufficiency = (route?: RouteExtended) => {
150
204
  enabled: Boolean(
151
205
  !isContractAddress &&
152
206
  !isContractAddressLoading &&
153
- account.address &&
207
+ relevantAccounts.length > 0 &&
154
208
  route
155
209
  ),
156
210
  refetchInterval,
@@ -1,16 +1,24 @@
1
1
  import { ChainType, isBatchingSupported } from '@lifi/sdk'
2
2
  import type { ExtendedChain } from '@lifi/sdk'
3
3
  import { useQuery } from '@tanstack/react-query'
4
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
5
+ import { getQueryKey } from '../utils/queries.js'
4
6
 
5
7
  export function useIsBatchingSupported(
6
8
  chain?: ExtendedChain,
7
9
  address?: string
8
10
  ) {
11
+ const { keyPrefix } = useWidgetConfig()
12
+
9
13
  const enabled = Boolean(
10
14
  chain && chain.chainType === ChainType.EVM && !!address
11
15
  )
12
16
  const { data, isLoading } = useQuery({
13
- queryKey: ['isBatchingSupported', chain?.id, address],
17
+ queryKey: [
18
+ getQueryKey('isBatchingSupported', keyPrefix),
19
+ chain?.id,
20
+ address,
21
+ ],
14
22
  queryFn: () => {
15
23
  return isBatchingSupported({ chainId: chain!.id })
16
24
  },
@@ -22,7 +22,7 @@ export const useIsContractAddress = (
22
22
  query: {
23
23
  refetchInterval: 300_000,
24
24
  staleTime: 300_000,
25
- enabled: Boolean(chainType === ChainType.EVM && chainId),
25
+ enabled: chainType === ChainType.EVM && !!chainId && !!address,
26
26
  },
27
27
  })
28
28
 
@@ -4,6 +4,7 @@ import { useAccount } from '@lifi/wallet-management'
4
4
  import { useMutation, useQueryClient } from '@tanstack/react-query'
5
5
  import { useCallback, useEffect, useRef } from 'react'
6
6
  import { shallow } from 'zustand/shallow'
7
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
7
8
  import {
8
9
  useRouteExecutionStore,
9
10
  useRouteExecutionStoreContext,
@@ -15,6 +16,7 @@ import {
15
16
  isRouteFailed,
16
17
  } from '../stores/routes/utils.js'
17
18
  import { WidgetEvent } from '../types/events.js'
19
+ import { getQueryKey } from '../utils/queries.js'
18
20
  import { useWidgetEvents } from './useWidgetEvents.js'
19
21
 
20
22
  interface RouteExecutionProps {
@@ -34,6 +36,7 @@ export const useRouteExecution = ({
34
36
  const queryClient = useQueryClient()
35
37
  const { account } = useAccount()
36
38
  const resumedAfterMount = useRef(false)
39
+ const { keyPrefix } = useWidgetConfig()
37
40
  const emitter = useWidgetEvents()
38
41
  const routeExecutionStoreContext = useRouteExecutionStoreContext()
39
42
  const routeExecution = useRouteExecutionStore(
@@ -73,16 +76,16 @@ export const useRouteExecution = ({
73
76
  if (executionCompleted || executionFailed) {
74
77
  const invalidateKeys = [
75
78
  [
76
- 'token-balances',
79
+ getQueryKey('token-balances', keyPrefix),
77
80
  clonedUpdatedRoute.fromAddress,
78
81
  clonedUpdatedRoute.fromChainId,
79
82
  ],
80
83
  [
81
- 'token-balances',
84
+ getQueryKey('token-balances', keyPrefix),
82
85
  clonedUpdatedRoute.toAddress,
83
86
  clonedUpdatedRoute.toChainId,
84
87
  ],
85
- ['transaction-history'],
88
+ [getQueryKey('transaction-history', keyPrefix)],
86
89
  ]
87
90
  for (const key of invalidateKeys) {
88
91
  queryClient.invalidateQueries(
@@ -121,7 +124,10 @@ export const useRouteExecution = ({
121
124
  if (!routeExecution?.route) {
122
125
  throw new Error('Execution route not found.')
123
126
  }
124
- queryClient.removeQueries({ queryKey: ['routes'], exact: false })
127
+ queryClient.removeQueries({
128
+ queryKey: [getQueryKey('routes', keyPrefix)],
129
+ exact: false,
130
+ })
125
131
  return executeRoute(routeExecution.route, {
126
132
  updateRouteHook,
127
133
  acceptExchangeRateUpdateHook,
@@ -0,0 +1,58 @@
1
+ import type { ExtendedChain, Route } from '@lifi/sdk'
2
+ import { useAccount } from '@lifi/wallet-management'
3
+ import { useMemo } from 'react'
4
+ import { useFieldValues } from '../stores/form/useFieldValues.js'
5
+ import { useChain } from './useChain.js'
6
+
7
+ export const useRouteRequiredAccountConnection = (
8
+ route?: Route,
9
+ chain?: ExtendedChain
10
+ ) => {
11
+ const { account, accounts } = useAccount({ chainType: chain?.chainType })
12
+ const [toAddress] = useFieldValues('toAddress')
13
+ const { getChainById } = useChain()
14
+
15
+ return useMemo(() => {
16
+ if (!route?.steps.length) {
17
+ return {
18
+ connected: account.isConnected,
19
+ }
20
+ }
21
+
22
+ const connectedChainTypes = new Map(
23
+ accounts
24
+ .filter((account) => account.isConnected && account.address)
25
+ .map((account) => [account.chainType, account])
26
+ )
27
+
28
+ if (!connectedChainTypes.size) {
29
+ return {
30
+ connected: false,
31
+ }
32
+ }
33
+
34
+ for (const step of route.steps) {
35
+ const chain = getChainById(step.action.fromChainId)
36
+ if (!chain) {
37
+ continue
38
+ }
39
+
40
+ const connectedAccount = connectedChainTypes.get(chain.chainType)
41
+ const isToAddressSatisfied = toAddress
42
+ ? connectedAccount?.address === step.action.fromAddress
43
+ : true
44
+
45
+ if (!connectedAccount || !isToAddressSatisfied) {
46
+ return {
47
+ connected: false,
48
+ missingChain: chain,
49
+ missingAccountAddress: !isToAddressSatisfied
50
+ ? step.action.fromAddress
51
+ : undefined,
52
+ }
53
+ }
54
+ }
55
+
56
+ return { connected: true }
57
+ }, [account.isConnected, route, accounts, getChainById, toAddress])
58
+ }
@@ -19,6 +19,7 @@ import { useSettings } from '../stores/settings/useSettings.js'
19
19
  import { defaultSlippage } from '../stores/settings/useSettingsStore.js'
20
20
  import { WidgetEvent } from '../types/events.js'
21
21
  import { getChainTypeFromAddress } from '../utils/chainType.js'
22
+ import { getQueryKey } from '../utils/queries.js'
22
23
  import { useChain } from './useChain.js'
23
24
  import { useDebouncedWatch } from './useDebouncedWatch.js'
24
25
  import { useGasRefuel } from './useGasRefuel.js'
@@ -43,6 +44,7 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
43
44
  fee,
44
45
  feeConfig,
45
46
  useRelayerRoutes,
47
+ keyPrefix,
46
48
  } = useWidgetConfig()
47
49
  const setExecutableRoute = useSetExecutableRoute()
48
50
  const queryClient = useQueryClient()
@@ -135,7 +137,7 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
135
137
 
136
138
  // Some values should be strictly typed and isEnabled ensures that
137
139
  const queryKey = [
138
- 'routes',
140
+ getQueryKey('routes', keyPrefix),
139
141
  account.address,
140
142
  fromChain?.id as number,
141
143
  fromToken?.address as string,
@@ -399,7 +401,13 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
399
401
  const { fromToken, toToken } = routesResult.routes[0]
400
402
  ;[fromToken, toToken].forEach((token) => {
401
403
  queryClient.setQueriesData<Token[]>(
402
- { queryKey: ['token-balances', fromAddress, token.chainId] },
404
+ {
405
+ queryKey: [
406
+ getQueryKey('token-balances', keyPrefix),
407
+ fromAddress,
408
+ token.chainId,
409
+ ],
410
+ },
403
411
  (data) => {
404
412
  if (data) {
405
413
  const clonedData = [...data]
@@ -464,11 +472,9 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
464
472
 
465
473
  const setReviewableRoute = (route: Route) => {
466
474
  const queryDataKey = queryKey.toSpliced(queryKey.length - 1, 1, route.id)
467
- queryClient.setQueryData(
468
- queryDataKey,
469
- { routes: [route] },
470
- { updatedAt: dataUpdatedAt || Date.now() }
471
- )
475
+ queryClient.setQueryData(queryDataKey, [route], {
476
+ updatedAt: dataUpdatedAt || Date.now(),
477
+ })
472
478
  setExecutableRoute(route)
473
479
  }
474
480
 
@@ -3,12 +3,12 @@ import { useAccount } from '@lifi/wallet-management'
3
3
  import { useChain } from '../hooks/useChain.js'
4
4
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
5
5
  import { useFieldValues } from '../stores/form/useFieldValues.js'
6
- import { RequiredUI } from '../types/widget.js'
6
+ import { HiddenUI, RequiredUI } from '../types/widget.js'
7
7
  import { isDelegationDesignatorCode } from '../utils/eip7702.js'
8
8
  import { useIsContractAddress } from './useIsContractAddress.js'
9
9
 
10
10
  export const useToAddressRequirements = (route?: RouteExtended) => {
11
- const { requiredUI } = useWidgetConfig()
11
+ const { requiredUI, hiddenUI } = useWidgetConfig()
12
12
  const [formFromChainId, formToChainId, formToAddress] = useFieldValues(
13
13
  'fromChain',
14
14
  'toChain',
@@ -57,9 +57,10 @@ export const useToAddressRequirements = (route?: RouteExtended) => {
57
57
  !fromContractCodeHasDelegationIndicator
58
58
 
59
59
  const requiredToAddress =
60
- requiredUI?.includes(RequiredUI.ToAddress) ||
61
- isDifferentChainType ||
62
- isCrossChainContractAddress
60
+ (isDifferentChainType ||
61
+ isCrossChainContractAddress ||
62
+ requiredUI?.includes(RequiredUI.ToAddress)) &&
63
+ !hiddenUI?.includes(HiddenUI.ToAddress)
63
64
 
64
65
  const accountNotDeployedAtDestination =
65
66
  isFromContractAddress &&
@@ -1,21 +1,24 @@
1
1
  import { type Token, type TokenAmount, getTokenBalances } from '@lifi/sdk'
2
2
  import { useQuery, useQueryClient } from '@tanstack/react-query'
3
3
  import { useCallback, useMemo } from 'react'
4
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
5
+ import { getQueryKey } from '../utils/queries.js'
4
6
 
5
7
  const defaultRefetchInterval = 30_000
6
8
 
7
9
  export const useTokenBalance = (accountAddress?: string, token?: Token) => {
8
10
  const queryClient = useQueryClient()
11
+ const { keyPrefix } = useWidgetConfig()
9
12
 
10
13
  const tokenBalanceQueryKey = useMemo(
11
14
  () =>
12
15
  [
13
- 'token-balance',
16
+ getQueryKey('token-balance', keyPrefix),
14
17
  accountAddress,
15
18
  token?.chainId,
16
19
  token?.address,
17
20
  ] as const,
18
- [token?.address, token?.chainId, accountAddress]
21
+ [token?.address, token?.chainId, accountAddress, keyPrefix]
19
22
  )
20
23
 
21
24
  const { data, isLoading, refetch } = useQuery({
@@ -45,7 +48,13 @@ export const useTokenBalance = (accountAddress?: string, token?: Token) => {
45
48
  }
46
49
 
47
50
  queryClient.setQueriesData<TokenAmount[]>(
48
- { queryKey: ['token-balances', accountAddress, tokenChainId] },
51
+ {
52
+ queryKey: [
53
+ getQueryKey('token-balances', keyPrefix),
54
+ accountAddress,
55
+ tokenChainId,
56
+ ],
57
+ },
49
58
  (data) => {
50
59
  if (data) {
51
60
  const clonedData = [...data]
@@ -2,7 +2,9 @@ import { getTokenBalances } from '@lifi/sdk'
2
2
  import { useAccount } from '@lifi/wallet-management'
3
3
  import { useQuery } from '@tanstack/react-query'
4
4
  import { formatUnits } from 'viem'
5
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
5
6
  import type { TokenAmount } from '../types/token.js'
7
+ import { getQueryKey } from '../utils/queries.js'
6
8
  import { useTokens } from './useTokens.js'
7
9
 
8
10
  const defaultRefetchInterval = 32_000
@@ -11,6 +13,7 @@ export const useTokenBalances = (selectedChainId?: number) => {
11
13
  const { tokens, featuredTokens, popularTokens, chain, isLoading } =
12
14
  useTokens(selectedChainId)
13
15
  const { account } = useAccount({ chainType: chain?.chainType })
16
+ const { keyPrefix } = useWidgetConfig()
14
17
 
15
18
  const isBalanceLoadingEnabled =
16
19
  Boolean(account.address) &&
@@ -23,7 +26,7 @@ export const useTokenBalances = (selectedChainId?: number) => {
23
26
  refetch,
24
27
  } = useQuery({
25
28
  queryKey: [
26
- 'token-balances',
29
+ getQueryKey('token-balances', keyPrefix),
27
30
  account.address,
28
31
  selectedChainId,
29
32
  tokens?.length,
@@ -1,6 +1,8 @@
1
1
  import { type ChainId, type TokensResponse, getToken } from '@lifi/sdk'
2
2
  import { useQuery, useQueryClient } from '@tanstack/react-query'
3
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
3
4
  import type { TokenAmount } from '../types/token.js'
5
+ import { getQueryKey } from '../utils/queries.js'
4
6
 
5
7
  export const useTokenSearch = (
6
8
  chainId?: number,
@@ -8,8 +10,9 @@ export const useTokenSearch = (
8
10
  enabled?: boolean
9
11
  ) => {
10
12
  const queryClient = useQueryClient()
13
+ const { keyPrefix } = useWidgetConfig()
11
14
  const { data, isLoading } = useQuery({
12
- queryKey: ['token-search', chainId, tokenQuery],
15
+ queryKey: [getQueryKey('token-search', keyPrefix), chainId, tokenQuery],
13
16
  queryFn: async ({ queryKey: [, chainId, tokenQuery], signal }) => {
14
17
  const token = await getToken(chainId as ChainId, tokenQuery as string, {
15
18
  signal,
@@ -17,7 +20,7 @@ export const useTokenSearch = (
17
20
 
18
21
  if (token) {
19
22
  queryClient.setQueriesData<TokensResponse>(
20
- { queryKey: ['tokens'] },
23
+ { queryKey: [getQueryKey('tokens', keyPrefix)] },
21
24
  (data) => {
22
25
  if (
23
26
  data &&
@@ -3,12 +3,13 @@ import { useQuery } from '@tanstack/react-query'
3
3
  import { useMemo } from 'react'
4
4
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
5
5
  import type { TokenAmount } from '../types/token.js'
6
+ import { getQueryKey } from '../utils/queries.js'
6
7
  import { useChains } from './useChains.js'
7
8
 
8
9
  export const useTokens = (selectedChainId?: number) => {
9
- const { tokens: configTokens } = useWidgetConfig()
10
+ const { tokens: configTokens, keyPrefix } = useWidgetConfig()
10
11
  const { data, isLoading } = useQuery({
11
- queryKey: ['tokens'],
12
+ queryKey: [getQueryKey('tokens', keyPrefix)],
12
13
  queryFn: () =>
13
14
  getTokens({
14
15
  chainTypes: [
@@ -3,12 +3,13 @@ import { useQuery } from '@tanstack/react-query'
3
3
  import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
4
4
  import { useSettingsStore } from '../stores/settings/useSettingsStore.js'
5
5
  import { isItemAllowed } from '../utils/item.js'
6
+ import { getQueryKey } from '../utils/queries.js'
6
7
 
7
8
  export const useTools = () => {
8
- const { bridges, exchanges } = useWidgetConfig()
9
+ const { bridges, exchanges, keyPrefix } = useWidgetConfig()
9
10
  const { data } = useQuery({
10
11
  queryKey: [
11
- 'tools',
12
+ getQueryKey('tools', keyPrefix),
12
13
  bridges?.allow,
13
14
  bridges?.deny,
14
15
  exchanges?.allow,
@@ -6,18 +6,27 @@ import {
6
6
  useQuery,
7
7
  useQueryClient,
8
8
  } from '@tanstack/react-query'
9
+ import { useMemo } from 'react'
10
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
11
+ import { getQueryKey } from '../utils/queries.js'
9
12
 
10
13
  export const useTransactionDetails = (transactionHash?: string) => {
11
14
  const { account, accounts } = useAccount()
12
15
  const queryClient = useQueryClient()
16
+ const { keyPrefix } = useWidgetConfig()
17
+
18
+ const transactionHistoryQueryKey = useMemo(
19
+ () => getQueryKey('transaction-history', keyPrefix),
20
+ [keyPrefix]
21
+ )
13
22
 
14
23
  const { data, isLoading } = useQuery({
15
- queryKey: ['transaction-history', transactionHash],
24
+ queryKey: [transactionHistoryQueryKey, transactionHash],
16
25
  queryFn: async ({ queryKey: [, transactionHash], signal }) => {
17
26
  if (transactionHash) {
18
27
  for (const account of accounts) {
19
28
  const cachedHistory = queryClient.getQueryData<StatusResponse[]>([
20
- 'transaction-history',
29
+ transactionHistoryQueryKey,
21
30
  account.address,
22
31
  ])
23
32
 
@@ -41,7 +50,7 @@ export const useTransactionDetails = (transactionHash?: string) => {
41
50
 
42
51
  if (fromAddress) {
43
52
  queryClient.setQueryData<StatusResponse[]>(
44
- ['transaction-history', fromAddress],
53
+ [transactionHistoryQueryKey, fromAddress],
45
54
  (data) => {
46
55
  return [...data!, transaction!]
47
56
  }
@@ -57,7 +66,7 @@ export const useTransactionDetails = (transactionHash?: string) => {
57
66
  for (const account of accounts) {
58
67
  const transaction = queryClient
59
68
  .getQueryData<StatusResponse[]>([
60
- 'transaction-history',
69
+ transactionHistoryQueryKey,
61
70
  account.address,
62
71
  ])
63
72
  ?.find((t) => t.sending.txHash === transactionHash)
@@ -3,13 +3,19 @@ import { type ExtendedTransactionInfo, getTransactionHistory } from '@lifi/sdk'
3
3
  import { useAccount } from '@lifi/wallet-management'
4
4
  import type { QueryFunction } from '@tanstack/react-query'
5
5
  import { useQueries } from '@tanstack/react-query'
6
+ import { useWidgetConfig } from '../providers/WidgetProvider/WidgetProvider.js'
7
+ import { getQueryKey } from '../utils/queries.js'
6
8
 
7
9
  export const useTransactionHistory = () => {
8
10
  const { accounts } = useAccount()
11
+ const { keyPrefix } = useWidgetConfig()
9
12
 
10
13
  const { data, isLoading } = useQueries({
11
14
  queries: accounts.map((account) => ({
12
- queryKey: ['transaction-history', account.address],
15
+ queryKey: [
16
+ getQueryKey('transaction-history', keyPrefix),
17
+ account.address,
18
+ ],
13
19
  queryFn: (async ({ queryKey: [, accountAddress], signal }) => {
14
20
  if (!accountAddress) {
15
21
  return []
package/src/i18n/en.json CHANGED
@@ -21,6 +21,7 @@
21
21
  "close": "Close",
22
22
  "confirm": "Confirm",
23
23
  "connectAnotherWallet": "Connect another wallet",
24
+ "connectChainWallet": "Connect {{chain}} wallet",
24
25
  "connectWallet": "Connect wallet",
25
26
  "contactSupport": "Contact support",
26
27
  "continue": "Continue",
@@ -67,7 +68,9 @@
67
68
  "gas": "Gas",
68
69
  "payWith": "Pay with",
69
70
  "receive": "Receive",
71
+ "received": "Received",
70
72
  "recentWallets": "Recent wallets",
73
+ "refunded": "Refunded",
71
74
  "selectChain": "Select chain",
72
75
  "selectWallet": "Select your wallet",
73
76
  "send": "Send",
@@ -91,7 +94,8 @@
91
94
  "emptyTokenList": "We couldn't find tokens on {{chainName}} chain or you don't have any. Please search by contract address if your token doesn't appear or choose another chain.",
92
95
  "emptyTransactionHistory": "Transaction history is only stored locally and will be deleted if you clear your browser data.",
93
96
  "routeNotFound": "Reasons for that could be: low liquidity, amount selected is too low, gas costs are too high or there are no routes for the selected combination.",
94
- "toAddressIsRequired": "The destination wallet address is required to proceed with the transfer."
97
+ "toAddressIsRequired": "The destination wallet address is required to proceed with the transfer.",
98
+ "missingRouteRequiredAccount": "Connect your {{chainName}} wallet to proceed. {{address}}"
95
99
  },
96
100
  "title": {
97
101
  "autoRefuel": "Get {{chainName}} gas",
@@ -102,9 +106,7 @@
102
106
  },
103
107
  "success": {
104
108
  "message": {
105
- "exchangePartiallySuccessful": "We've tried to complete the transaction, but {{tool}} couldn't proceed due to either slippage settings or lack of liquidity for the {{tokenSymbol}} token.",
106
- "exchangeSuccessful": "There are now {{amount, numberExt}} {{tokenSymbol}} in {{walletAddress}} wallet on {{chainName}} chain.",
107
- "checkoutSuccessful": "You now own {{assetName}} in {{walletAddress}} wallet on {{chainName}} chain."
109
+ "exchangePartiallySuccessful": "We've tried to complete the transaction, but {{tool}} couldn't proceed due to either slippage settings or lack of liquidity for the {{tokenSymbol}} token."
108
110
  },
109
111
  "title": {
110
112
  "bridgePartiallySuccessful": "Bridge partially successful",
@@ -73,6 +73,7 @@ export const ReviewButton: React.FC = () => {
73
73
  text={getButtonText()}
74
74
  onClick={handleClick}
75
75
  disabled={currentRoute && requiredToAddress && !toAddress}
76
+ route={currentRoute}
76
77
  />
77
78
  )
78
79
  }
@@ -21,6 +21,7 @@ export const StartTransactionButton: React.FC<StartTransactionButtonProps> = ({
21
21
  text={text}
22
22
  disabled={hasNonGasMessages}
23
23
  loading={isLoading || loading}
24
+ route={route}
24
25
  />
25
26
  )
26
27
  }