0xtrails 0.6.0 → 0.6.2

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 (88) hide show
  1. package/dist/{ccip-Dw5AN7oU.js → ccip-CZfykYU7.js} +4 -4
  2. package/dist/chains.d.ts +9 -2
  3. package/dist/chains.d.ts.map +1 -1
  4. package/dist/constants.d.ts +1 -0
  5. package/dist/constants.d.ts.map +1 -1
  6. package/dist/contractUtils.d.ts +2 -1
  7. package/dist/contractUtils.d.ts.map +1 -1
  8. package/dist/{index-BtVUTbEZ.js → index-S9pphnT9.js} +29732 -36767
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +300 -242
  12. package/dist/prepareSend.d.ts.map +1 -1
  13. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  14. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  15. package/dist/transactionIntent/types.d.ts +3 -1
  16. package/dist/transactionIntent/types.d.ts.map +1 -1
  17. package/dist/widget/components/ChainImage.d.ts.map +1 -1
  18. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  19. package/dist/widget/components/DepositTracker.d.ts +12 -0
  20. package/dist/widget/components/DepositTracker.d.ts.map +1 -0
  21. package/dist/widget/components/Disconnect.d.ts.map +1 -1
  22. package/dist/widget/components/FeeBreakdown.d.ts.map +1 -1
  23. package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
  24. package/dist/widget/components/QRCodeOptions.d.ts +9 -0
  25. package/dist/widget/components/QRCodeOptions.d.ts.map +1 -0
  26. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  27. package/dist/widget/components/Receipt.d.ts.map +1 -1
  28. package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
  29. package/dist/widget/components/Toast.d.ts.map +1 -1
  30. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  31. package/dist/widget/components/WalletConnectionPending.d.ts.map +1 -1
  32. package/dist/widget/css/compiled.css +1 -1
  33. package/dist/widget/css/index.css +103 -38
  34. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  35. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  36. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  37. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  38. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  39. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  40. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  41. package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -1
  42. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  43. package/dist/widget/index.js +1 -1
  44. package/dist/widget/widget.d.ts.map +1 -1
  45. package/package.json +6 -9
  46. package/src/chains.ts +37 -4
  47. package/src/constants.ts +1 -0
  48. package/src/contractUtils.ts +8 -7
  49. package/src/estimate.ts +2 -2
  50. package/src/index.ts +2 -0
  51. package/src/intents.ts +2 -2
  52. package/src/paymasterSend.ts +2 -2
  53. package/src/prepareSend.ts +34 -3
  54. package/src/sendUserOp.ts +2 -2
  55. package/src/tokens.ts +2 -2
  56. package/src/transactionIntent/deposits/gaslessDeposit.ts +2 -2
  57. package/src/transactionIntent/handlers/crossChain.ts +51 -2
  58. package/src/transactionIntent/handlers/sameChainSameToken.ts +52 -2
  59. package/src/transactionIntent/quote/normalizeQuote.ts +2 -2
  60. package/src/transactionIntent/types.ts +9 -1
  61. package/src/widget/compiled.css +1 -1
  62. package/src/widget/components/ChainImage.tsx +10 -7
  63. package/src/widget/components/ChainList.tsx +1 -1
  64. package/src/widget/components/ClassicSwap.tsx +8 -4
  65. package/src/widget/components/ConnectedWallets.tsx +1 -1
  66. package/src/widget/components/DepositTracker.tsx +298 -0
  67. package/src/widget/components/Disconnect.tsx +24 -3
  68. package/src/widget/components/FeeBreakdown.tsx +3 -3
  69. package/src/widget/components/QRCodeDeposit.tsx +29 -19
  70. package/src/widget/components/QRCodeOptions.tsx +65 -0
  71. package/src/widget/components/QuoteDetails.tsx +694 -803
  72. package/src/widget/components/Receipt.tsx +76 -40
  73. package/src/widget/components/ThemeProvider.tsx +7 -12
  74. package/src/widget/components/Toast.tsx +3 -2
  75. package/src/widget/components/TokenSelector.tsx +1 -1
  76. package/src/widget/components/Tooltip.tsx +1 -1
  77. package/src/widget/components/TransferPendingVertical.tsx +11 -2
  78. package/src/widget/components/WalletConnectionPending.tsx +28 -5
  79. package/src/widget/hooks/useCheckout.ts +10 -2
  80. package/src/widget/hooks/useCurrentScreen.tsx +1 -0
  81. package/src/widget/hooks/useDebugScreens.ts +1 -0
  82. package/src/widget/hooks/useIntentTransactionHistory.ts +114 -143
  83. package/src/widget/hooks/useQuote.ts +92 -6
  84. package/src/widget/hooks/useSelectedFeeOption.tsx +86 -29
  85. package/src/widget/hooks/useSendForm.ts +43 -7
  86. package/src/widget/index.css +103 -38
  87. package/src/widget/widget.tsx +48 -5
  88. package/dist/0xtrails.css +0 -1
@@ -11,7 +11,11 @@ import {
11
11
  zeroAddress,
12
12
  } from "viem"
13
13
  import { useAccount } from "wagmi"
14
- import { getChainInfo, useSupportedChains } from "../../chains.js"
14
+ import {
15
+ getChainInfo,
16
+ useSupportedChains,
17
+ useChainRpcClient,
18
+ } from "../../chains.js"
15
19
  import { getFullErrorMessage, getPrettifiedErrorMessage } from "../../error.js"
16
20
  import {
17
21
  prepareSend,
@@ -263,14 +267,26 @@ export function useSendForm({
263
267
  chainId: selectedDestinationChain?.id,
264
268
  })
265
269
 
270
+ // Get RPC clients for known chainIds using hooks (reads from TrailsProvider context)
271
+ const destinationChainPublicClient = useChainRpcClient(
272
+ selectedDestinationChain?.id,
273
+ )
274
+ const originChainPublicClient = useChainRpcClient(selectedToken?.chainId)
275
+
266
276
  // Check if recipient is a contract address
267
277
  useEffect(() => {
268
278
  const checkRecipientContract = async () => {
269
- if (recipient && isAddress(recipient) && selectedDestinationChain?.id) {
279
+ if (
280
+ recipient &&
281
+ isAddress(recipient) &&
282
+ selectedDestinationChain?.id &&
283
+ destinationChainPublicClient
284
+ ) {
270
285
  try {
271
286
  const isContract = await getIsContract(
272
287
  recipient as `0x${string}`,
273
288
  selectedDestinationChain.id,
289
+ destinationChainPublicClient,
274
290
  )
275
291
  logger.console.log("[trails-sdk] isRecipientContract:", isContract)
276
292
  setIsRecipientContract(isContract)
@@ -287,16 +303,21 @@ export function useSendForm({
287
303
  }
288
304
 
289
305
  checkRecipientContract()
290
- }, [recipient, selectedDestinationChain?.id])
306
+ }, [recipient, selectedDestinationChain?.id, destinationChainPublicClient])
291
307
 
292
308
  // Check if sender is a contract address on origin chain
293
309
  useEffect(() => {
294
310
  const checkSenderContractOnOrigin = async () => {
295
- if (account?.address && selectedToken?.chainId) {
311
+ if (
312
+ account?.address &&
313
+ selectedToken?.chainId &&
314
+ originChainPublicClient
315
+ ) {
296
316
  try {
297
317
  const isContract = await getIsContract(
298
318
  account.address as `0x${string}`,
299
319
  selectedToken.chainId,
320
+ originChainPublicClient,
300
321
  )
301
322
  logger.console.log(
302
323
  "[trails-sdk] isSenderContractOnOrigin:",
@@ -316,16 +337,21 @@ export function useSendForm({
316
337
  }
317
338
 
318
339
  checkSenderContractOnOrigin()
319
- }, [account?.address, selectedToken?.chainId])
340
+ }, [account?.address, selectedToken?.chainId, originChainPublicClient])
320
341
 
321
342
  // Check if sender is a contract address on destination chain
322
343
  useEffect(() => {
323
344
  const checkSenderContractOnDestination = async () => {
324
- if (account?.address && selectedDestinationChain?.id) {
345
+ if (
346
+ account?.address &&
347
+ selectedDestinationChain?.id &&
348
+ destinationChainPublicClient
349
+ ) {
325
350
  try {
326
351
  const isContract = await getIsContract(
327
352
  account.address as `0x${string}`,
328
353
  selectedDestinationChain.id,
354
+ destinationChainPublicClient,
329
355
  )
330
356
  logger.console.log(
331
357
  "[trails-sdk] isSenderContractOnDestination:",
@@ -345,7 +371,11 @@ export function useSendForm({
345
371
  }
346
372
 
347
373
  checkSenderContractOnDestination()
348
- }, [account?.address, selectedDestinationChain?.id])
374
+ }, [
375
+ account?.address,
376
+ selectedDestinationChain?.id,
377
+ destinationChainPublicClient,
378
+ ])
349
379
 
350
380
  const isCustomToken = useMemo(() => toToken?.startsWith("0x"), [toToken])
351
381
 
@@ -886,6 +916,8 @@ export function useSendForm({
886
916
  walletId,
887
917
  sequenceIndexerUrl,
888
918
  sequenceProjectAccessKey: trailsApiKey,
919
+ originPublicClient: originChainPublicClient ?? undefined,
920
+ destinationPublicClient: destinationChainPublicClient ?? undefined,
889
921
  }
890
922
 
891
923
  logger.console.log(
@@ -975,14 +1007,18 @@ export function useSendForm({
975
1007
  selectedFeeOption,
976
1008
  walletId,
977
1009
  buildQuoteInputsFingerprint,
1010
+ originChainPublicClient,
1011
+ destinationChainPublicClient,
978
1012
  ])
979
1013
 
980
1014
  // Auto-fetch quotes when inputs change (debounced)
981
1015
  // biome-ignore lint/correctness/useExhaustiveDependencies: getQuote is intentionally excluded to prevent infinite loop
982
1016
  useEffect(() => {
983
1017
  // Only trigger if we have the essential inputs
1018
+ // Block empty string or exactly "0"
984
1019
  if (
985
1020
  !amount ||
1021
+ amount === "0" ||
986
1022
  !destinationTokenAddress ||
987
1023
  !isValidRecipient ||
988
1024
  !selectedDestToken?.symbol ||
@@ -1,11 +1,9 @@
1
1
  @config "../../tailwind.config.ts";
2
- @import "@0xsequence/design-system/preset";
3
2
  @import "tailwindcss";
4
3
  @tailwind base;
5
4
  @tailwind components;
6
5
  @tailwind utilities;
7
6
 
8
-
9
7
  *:focus {
10
8
  outline: none;
11
9
  }
@@ -13,7 +11,10 @@
13
11
  /* Trails Widget Theme Variables - Easy to customize */
14
12
  :root {
15
13
  /* Font Family - Customizable font for the entire widget */
16
- --trails-font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
14
+ --trails-font-family: ui-sans-serif, system-ui, -apple-system,
15
+ BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
16
+ sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
17
+ "Noto Color Emoji";
17
18
 
18
19
  /* Border Radius - Customizable border radius for the widget */
19
20
  --trails-border-radius-widget: 32px; /* Main widget container border radius */
@@ -30,20 +31,36 @@
30
31
 
31
32
  /* Primary Colors - These apply to both themes */
32
33
  --trails-primary: rgb(21 93 252); /* #155DFC - Change this to customize */
33
- --trails-primary-hover: rgb(17 75 202); /* Darker shade of #155DFC - Change this for hover state */
34
+ --trails-primary-hover: rgb(
35
+ 17 75 202
36
+ ); /* Darker shade of #155DFC - Change this for hover state */
34
37
  --trails-primary-disabled: rgb(212 212 216); /* #D4D4D8 - Disabled state */
35
- --trails-primary-disabled-text: rgb(107 114 128); /* gray-500 - Disabled text */
38
+ --trails-primary-disabled-text: rgb(
39
+ 107 114 128
40
+ ); /* gray-500 - Disabled text */
36
41
 
37
42
  /* Modal Button Colors - Customizable modal trigger button */
38
- --trails-modal-button-bg: var(--trails-primary, rgb(21 93 252)); /* Defaults to primary color */
39
- --trails-modal-button-hover-bg: var(--trails-primary-hover, rgb(17 75 202)); /* Defaults to primary hover */
43
+ --trails-modal-button-bg: var(
44
+ --trails-primary,
45
+ rgb(21 93 252)
46
+ ); /* Defaults to primary color */
47
+ --trails-modal-button-hover-bg: var(
48
+ --trails-primary-hover,
49
+ rgb(17 75 202)
50
+ ); /* Defaults to primary hover */
40
51
  --trails-modal-button-text: rgb(255 255 255); /* white text */
41
52
  --trails-modal-button-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); /* subtle shadow */
42
53
 
43
54
  /* Percentage Button Colors - Customizable percentage buttons */
44
- --trails-percentage-button-bg: rgb(228 228 231); /* #E4E4E7 - Light gray background */
45
- --trails-percentage-button-text: rgb(113 113 123); /* #71717B - Dark gray text */
46
- --trails-percentage-button-hover-bg: rgb(212 212 216); /* #D4D4D8 - Slightly darker on hover */
55
+ --trails-percentage-button-bg: rgb(
56
+ 228 228 231
57
+ ); /* #E4E4E7 - Light gray background */
58
+ --trails-percentage-button-text: rgb(
59
+ 113 113 123
60
+ ); /* #71717B - Dark gray text */
61
+ --trails-percentage-button-hover-bg: rgb(
62
+ 212 212 216
63
+ ); /* #D4D4D8 - Slightly darker on hover */
47
64
  }
48
65
 
49
66
  /* Utility Classes that use CSS Variables */
@@ -127,8 +144,6 @@
127
144
  background-color: var(--trails-percentage-button-hover-bg);
128
145
  }
129
146
 
130
-
131
-
132
147
  /* Font Family Utility Class */
133
148
  .trails-font {
134
149
  font-family: var(--trails-font-family);
@@ -197,8 +212,14 @@
197
212
  }
198
213
 
199
214
  .trails-dropdown:focus {
200
- border-color: var(--trails-dropdown-focus-border, var(--trails-dropdown-border));
201
- --tw-ring-color: var(--trails-dropdown-focus-border, var(--trails-dropdown-border));
215
+ border-color: var(
216
+ --trails-dropdown-focus-border,
217
+ var(--trails-dropdown-border)
218
+ );
219
+ --tw-ring-color: var(
220
+ --trails-dropdown-focus-border,
221
+ var(--trails-dropdown-border)
222
+ );
202
223
  }
203
224
 
204
225
  .trails-dropdown-item {
@@ -242,7 +263,9 @@
242
263
  --trails-bg-primary: rgb(255 255 255); /* white */
243
264
  --trails-bg-secondary: rgb(244 244 245); /* #F4F4F5 */
244
265
  --trails-bg-secondary-hover: rgb(228 228 231); /* #E4E4E7 */
245
- --trails-bg-secondary-focus-border: rgb(244 244 245); /* #F4F4F5 - same as secondary bg */
266
+ --trails-bg-secondary-focus-border: rgb(
267
+ 244 244 245
268
+ ); /* #F4F4F5 - same as secondary bg */
246
269
  --trails-bg-tertiary: rgb(243 244 246); /* gray-100 */
247
270
  --trails-bg-card: rgb(255 255 255); /* white */
248
271
  --trails-bg-overlay: rgb(255 255 255); /* white */
@@ -277,11 +300,19 @@
277
300
  --trails-dropdown-hover-bg: rgb(249 250 251); /* gray-50 */
278
301
  --trails-dropdown-selected-bg: rgb(243 244 246); /* gray-100 */
279
302
  --trails-dropdown-selected-text: rgb(17 24 39); /* gray-900 */
280
- --trails-dropdown-focus-border: rgb(21 93 252); /* #155DFC - matches input focus border */
303
+ --trails-dropdown-focus-border: rgb(
304
+ 21 93 252
305
+ ); /* #155DFC - matches input focus border */
281
306
 
282
307
  /* Modal Button Colors - Light Mode */
283
- --trails-modal-button-bg: var(--trails-primary, rgb(21 93 252)); /* #155DFC for light mode */
284
- --trails-modal-button-hover-bg: var(--trails-primary-hover, rgb(17 75 202)); /* Darker shade of #155DFC for light mode */
308
+ --trails-modal-button-bg: var(
309
+ --trails-primary,
310
+ rgb(21 93 252)
311
+ ); /* #155DFC for light mode */
312
+ --trails-modal-button-hover-bg: var(
313
+ --trails-primary-hover,
314
+ rgb(17 75 202)
315
+ ); /* Darker shade of #155DFC for light mode */
285
316
  --trails-modal-button-text: rgb(255 255 255); /* white text */
286
317
  --trails-modal-button-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); /* subtle shadow for light mode */
287
318
 
@@ -319,13 +350,18 @@
319
350
  --trails-error-border: rgb(254 202 202); /* red-200 */
320
351
 
321
352
  /* Shadow */
322
- --trails-shadow:
323
- 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
353
+ --trails-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
324
354
 
325
355
  /* Percentage Button Colors - Light Mode */
326
- --trails-percentage-button-bg: rgb(228 228 231); /* #E4E4E7 - Light gray background */
327
- --trails-percentage-button-text: rgb(113 113 123); /* #71717B - Dark gray text */
328
- --trails-percentage-button-hover-bg: rgb(212 212 216); /* #D4D4D8 - Slightly darker on hover */
356
+ --trails-percentage-button-bg: rgb(
357
+ 228 228 231
358
+ ); /* #E4E4E7 - Light gray background */
359
+ --trails-percentage-button-text: rgb(
360
+ 113 113 123
361
+ ); /* #71717B - Dark gray text */
362
+ --trails-percentage-button-hover-bg: rgb(
363
+ 212 212 216
364
+ ); /* #D4D4D8 - Slightly darker on hover */
329
365
  }
330
366
 
331
367
  /* Dark Mode Theme Variables */
@@ -334,7 +370,9 @@
334
370
  --trails-bg-primary: rgb(17 24 39); /* gray-900 */
335
371
  --trails-bg-secondary: rgb(31 41 55); /* gray-800 */
336
372
  --trails-bg-secondary-hover: rgb(55 65 81); /* gray-700 */
337
- --trails-bg-secondary-focus-border: rgb(31 41 55); /* gray-800 - same as secondary bg */
373
+ --trails-bg-secondary-focus-border: rgb(
374
+ 31 41 55
375
+ ); /* gray-800 - same as secondary bg */
338
376
  --trails-bg-tertiary: rgb(55 65 81); /* gray-700 */
339
377
  --trails-bg-card: rgb(31 41 55); /* gray-800 */
340
378
  --trails-bg-overlay: rgb(17 24 39); /* gray-900 */
@@ -369,20 +407,30 @@
369
407
  --trails-dropdown-hover-bg: rgb(55 65 81); /* gray-700 */
370
408
  --trails-dropdown-selected-bg: rgb(55 65 81); /* gray-700 */
371
409
  --trails-dropdown-selected-text: rgb(255 255 255); /* white */
372
- --trails-dropdown-focus-border: rgb(21 93 252); /* #155DFC - matches input focus border */
410
+ --trails-dropdown-focus-border: rgb(
411
+ 21 93 252
412
+ ); /* #155DFC - matches input focus border */
373
413
 
374
414
  /* Modal Button Colors - Dark Mode */
375
- --trails-modal-button-bg: var(--trails-primary, rgb(21 93 252)); /* #155DFC for dark mode */
376
- --trails-modal-button-hover-bg: var(--trails-primary-hover, rgb(17 75 202)); /* Darker shade of #155DFC for dark mode */
415
+ --trails-modal-button-bg: var(
416
+ --trails-primary,
417
+ rgb(21 93 252)
418
+ ); /* #155DFC for dark mode */
419
+ --trails-modal-button-hover-bg: var(
420
+ --trails-primary-hover,
421
+ rgb(17 75 202)
422
+ ); /* Darker shade of #155DFC for dark mode */
377
423
  --trails-modal-button-text: rgb(255 255 255); /* white text */
378
424
  --trails-modal-button-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.1); /* subtle shadow for dark mode */
379
425
 
380
- /* Token List Colors */
426
+ /* Token List Colors */
381
427
  --trails-list-bg: rgb(31 41 55); /* gray-800 background for token list */
382
428
  --trails-list-border: rgb(55 65 81); /* gray-700 border - good balance */
383
429
  --trails-list-hover-bg: rgb(55 65 81); /* gray-700 hover */
384
430
  --trails-list-item-bg: transparent; /* transparent background for list items */
385
- --trails-list-item-selected-bg: rgb(30 58 138); /* blue-800 selected for dark mode */
431
+ --trails-list-item-selected-bg: rgb(
432
+ 30 58 138
433
+ ); /* blue-800 selected for dark mode */
386
434
 
387
435
  /* Widget Border - Customizable widget border */
388
436
  --trails-widget-border: none; /* Default widget border */
@@ -411,13 +459,18 @@
411
459
  --trails-error-border: rgb(239 68 68 / 0.3); /* red-500 with opacity */
412
460
 
413
461
  /* Shadow */
414
- --trails-shadow:
415
- 0 1px 3px 0 rgb(0 0 0 / 0.3), 0 1px 2px -1px rgb(0 0 0 / 0.3);
462
+ --trails-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.3), 0 1px 2px -1px rgb(0 0 0 / 0.3);
416
463
 
417
464
  /* Percentage Button Colors - Dark Mode */
418
- --trails-percentage-button-bg: rgb(55 65 81); /* gray-700 - Dark gray background */
419
- --trails-percentage-button-text: rgb(209 213 219); /* gray-300 - Light gray text */
420
- --trails-percentage-button-hover-bg: rgb(75 85 99); /* gray-600 - Slightly lighter on hover */
465
+ --trails-percentage-button-bg: rgb(
466
+ 55 65 81
467
+ ); /* gray-700 - Dark gray background */
468
+ --trails-percentage-button-text: rgb(
469
+ 209 213 219
470
+ ); /* gray-300 - Light gray text */
471
+ --trails-percentage-button-hover-bg: rgb(
472
+ 75 85 99
473
+ ); /* gray-600 - Slightly lighter on hover */
421
474
  }
422
475
 
423
476
  /* Custom Scrollbar Styles */
@@ -489,7 +542,10 @@
489
542
 
490
543
  /* Dark mode primary button */
491
544
  .dark .bg-blue-500 {
492
- background-color: var(--trails-primary, rgb(21 93 252)); /* #155DFC for dark mode */
545
+ background-color: var(
546
+ --trails-primary,
547
+ rgb(21 93 252)
548
+ ); /* #155DFC for dark mode */
493
549
  }
494
550
 
495
551
  /* Light mode hover */
@@ -499,7 +555,10 @@
499
555
 
500
556
  /* Dark mode hover */
501
557
  .dark .hover\:bg-blue-600:hover {
502
- background-color: var(--trails-primary-hover, rgb(17 75 202)); /* Darker shade of #155DFC for dark mode */
558
+ background-color: var(
559
+ --trails-primary-hover,
560
+ rgb(17 75 202)
561
+ ); /* Darker shade of #155DFC for dark mode */
503
562
  }
504
563
 
505
564
  /* Light mode disabled background */
@@ -542,7 +601,10 @@
542
601
 
543
602
  /* Modal Button Utility Classes */
544
603
  .trails-modal-button {
545
- background-color: var(--trails-modal-button-bg, var(--trails-primary, rgb(59 130 246)));
604
+ background-color: var(
605
+ --trails-modal-button-bg,
606
+ var(--trails-primary, rgb(59 130 246))
607
+ );
546
608
  color: var(--trails-modal-button-text, rgb(255 255 255));
547
609
  box-shadow: var(--trails-modal-button-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05));
548
610
  transition: all 0.2s ease-in-out;
@@ -550,5 +612,8 @@
550
612
  }
551
613
 
552
614
  .trails-modal-button:hover {
553
- background-color: var(--trails-modal-button-hover-bg, var(--trails-primary-hover, rgb(37 99 235)));
615
+ background-color: var(
616
+ --trails-modal-button-hover-bg,
617
+ var(--trails-primary-hover, rgb(37 99 235))
618
+ );
554
619
  }
@@ -1,4 +1,3 @@
1
- import "@0xsequence/design-system/preset"
2
1
  import { AaveClient, AaveProvider } from "@aave/react"
3
2
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
4
3
  import { AnimatePresence, motion } from "motion/react"
@@ -16,7 +15,7 @@ import React, {
16
15
  } from "react"
17
16
  import { createPortal } from "react-dom"
18
17
  import type { Chain, WalletClient } from "viem"
19
- import { createWalletClient, custom, http, isAddress } from "viem"
18
+ import { createWalletClient, custom, defineChain, http, isAddress } from "viem"
20
19
  import type { Connector } from "wagmi"
21
20
  import {
22
21
  createConfig,
@@ -88,6 +87,7 @@ import type { MeshConnectProps } from "./components/MeshConnectIframe.js"
88
87
  import Modal from "./components/Modal.js"
89
88
  import { Pay } from "./components/Pay.js"
90
89
  import QRCodeDeposit from "./components/QRCodeDeposit.js"
90
+ import QRCodeOptions from "./components/QRCodeOptions.js"
91
91
  import QRCodeWalletSelect from "./components/QRCodeWalletSelect.js"
92
92
  import Receipt from "./components/Receipt.js"
93
93
  import { Receive } from "./components/Receive.js"
@@ -306,9 +306,34 @@ const useWalletManager = (
306
306
  const activeProvider = await connector.getProvider()
307
307
 
308
308
  if (activeProvider && address && chainId) {
309
- const chain = getChainInfo(chainId)
309
+ let chain = getChainInfo(chainId)
310
+
311
+ // If chain is not supported, create a minimal chain object.
312
+ // This allows walletClient to be created even on unsupported networks.
313
+ // The Problem:
314
+ // When Metamask is on a network not supported by the wagmi config, useWalletManager
315
+ // in widget.tsx calls getChainInfo(chainId), which returns null for unsupported chains.
316
+ // The function then returns early without creating a walletClient, so walletClient?.account is undefined,
317
+ // causing the "Connect your wallet" message in the button.
310
318
  if (!chain) {
311
- return
319
+ logger.console.warn(
320
+ `[trails-sdk] Chain ${chainId} not found in supported chains, creating minimal chain object`,
321
+ )
322
+ // Create a minimal chain definition for unsupported chains
323
+ chain = defineChain({
324
+ id: chainId,
325
+ name: `Chain ${chainId}`,
326
+ nativeCurrency: {
327
+ name: "Ether",
328
+ symbol: "ETH",
329
+ decimals: 18,
330
+ },
331
+ rpcUrls: {
332
+ default: {
333
+ http: [],
334
+ },
335
+ },
336
+ }) as Chain
312
337
  }
313
338
 
314
339
  const client = createWalletClient({
@@ -969,6 +994,13 @@ const WidgetContent = forwardRef<TrailsWidgetRef>((_, ref) => {
969
994
  address,
970
995
  )
971
996
 
997
+ // Clear fee option preference from localStorage when wallet changes
998
+ try {
999
+ localStorage.removeItem("trails-fee-option-preference")
1000
+ } catch {
1001
+ // Ignore localStorage errors (e.g., in private browsing mode)
1002
+ }
1003
+
972
1004
  // Check if we're on screens that should reset when account changes
973
1005
  const screensToReset = [
974
1006
  "send-form",
@@ -1334,7 +1366,8 @@ const WidgetContent = forwardRef<TrailsWidgetRef>((_, ref) => {
1334
1366
  setPrepareSendQuote(null)
1335
1367
  setTotalCompletionSeconds(null)
1336
1368
  clearHistory()
1337
- // Reset selected fee token for new checkout
1369
+ // Clear selected fee option, but localStorage preference is preserved
1370
+ // Auto-selection will use the preference when fee options render next time
1338
1371
  clearSelectedFeeOption()
1339
1372
  }, [
1340
1373
  setSelectedFundMethod,
@@ -1642,6 +1675,16 @@ const WidgetContent = forwardRef<TrailsWidgetRef>((_, ref) => {
1642
1675
  setCurrentScreen("home")
1643
1676
  }}
1644
1677
  onSelectQrCode={() => {
1678
+ setCurrentScreen("qrcode-options")
1679
+ }}
1680
+ />
1681
+ )
1682
+ case "qrcode-options":
1683
+ return (
1684
+ <QRCodeOptions
1685
+ onBack={handleBack}
1686
+ onSelectWalletConnect={handleSelectWalletConnect}
1687
+ onSelectQRCode={() => {
1645
1688
  setSelectedFundMethod("qr-code")
1646
1689
  setCurrentScreen("home")
1647
1690
  }}
package/dist/0xtrails.css DELETED
@@ -1 +0,0 @@
1
- @source "./";:root,[data-theme=dark]{--seq-color-positive: #1fc266;--seq-color-negative: #c2501f;--seq-color-info: #0076cc;--seq-color-warning: #f4b03e;--seq-color-primary: rgba(255, 255, 255, 1);--seq-color-secondary: rgba(255, 255, 255, .8);--seq-color-muted: rgba(255, 255, 255, .5);--seq-color-inverse: rgba(0, 0, 0, 1);--seq-color-background-primary: rgba(0, 0, 0, 1);--seq-color-background-secondary: rgba(255, 255, 255, .1);--seq-color-background-contrast: rgba(0, 0, 0, .5);--seq-color-background-muted: rgba(255, 255, 255, .05);--seq-color-background-control: rgba(255, 255, 255, .25);--seq-color-background-inverse: rgba(255, 255, 255, 1);--seq-color-background-backdrop: rgba(34, 34, 34, .9);--seq-color-background-overlay: rgba(0, 0, 0, .7);--seq-color-background-raised: rgba(54, 54, 54, .7);--seq-color-border-normal: rgba(255, 255, 255, .25);--seq-color-border-focus: rgba(255, 255, 255, .5);--seq-color-border-error: rgba(255, 69, 0, 1);--seq-color-button-glass: rgba(255, 255, 255, .15);--seq-color-button-emphasis: rgba(0, 0, 0, .5);--seq-color-button-inverse: rgba(255, 255, 255, .8);--seq-color-gradient-backdrop: linear-gradient( 243.18deg, rgba(86, 52, 189, .85) 0%, rgba(49, 41, 223, .85) 63.54%, rgba(7, 98, 149, .85) 100% );--seq-color-gradient-primary: linear-gradient( 89.69deg, #4411e1 .27%, #7537f9 99.73% );--seq-color-gradient-secondary: linear-gradient( 32.51deg, #951990 -15.23%, #3a35b1 48.55%, #20a8b0 100% );--seq-color-gradient-skeleton: linear-gradient( -45deg, transparent, var(--seq-color-background-secondary), transparent )}[data-theme=light]{--seq-color-positive: #1fc266;--seq-color-negative: #c2501f;--seq-color-info: #0076cc;--seq-color-warning: #f4b03e;--seq-color-primary: rgba(0, 0, 0, 1);--seq-color-secondary: rgba(0, 0, 0, .8);--seq-color-muted: rgba(0, 0, 0, .5);--seq-color-inverse: rgba(255, 255, 255, 1);--seq-color-background-primary: rgba(244, 244, 244, 1);--seq-color-background-secondary: rgba(0, 0, 0, .1);--seq-color-background-contrast: rgba(244, 244, 244, .5);--seq-color-background-muted: rgba(0, 0, 0, .05);--seq-color-background-control: rgba(0, 0, 0, .25);--seq-color-background-inverse: rgba(0, 0, 0, 1);--seq-color-background-backdrop: rgba(221, 221, 221, .9);--seq-color-background-overlay: rgba(244, 244, 244, .7);--seq-color-background-raised: rgba(192, 192, 192, .7);--seq-color-border-normal: rgba(0, 0, 0, .25);--seq-color-border-focus: rgba(0, 0, 0, .5);--seq-color-border-error: rgba(255, 69, 0, 1);--seq-color-button-glass: rgba(0, 0, 0, .15);--seq-color-button-emphasis: rgba(255, 255, 255, .5);--seq-color-button-inverse: rgba(0, 0, 0, .8);--seq-color-gradient-backdrop: linear-gradient( 243.18deg, rgba(86, 52, 189, .85) 0%, rgba(49, 41, 223, .85) 63.54%, rgba(7, 98, 149, .85) 100% );--seq-color-gradient-primary: linear-gradient( 89.69deg, #4411e1 .27%, #7537f9 99.73% );--seq-color-gradient-secondary: linear-gradient( 32.51deg, #951990 -15.23%, #3a35b1 48.55%, #20a8b0 100% );--seq-color-gradient-skeleton: linear-gradient( -45deg, transparent, var(--seq-color-background-secondary), transparent )}@theme inline{ --font-body: "Inter", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --font-mono: "Roboto", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --color-primary: var(--seq-color-primary); --color-secondary: var(--seq-color-secondary); --color-muted: var(--seq-color-muted); --color-inverse: var(--seq-color-inverse); --color-positive: var(--seq-color-positive); --color-negative: var(--seq-color-negative); --color-info: var(--seq-color-info); --color-warning: var(--seq-color-warning); --color-background-primary: var(--seq-color-background-primary); --color-background-secondary: var(--seq-color-background-secondary); --color-background-contrast: var(--seq-color-background-contrast); --color-background-muted: var(--seq-color-background-muted); --color-background-control: var(--seq-color-background-control); --color-background-inverse: var(--seq-color-background-inverse); --color-background-backdrop: var(--seq-color-background-backdrop); --color-background-overlay: var(--seq-color-background-overlay); --color-background-raised: var(--seq-color-background-raised); --color-border-normal: var(--seq-color-border-normal); --color-border-focus: var(--seq-color-border-focus); --color-border-error: var(--seq-color-border-error); --color-button-glass: var(--seq-color-button-glass); --color-button-emphasis: var(--seq-color-button-emphasis); --color-button-inverse: var(--seq-color-button-inverse); --background-image-gradient-backdrop: var(--seq-color-gradient-backdrop); --background-image-gradient-primary: var(--seq-color-gradient-primary); --background-image-gradient-secondary: var(--seq-color-gradient-secondary); --background-image-gradient-skeleton: var(--seq-color-gradient-skeleton); --animate-skeleton: skeleton 1s ease infinite; --animate-swipe-out: swipe-out .2s ease-out; @keyframes skeleton { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } @keyframes swipe-out { from { transform: translateX(var(--radix-toast-swipe-end-x)); } to { transform: translateX(100%); } } }