@lifi/widget 3.14.0-beta.0 → 3.14.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 (112) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/esm/components/ActiveTransactions/ActiveTransactionItem.js +0 -1
  3. package/dist/esm/components/ActiveTransactions/ActiveTransactionItem.js.map +1 -1
  4. package/dist/esm/components/AlertMessage/AlertMessage.d.ts +2 -2
  5. package/dist/esm/components/AlertMessage/AlertMessage.js +1 -1
  6. package/dist/esm/components/AlertMessage/AlertMessage.js.map +1 -1
  7. package/dist/esm/components/AmountInput/PriceFormHelperText.js +7 -4
  8. package/dist/esm/components/AmountInput/PriceFormHelperText.js.map +1 -1
  9. package/dist/esm/components/FeeBreakdownTooltip.js +3 -4
  10. package/dist/esm/components/FeeBreakdownTooltip.js.map +1 -1
  11. package/dist/esm/components/GasMessage/FundsSufficiencyMessage.js +1 -1
  12. package/dist/esm/components/GasMessage/FundsSufficiencyMessage.js.map +1 -1
  13. package/dist/esm/components/RouteCard/RouteCard.js +4 -8
  14. package/dist/esm/components/RouteCard/RouteCard.js.map +1 -1
  15. package/dist/esm/components/Step/CircularProgress.js +1 -2
  16. package/dist/esm/components/Step/CircularProgress.js.map +1 -1
  17. package/dist/esm/components/Step/CircularProgress.style.js +2 -13
  18. package/dist/esm/components/Step/CircularProgress.style.js.map +1 -1
  19. package/dist/esm/components/Step/StepProcess.js +1 -2
  20. package/dist/esm/components/Step/StepProcess.js.map +1 -1
  21. package/dist/esm/components/Step/StepTimer.js +1 -2
  22. package/dist/esm/components/Step/StepTimer.js.map +1 -1
  23. package/dist/esm/components/StepActions/StepActions.js +8 -8
  24. package/dist/esm/components/StepActions/StepActions.js.map +1 -1
  25. package/dist/esm/components/ToAddressRequiredMessage.js +1 -1
  26. package/dist/esm/components/ToAddressRequiredMessage.js.map +1 -1
  27. package/dist/esm/components/Token/Token.js +3 -3
  28. package/dist/esm/components/Token/Token.js.map +1 -1
  29. package/dist/esm/components/TokenList/TokenListItem.js +4 -6
  30. package/dist/esm/components/TokenList/TokenListItem.js.map +1 -1
  31. package/dist/esm/components/TokenRate/TokenRate.js +5 -7
  32. package/dist/esm/components/TokenRate/TokenRate.js.map +1 -1
  33. package/dist/esm/components/TransactionDetails.js +3 -7
  34. package/dist/esm/components/TransactionDetails.js.map +1 -1
  35. package/dist/esm/config/version.d.ts +1 -1
  36. package/dist/esm/config/version.js +1 -1
  37. package/dist/esm/config/version.js.map +1 -1
  38. package/dist/esm/hooks/useProcessMessage.js +6 -18
  39. package/dist/esm/hooks/useProcessMessage.js.map +1 -1
  40. package/dist/esm/hooks/useRoutes.d.ts +2 -2
  41. package/dist/esm/hooks/useRoutes.js +58 -99
  42. package/dist/esm/hooks/useRoutes.js.map +1 -1
  43. package/dist/esm/i18n/en.json +14 -16
  44. package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.d.ts +1 -0
  45. package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.js +6 -4
  46. package/dist/esm/pages/SendToWallet/ConfirmAddressSheet.js.map +1 -1
  47. package/dist/esm/pages/SendToWallet/SendToWalletPage.js +5 -3
  48. package/dist/esm/pages/SendToWallet/SendToWalletPage.js.map +1 -1
  49. package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.js +2 -2
  50. package/dist/esm/pages/TransactionPage/ExchangeRateBottomSheet.js.map +1 -1
  51. package/dist/esm/providers/I18nProvider/I18nProvider.js +3 -1
  52. package/dist/esm/providers/I18nProvider/I18nProvider.js.map +1 -1
  53. package/dist/esm/providers/WalletProvider/SDKProviders.js +15 -2
  54. package/dist/esm/providers/WalletProvider/SDKProviders.js.map +1 -1
  55. package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.d.ts +8 -0
  56. package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.js +95 -0
  57. package/dist/esm/providers/WalletProvider/getSafeMultisigConfig.js.map +1 -0
  58. package/dist/esm/types/widget.d.ts +0 -1
  59. package/dist/esm/utils/compactNumberFormatter.d.ts +10 -0
  60. package/dist/esm/utils/compactNumberFormatter.js +81 -0
  61. package/dist/esm/utils/compactNumberFormatter.js.map +1 -0
  62. package/dist/esm/utils/compactNumberFormatter.test.d.ts +1 -0
  63. package/dist/esm/utils/compactNumberFormatter.test.js +64 -0
  64. package/dist/esm/utils/compactNumberFormatter.test.js.map +1 -0
  65. package/dist/esm/utils/converters.js +2 -2
  66. package/dist/esm/utils/converters.js.map +1 -1
  67. package/dist/esm/utils/fees.js +2 -3
  68. package/dist/esm/utils/fees.js.map +1 -1
  69. package/dist/esm/utils/format.d.ts +1 -10
  70. package/dist/esm/utils/format.js +8 -47
  71. package/dist/esm/utils/format.js.map +1 -1
  72. package/dist/esm/utils/getPriceImpact.js +7 -6
  73. package/dist/esm/utils/getPriceImpact.js.map +1 -1
  74. package/dist/esm/utils/percentFormatter.js.map +1 -0
  75. package/package.json +8 -8
  76. package/src/components/ActiveTransactions/ActiveTransactionItem.tsx +0 -1
  77. package/src/components/AlertMessage/AlertMessage.tsx +3 -3
  78. package/src/components/AmountInput/PriceFormHelperText.tsx +8 -4
  79. package/src/components/FeeBreakdownTooltip.tsx +3 -4
  80. package/src/components/GasMessage/FundsSufficiencyMessage.tsx +1 -1
  81. package/src/components/RouteCard/RouteCard.tsx +6 -9
  82. package/src/components/Step/CircularProgress.style.tsx +2 -13
  83. package/src/components/Step/CircularProgress.tsx +1 -2
  84. package/src/components/Step/StepProcess.tsx +1 -2
  85. package/src/components/Step/StepTimer.tsx +1 -3
  86. package/src/components/StepActions/StepActions.tsx +16 -13
  87. package/src/components/ToAddressRequiredMessage.tsx +1 -1
  88. package/src/components/Token/Token.tsx +7 -2
  89. package/src/components/TokenList/TokenListItem.tsx +9 -9
  90. package/src/components/TokenRate/TokenRate.tsx +5 -11
  91. package/src/components/TransactionDetails.tsx +4 -8
  92. package/src/config/version.ts +1 -1
  93. package/src/hooks/useProcessMessage.ts +5 -24
  94. package/src/hooks/useRoutes.ts +66 -127
  95. package/src/i18n/en.json +14 -16
  96. package/src/pages/SendToWallet/ConfirmAddressSheet.tsx +28 -6
  97. package/src/pages/SendToWallet/SendToWalletPage.tsx +8 -2
  98. package/src/pages/TransactionPage/ExchangeRateBottomSheet.tsx +2 -2
  99. package/src/providers/I18nProvider/I18nProvider.tsx +3 -1
  100. package/src/providers/WalletProvider/SDKProviders.tsx +16 -2
  101. package/src/providers/WalletProvider/getSafeMultisigConfig.ts +144 -0
  102. package/src/types/widget.ts +0 -1
  103. package/src/utils/compactNumberFormatter.test.ts +67 -0
  104. package/src/utils/compactNumberFormatter.ts +91 -0
  105. package/src/utils/converters.ts +6 -4
  106. package/src/utils/fees.ts +6 -4
  107. package/src/utils/format.ts +14 -60
  108. package/src/utils/getPriceImpact.ts +15 -6
  109. package/dist/esm/providers/I18nProvider/percentFormatter.js.map +0 -1
  110. /package/dist/esm/{providers/I18nProvider → utils}/percentFormatter.d.ts +0 -0
  111. /package/dist/esm/{providers/I18nProvider → utils}/percentFormatter.js +0 -0
  112. /package/src/{providers/I18nProvider → utils}/percentFormatter.ts +0 -0
@@ -39,7 +39,6 @@ const processStatusMessages: Record<
39
39
  ProcessStatus,
40
40
  (
41
41
  t: TFunction,
42
- step: LiFiStep,
43
42
  subvariant?: WidgetSubvariant,
44
43
  subvariantOptions?: SubvariantOptions
45
44
  ) => string
@@ -48,18 +47,9 @@ const processStatusMessages: Record<
48
47
  > = {
49
48
  TOKEN_ALLOWANCE: {
50
49
  STARTED: (t) => t('main.process.tokenAllowance.started'),
51
- ACTION_REQUIRED: (t, step) =>
52
- t('main.process.tokenAllowance.actionRequired', {
53
- tokenSymbol: step.action.fromToken.symbol,
54
- }),
55
- PENDING: (t, step) =>
56
- t('main.process.tokenAllowance.pending', {
57
- tokenSymbol: step.action.fromToken.symbol,
58
- }),
59
- DONE: (t, step) =>
60
- t('main.process.tokenAllowance.done', {
61
- tokenSymbol: step.action.fromToken.symbol,
62
- }),
50
+ ACTION_REQUIRED: (t) => t('main.process.tokenAllowance.pending'),
51
+ PENDING: (t) => t('main.process.tokenAllowance.pending'),
52
+ DONE: (t) => t('main.process.tokenAllowance.done'),
63
53
  },
64
54
  SWITCH_CHAIN: {
65
55
  ACTION_REQUIRED: (t) => t('main.process.switchChain.actionRequired'),
@@ -67,30 +57,22 @@ const processStatusMessages: Record<
67
57
  },
68
58
  SWAP: {
69
59
  STARTED: (t) => t('main.process.swap.started'),
70
- PERMIT_REQUIRED: (t, step) =>
71
- t('main.process.swap.permitRequired', {
72
- tokenSymbol: step.action.fromToken.symbol,
73
- }),
74
60
  ACTION_REQUIRED: (t) => t('main.process.swap.actionRequired'),
75
61
  PENDING: (t) => t('main.process.swap.pending'),
76
- DONE: (t, _, subvariant, subvariantOptions) =>
62
+ DONE: (t, subvariant, subvariantOptions) =>
77
63
  subvariant === 'custom'
78
64
  ? t(`main.process.${subvariantOptions?.custom ?? 'checkout'}.done`)
79
65
  : t('main.process.swap.done'),
80
66
  },
81
67
  CROSS_CHAIN: {
82
68
  STARTED: (t) => t('main.process.bridge.started'),
83
- PERMIT_REQUIRED: (t, step) =>
84
- t('main.process.bridge.permitRequired', {
85
- tokenSymbol: step.action.fromToken.symbol,
86
- }),
87
69
  ACTION_REQUIRED: (t) => t('main.process.bridge.actionRequired'),
88
70
  PENDING: (t) => t('main.process.bridge.pending'),
89
71
  DONE: (t) => t('main.process.bridge.done'),
90
72
  },
91
73
  RECEIVING_CHAIN: {
92
74
  PENDING: (t) => t('main.process.receivingChain.pending'),
93
- DONE: (t, _, subvariant, subvariantOptions) =>
75
+ DONE: (t, subvariant, subvariantOptions) =>
94
76
  subvariant === 'custom'
95
77
  ? t(`main.process.${subvariantOptions?.custom ?? 'checkout'}.done`)
96
78
  : t('main.process.receivingChain.done'),
@@ -247,7 +229,6 @@ export function getProcessMessage(
247
229
  ]?.(t) ??
248
230
  processStatusMessages[process.type]?.[process.status]?.(
249
231
  t,
250
- step,
251
232
  subvariant,
252
233
  subvariantOptions
253
234
  )
@@ -1,12 +1,5 @@
1
- import type { Route, Token } from '@lifi/sdk'
2
- import {
3
- LiFiErrorCode,
4
- convertQuoteToRoute,
5
- getContractCallsQuote,
6
- getRelayerQuote,
7
- getRoutes,
8
- isEVMPermitStep,
9
- } from '@lifi/sdk'
1
+ import type { Route, RoutesResponse, Token } from '@lifi/sdk'
2
+ import { LiFiErrorCode, getContractCallsQuote, getRoutes } from '@lifi/sdk'
10
3
  import { useAccount } from '@lifi/wallet-management'
11
4
  import { useQuery, useQueryClient } from '@tanstack/react-query'
12
5
  import { parseUnits } from 'viem'
@@ -39,7 +32,6 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
39
32
  exchanges,
40
33
  fee,
41
34
  feeConfig,
42
- useRelayerRoutes,
43
35
  } = useWidgetConfig()
44
36
  const setExecutableRoute = useSetExecutableRoute()
45
37
  const queryClient = useQueryClient()
@@ -266,9 +258,27 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
266
258
  contractCallQuote.toolDetails = toolDetails
267
259
  }
268
260
 
269
- const route: Route = convertQuoteToRoute(contractCallQuote)
261
+ const route: Route = {
262
+ id: crypto.randomUUID(),
263
+ fromChainId: contractCallQuote.action.fromChainId,
264
+ fromAmountUSD: contractCallQuote.estimate.fromAmountUSD || '',
265
+ fromAmount: contractCallQuote.action.fromAmount,
266
+ fromToken: contractCallQuote.action.fromToken,
267
+ fromAddress: contractCallQuote.action.fromAddress,
268
+ toChainId: contractCallQuote.action.toChainId,
269
+ toAmountUSD: contractCallQuote.estimate.toAmountUSD || '',
270
+ toAmount: contractCallQuote.estimate.toAmount,
271
+ toAmountMin: contractCallQuote.estimate.toAmountMin,
272
+ toToken: toToken!,
273
+ toAddress:
274
+ contractCallQuote.action.toAddress ||
275
+ contractCallQuote.action.fromAddress,
276
+ gasCostUSD: contractCallQuote.estimate.gasCosts?.[0].amountUSD,
277
+ steps: [contractCallQuote],
278
+ insurance: { state: 'NOT_INSURABLE', feeAmountUsd: '0' },
279
+ }
270
280
 
271
- return [route]
281
+ return { routes: [route] } as RoutesResponse
272
282
  }
273
283
 
274
284
  // Prevent sending a request for the same chain token combinations.
@@ -276,110 +286,50 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
276
286
  return
277
287
  }
278
288
 
279
- const isObservableRelayerRoute =
280
- observableRoute?.steps?.some(isEVMPermitStep)
281
-
282
- const shouldUseMainRoutes =
283
- !observableRoute || !isObservableRelayerRoute
284
- const shouldUseRelayerQuote =
285
- fromAddress &&
286
- useRelayerRoutes &&
287
- (!observableRoute || isObservableRelayerRoute)
288
-
289
- const [routesResult, relayerRouteResult] = await Promise.all([
290
- shouldUseMainRoutes
291
- ? getRoutes(
292
- {
293
- fromAddress,
294
- fromAmount: fromAmount.toString(),
295
- fromChainId,
296
- fromTokenAddress,
297
- toAddress,
298
- toChainId,
299
- toTokenAddress,
300
- fromAmountForGas:
301
- enabledRefuel && gasRecommendationFromAmount
302
- ? gasRecommendationFromAmount
303
- : undefined,
304
- options: {
305
- allowSwitchChain:
306
- subvariant === 'refuel' ? false : allowSwitchChain,
307
- bridges:
308
- allowBridges?.length || disabledBridges.length
309
- ? {
310
- allow: allowBridges,
311
- deny: disabledBridges.length
312
- ? disabledBridges
313
- : undefined,
314
- }
289
+ const data = await getRoutes(
290
+ {
291
+ fromAddress,
292
+ fromAmount: fromAmount.toString(),
293
+ fromChainId,
294
+ fromTokenAddress,
295
+ toAddress,
296
+ toChainId,
297
+ toTokenAddress,
298
+ fromAmountForGas:
299
+ enabledRefuel && gasRecommendationFromAmount
300
+ ? gasRecommendationFromAmount
301
+ : undefined,
302
+ options: {
303
+ allowSwitchChain:
304
+ subvariant === 'refuel' ? false : allowSwitchChain,
305
+ bridges:
306
+ allowBridges?.length || disabledBridges.length
307
+ ? {
308
+ allow: allowBridges,
309
+ deny: disabledBridges.length
310
+ ? disabledBridges
315
311
  : undefined,
316
- exchanges:
317
- allowExchanges?.length || disabledExchanges.length
318
- ? {
319
- allow: allowExchanges,
320
- deny: disabledExchanges.length
321
- ? disabledExchanges
322
- : undefined,
323
- }
312
+ }
313
+ : undefined,
314
+ exchanges:
315
+ allowExchanges?.length || disabledExchanges.length
316
+ ? {
317
+ allow: allowExchanges,
318
+ deny: disabledExchanges.length
319
+ ? disabledExchanges
324
320
  : undefined,
325
- order: routePriority,
326
- slippage: formattedSlippage,
327
- fee: calculatedFee || fee,
328
- },
329
- },
330
- { signal }
331
- )
332
- : Promise.resolve(null),
333
- shouldUseRelayerQuote
334
- ? getRelayerQuote(
335
- {
336
- fromAddress,
337
- fromAmount: fromAmount.toString(),
338
- fromChain: fromChainId,
339
- fromToken: fromTokenAddress,
340
- toAddress,
341
- toChain: toChainId,
342
- toToken: toTokenAddress,
343
- fromAmountForGas:
344
- enabledRefuel && gasRecommendationFromAmount
345
- ? gasRecommendationFromAmount
346
- : undefined,
347
- order: routePriority,
348
- slippage: formattedSlippage,
349
- fee: calculatedFee || fee,
350
- ...(allowBridges?.length || disabledBridges.length
351
- ? {
352
- allowBridges: allowBridges,
353
- denyBridges: disabledBridges.length
354
- ? disabledBridges
355
- : undefined,
356
- }
357
- : undefined),
358
- ...(allowExchanges?.length || disabledExchanges.length
359
- ? {
360
- allowExchanges: allowExchanges,
361
- denyExchanges: disabledExchanges.length
362
- ? disabledExchanges
363
- : undefined,
364
- }
365
- : undefined),
366
- },
367
- { signal }
368
- )
369
- .then((response) => {
370
- const quote = {
371
- ...response.data.quote.step,
372
- ...response.data.quote,
373
- }
374
- return convertQuoteToRoute(quote)
375
- })
376
- .catch(() => null)
377
- : Promise.resolve(null),
378
- ])
379
-
380
- if (routesResult?.routes[0] && fromAddress) {
321
+ }
322
+ : undefined,
323
+ order: routePriority,
324
+ slippage: formattedSlippage,
325
+ fee: calculatedFee || fee,
326
+ },
327
+ },
328
+ { signal }
329
+ )
330
+ if (data.routes[0] && fromAddress) {
381
331
  // Update local tokens cache to keep priceUSD in sync
382
- const { fromToken, toToken } = routesResult.routes[0]
332
+ const { fromToken, toToken } = data.routes[0]
383
333
  ;[fromToken, toToken].forEach((token) => {
384
334
  queryClient.setQueriesData<Token[]>(
385
335
  { queryKey: ['token-balances', fromAddress, token.chainId] },
@@ -399,16 +349,8 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
399
349
  )
400
350
  })
401
351
  }
402
-
403
- const routes = routesResult?.routes ?? []
404
-
405
- // Add relayer route if available
406
- if (relayerRouteResult) {
407
- routes.splice(1, 0, relayerRouteResult)
408
- }
409
-
410
- emitter.emit(WidgetEvent.AvailableRoutes, routes)
411
- return routes
352
+ emitter.emit(WidgetEvent.AvailableRoutes, data.routes)
353
+ return data
412
354
  },
413
355
  enabled: isEnabled,
414
356
  staleTime: refetchTime,
@@ -419,9 +361,6 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
419
361
  )
420
362
  },
421
363
  retry(failureCount, error: any) {
422
- if (process.env.NODE_ENV === 'development') {
423
- console.warn('Route query failed:', { failureCount, error })
424
- }
425
364
  if (failureCount >= 5) {
426
365
  return false
427
366
  }
@@ -443,7 +382,7 @@ export const useRoutes = ({ observableRoute }: RoutesProps = {}) => {
443
382
  }
444
383
 
445
384
  return {
446
- routes: data,
385
+ routes: data?.routes,
447
386
  isLoading: isEnabled && isLoading,
448
387
  isFetching,
449
388
  isFetched,
package/src/i18n/en.json CHANGED
@@ -6,7 +6,8 @@
6
6
  "format": {
7
7
  "currency": "{{value, currencyExt(currency: USD)}}",
8
8
  "number": "{{value, number(maximumFractionDigits: 9)}}",
9
- "percent": "{{value, percent(maximumFractionDigits: 2)}}"
9
+ "percent": "{{value, percent(maximumFractionDigits: 2)}}",
10
+ "tokenAmount": "{{value, numberExt}}"
10
11
  },
11
12
  "button": {
12
13
  "auto": "Auto",
@@ -88,7 +89,8 @@
88
89
  "emptyBridgesList": "We couldn't find any bridges that match your search",
89
90
  "emptyExchangesList": "We couldn't find any exchanges that match your search",
90
91
  "emptyTransactionHistory": "Transaction history is only stored locally and will be deleted if you clear your browser data.",
91
- "fundsToExchange": "Funds sent to an exchange may be lost",
92
+ "smartContractAccount": "Always ensure your smart contract account is set up on the destination chain to avoid potential fund loss.",
93
+ "fundsToExchange": "Funds sent directly to exchanges might not be recoverable.",
92
94
  "toAddressIsRequired": "Please provide the destination wallet address to which the funds will be transferred.",
93
95
  "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
96
  },
@@ -220,10 +222,9 @@
220
222
  "priceImpact": "Price impact",
221
223
  "process": {
222
224
  "bridge": {
223
- "permitRequired": "Sign permit for {{tokenSymbol}}",
224
- "actionRequired": "Sign bridge transaction",
225
+ "actionRequired": "Please sign the transaction",
225
226
  "done": "Bridge transaction confirmed",
226
- "pending": "Bridge transaction pending",
227
+ "pending": "Waiting for bridge transaction",
227
228
  "started": "Preparing bridge transaction"
228
229
  },
229
230
  "checkout": {
@@ -239,21 +240,19 @@
239
240
  "refunded": "Bridge transaction refunded"
240
241
  },
241
242
  "swap": {
242
- "permitRequired": "Sign permit for {{tokenSymbol}}",
243
- "actionRequired": "Sign swap transaction",
243
+ "actionRequired": "Please sign the transaction",
244
244
  "done": "Swap completed",
245
- "pending": "Swap transaction pending",
245
+ "pending": "Waiting for swap transaction",
246
246
  "started": "Preparing swap transaction"
247
247
  },
248
248
  "switchChain": {
249
- "actionRequired": "Confirm chain switch",
250
- "done": "Chain switched"
249
+ "actionRequired": "Chain switch required",
250
+ "done": "Chain switched successfully"
251
251
  },
252
252
  "tokenAllowance": {
253
- "actionRequired": "Approve {{tokenSymbol}} spending",
254
- "done": "{{tokenSymbol}} spending approved",
255
- "pending": "{{tokenSymbol}} approval pending",
256
- "started": "Preparing approval transaction"
253
+ "done": "Token allowance approved",
254
+ "pending": "Waiting for token allowance",
255
+ "started": "Setting token allowance"
257
256
  }
258
257
  },
259
258
  "quotedAmount": "Quoted amount",
@@ -281,8 +280,7 @@
281
280
  "transferId": "Transfer ID",
282
281
  "tags": {
283
282
  "cheapest": "Best Return",
284
- "fastest": "Fastest",
285
- "gasless": "Gasless"
283
+ "fastest": "Fastest"
286
284
  },
287
285
  "to": "To",
288
286
  "tokenOnChain": "{{tokenSymbol}} on {{chainName}}",
@@ -1,11 +1,12 @@
1
- import { Info, Wallet } from '@mui/icons-material'
2
- import { Button, Typography } from '@mui/material'
1
+ import { Info, Wallet, Warning } from '@mui/icons-material'
2
+ import { Box, Button, Typography } from '@mui/material'
3
3
  import type { MutableRefObject } from 'react'
4
4
  import { forwardRef } from 'react'
5
5
  import { useTranslation } from 'react-i18next'
6
6
  import { AlertMessage } from '../../components/AlertMessage/AlertMessage.js'
7
7
  import { BottomSheet } from '../../components/BottomSheet/BottomSheet.js'
8
8
  import type { BottomSheetBase } from '../../components/BottomSheet/types.js'
9
+ import { useIsContractAddress } from '../../hooks/useIsContractAddress.js'
9
10
  import { useNavigateBack } from '../../hooks/useNavigateBack.js'
10
11
  import type { Bookmark } from '../../stores/bookmarks/types.js'
11
12
  import { useFieldActions } from '../../stores/form/useFieldActions.js'
@@ -21,16 +22,22 @@ import {
21
22
  interface ConfirmAddressSheetProps {
22
23
  onConfirm: (wallet: Bookmark) => void
23
24
  validatedBookmark?: Bookmark
25
+ chainId?: number
24
26
  }
25
27
 
26
28
  export const ConfirmAddressSheet = forwardRef<
27
29
  BottomSheetBase,
28
30
  ConfirmAddressSheetProps
29
- >(({ validatedBookmark, onConfirm }, ref) => {
31
+ >(({ validatedBookmark, onConfirm, chainId }, ref) => {
30
32
  const { t } = useTranslation()
31
33
  const { navigateBack } = useNavigateBack()
32
34
  const { setFieldValue } = useFieldActions()
33
35
  const { setSendToWallet } = useSendToWalletActions()
36
+ const isContractAddress = useIsContractAddress(
37
+ validatedBookmark?.address,
38
+ chainId,
39
+ validatedBookmark?.chainType
40
+ )
34
41
 
35
42
  const handleClose = () => {
36
43
  ;(ref as MutableRefObject<BottomSheetBase>).current?.close()
@@ -71,12 +78,27 @@ export const ConfirmAddressSheet = forwardRef<
71
78
  </SheetAddressContainer>
72
79
  <AlertMessage
73
80
  title={
74
- <Typography variant="body2">
75
- {t('info.message.fundsToExchange')}
76
- </Typography>
81
+ <Box sx={{ display: 'grid', gap: 1 }}>
82
+ <Typography variant="body2" fontWeight={500}>
83
+ {t('info.message.fundsToExchange')}
84
+ </Typography>
85
+ </Box>
77
86
  }
78
87
  icon={<Info />}
88
+ multiline
79
89
  />
90
+ {isContractAddress ? (
91
+ <AlertMessage
92
+ title={
93
+ <Typography variant="body2" fontWeight={500}>
94
+ {t('info.message.smartContractAccount')}
95
+ </Typography>
96
+ }
97
+ icon={<Warning />}
98
+ severity="warning"
99
+ multiline
100
+ />
101
+ ) : null}
80
102
  <SendToWalletButtonRow>
81
103
  <Button variant="text" onClick={handleClose} fullWidth>
82
104
  {t('button.cancel')}
@@ -1,3 +1,4 @@
1
+ import { ChainType } from '@lifi/sdk'
1
2
  import { useAccount } from '@lifi/wallet-management'
2
3
  import {
3
4
  Error as ErrorIcon,
@@ -58,8 +59,6 @@ export const SendToWalletPage = () => {
58
59
  const [validatedWallet, setValidatedWallet] = useState<Bookmark>()
59
60
  const [errorMessage, setErrorMessage] = useState('')
60
61
  const { validateAddress, isValidating } = useAddressValidation()
61
- const { accounts } = useAccount()
62
- const connectedWallets = accounts.filter((account) => account.isConnected)
63
62
  const { requiredToChainType } = useToAddressRequirements()
64
63
  const [toChainId] = useFieldValues('toChain')
65
64
  const { chain: toChain } = useChain(toChainId)
@@ -67,6 +66,12 @@ export const SendToWalletPage = () => {
67
66
  const [isBookmarkButtonLoading, setIsBookmarkButtonLoading] = useState(false)
68
67
  const { variant } = useWidgetConfig()
69
68
 
69
+ const { accounts } = useAccount()
70
+ const connectedWallets = accounts.filter((account) => account.isConnected)
71
+ const connectedEVMChainId = connectedWallets.find(
72
+ (account) => account.chainType === ChainType.EVM
73
+ )?.chainId
74
+
70
75
  useHeader(t('header.sendToWallet'))
71
76
 
72
77
  const handleInputChange = (e: ChangeEvent) => {
@@ -241,6 +246,7 @@ export const SendToWalletPage = () => {
241
246
  ref={confirmAddressSheetRef}
242
247
  validatedBookmark={validatedWallet}
243
248
  onConfirm={handleOnConfirm}
249
+ chainId={connectedEVMChainId || toChainId}
244
250
  />
245
251
  <BookmarkAddressSheet
246
252
  ref={bookmarkAddressSheetRef}
@@ -146,7 +146,7 @@ const ExchangeRateBottomSheetContent: React.FC<
146
146
  fontWeight: 600,
147
147
  }}
148
148
  >
149
- {t('format.number', {
149
+ {t('format.tokenAmount', {
150
150
  value: formatTokenAmount(
151
151
  BigInt(data.oldToAmount),
152
152
  data.toToken.decimals
@@ -168,7 +168,7 @@ const ExchangeRateBottomSheetContent: React.FC<
168
168
  fontWeight: 600,
169
169
  }}
170
170
  >
171
- {t('format.number', {
171
+ {t('format.tokenAmount', {
172
172
  value: formatTokenAmount(
173
173
  BigInt(data?.newToAmount),
174
174
  data?.toToken.decimals
@@ -4,11 +4,12 @@ import { useMemo } from 'react'
4
4
  import { I18nextProvider } from 'react-i18next'
5
5
  import * as supportedLanguages from '../../i18n/index.js'
6
6
  import { useSettings } from '../../stores/settings/useSettings.js'
7
+ import { compactNumberFormatter } from '../../utils/compactNumberFormatter.js'
7
8
  import { deepMerge } from '../../utils/deepMerge.js'
8
9
  import { isItemAllowed } from '../../utils/item.js'
10
+ import { percentFormatter } from '../../utils/percentFormatter.js'
9
11
  import { useWidgetConfig } from '../WidgetProvider/WidgetProvider.js'
10
12
  import { currencyExtendedFormatter } from './currencyExtendedFormatter.js'
11
- import { percentFormatter } from './percentFormatter.js'
12
13
  import type { LanguageKey, LanguageTranslationResources } from './types.js'
13
14
 
14
15
  export const I18nProvider: React.FC<React.PropsWithChildren> = ({
@@ -63,6 +64,7 @@ export const I18nProvider: React.FC<React.PropsWithChildren> = ({
63
64
 
64
65
  i18n.init()
65
66
 
67
+ i18n.services.formatter?.addCached('numberExt', compactNumberFormatter)
66
68
  i18n.services.formatter?.addCached('currencyExt', currencyExtendedFormatter)
67
69
  i18n.services.formatter?.addCached('percent', percentFormatter)
68
70
 
@@ -5,18 +5,20 @@ import { ChainType, EVM, Solana, UTXO, config } from '@lifi/sdk'
5
5
  import type { SignerWalletAdapter } from '@solana/wallet-adapter-base'
6
6
  import { useWallet } from '@solana/wallet-adapter-react'
7
7
  import { useEffect } from 'react'
8
- import { useConfig as useWagmiConfig } from 'wagmi'
8
+ import { useAccount, useConfig as useWagmiConfig } from 'wagmi'
9
9
  import {
10
10
  getConnectorClient as getWagmiConnectorClient,
11
11
  switchChain,
12
12
  } from 'wagmi/actions'
13
13
  import { useWidgetConfig } from '../WidgetProvider/WidgetProvider.js'
14
+ import { getSafeMultisigConfig } from './getSafeMultisigConfig.js'
14
15
 
15
16
  export const SDKProviders = () => {
16
17
  const { sdkConfig } = useWidgetConfig()
17
18
  const { wallet } = useWallet()
18
19
  const wagmiConfig = useWagmiConfig()
19
20
  const bigmiConfig = useBigmiConfig()
21
+ const account = useAccount({ config: wagmiConfig })
20
22
 
21
23
  useEffect(() => {
22
24
  // Configure SDK Providers
@@ -31,6 +33,11 @@ export const SDKProviders = () => {
31
33
  (provider) => provider.type === ChainType.UTXO
32
34
  )
33
35
  if (!hasConfiguredEVMProvider) {
36
+ // TODO: refactor this in favor of EIP-5792: Wallet Call API
37
+ const multisig =
38
+ account.connector?.id === 'safe'
39
+ ? getSafeMultisigConfig(account.connector)
40
+ : undefined
34
41
  providers.push(
35
42
  EVM({
36
43
  getWalletClient: () => getWagmiConnectorClient(wagmiConfig),
@@ -38,6 +45,7 @@ export const SDKProviders = () => {
38
45
  const chain = await switchChain(wagmiConfig, { chainId })
39
46
  return getWagmiConnectorClient(wagmiConfig, { chainId: chain.id })
40
47
  },
48
+ multisig,
41
49
  })
42
50
  )
43
51
  }
@@ -61,7 +69,13 @@ export const SDKProviders = () => {
61
69
  providers.push(...sdkConfig.providers)
62
70
  }
63
71
  config.setProviders(providers)
64
- }, [bigmiConfig, sdkConfig?.providers, wagmiConfig, wallet?.adapter])
72
+ }, [
73
+ account.connector,
74
+ bigmiConfig,
75
+ sdkConfig?.providers,
76
+ wagmiConfig,
77
+ wallet?.adapter,
78
+ ])
65
79
 
66
80
  return null
67
81
  }