0xtrails 0.8.2 → 0.8.3

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 (68) hide show
  1. package/dist/aave.d.ts.map +1 -1
  2. package/dist/{ccip-ru_Yzdas.js → ccip-Bs-QcZXm.js} +13 -13
  3. package/dist/constants.d.ts +2 -0
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/fees.d.ts +11 -17
  6. package/dist/fees.d.ts.map +1 -1
  7. package/dist/{index-Si7cO9V7.js → index-C_EsqqSn.js} +20320 -20063
  8. package/dist/index.js +425 -847
  9. package/dist/intents.d.ts +1 -2
  10. package/dist/intents.d.ts.map +1 -1
  11. package/dist/prepareSend.d.ts.map +1 -1
  12. package/dist/recover.d.ts +8 -9
  13. package/dist/recover.d.ts.map +1 -1
  14. package/dist/tokenBalances.d.ts +51 -0
  15. package/dist/tokenBalances.d.ts.map +1 -1
  16. package/dist/trailsRouter.d.ts +15 -0
  17. package/dist/trailsRouter.d.ts.map +1 -1
  18. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +1 -3
  19. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  20. package/dist/transactionIntent/deposits/standardDeposit.d.ts +1 -3
  21. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  22. package/dist/transactionIntent/handlers/crossChain.d.ts +2 -4
  23. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  24. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +5 -4
  25. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  26. package/dist/transactionIntent/quote/normalizeQuote.d.ts +1 -1
  27. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  28. package/dist/transactionIntent/quote/quoteHelpers.d.ts +1 -1
  29. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
  30. package/dist/transactionIntent/types.d.ts +11 -18
  31. package/dist/transactionIntent/types.d.ts.map +1 -1
  32. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  33. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  34. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  35. package/dist/widget/components/SlippageToleranceSettings.d.ts +2 -1
  36. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  37. package/dist/widget/css/compiled.css +1 -1
  38. package/dist/widget/hooks/useQuote.d.ts +94 -35
  39. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  40. package/dist/widget/hooks/useSendForm.d.ts +2 -2
  41. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  42. package/dist/widget/hooks/useTrailsSendTransaction.d.ts.map +1 -1
  43. package/dist/widget/index.js +1 -1
  44. package/package.json +2 -2
  45. package/src/aave.ts +4 -0
  46. package/src/constants.ts +4 -0
  47. package/src/fees.ts +47 -72
  48. package/src/intents.ts +1 -3
  49. package/src/morpho.ts +1 -1
  50. package/src/prepareSend.ts +42 -6
  51. package/src/recover.ts +116 -172
  52. package/src/tokenBalances.ts +301 -1
  53. package/src/trailsRouter.ts +77 -0
  54. package/src/transactionIntent/deposits/depositOrchestrator.ts +0 -6
  55. package/src/transactionIntent/deposits/standardDeposit.ts +167 -184
  56. package/src/transactionIntent/handlers/crossChain.ts +8 -11
  57. package/src/transactionIntent/handlers/sameChainSameToken.ts +619 -608
  58. package/src/transactionIntent/quote/normalizeQuote.ts +32 -46
  59. package/src/transactionIntent/quote/quoteHelpers.ts +4 -2
  60. package/src/transactionIntent/types.ts +11 -18
  61. package/src/widget/compiled.css +1 -1
  62. package/src/widget/components/AccountIntentTransactionHistory.tsx +50 -18
  63. package/src/widget/components/ClassicSwap.tsx +25 -30
  64. package/src/widget/components/QuoteDetails.tsx +18 -27
  65. package/src/widget/components/SlippageToleranceSettings.tsx +55 -25
  66. package/src/widget/hooks/useQuote.ts +317 -79
  67. package/src/widget/hooks/useSendForm.ts +123 -764
  68. package/src/widget/hooks/useTrailsSendTransaction.ts +0 -2
@@ -11,7 +11,7 @@ import { SearchInputField } from "./SearchInputField.js"
11
11
  import { Identicon } from "./Identicon.js"
12
12
  import { truncateAddress } from "../../utils.js"
13
13
  import { useConnections, useAccount, useWalletClient } from "wagmi"
14
- import { ChevronDown } from "lucide-react"
14
+ import { ChevronDown, Info } from "lucide-react"
15
15
  import { getExplorerUrl } from "../../explorer.js"
16
16
  import { ErrorDisplay } from "./ErrorDisplay.js"
17
17
  import { logger } from "../../logger.js"
@@ -79,6 +79,7 @@ const TransactionItem: React.FC<{
79
79
  intentError,
80
80
  balancesError,
81
81
  hasIntentBalance,
82
+ recoverToken,
82
83
  refetchIntent,
83
84
  } = useIntentRecover({
84
85
  intentId: transaction.intentId && !refundTxHash ? transaction.intentId : "",
@@ -341,23 +342,54 @@ const TransactionItem: React.FC<{
341
342
  </svg>
342
343
  </a>
343
344
  ) : canRecover ? (
344
- <button
345
- type="button"
346
- onClick={handleRecover}
347
- disabled={
348
- isRecovering ||
349
- isLoadingIntent ||
350
- isLoadingBalances ||
351
- !!intentError ||
352
- !!balancesError
353
- }
354
- className="flex items-center justify-center gap-1 py-1 px-3 rounded-md transition-colors cursor-pointer text-xs font-medium text-white bg-orange-600 hover:bg-orange-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
355
- aria-label="Recover intent"
356
- >
357
- {isRecovering || isLoadingIntent || isLoadingBalances
358
- ? "Recovering..."
359
- : "Recover"}
360
- </button>
345
+ <div className="flex items-center gap-1">
346
+ <button
347
+ type="button"
348
+ onClick={handleRecover}
349
+ disabled={
350
+ isRecovering ||
351
+ isLoadingIntent ||
352
+ isLoadingBalances ||
353
+ !!intentError ||
354
+ !!balancesError
355
+ }
356
+ className="flex items-center justify-center gap-1 py-1 px-3 rounded-md transition-colors cursor-pointer text-xs font-medium text-white bg-orange-600 hover:bg-orange-700 disabled:bg-gray-400 disabled:cursor-not-allowed"
357
+ aria-label="Recover intent"
358
+ >
359
+ {isRecovering || isLoadingIntent || isLoadingBalances
360
+ ? "Recovering..."
361
+ : "Recover"}
362
+ </button>
363
+ {/* Info tooltip showing recoverable token details */}
364
+ {recoverToken &&
365
+ !isRecovering &&
366
+ !isLoadingIntent &&
367
+ !isLoadingBalances && (
368
+ <div className="relative group">
369
+ <Info
370
+ className="w-4 h-4 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 cursor-help"
371
+ aria-label="Token balance info"
372
+ />
373
+ <div className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-3 py-2 bg-gray-900 dark:bg-gray-700 text-white text-xs rounded-lg shadow-lg opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 whitespace-nowrap z-50 pointer-events-none">
374
+ <div className="flex flex-col gap-0.5">
375
+ <span className="font-medium">
376
+ Recover {recoverToken.symbol}
377
+ </span>
378
+ <span className="text-gray-300">
379
+ {recoverToken.balanceFormatted} {recoverToken.symbol}
380
+ </span>
381
+ {recoverToken.balanceUsdDisplay && (
382
+ <span className="text-gray-400">
383
+ ≈ {recoverToken.balanceUsdDisplay}
384
+ </span>
385
+ )}
386
+ </div>
387
+ {/* Tooltip arrow */}
388
+ <div className="absolute top-full left-1/2 -translate-x-1/2 -mt-px border-4 border-transparent border-t-gray-900 dark:border-t-gray-700" />
389
+ </div>
390
+ </div>
391
+ )}
392
+ </div>
361
393
  ) : null}
362
394
  {recoverError && (
363
395
  <div className="w-full">
@@ -249,15 +249,17 @@ export const ClassicSwap: React.FC<ClassicSwapProps> = ({
249
249
  setLastInputType("buy")
250
250
  }, [])
251
251
 
252
- // Handle buy input focus - clear field when user wants to type
252
+ // Handle buy input focus - only copy displayed value to state for editing
253
+ // Don't switch trade type or clear sellAmount here - that happens in handleBuyAmountChange
254
+ // This prevents unnecessary requotes when user just focuses without editing
253
255
  const handleBuyInputFocus = useCallback(() => {
254
- // When focusing on buy field and it's in EXACT_INPUT mode (showing calculated value), switch to EXACT_OUTPUT mode
255
- if (tradeType === TradeType.EXACT_INPUT && !buyAmount) {
256
- setBuyAmount("")
257
- setTradeType(TradeType.EXACT_OUTPUT)
258
- setLastInputType("buy")
256
+ // When focusing on buy field in EXACT_INPUT mode, copy the calculated value
257
+ // to buyAmount state so user can edit it. The actual mode switch happens
258
+ // when the user starts typing (in handleBuyAmountChange)
259
+ if (tradeType === TradeType.EXACT_INPUT && toAmountDisplay && !buyAmount) {
260
+ setBuyAmount(toAmountDisplay)
259
261
  }
260
- }, [tradeType, buyAmount])
262
+ }, [tradeType, toAmountDisplay, buyAmount])
261
263
 
262
264
  // Update amounts when quote is received
263
265
  useEffect(() => {
@@ -748,7 +750,7 @@ export const ClassicSwap: React.FC<ClassicSwapProps> = ({
748
750
  value={
749
751
  tradeType === TradeType.EXACT_OUTPUT
750
752
  ? buyAmount
751
- : toAmountDisplay || ""
753
+ : buyAmount || toAmountDisplay || ""
752
754
  }
753
755
  onChange={(e) => handleBuyAmountChange(e.target.value)}
754
756
  onFocus={handleBuyInputFocus}
@@ -780,31 +782,24 @@ export const ClassicSwap: React.FC<ClassicSwapProps> = ({
780
782
  </div>
781
783
 
782
784
  {/* Bottom Info Row */}
783
- <div
784
- className={
785
- !prepareSendQuote?.destinationAmountUsdDisplay && !isLoadingQuote
786
- ? "flex justify-end mt-4"
787
- : "mt-4 flex items-center justify-between"
788
- }
789
- >
785
+ <div className="mt-4 flex items-center justify-between">
790
786
  {/* Destination Amount USD from Quote */}
791
- {(prepareSendQuote?.destinationAmountUsdDisplay ||
792
- (isLoadingQuote && tradeType === TradeType.EXACT_INPUT)) && (
793
- <div className="text-xs text-gray-500 dark:text-gray-400">
794
- ≈{" "}
795
- {isLoadingQuote && tradeType === TradeType.EXACT_INPUT
796
- ? "$0.00"
797
- : prepareSendQuote?.destinationAmountUsdDisplay}
798
- </div>
799
- )}
787
+ <div className="text-xs text-gray-500 dark:text-gray-400">
788
+ {(prepareSendQuote?.destinationAmountUsdDisplay ||
789
+ (isLoadingQuote && tradeType === TradeType.EXACT_INPUT)) && (
790
+ <>
791
+ {" "}
792
+ {isLoadingQuote && tradeType === TradeType.EXACT_INPUT
793
+ ? "$0.00"
794
+ : prepareSendQuote?.destinationAmountUsdDisplay}
795
+ </>
796
+ )}
797
+ </div>
800
798
 
801
- {/* Dest Token Balance */}
799
+ {/* Dest Token Balance - always on right */}
802
800
  {destinationToken && (
803
- <div className="flex justify-end">
804
- <div className="text-xs text-gray-500 dark:text-gray-400">
805
- Balance:{" "}
806
- {isBalanceVisible ? destinationBalanceDisplay : "0.00"}
807
- </div>
801
+ <div className="text-xs text-gray-500 dark:text-gray-400">
802
+ Balance: {isBalanceVisible ? destinationBalanceDisplay : "0.00"}
808
803
  </div>
809
804
  )}
810
805
  </div>
@@ -280,7 +280,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
280
280
  />
281
281
  </RowLabel>
282
282
  <RowValue>
283
- <span title={`$${quote.destGasUsd ?? 0}`}>
283
+ <span title={`$${quote.destinationGasUsd ?? 0}`}>
284
284
  {
285
285
  quote.trailsFeeBreakdown.destinationRelayFee
286
286
  .usdValue
@@ -301,37 +301,28 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
301
301
  if (!quote?.trailsFeeBreakdown) return null
302
302
 
303
303
  // Check if provider fee is non-zero
304
- const hasProviderFee = (quote.providerUsd ?? 0) > 0
304
+ const hasProviderFee = (quote.providerFeeUsd ?? 0) > 0
305
305
 
306
306
  // Check if trails fee is non-zero
307
- const hasTrailsFee = (quote.trailsUsd ?? 0) > 0
307
+ const hasTrailsFee = (quote.trailsFeeUsd ?? 0) > 0
308
308
 
309
309
  if (!hasProviderFee && !hasTrailsFee) return null
310
310
 
311
311
  return (
312
312
  <RowGroup>
313
- {/* All Provider Fees = provider fee + swap fee */}
314
- {((quote.providerUsd ?? 0) > 0 ||
315
- (quote.swapFeesUsd ?? 0) > 0) &&
316
- quote.allProviderFeesUsdDisplay &&
317
- (() => {
318
- const allProviderFees =
319
- (quote.providerUsd ?? 0) + (quote.swapFeesUsd ?? 0)
320
- if (allProviderFees <= 0) return null
321
-
322
- return (
323
- <Row>
324
- <RowLabel tooltip="Total provider fees including bridge fees and swap fees">
325
- All provider fees
326
- </RowLabel>
327
- <RowValue>
328
- <span title={`$${quote.allProviderFeesUsd ?? 0}`}>
329
- {quote.allProviderFeesUsdDisplay}
330
- </span>
331
- </RowValue>
332
- </Row>
333
- )
334
- })()}
313
+ {/* All Provider Fees (swap spread is shown in priceImpact) */}
314
+ {(quote.totalProviderFeesUsd ?? 0) > 0 && (
315
+ <Row>
316
+ <RowLabel tooltip="Total provider fees for bridge and routing">
317
+ All provider fees
318
+ </RowLabel>
319
+ <RowValue>
320
+ <span title={`$${quote.totalProviderFeesUsd ?? 0}`}>
321
+ {quote.totalProviderFeesUsdDisplay}
322
+ </span>
323
+ </RowValue>
324
+ </Row>
325
+ )}
335
326
 
336
327
  {hasProviderFee &&
337
328
  quote.trailsFeeBreakdown.providerFee &&
@@ -394,7 +385,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
394
385
  )}
395
386
  </RowLabel>
396
387
  <RowValue>
397
- <span title={`$${quote.providerUsd ?? 0}`}>
388
+ <span title={`$${quote.providerFeeUsd ?? 0}`}>
398
389
  {providerFee.usdValue}
399
390
  </span>
400
391
  </RowValue>
@@ -497,7 +488,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
497
488
  <TriangleAlert className="size-3" />
498
489
  </span>
499
490
  )}
500
- {quote.priceImpact}%
491
+ {Number(quote.priceImpact).toFixed(2)}%
501
492
  </RowValue>
502
493
  </Row>
503
494
  {quote.priceImpactUsdDisplay && (
@@ -1,11 +1,12 @@
1
1
  import type React from "react"
2
2
  import { useState, useEffect } from "react"
3
3
  import { HelpCircle } from "lucide-react"
4
- import { useTrails } from "../providers/TrailsProvider.js"
4
+ import { SLIPPAGE_AUTO } from "../../constants.js"
5
5
 
6
6
  // Convert decimal format to percentage for display
7
7
  // Format: "0.05" (5%) -> "5"
8
8
  const decimalToPercentage = (decimal: string): string => {
9
+ if (decimal === SLIPPAGE_AUTO) return SLIPPAGE_AUTO
9
10
  const num = parseFloat(decimal)
10
11
  return (num * 100).toString()
11
12
  }
@@ -13,6 +14,7 @@ const decimalToPercentage = (decimal: string): string => {
13
14
  // Convert percentage to decimal format for storage
14
15
  // Format: "5" (5%) -> "0.05"
15
16
  const percentageToDecimal = (percentage: string): string => {
17
+ if (percentage === SLIPPAGE_AUTO) return SLIPPAGE_AUTO
16
18
  const num = parseFloat(percentage)
17
19
  return (num / 100).toString()
18
20
  }
@@ -20,11 +22,23 @@ const percentageToDecimal = (percentage: string): string => {
20
22
  // Local storage key for user's slippage preference
21
23
  const SLIPPAGE_STORAGE_KEY = "trails-slippage-tolerance"
22
24
 
25
+ // Helper function to check if slippage is in AUTO mode
26
+ export const isSlippageAuto = (value: string | null | undefined): boolean => {
27
+ return value === SLIPPAGE_AUTO || value === null || value === undefined
28
+ }
29
+
23
30
  // Helper function to get current slippage tolerance (for use in SDK functions)
24
31
  // Returns the user's stored preference or falls back to the provided default
25
- export const getSlippageToleranceValue = (defaultValue: string): string => {
32
+ // Returns null if AUTO mode is selected (backend will calculate optimal slippage)
33
+ export const getSlippageToleranceValue = (
34
+ defaultValue: string,
35
+ ): string | null => {
26
36
  try {
27
37
  const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
38
+ if (stored === SLIPPAGE_AUTO || stored === null) {
39
+ // AUTO mode - return null so backend calculates optimal slippage
40
+ return null
41
+ }
28
42
  return stored || defaultValue
29
43
  } catch (_error) {
30
44
  return defaultValue
@@ -38,7 +52,6 @@ interface SlippageToleranceSettingsProps {
38
52
  export const SlippageToleranceSettings: React.FC<
39
53
  SlippageToleranceSettingsProps
40
54
  > = ({ className = "" }) => {
41
- const config = useTrails()
42
55
  const [displayValue, setDisplayValue] = useState("")
43
56
  const [showTooltip, setShowTooltip] = useState(false)
44
57
 
@@ -49,14 +62,14 @@ export const SlippageToleranceSettings: React.FC<
49
62
  if (stored) {
50
63
  setDisplayValue(decimalToPercentage(stored))
51
64
  } else {
52
- // Default to config value
53
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
65
+ // Default to AUTO mode
66
+ setDisplayValue(SLIPPAGE_AUTO)
54
67
  }
55
68
  } catch (_error) {
56
- // Fallback to config if localStorage fails
57
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
69
+ // Fallback to AUTO if localStorage fails
70
+ setDisplayValue(SLIPPAGE_AUTO)
58
71
  }
59
- }, [config.slippageTolerance])
72
+ }, [])
60
73
 
61
74
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
62
75
  const value = e.target.value
@@ -73,17 +86,13 @@ export const SlippageToleranceSettings: React.FC<
73
86
  }
74
87
 
75
88
  const handleInputBlur = () => {
76
- if (displayValue === "") {
77
- // Reset to stored value or config default
89
+ if (displayValue === "" || displayValue === SLIPPAGE_AUTO) {
90
+ // Reset to AUTO mode
91
+ setDisplayValue(SLIPPAGE_AUTO)
78
92
  try {
79
- const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
80
- if (stored) {
81
- setDisplayValue(decimalToPercentage(stored))
82
- } else {
83
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
84
- }
93
+ localStorage.setItem(SLIPPAGE_STORAGE_KEY, SLIPPAGE_AUTO)
85
94
  } catch (_error) {
86
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
95
+ // Ignore localStorage errors
87
96
  }
88
97
  return
89
98
  }
@@ -91,17 +100,17 @@ export const SlippageToleranceSettings: React.FC<
91
100
  const percentage = parseFloat(displayValue)
92
101
 
93
102
  // Validate range (0.01% to 50%)
94
- if (percentage < 0.01 || percentage > 50) {
95
- // Reset to stored value or config default
103
+ if (Number.isNaN(percentage) || percentage < 0.01 || percentage > 50) {
104
+ // Reset to stored value or AUTO default
96
105
  try {
97
106
  const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
98
- if (stored) {
107
+ if (stored && stored !== SLIPPAGE_AUTO) {
99
108
  setDisplayValue(decimalToPercentage(stored))
100
109
  } else {
101
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
110
+ setDisplayValue(SLIPPAGE_AUTO)
102
111
  }
103
112
  } catch (_error) {
104
- setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
113
+ setDisplayValue(SLIPPAGE_AUTO)
105
114
  }
106
115
  return
107
116
  }
@@ -124,6 +133,15 @@ export const SlippageToleranceSettings: React.FC<
124
133
  }
125
134
  }
126
135
 
136
+ const handleAutoClick = () => {
137
+ setDisplayValue(SLIPPAGE_AUTO)
138
+ try {
139
+ localStorage.setItem(SLIPPAGE_STORAGE_KEY, SLIPPAGE_AUTO)
140
+ } catch (error) {
141
+ console.warn("Failed to save slippage tolerance to localStorage:", error)
142
+ }
143
+ }
144
+
127
145
  const handlePresetClick = (percentage: number) => {
128
146
  const percentageStr = percentage.toString()
129
147
  setDisplayValue(percentageStr)
@@ -152,8 +170,9 @@ export const SlippageToleranceSettings: React.FC<
152
170
  </button>
153
171
  {showTooltip && (
154
172
  <div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 w-64 p-2 text-xs text-white bg-gray-900 dark:bg-gray-700 rounded-md shadow-lg z-10">
155
- Higher slippage tolerance allows for larger price movements but
156
- may result in less favorable rates. Maximum 50%.
173
+ Auto mode calculates optimal slippage based on transaction size
174
+ and routing. Higher slippage allows for larger price movements but
175
+ may result in less favorable rates.
157
176
  <div className="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-gray-900 dark:border-t-gray-700"></div>
158
177
  </div>
159
178
  )}
@@ -162,7 +181,18 @@ export const SlippageToleranceSettings: React.FC<
162
181
 
163
182
  {/* Preset buttons */}
164
183
  <div className="flex items-center space-x-2">
165
- {[0.1, 0.5, 1, 3, 5].map((preset) => (
184
+ <button
185
+ type="button"
186
+ onClick={handleAutoClick}
187
+ className={`px-2 py-1 text-xs font-medium trails-border-radius-container border border-solid transition-colors cursor-pointer ${
188
+ displayValue === SLIPPAGE_AUTO
189
+ ? "bg-blue-500 text-white border-blue-500"
190
+ : "border-gray-300 text-gray-600 dark:border-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:trails-hover-bg hover:border-gray-400 dark:hover:border-gray-500"
191
+ }`}
192
+ >
193
+ Auto
194
+ </button>
195
+ {[0.5, 1, 3, 5].map((preset) => (
166
196
  <button
167
197
  key={preset}
168
198
  type="button"