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
@@ -1,6 +1,5 @@
1
1
  import { TokenImage } from "./TokenImage.js"
2
2
  import { ChainImage } from "./ChainImage.js"
3
- import { InfoIcon } from "@0xsequence/design-system"
4
3
  import { Tooltip } from "./Tooltip.js"
5
4
  import type React from "react"
6
5
  import { getExplorerUrlForAddress } from "../../explorer.js"
@@ -10,7 +9,7 @@ import { truncateAddress } from "../../utils.js"
10
9
  import { PriceImpactWarning } from "./PriceImpactWarning.js"
11
10
  import { usePriceImpactWarning } from "../hooks/usePriceImpactWarning.js"
12
11
  import { formatUsdAmountDisplay } from "../../tokenBalances.js"
13
- import { Copy, Check } from "lucide-react"
12
+ import { Copy, Check, Info } from "lucide-react"
14
13
 
15
14
  interface QuoteDetailsProps {
16
15
  quote?: PrepareSendQuote | null
@@ -37,7 +36,9 @@ const formatCompletionTime = (seconds: number): string => {
37
36
  const remainingMinutes = Math.floor((seconds % 3600) / 60)
38
37
  const remainingSeconds = seconds % 60
39
38
  if (remainingMinutes > 0 || remainingSeconds > 0) {
40
- return `${hours}h${remainingMinutes}m${remainingSeconds > 0 ? `${remainingSeconds}s` : ""}`
39
+ return `${hours}h${remainingMinutes}m${
40
+ remainingSeconds > 0 ? `${remainingSeconds}s` : ""
41
+ }`
41
42
  } else {
42
43
  return `${hours}h`
43
44
  }
@@ -56,11 +57,9 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
56
57
  const [showCalldata, setShowCalldata] = useState(false)
57
58
  const [showOriginRate, setShowOriginRate] = useState(true)
58
59
  const [isExpanded, setIsExpanded] = useState(false)
59
- const [showMoreInfo, setShowMoreInfo] = useState(false)
60
60
  const [intentIdCopied, setIntentIdCopied] = useState(false)
61
61
  const containerRef = useRef<HTMLDivElement>(null)
62
62
  const calldataRef = useRef<HTMLDivElement>(null)
63
- const moreInfoRef = useRef<HTMLDivElement>(null)
64
63
 
65
64
  const priceImpactConfig = usePriceImpactWarning()
66
65
 
@@ -100,7 +99,9 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
100
99
 
101
100
  return (
102
101
  <div
103
- className={`relative transition-opacity duration-300 ${isRefetching ? "opacity-50" : ""}`}
102
+ className={`relative transition-opacity duration-300 ${
103
+ isRefetching ? "opacity-50" : ""
104
+ }`}
104
105
  >
105
106
  {/* Price Impact Warning - always visible when conditions are met */}
106
107
  <PriceImpactWarning
@@ -116,7 +117,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
116
117
  <span className="text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
117
118
  Balance Status:
118
119
  <Tooltip message="Your wallet does not have sufficient balance to complete this transaction">
119
- <InfoIcon className="w-3 h-3 text-amber-500 dark:text-amber-400 cursor-pointer" />
120
+ <Info className="w-3 h-3 text-amber-500 dark:text-amber-400 cursor-pointer" />
120
121
  </Tooltip>
121
122
  </span>
122
123
  <span className="font-medium text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
@@ -139,92 +140,66 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
139
140
  </div>
140
141
  )}
141
142
 
142
- {/* More Details Button - only visible when collapsed */}
143
- {!isExpanded && (
144
- <div className={`flex justify-center`}>
145
- {swapMode ? (
146
- <button
147
- type="button"
148
- onClick={() => setIsExpanded(true)}
149
- className="w-full flex items-center justify-between py-2 px-4 trails-border-radius-button transition-colors cursor-pointer text-xs"
150
- aria-label="Show more details"
151
- >
152
- <div className="flex items-center gap-2 text-gray-600 dark:text-gray-400 whitespace-nowrap max-w-48 truncate">
153
- {quote?.originTokenRate && (
154
- <span className="font-medium">{quote.originTokenRate}</span>
155
- )}
156
- </div>
157
- <div className="flex items-center gap-2 text-gray-600 dark:text-gray-400">
158
- {quote?.completionEstimateSeconds != null && (
159
- <>
160
- <svg
161
- className="w-3 h-3"
162
- fill="none"
163
- stroke="currentColor"
164
- viewBox="0 0 24 24"
165
- aria-hidden="true"
166
- >
167
- <path
168
- strokeLinecap="round"
169
- strokeLinejoin="round"
170
- strokeWidth={2}
171
- d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
172
- />
173
- </svg>
174
- <span className="font-medium">
175
- ~{formatCompletionTime(quote.completionEstimateSeconds)}
176
- </span>
177
- </>
178
- )}
179
- {quote?.gasCostUsd != null && quote?.gasCostUsd > 0 && (
180
- <>
181
- <svg
182
- aria-hidden="true"
183
- focusable="false"
184
- data-prefix="fas"
185
- data-icon="gas-pump"
186
- className="svg-inline--fa fa-gas-pump"
187
- role="img"
188
- xmlns="http://www.w3.org/2000/svg"
189
- viewBox="0 0 512 512"
190
- width="12"
191
- >
192
- <path
193
- fill="currentColor"
194
- d="M32 64C32 28.7 60.7 0 96 0H256c35.3 0 64 28.7 64 64V256h8c48.6 0 88 39.4 88 88v32c0 13.3 10.7 24 24 24s24-10.7 24-24V222c-27.6-7.1-48-32.2-48-62V96L384 64c-8.8-8.8-8.8-23.2 0-32s23.2-8.8 32 0l77.3 77.3c12 12 18.7 28.3 18.7 45.3V168v24 32V376c0 39.8-32.2 72-72 72s-72-32.2-72-72V344c0-22.1-17.9-40-40-40h-8V448c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32V64zM96 80v96c0 8.8 7.2 16 16 16H240c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16H112c-8.8 0-16 7.2-16 16z"
195
- />
196
- </svg>
197
- <span className="font-medium">
198
- {quote.gasCostUsdDisplay}
199
- </span>
200
- </>
201
- )}
202
- <svg
203
- className="w-3 h-3 transition-transform duration-300 ease-out"
204
- fill="none"
205
- stroke="currentColor"
206
- viewBox="0 0 24 24"
207
- aria-hidden="true"
208
- >
209
- <path
210
- strokeLinecap="round"
211
- strokeLinejoin="round"
212
- strokeWidth={2}
213
- d="M19 9l-7 7-7-7"
214
- />
215
- </svg>
216
- </div>
217
- </button>
218
- ) : (
219
- <button
220
- type="button"
221
- onClick={() => setIsExpanded(true)}
222
- className={`w-full max-w-md flex items-center ${compact ? "justify-center" : "justify-between"} gap-2 py-1 px-1 trails-border-radius-button transition-colors cursor-pointer text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300`}
223
- aria-label="Show transaction details"
224
- >
225
- <span>Transaction details</span>
143
+ <div className={`flex justify-center`}>
144
+ {swapMode ? (
145
+ <button
146
+ type="button"
147
+ onClick={() => setIsExpanded(!isExpanded)}
148
+ className="w-full flex items-center justify-between px-2 py-2 trails-border-radius-button transition-colors cursor-pointer text-xs"
149
+ aria-label="Show more details"
150
+ >
151
+ <div className="flex items-center gap-2 text-gray-600 dark:text-gray-400 whitespace-nowrap max-w-48 truncate">
152
+ {quote?.originTokenRate && (
153
+ <span className="font-medium">{quote.originTokenRate}</span>
154
+ )}
155
+ </div>
156
+ <div className="flex items-center gap-2 text-gray-600 dark:text-gray-400">
157
+ {quote?.completionEstimateSeconds != null && (
158
+ <>
159
+ <svg
160
+ className="w-3 h-3"
161
+ fill="none"
162
+ stroke="currentColor"
163
+ viewBox="0 0 24 24"
164
+ aria-hidden="true"
165
+ >
166
+ <path
167
+ strokeLinecap="round"
168
+ strokeLinejoin="round"
169
+ strokeWidth={2}
170
+ d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"
171
+ />
172
+ </svg>
173
+ <span className="font-medium">
174
+ ~{formatCompletionTime(quote.completionEstimateSeconds)}
175
+ </span>
176
+ </>
177
+ )}
178
+ {quote?.gasCostUsd != null && quote?.gasCostUsd > 0 && (
179
+ <>
180
+ <svg
181
+ aria-hidden="true"
182
+ focusable="false"
183
+ data-prefix="fas"
184
+ data-icon="gas-pump"
185
+ className="svg-inline--fa fa-gas-pump"
186
+ role="img"
187
+ xmlns="http://www.w3.org/2000/svg"
188
+ viewBox="0 0 512 512"
189
+ width="12"
190
+ >
191
+ <path
192
+ fill="currentColor"
193
+ d="M32 64C32 28.7 60.7 0 96 0H256c35.3 0 64 28.7 64 64V256h8c48.6 0 88 39.4 88 88v32c0 13.3 10.7 24 24 24s24-10.7 24-24V222c-27.6-7.1-48-32.2-48-62V96L384 64c-8.8-8.8-8.8-23.2 0-32s23.2-8.8 32 0l77.3 77.3c12 12 18.7 28.3 18.7 45.3V168v24 32V376c0 39.8-32.2 72-72 72s-72-32.2-72-72V344c0-22.1-17.9-40-40-40h-8V448c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32V64zM96 80v96c0 8.8 7.2 16 16 16H240c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16H112c-8.8 0-16 7.2-16 16z"
194
+ />
195
+ </svg>
196
+ <span className="font-medium">{quote.gasCostUsdDisplay}</span>
197
+ </>
198
+ )}
226
199
  <svg
227
- className="w-3 h-3 transition-transform duration-300 ease-out"
200
+ className={`w-3 h-3 transition-transform duration-300 ease-out ${
201
+ isExpanded ? "rotate-180" : ""
202
+ }`}
228
203
  fill="none"
229
204
  stroke="currentColor"
230
205
  viewBox="0 0 24 24"
@@ -237,10 +212,37 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
237
212
  d="M19 9l-7 7-7-7"
238
213
  />
239
214
  </svg>
240
- </button>
241
- )}
242
- </div>
243
- )}
215
+ </div>
216
+ </button>
217
+ ) : (
218
+ <button
219
+ type="button"
220
+ onClick={() => setIsExpanded(!isExpanded)}
221
+ className={`w-full max-w-md flex items-center ${
222
+ compact ? "justify-center" : "justify-between"
223
+ } gap-2 py-1 px-1 trails-border-radius-button transition-colors cursor-pointer text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300`}
224
+ aria-label="Show transaction details"
225
+ >
226
+ <span>Transaction details</span>
227
+ <svg
228
+ className={`w-3 h-3 transition-transform duration-300 ease-out ${
229
+ isExpanded ? "rotate-180" : ""
230
+ }`}
231
+ fill="none"
232
+ stroke="currentColor"
233
+ viewBox="0 0 24 24"
234
+ aria-hidden="true"
235
+ >
236
+ <path
237
+ strokeLinecap="round"
238
+ strokeLinejoin="round"
239
+ strokeWidth={2}
240
+ d="M19 9l-7 7-7-7"
241
+ />
242
+ </svg>
243
+ </button>
244
+ )}
245
+ </div>
244
246
 
245
247
  {/* Details container */}
246
248
  <div
@@ -249,66 +251,15 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
249
251
  isExpanded ? "max-h-[250px] opacity-100" : "max-h-0 opacity-0"
250
252
  }`}
251
253
  >
252
- <div
253
- className={`text-sm ${swapMode ? "p-2 space-y-2" : "p-4 rounded-lg space-y-4 trails-bg-secondary"}`}
254
- >
255
- {/* Close Button - only visible when expanded, at top center */}
256
- <div className={`flex justify-center mb-4 -mt-2`}>
257
- {swapMode ? (
258
- <button
259
- type="button"
260
- onClick={() => setIsExpanded(false)}
261
- className="w-full flex items-center justify-end py-2 text-xs transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 cursor-pointer"
262
- aria-label="Close details"
263
- >
264
- <svg
265
- className="w-3 h-3 transition-transform duration-300 ease-out rotate-180"
266
- fill="none"
267
- stroke="currentColor"
268
- viewBox="0 0 24 24"
269
- aria-hidden="true"
270
- >
271
- <path
272
- strokeLinecap="round"
273
- strokeLinejoin="round"
274
- strokeWidth={2}
275
- d="M19 9l-7 7-7-7"
276
- />
277
- </svg>
278
- </button>
279
- ) : (
280
- <button
281
- type="button"
282
- onClick={() => setIsExpanded(false)}
283
- className="flex items-center gap-1 px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 dark:bg-gray-700 dark:hover:bg-gray-600 trails-border-radius-button transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 cursor-pointer"
284
- aria-label="Close details"
285
- >
286
- <span>Close</span>
287
- <svg
288
- className="w-3 h-3 transition-transform duration-300 ease-out"
289
- fill="none"
290
- stroke="currentColor"
291
- viewBox="0 0 24 24"
292
- aria-hidden="true"
293
- >
294
- <path
295
- strokeLinecap="round"
296
- strokeLinejoin="round"
297
- strokeWidth={2}
298
- d="M19 9l-7 7-7-7"
299
- />
300
- </svg>
301
- </button>
302
- )}
303
- </div>
304
- <div className="space-y-3">
254
+ <div className={`text-sm p-2 space-y-2`}>
255
+ <div className="space-y-2">
305
256
  {/* Estimated Time */}
306
- {quote?.completionEstimateSeconds != null && (
257
+ {/* {quote?.completionEstimateSeconds != null && (
307
258
  <div className="flex justify-between items-center">
308
259
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
309
260
  Estimated Time:
310
261
  <Tooltip message="Estimated time for the transaction to complete across all chains">
311
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
262
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
312
263
  </Tooltip>
313
264
  </span>
314
265
  <span className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1">
@@ -329,79 +280,102 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
329
280
  ~{formatCompletionTime(quote.completionEstimateSeconds)}
330
281
  </span>
331
282
  </div>
332
- )}
283
+ )} */}
333
284
 
334
285
  {/* Spacer */}
335
- <div className="h-2" />
286
+ {/* <div className="h-2" /> */}
336
287
 
337
288
  {/* Gas Costs Section */}
338
289
  {quote?.trailsFeeBreakdown &&
339
290
  (quote?.trailsFeeBreakdown.originRelayFee ||
340
291
  quote?.trailsFeeBreakdown.destinationRelayFee) && (
341
292
  <>
342
- {/* Origin Gas */}
343
- {quote.trailsFeeBreakdown.originRelayFee && (
344
- <div className="flex justify-between items-center">
345
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
346
- Origin Gas
347
- <ChainImage chainId={quote.originChain.id} size={16} />:
348
- <Tooltip message="Gas fee for executing the transaction on the origin chain">
349
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
350
- </Tooltip>
351
- </span>
352
- <span className="font-medium text-xs text-gray-900 dark:text-white">
353
- {quote.trailsFeeBreakdown.originRelayFee.usdValue}
354
- </span>
355
- </div>
356
- )}
293
+ {/* Total Fees */}
294
+ {(() => {
295
+ // Calculate total gas costs
296
+ const originGasUsd = parseFloat(
297
+ quote.trailsFeeBreakdown?.originRelayFee?.usdValue?.replace(
298
+ /[^0-9.-]/g,
299
+ "",
300
+ ) || "0",
301
+ )
302
+ const destGasUsd = parseFloat(
303
+ quote.trailsFeeBreakdown?.destinationRelayFee?.usdValue?.replace(
304
+ /[^0-9.-]/g,
305
+ "",
306
+ ) || "0",
307
+ )
308
+ const totalGasUsd = originGasUsd + destGasUsd
357
309
 
358
- {/* Destination Gas */}
359
- {quote.trailsFeeBreakdown.destinationRelayFee && (
360
- <div className="flex justify-between items-center">
361
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
362
- Destination Gas
363
- <ChainImage
364
- chainId={quote.destinationChain.id}
365
- size={16}
366
- />
367
- :
368
- <Tooltip message="Gas fee for executing the transaction on the destination chain">
369
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
370
- </Tooltip>
371
- </span>
372
- <span className="font-medium text-xs text-gray-900 dark:text-white">
373
- {quote.trailsFeeBreakdown.destinationRelayFee.usdValue}
374
- </span>
375
- </div>
376
- )}
310
+ // Calculate total provider costs (including swap fees)
311
+ const providerUsd = parseFloat(
312
+ quote.trailsFeeBreakdown?.providerFee?.usdValue?.replace(
313
+ /[^0-9.-]/g,
314
+ "",
315
+ ) || "0",
316
+ )
317
+ const trailsUsd = parseFloat(
318
+ quote.trailsFeeBreakdown?.trailsFee?.usdValue?.replace(
319
+ /[^0-9.-]/g,
320
+ "",
321
+ ) || "0",
322
+ )
323
+ const originUsd = parseFloat(
324
+ quote.originAmountUsdDisplay?.replace(/[^0-9.-]/g, "") ||
325
+ "0",
326
+ )
327
+ const destUsd = parseFloat(
328
+ quote.destinationAmountUsdDisplay?.replace(
329
+ /[^0-9.-]/g,
330
+ "",
331
+ ) || "0",
332
+ )
333
+ const totalFeesUsd = parseFloat(
334
+ quote.fees?.totalFeeAmountUsdDisplay?.replace(
335
+ /[^0-9.-]/g,
336
+ "",
337
+ ) || "0",
338
+ )
339
+ const swapFeesUsd = Math.max(
340
+ 0,
341
+ originUsd - destUsd - totalFeesUsd,
342
+ )
343
+ const totalProviderUsd =
344
+ providerUsd + trailsUsd + swapFeesUsd
345
+
346
+ // Sum of all gas costs and all provider costs
347
+ const grandTotalUsd = totalGasUsd + totalProviderUsd
348
+
349
+ if (grandTotalUsd <= 0) return null
350
+
351
+ return (
352
+ <div className="flex justify-between items-center">
353
+ <span className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-1">
354
+ Fees total
355
+ <Tooltip message="The total fees for this transaction, including gas costs and all provider fees">
356
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
357
+ </Tooltip>
358
+ </span>
359
+ <span className="font-semibold text-sm text-gray-900 dark:text-white">
360
+ ≈ {formatUsdAmountDisplay(grandTotalUsd)}
361
+ </span>
362
+ </div>
363
+ )
364
+ })()}
365
+
366
+ <div className="h-0" />
377
367
 
378
368
  {/* All Gas Costs */}
379
369
  {(quote.trailsFeeBreakdown.originRelayFee ||
380
370
  quote.trailsFeeBreakdown.destinationRelayFee) && (
381
371
  <div className="flex justify-between items-center">
382
372
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
383
- All gas costs:
373
+ All gas costs
384
374
  <Tooltip message="Total gas costs for executing transactions on both origin and destination chains">
385
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
375
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
386
376
  </Tooltip>
387
377
  </span>
388
- <span className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 pt-2 border-t border-gray-200 dark:border-gray-700">
389
- <svg
390
- aria-hidden="true"
391
- focusable="false"
392
- data-prefix="fas"
393
- data-icon="gas-pump"
394
- className="svg-inline--fa fa-gas-pump"
395
- role="img"
396
- xmlns="http://www.w3.org/2000/svg"
397
- viewBox="0 0 512 512"
398
- width="12"
399
- >
400
- <path
401
- fill="currentColor"
402
- d="M32 64C32 28.7 60.7 0 96 0H256c35.3 0 64 28.7 64 64V256h8c48.6 0 88 39.4 88 88v32c0 13.3 10.7 24 24 24s24-10.7 24-24V222c-27.6-7.1-48-32.2-48-62V96L384 64c-8.8-8.8-8.8-23.2 0-32s23.2-8.8 32 0l77.3 77.3c12 12 18.7 28.3 18.7 45.3V168v24 32V376c0 39.8-32.2 72-72 72s-72-32.2-72-72V344c0-22.1-17.9-40-40-40h-8V448c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32V64zM96 80v96c0 8.8 7.2 16 16 16H240c8.8 0 16-7.2 16-16V80c0-8.8-7.2-16-16-16H112c-8.8 0-16 7.2-16 16z"
403
- />
404
- </svg>
378
+ <span className="font-medium text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
405
379
  {(() => {
406
380
  const originGasUsd = parseFloat(
407
381
  quote.trailsFeeBreakdown.originRelayFee?.usdValue?.replace(
@@ -422,8 +396,43 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
422
396
  </div>
423
397
  )}
424
398
 
399
+ {/* Origin Gas */}
400
+ {quote.trailsFeeBreakdown.originRelayFee && (
401
+ <div className="flex justify-between items-center">
402
+ <span className="text-xs text-gray-400 dark:text-gray-600 flex items-center gap-1">
403
+ Origin Gas
404
+ <ChainImage chainId={quote.originChain.id} size={16} />
405
+ <Tooltip message="Gas fee for executing the transaction on the origin chain">
406
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
407
+ </Tooltip>
408
+ </span>
409
+ <span className="font-medium text-xs text-gray-400 dark:text-gray-600">
410
+ {quote.trailsFeeBreakdown.originRelayFee.usdValue}
411
+ </span>
412
+ </div>
413
+ )}
414
+
415
+ {/* Destination Gas */}
416
+ {quote.trailsFeeBreakdown.destinationRelayFee && (
417
+ <div className="flex justify-between items-center">
418
+ <span className="text-xs text-gray-400 dark:text-gray-600 flex items-center gap-1">
419
+ Destination Gas
420
+ <ChainImage
421
+ chainId={quote.destinationChain.id}
422
+ size={16}
423
+ />
424
+ <Tooltip message="Gas fee for executing the transaction on the destination chain">
425
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
426
+ </Tooltip>
427
+ </span>
428
+ <span className="font-medium text-xs text-gray-400 dark:text-gray-600">
429
+ {quote.trailsFeeBreakdown.destinationRelayFee.usdValue}
430
+ </span>
431
+ </div>
432
+ )}
433
+
425
434
  {/* Spacer */}
426
- <div className="h-2" />
435
+ <div className="h-1" />
427
436
  </>
428
437
  )}
429
438
 
@@ -456,149 +465,6 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
456
465
  return (
457
466
  <>
458
467
  {/* Bridge/Swap Provider Fee */}
459
- {hasProviderFee &&
460
- quote.trailsFeeBreakdown.providerFee &&
461
- (() => {
462
- const providerFee = quote.trailsFeeBreakdown.providerFee
463
- const isCrossChain =
464
- quote.originChain.id !== quote.destinationChain.id
465
- const providerName = quote.quoteProvider?.name || ""
466
-
467
- return (
468
- <div className="flex justify-between items-center">
469
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
470
- {isCrossChain ? (
471
- providerName ? (
472
- <>
473
- Bridge (
474
- <a
475
- href={quote.quoteProvider?.url}
476
- target="_blank"
477
- rel="noopener noreferrer"
478
- className="hover:underline flex items-center gap-0.5"
479
- >
480
- {providerName}
481
- <svg
482
- className="w-3 h-3"
483
- fill="none"
484
- stroke="currentColor"
485
- viewBox="0 0 24 24"
486
- aria-hidden="true"
487
- >
488
- <path
489
- strokeLinecap="round"
490
- strokeLinejoin="round"
491
- strokeWidth={2}
492
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
493
- />
494
- </svg>
495
- </a>
496
- ):
497
- </>
498
- ) : (
499
- <>Bridge:</>
500
- )
501
- ) : providerName ? (
502
- <>
503
- Liquidity Provider (
504
- <a
505
- href={quote.quoteProvider?.url}
506
- target="_blank"
507
- rel="noopener noreferrer"
508
- className="hover:underline flex items-center gap-0.5"
509
- >
510
- {providerName}
511
- <svg
512
- className="w-3 h-3"
513
- fill="none"
514
- stroke="currentColor"
515
- viewBox="0 0 24 24"
516
- aria-hidden="true"
517
- >
518
- <path
519
- strokeLinecap="round"
520
- strokeLinejoin="round"
521
- strokeWidth={2}
522
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
523
- />
524
- </svg>
525
- </a>
526
- ):
527
- </>
528
- ) : (
529
- <>Liquidity Provider:</>
530
- )}
531
- <Tooltip message="Fee charged by the bridge/swap provider for executing the transaction">
532
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
533
- </Tooltip>
534
- </span>
535
- <span className="font-medium text-xs text-gray-900 dark:text-white">
536
- {providerFee.usdValue}
537
- </span>
538
- </div>
539
- )
540
- })()}
541
-
542
- {/* Swap Fees (implicit costs) */}
543
- {(() => {
544
- // Calculate swap fees: (originAmount - destinationAmount) - totalFees
545
- const originUsd = parseFloat(
546
- quote.originAmountUsdDisplay?.replace(/[^0-9.-]/g, "") ||
547
- "0",
548
- )
549
- const destUsd = parseFloat(
550
- quote.destinationAmountUsdDisplay?.replace(
551
- /[^0-9.-]/g,
552
- "",
553
- ) || "0",
554
- )
555
- const totalFeesUsd = parseFloat(
556
- quote.fees?.totalFeeAmountUsdDisplay?.replace(
557
- /[^0-9.-]/g,
558
- "",
559
- ) || "0",
560
- )
561
-
562
- const swapFeesUsd = originUsd - destUsd - totalFeesUsd
563
-
564
- // Only show if swap fees > 0
565
- if (swapFeesUsd <= 0) return null
566
-
567
- return (
568
- <div className="flex justify-between items-center">
569
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
570
- Swap:
571
- <Tooltip message="Implicit costs including DEX fees, liquidity provider fees, and routing costs">
572
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
573
- </Tooltip>
574
- </span>
575
- <span className="font-medium text-xs text-gray-900 dark:text-white">
576
- {formatUsdAmountDisplay(swapFeesUsd)}
577
- </span>
578
- </div>
579
- )
580
- })()}
581
-
582
- {/* Trails Platform Fee */}
583
- {hasTrailsFee &&
584
- quote.trailsFeeBreakdown.trailsFee &&
585
- (() => {
586
- const trailsFee = quote.trailsFeeBreakdown.trailsFee
587
-
588
- return (
589
- <div className="flex justify-between items-center">
590
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
591
- Trails:
592
- <Tooltip message="Platform fee for using the Trails service">
593
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
594
- </Tooltip>
595
- </span>
596
- <span className="font-medium text-xs text-gray-900 dark:text-white">
597
- {trailsFee.usdValue}
598
- </span>
599
- </div>
600
- )
601
- })()}
602
468
 
603
469
  {/* All Provider Costs */}
604
470
  {(hasProviderFee || hasTrailsFee) &&
@@ -640,57 +506,116 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
640
506
  originUsd - destUsd - totalFeesUsd,
641
507
  )
642
508
 
643
- const totalProviderUsd =
644
- providerUsd + trailsUsd + swapFeesUsd
509
+ const totalProviderUsd =
510
+ providerUsd + trailsUsd + swapFeesUsd
511
+
512
+ return (
513
+ <div className="flex justify-between items-center">
514
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
515
+ All provider costs
516
+ <Tooltip message="Total fees charged by providers, including bridge/swap, platform fees, and implicit swap costs">
517
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
518
+ </Tooltip>
519
+ </span>
520
+ <span className="font-medium text-xs text-gray-600 dark:text-gray-400">
521
+ {formatUsdAmountDisplay(totalProviderUsd)}
522
+ </span>
523
+ </div>
524
+ )
525
+ })()}
526
+
527
+ {hasProviderFee &&
528
+ quote.trailsFeeBreakdown.providerFee &&
529
+ (() => {
530
+ const providerFee = quote.trailsFeeBreakdown.providerFee
531
+ const isCrossChain =
532
+ quote.originChain.id !== quote.destinationChain.id
533
+ const providerName = quote.quoteProvider?.name || ""
645
534
 
646
535
  return (
647
536
  <div className="flex justify-between items-center">
648
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
649
- All provider costs:
650
- <Tooltip message="Total fees charged by providers, including bridge/swap, platform fees, and implicit swap costs">
651
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
537
+ <span className="text-xs text-gray-400 dark:text-gray-600 flex items-center gap-1">
538
+ {isCrossChain ? (
539
+ providerName ? (
540
+ <>
541
+ Bridge
542
+ <span>
543
+ (
544
+ <a
545
+ href={quote.quoteProvider?.url}
546
+ target="_blank"
547
+ rel="noopener noreferrer"
548
+ className="hover:underline inline-flex items-center gap-0.5 text-blue-500"
549
+ >
550
+ {providerName}
551
+ <svg
552
+ className="w-3 h-3"
553
+ fill="none"
554
+ stroke="currentColor"
555
+ viewBox="0 0 24 24"
556
+ aria-hidden="true"
557
+ >
558
+ <path
559
+ strokeLinecap="round"
560
+ strokeLinejoin="round"
561
+ strokeWidth={2}
562
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
563
+ />
564
+ </svg>
565
+ </a>
566
+ )
567
+ </span>
568
+ </>
569
+ ) : (
570
+ <>Bridge:</>
571
+ )
572
+ ) : providerName ? (
573
+ <>
574
+ Liquidity Provider{" "}
575
+ <span>
576
+ (
577
+ <a
578
+ href={quote.quoteProvider?.url}
579
+ target="_blank"
580
+ rel="noopener noreferrer"
581
+ className="hover:underline inline-flex items-center gap-0.5 text-blue-500"
582
+ >
583
+ {providerName}
584
+ <svg
585
+ className="w-3 h-3"
586
+ fill="none"
587
+ stroke="currentColor"
588
+ viewBox="0 0 24 24"
589
+ aria-hidden="true"
590
+ >
591
+ <path
592
+ strokeLinecap="round"
593
+ strokeLinejoin="round"
594
+ strokeWidth={2}
595
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
596
+ />
597
+ </svg>
598
+ </a>
599
+ )
600
+ </span>
601
+ </>
602
+ ) : (
603
+ <>Liquidity Provider</>
604
+ )}
605
+ <Tooltip message="Fee charged by the bridge/swap provider for executing the transaction">
606
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
652
607
  </Tooltip>
653
608
  </span>
654
- <span className="font-medium text-xs text-gray-900 dark:text-white pt-2 border-t border-gray-200 dark:border-gray-700">
655
- {formatUsdAmountDisplay(totalProviderUsd)}
609
+ <span className="font-medium text-xs text-gray-400 dark:text-gray-600">
610
+ {providerFee.usdValue}
656
611
  </span>
657
612
  </div>
658
613
  )
659
614
  })()}
660
615
 
661
- {/* Spacer */}
662
- <div className="h-2" />
663
-
664
- {/* Total Fees */}
616
+ {/* Swap Fees (implicit costs) */}
665
617
  {(() => {
666
- // Calculate total gas costs
667
- const originGasUsd = parseFloat(
668
- quote.trailsFeeBreakdown?.originRelayFee?.usdValue?.replace(
669
- /[^0-9.-]/g,
670
- "",
671
- ) || "0",
672
- )
673
- const destGasUsd = parseFloat(
674
- quote.trailsFeeBreakdown?.destinationRelayFee?.usdValue?.replace(
675
- /[^0-9.-]/g,
676
- "",
677
- ) || "0",
678
- )
679
- const totalGasUsd = originGasUsd + destGasUsd
680
-
681
- // Calculate total provider costs (including swap fees)
682
- const providerUsd = parseFloat(
683
- quote.trailsFeeBreakdown?.providerFee?.usdValue?.replace(
684
- /[^0-9.-]/g,
685
- "",
686
- ) || "0",
687
- )
688
- const trailsUsd = parseFloat(
689
- quote.trailsFeeBreakdown?.trailsFee?.usdValue?.replace(
690
- /[^0-9.-]/g,
691
- "",
692
- ) || "0",
693
- )
618
+ // Calculate swap fees: (originAmount - destinationAmount) - totalFees
694
619
  const originUsd = parseFloat(
695
620
  quote.originAmountUsdDisplay?.replace(/[^0-9.-]/g, "") ||
696
621
  "0",
@@ -707,39 +632,53 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
707
632
  "",
708
633
  ) || "0",
709
634
  )
710
- const swapFeesUsd = Math.max(
711
- 0,
712
- originUsd - destUsd - totalFeesUsd,
713
- )
714
- const totalProviderUsd =
715
- providerUsd + trailsUsd + swapFeesUsd
716
635
 
717
- // Sum of all gas costs and all provider costs
718
- const grandTotalUsd = totalGasUsd + totalProviderUsd
636
+ const swapFeesUsd = originUsd - destUsd - totalFeesUsd
719
637
 
720
- if (grandTotalUsd <= 0) return null
638
+ // Only show if swap fees > 0
639
+ if (swapFeesUsd <= 0) return null
721
640
 
722
641
  return (
723
642
  <div className="flex justify-between items-center">
724
- <span className="text-xs font-semibold text-gray-700 dark:text-gray-300 flex items-center gap-1">
725
- Total fees:
726
- <Tooltip message="The total fees for this transaction, including gas costs and all provider fees">
727
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
643
+ <span className="text-xs text-gray-400 dark:text-gray-600 flex items-center gap-1">
644
+ Swap
645
+ <Tooltip message="Implicit costs including DEX fees, liquidity provider fees, and routing costs">
646
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
728
647
  </Tooltip>
729
648
  </span>
730
- <span className="font-semibold text-xs text-gray-900 dark:text-white">
731
- {formatUsdAmountDisplay(grandTotalUsd)}
649
+ <span className="font-medium text-xs text-gray-400 dark:text-gray-600">
650
+ {formatUsdAmountDisplay(swapFeesUsd)}
732
651
  </span>
733
652
  </div>
734
653
  )
735
654
  })()}
736
655
 
737
- {/* Spacer */}
738
- <div className="h-2" />
656
+ {/* Trails Platform Fee */}
657
+ {hasTrailsFee &&
658
+ quote.trailsFeeBreakdown.trailsFee &&
659
+ (() => {
660
+ const trailsFee = quote.trailsFeeBreakdown.trailsFee
661
+
662
+ return (
663
+ <div className="flex justify-between items-center">
664
+ <span className="text-xs text-gray-400 dark:text-gray-600 flex items-center gap-1">
665
+ Trails
666
+ <Tooltip message="Platform fee for using the Trails service">
667
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
668
+ </Tooltip>
669
+ </span>
670
+ <span className="font-medium text-xs text-gray-400 dark:text-gray-600">
671
+ {trailsFee.usdValue}
672
+ </span>
673
+ </div>
674
+ )
675
+ })()}
739
676
  </>
740
677
  )
741
678
  })()}
742
679
 
680
+ <div className="h-px bg-gray-200 dark:bg-gray-800 my-4" />
681
+
743
682
  {/* Transaction Details Section */}
744
683
  {(() => {
745
684
  const hasSlippage =
@@ -755,30 +694,32 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
755
694
 
756
695
  return (
757
696
  <>
758
- <div className="text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2 text-center">
759
- Transaction details
697
+ <div>
698
+ <span className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-1">
699
+ Transaction details
700
+ </span>
760
701
  </div>
761
702
 
762
703
  {/* Intent ID */}
763
704
  {hasIntentId && (
764
705
  <div className="flex justify-between items-center gap-2">
765
706
  <span className="text-xs text-gray-600 dark:text-gray-400">
766
- Intent ID:
707
+ Intent ID
767
708
  </span>
768
- <div className="flex items-center gap-2 text-xs font-medium text-gray-900 dark:text-white">
709
+ <div className="flex items-center gap-1 text-xs font-medium text-gray-600 dark:text-gray-400">
769
710
  <span title={quote.intentId ?? undefined}>
770
- {truncateAddress(quote?.intentId ?? "", 10, 8)}
711
+ {truncateAddress(quote?.intentId ?? "", 9, 3)}
771
712
  </span>
772
713
  <button
773
714
  type="button"
774
715
  onClick={handleCopyIntentId}
775
- className="p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
716
+ className="p-0.5 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
776
717
  aria-label="Copy intent ID"
777
718
  >
778
719
  {intentIdCopied ? (
779
- <Check className="w-3.5 h-3.5 text-emerald-500" />
720
+ <Check className="w-3 h-3 text-emerald-500" />
780
721
  ) : (
781
- <Copy className="w-3.5 h-3.5 text-gray-500 dark:text-gray-400" />
722
+ <Copy className="w-3 h-3 text-gray-500 dark:text-gray-400" />
782
723
  )}
783
724
  </button>
784
725
  </div>
@@ -789,12 +730,12 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
789
730
  {hasSlippage && (
790
731
  <div className="flex justify-between items-center">
791
732
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
792
- Max slippage:
733
+ Max slippage
793
734
  <Tooltip message="The maximum percentage by which the exchange rate can change before the transaction fails. Higher slippage means more tolerance for price changes but potentially worse rates.">
794
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
735
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
795
736
  </Tooltip>
796
737
  </span>
797
- <span className="font-medium text-xs text-gray-900 dark:text-white">
738
+ <span className="font-medium text-xs text-gray-600 dark:text-gray-400">
798
739
  {quote.slippageTolerance}%
799
740
  </span>
800
741
  </div>
@@ -805,9 +746,9 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
805
746
  <div className="space-y-1">
806
747
  <div className="flex justify-between items-center">
807
748
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
808
- Price impact:
749
+ Price impact
809
750
  <Tooltip message="The percentage change in the token price caused by your trade. Higher impact means your trade affects the market price more, potentially resulting in worse rates.">
810
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
751
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
811
752
  </Tooltip>
812
753
  </span>
813
754
  <span
@@ -816,7 +757,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
816
757
  ? "text-red-600 dark:text-red-400"
817
758
  : Math.abs(Number(quote.priceImpact)) > 0.5
818
759
  ? "text-orange-600 dark:text-orange-400"
819
- : "text-gray-900 dark:text-white"
760
+ : "text-gray-600 dark:text-gray-400"
820
761
  }`}
821
762
  >
822
763
  {Math.abs(Number(quote.priceImpact)) > 0.5 && (
@@ -853,401 +794,351 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
853
794
  )
854
795
  })()}
855
796
 
856
- {/* More Info Section */}
857
- <div className="space-y-2">
858
- <button
859
- type="button"
860
- onClick={() => {
861
- setShowMoreInfo(!showMoreInfo)
862
- if (!showMoreInfo) {
863
- setTimeout(() => {
864
- if (moreInfoRef.current) {
865
- moreInfoRef.current.scrollIntoView({
866
- behavior: "smooth",
867
- block: "nearest",
868
- })
869
- }
870
- }, 150)
871
- }
872
- }}
873
- className="flex items-center gap-1 text-xs hover:underline cursor-pointer transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
874
- aria-label={showMoreInfo ? "Hide more info" : "Show more info"}
875
- >
876
- <span>More</span>
877
- <svg
878
- className={`w-3 h-3 transition-transform duration-300 ease-out ${
879
- showMoreInfo ? "rotate-180" : ""
880
- }`}
881
- fill="none"
882
- stroke="currentColor"
883
- viewBox="0 0 24 24"
884
- aria-hidden="true"
885
- >
886
- <path
887
- strokeLinecap="round"
888
- strokeLinejoin="round"
889
- strokeWidth={2}
890
- d="M19 9l-7 7-7-7"
891
- />
892
- </svg>
893
- </button>
797
+ <div className="space-y-3 pt-2">
798
+ {/* Exchange Rate */}
799
+ {quote?.originTokenRate && quote?.destinationTokenRate && (
800
+ <div className="flex justify-between items-center">
801
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
802
+ Exchange Rate
803
+ <Tooltip message="The current exchange rate between the origin and destination tokens">
804
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
805
+ </Tooltip>
806
+ </span>
807
+ <button
808
+ type="button"
809
+ onClick={() => setShowOriginRate(!showOriginRate)}
810
+ className="font-medium text-xs hover:underline cursor-pointer text-gray-600 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
811
+ >
812
+ {showOriginRate
813
+ ? quote.originTokenRate
814
+ : quote.destinationTokenRate}
815
+ </button>
816
+ </div>
817
+ )}
894
818
 
895
- <div
896
- ref={moreInfoRef}
897
- className={`overflow-hidden transition-all duration-300 ease-out ${
898
- showMoreInfo
899
- ? "max-h-[500px] opacity-100"
900
- : "max-h-0 opacity-0"
901
- }`}
902
- >
903
- <div className="space-y-3 pt-2">
904
- {/* Exchange Rate */}
905
- {quote?.originTokenRate && quote?.destinationTokenRate && (
906
- <div className="flex justify-between items-center">
907
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
908
- Exchange Rate:
909
- <Tooltip message="The current exchange rate between the origin and destination tokens">
910
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
911
- </Tooltip>
912
- </span>
913
- <button
914
- type="button"
915
- onClick={() => setShowOriginRate(!showOriginRate)}
916
- className="font-medium text-xs hover:underline cursor-pointer text-gray-900 hover:text-gray-700 dark:text-white dark:hover:text-gray-300"
917
- >
918
- {showOriginRate
919
- ? quote.originTokenRate
920
- : quote.destinationTokenRate}
921
- </button>
819
+ {/* Origin Transfer Amount */}
820
+ {quote?.originAmount &&
821
+ quote?.originToken.symbol &&
822
+ quote?.originChain.id && (
823
+ <div className="flex justify-between items-start">
824
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
825
+ Origin Transfer Amount
826
+ <Tooltip message="The amount of tokens you will send from the origin chain">
827
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
828
+ </Tooltip>
829
+ </span>
830
+ <div className="text-right">
831
+ {quote.originToken.contractAddress ===
832
+ "0x0000000000000000000000000000000000000000" ? (
833
+ <>
834
+ <div className="font-medium text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 justify-end">
835
+ <TokenImage
836
+ imageUrl={quote.originToken.imageUrl}
837
+ symbol={quote.originToken.symbol}
838
+ chainId={quote.originChain.id}
839
+ contractAddress={
840
+ quote.originToken.contractAddress
841
+ }
842
+ size={16}
843
+ />
844
+ {quote.originAmountDisplay}{" "}
845
+ {quote.originToken.symbol}
846
+ </div>
847
+ {quote.originAmountUsdDisplay && (
848
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
849
+ ≈ {quote.originAmountUsdDisplay}
850
+ </div>
851
+ )}
852
+ </>
853
+ ) : (
854
+ <>
855
+ <a
856
+ href={getExplorerUrlForAddress({
857
+ address: quote.originToken.contractAddress,
858
+ chainId: quote.originChain.id,
859
+ })}
860
+ target="_blank"
861
+ rel="noopener noreferrer"
862
+ className="hover:underline cursor-pointer"
863
+ >
864
+ <div className="font-medium text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 justify-end">
865
+ <TokenImage
866
+ imageUrl={quote.originToken.imageUrl}
867
+ symbol={quote.originToken.symbol}
868
+ chainId={quote.originChain.id}
869
+ contractAddress={
870
+ quote.originToken.contractAddress
871
+ }
872
+ size={16}
873
+ />
874
+ {quote.originAmountDisplay}{" "}
875
+ {quote.originToken.symbol}
876
+ </div>
877
+ </a>
878
+ {quote.originAmountUsdDisplay && (
879
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
880
+ ≈ {quote.originAmountUsdDisplay}
881
+ </div>
882
+ )}
883
+ </>
884
+ )}
922
885
  </div>
923
- )}
886
+ </div>
887
+ )}
924
888
 
925
- {/* Origin Transfer Amount */}
926
- {quote?.originAmount &&
927
- quote?.originToken.symbol &&
928
- quote?.originChain.id && (
929
- <div className="flex justify-between items-start">
930
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
931
- Origin Transfer Amount:
932
- <Tooltip message="The amount of tokens you will send from the origin chain">
933
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
934
- </Tooltip>
935
- </span>
936
- <div className="text-right">
937
- {quote.originToken.contractAddress ===
938
- "0x0000000000000000000000000000000000000000" ? (
939
- <>
940
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
941
- <TokenImage
942
- imageUrl={quote.originToken.imageUrl}
943
- symbol={quote.originToken.symbol}
944
- chainId={quote.originChain.id}
945
- contractAddress={
946
- quote.originToken.contractAddress
947
- }
948
- size={16}
949
- />
950
- {quote.originAmountDisplay}{" "}
951
- {quote.originToken.symbol}
952
- </div>
953
- {quote.originAmountUsdDisplay && (
954
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
955
- {quote.originAmountUsdDisplay}
956
- </div>
957
- )}
958
- </>
959
- ) : (
960
- <>
961
- <a
962
- href={getExplorerUrlForAddress({
963
- address: quote.originToken.contractAddress,
964
- chainId: quote.originChain.id,
965
- })}
966
- target="_blank"
967
- rel="noopener noreferrer"
968
- className="hover:underline cursor-pointer"
969
- >
970
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
971
- <TokenImage
972
- imageUrl={quote.originToken.imageUrl}
973
- symbol={quote.originToken.symbol}
974
- chainId={quote.originChain.id}
975
- contractAddress={
976
- quote.originToken.contractAddress
977
- }
978
- size={16}
979
- />
980
- {quote.originAmountDisplay}{" "}
981
- {quote.originToken.symbol}
982
- </div>
983
- </a>
984
- {quote.originAmountUsdDisplay && (
985
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
986
- ≈ {quote.originAmountUsdDisplay}
987
- </div>
988
- )}
989
- </>
889
+ {/* Destination Target Amount */}
890
+ {quote?.destinationToken.symbol &&
891
+ quote?.destinationAmount &&
892
+ quote?.destinationAmountUsdDisplay &&
893
+ quote?.destinationChain.id && (
894
+ <div className="flex justify-between items-start">
895
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
896
+ Destination Target Amount
897
+ <Tooltip message="The amount of tokens you will receive on the destination chain after the swap and/or bridge">
898
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
899
+ </Tooltip>
900
+ </span>
901
+ <div className="text-right">
902
+ {quote.destinationToken.contractAddress ===
903
+ "0x0000000000000000000000000000000000000000" ? (
904
+ <>
905
+ <div className="font-medium text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 justify-end">
906
+ <TokenImage
907
+ imageUrl={quote.destinationToken.imageUrl}
908
+ symbol={quote.destinationToken.symbol}
909
+ chainId={quote.destinationChain.id}
910
+ contractAddress={
911
+ quote.destinationToken.contractAddress
912
+ }
913
+ size={16}
914
+ />
915
+ {quote.destinationAmountDisplay}{" "}
916
+ {quote.destinationToken.symbol}
917
+ </div>
918
+ {quote.destinationAmountUsdDisplay && (
919
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
920
+ ≈ {quote.destinationAmountUsdDisplay}
921
+ </div>
990
922
  )}
991
- </div>
992
- </div>
993
- )}
994
-
995
- {/* Destination Target Amount */}
996
- {quote?.destinationToken.symbol &&
997
- quote?.destinationAmount &&
998
- quote?.destinationAmountUsdDisplay &&
999
- quote?.destinationChain.id && (
1000
- <div className="flex justify-between items-start">
1001
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1002
- Destination Target Amount:
1003
- <Tooltip message="The amount of tokens you will receive on the destination chain after the swap and/or bridge">
1004
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1005
- </Tooltip>
1006
- </span>
1007
- <div className="text-right">
1008
- {quote.destinationToken.contractAddress ===
1009
- "0x0000000000000000000000000000000000000000" ? (
1010
- <>
1011
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
1012
- <TokenImage
1013
- imageUrl={quote.destinationToken.imageUrl}
1014
- symbol={quote.destinationToken.symbol}
1015
- chainId={quote.destinationChain.id}
1016
- contractAddress={
1017
- quote.destinationToken.contractAddress
1018
- }
1019
- size={16}
1020
- />
1021
- {quote.destinationAmountDisplay}{" "}
1022
- {quote.destinationToken.symbol}
1023
- </div>
1024
- {quote.destinationAmountUsdDisplay && (
1025
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
1026
- ≈ {quote.destinationAmountUsdDisplay}
1027
- </div>
1028
- )}
1029
- </>
1030
- ) : (
1031
- <>
1032
- <a
1033
- href={getExplorerUrlForAddress({
1034
- address:
1035
- quote.destinationToken.contractAddress,
1036
- chainId: quote.destinationChain.id,
1037
- })}
1038
- target="_blank"
1039
- rel="noopener noreferrer"
1040
- className="hover:underline cursor-pointer"
1041
- >
1042
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
1043
- <TokenImage
1044
- imageUrl={quote.destinationToken.imageUrl}
1045
- symbol={quote.destinationToken.symbol}
1046
- chainId={quote.destinationChain.id}
1047
- contractAddress={
1048
- quote.destinationToken.contractAddress
1049
- }
1050
- size={16}
1051
- />
1052
- {quote.destinationAmountDisplay}{" "}
1053
- {quote.destinationToken.symbol}
1054
- </div>
1055
- </a>
1056
- {quote.destinationAmountUsdDisplay && (
1057
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
1058
- ≈ {quote.destinationAmountUsdDisplay}
1059
- </div>
1060
- )}
1061
- </>
923
+ </>
924
+ ) : (
925
+ <>
926
+ <a
927
+ href={getExplorerUrlForAddress({
928
+ address: quote.destinationToken.contractAddress,
929
+ chainId: quote.destinationChain.id,
930
+ })}
931
+ target="_blank"
932
+ rel="noopener noreferrer"
933
+ className="hover:underline cursor-pointer"
934
+ >
935
+ <div className="font-medium text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 justify-end">
936
+ <TokenImage
937
+ imageUrl={quote.destinationToken.imageUrl}
938
+ symbol={quote.destinationToken.symbol}
939
+ chainId={quote.destinationChain.id}
940
+ contractAddress={
941
+ quote.destinationToken.contractAddress
942
+ }
943
+ size={16}
944
+ />
945
+ {quote.destinationAmountDisplay}{" "}
946
+ {quote.destinationToken.symbol}
947
+ </div>
948
+ </a>
949
+ {quote.destinationAmountUsdDisplay && (
950
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
951
+ {quote.destinationAmountUsdDisplay}
952
+ </div>
1062
953
  )}
1063
- </div>
1064
- </div>
1065
- )}
1066
-
1067
- {/* Origin Deposit Address */}
1068
- {quote?.originDepositAddress && (
1069
- <div className="flex justify-between items-center">
1070
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1071
- Origin Deposit Address:
1072
- <Tooltip message="This is the intent address to deposit to that will then execute the swap and/or bridge">
1073
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1074
- </Tooltip>
1075
- </span>
1076
- <a
1077
- href={getExplorerUrlForAddress({
1078
- address: quote.originDepositAddress,
1079
- chainId: quote.originChain.id,
1080
- })}
1081
- target="_blank"
1082
- rel="noopener noreferrer"
1083
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
1084
- >
1085
- {truncateAddress(quote.originDepositAddress)}
1086
- <svg
1087
- className="w-3 h-3"
1088
- fill="none"
1089
- stroke="currentColor"
1090
- viewBox="0 0 24 24"
1091
- aria-hidden="true"
1092
- >
1093
- <path
1094
- strokeLinecap="round"
1095
- strokeLinejoin="round"
1096
- strokeWidth={2}
1097
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1098
- />
1099
- </svg>
1100
- </a>
954
+ </>
955
+ )}
1101
956
  </div>
1102
- )}
957
+ </div>
958
+ )}
1103
959
 
1104
- {/* Destination Deposit Address */}
1105
- {quote?.destinationDepositAddress &&
1106
- quote?.destinationDepositAddress !==
1107
- quote?.originDepositAddress && (
1108
- <div className="flex justify-between items-center">
1109
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1110
- Destination Deposit Address:
1111
- <Tooltip message="This is the address that will receive the tokens after any swap and/or bridge from the origin chain">
1112
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1113
- </Tooltip>
1114
- </span>
1115
- <a
1116
- href={getExplorerUrlForAddress({
1117
- address: quote.destinationDepositAddress,
1118
- chainId: quote.destinationChain.id,
1119
- })}
1120
- target="_blank"
1121
- rel="noopener noreferrer"
1122
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
1123
- >
1124
- {truncateAddress(quote.destinationDepositAddress)}
1125
- <svg
1126
- className="w-3 h-3"
1127
- fill="none"
1128
- stroke="currentColor"
1129
- viewBox="0 0 24 24"
1130
- aria-hidden="true"
1131
- >
1132
- <path
1133
- strokeLinecap="round"
1134
- strokeLinejoin="round"
1135
- strokeWidth={2}
1136
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1137
- />
1138
- </svg>
1139
- </a>
1140
- </div>
1141
- )}
960
+ {/* Origin Deposit Address */}
961
+ {quote?.originDepositAddress && (
962
+ <div className="flex justify-between items-center">
963
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
964
+ Origin Deposit Address
965
+ <Tooltip message="This is the intent address to deposit to that will then execute the swap and/or bridge">
966
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
967
+ </Tooltip>
968
+ </span>
969
+ <a
970
+ href={getExplorerUrlForAddress({
971
+ address: quote.originDepositAddress,
972
+ chainId: quote.originChain.id,
973
+ })}
974
+ target="_blank"
975
+ rel="noopener noreferrer"
976
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-blue-500"
977
+ >
978
+ {truncateAddress(quote.originDepositAddress)}
979
+ <svg
980
+ className="w-3 h-3"
981
+ fill="none"
982
+ stroke="currentColor"
983
+ viewBox="0 0 24 24"
984
+ aria-hidden="true"
985
+ >
986
+ <path
987
+ strokeLinecap="round"
988
+ strokeLinejoin="round"
989
+ strokeWidth={2}
990
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
991
+ />
992
+ </svg>
993
+ </a>
994
+ </div>
995
+ )}
1142
996
 
1143
- {/* Destination Target Address */}
1144
- {quote?.destinationAddress && (
1145
- <div className="flex justify-between items-center">
1146
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1147
- Destination Target Address:
1148
- <Tooltip message="This is the final execution address or recipient address">
1149
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1150
- </Tooltip>
1151
- </span>
1152
- <a
1153
- href={getExplorerUrlForAddress({
1154
- address: quote.destinationAddress,
1155
- chainId: quote.destinationChain.id,
1156
- })}
1157
- target="_blank"
1158
- rel="noopener noreferrer"
1159
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
997
+ {/* Destination Deposit Address */}
998
+ {quote?.destinationDepositAddress &&
999
+ quote?.destinationDepositAddress !==
1000
+ quote?.originDepositAddress && (
1001
+ <div className="flex justify-between items-center">
1002
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1003
+ Destination Deposit Address
1004
+ <Tooltip message="This is the address that will receive the tokens after any swap and/or bridge from the origin chain">
1005
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1006
+ </Tooltip>
1007
+ </span>
1008
+ <a
1009
+ href={getExplorerUrlForAddress({
1010
+ address: quote.destinationDepositAddress,
1011
+ chainId: quote.destinationChain.id,
1012
+ })}
1013
+ target="_blank"
1014
+ rel="noopener noreferrer"
1015
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-blue-500"
1016
+ >
1017
+ {truncateAddress(quote.destinationDepositAddress)}
1018
+ <svg
1019
+ className="w-3 h-3"
1020
+ fill="none"
1021
+ stroke="currentColor"
1022
+ viewBox="0 0 24 24"
1023
+ aria-hidden="true"
1160
1024
  >
1161
- {truncateAddress(quote.destinationAddress)}
1162
- <svg
1163
- className="w-3 h-3"
1164
- fill="none"
1165
- stroke="currentColor"
1166
- viewBox="0 0 24 24"
1167
- aria-hidden="true"
1168
- >
1169
- <path
1170
- strokeLinecap="round"
1171
- strokeLinejoin="round"
1172
- strokeWidth={2}
1173
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1174
- />
1175
- </svg>
1176
- </a>
1177
- </div>
1178
- )}
1025
+ <path
1026
+ strokeLinecap="round"
1027
+ strokeLinejoin="round"
1028
+ strokeWidth={2}
1029
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1030
+ />
1031
+ </svg>
1032
+ </a>
1033
+ </div>
1034
+ )}
1179
1035
 
1180
- {/* Custom Calldata */}
1181
- {quote?.destinationCalldata && (
1182
- <div className="space-y-2">
1183
- <button
1184
- type="button"
1185
- onClick={() => {
1186
- setShowCalldata(!showCalldata)
1187
- // Auto-scroll to calldata when expanding
1188
- if (!showCalldata) {
1189
- setTimeout(() => {
1190
- if (calldataRef.current) {
1191
- calldataRef.current.scrollIntoView({
1192
- behavior: "smooth",
1193
- block: "nearest",
1194
- })
1195
- }
1196
- }, 150) // Delay to let the expansion animation start
1036
+ {/* Destination Target Address */}
1037
+ {quote?.destinationAddress && (
1038
+ <div className="flex justify-between items-center">
1039
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1040
+ Destination Target Address
1041
+ <Tooltip message="This is the final execution address or recipient address">
1042
+ <Info className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1043
+ </Tooltip>
1044
+ </span>
1045
+ <a
1046
+ href={getExplorerUrlForAddress({
1047
+ address: quote.destinationAddress,
1048
+ chainId: quote.destinationChain.id,
1049
+ })}
1050
+ target="_blank"
1051
+ rel="noopener noreferrer"
1052
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-blue-500"
1053
+ >
1054
+ {truncateAddress(quote.destinationAddress)}
1055
+ <svg
1056
+ className="w-3 h-3"
1057
+ fill="none"
1058
+ stroke="currentColor"
1059
+ viewBox="0 0 24 24"
1060
+ aria-hidden="true"
1061
+ >
1062
+ <path
1063
+ strokeLinecap="round"
1064
+ strokeLinejoin="round"
1065
+ strokeWidth={2}
1066
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1067
+ />
1068
+ </svg>
1069
+ </a>
1070
+ </div>
1071
+ )}
1072
+
1073
+ {/* Custom Calldata */}
1074
+ {quote?.destinationCalldata && (
1075
+ <div className="space-y-2">
1076
+ <button
1077
+ type="button"
1078
+ onClick={() => {
1079
+ setShowCalldata(!showCalldata)
1080
+ // Auto-scroll to calldata when expanding
1081
+ if (!showCalldata) {
1082
+ setTimeout(() => {
1083
+ if (calldataRef.current) {
1084
+ calldataRef.current.scrollIntoView({
1085
+ behavior: "smooth",
1086
+ block: "nearest",
1087
+ })
1197
1088
  }
1198
- }}
1199
- className="flex items-center gap-1 text-xs hover:underline cursor-pointer transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
1200
- aria-label={
1201
- showCalldata
1202
- ? "Hide custom calldata"
1203
- : "Show custom calldata"
1204
- }
1205
- >
1206
- <span className="text-[10px]">
1207
- Includes custom destination calldata
1208
- </span>
1209
- <svg
1210
- className={`w-3 h-3 transition-transform duration-300 ease-out ${
1211
- showCalldata ? "rotate-180" : ""
1212
- }`}
1213
- fill="none"
1214
- stroke="currentColor"
1215
- viewBox="0 0 24 24"
1216
- aria-hidden="true"
1217
- >
1218
- <path
1219
- strokeLinecap="round"
1220
- strokeLinejoin="round"
1221
- strokeWidth={2}
1222
- d="M19 9l-7 7-7-7"
1223
- />
1224
- </svg>
1225
- </button>
1226
- <div
1227
- ref={calldataRef}
1228
- className={`overflow-hidden transition-all duration-300 ease-out ${
1229
- showCalldata
1230
- ? "max-h-32 opacity-100"
1231
- : "max-h-0 opacity-0"
1232
- }`}
1233
- >
1234
- <div className="mt-2">
1235
- <textarea
1236
- value={quote.destinationCalldata}
1237
- readOnly
1238
- className={`w-full p-2 text-xs font-mono rounded border border-solid resize-none transition-all duration-200 bg-gray-100 dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-800 dark:text-gray-200`}
1239
- rows={4}
1240
- placeholder="No custom calldata"
1241
- />
1242
- </div>
1243
- </div>
1089
+ }, 150) // Delay to let the expansion animation start
1090
+ }
1091
+ }}
1092
+ className="flex items-center gap-1 text-xs hover:underline cursor-pointer transition-colors duration-200 text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
1093
+ aria-label={
1094
+ showCalldata
1095
+ ? "Hide custom calldata"
1096
+ : "Show custom calldata"
1097
+ }
1098
+ >
1099
+ <span className="text-[10px]">
1100
+ Includes custom destination calldata
1101
+ </span>
1102
+ <svg
1103
+ className={`w-3 h-3 transition-transform duration-300 ease-out ${
1104
+ showCalldata ? "rotate-180" : ""
1105
+ }`}
1106
+ fill="none"
1107
+ stroke="currentColor"
1108
+ viewBox="0 0 24 24"
1109
+ aria-hidden="true"
1110
+ >
1111
+ <path
1112
+ strokeLinecap="round"
1113
+ strokeLinejoin="round"
1114
+ strokeWidth={2}
1115
+ d="M19 9l-7 7-7-7"
1116
+ />
1117
+ </svg>
1118
+ </button>
1119
+ <div
1120
+ ref={calldataRef}
1121
+ className={`overflow-hidden transition-all duration-300 ease-out ${
1122
+ showCalldata
1123
+ ? "max-h-32 opacity-100"
1124
+ : "max-h-0 opacity-0"
1125
+ }`}
1126
+ >
1127
+ <div className="mt-2">
1128
+ <textarea
1129
+ value={quote.destinationCalldata}
1130
+ readOnly
1131
+ className={`w-full p-2 text-xs font-mono rounded border border-solid resize-none transition-all duration-200 bg-gray-100 dark:bg-gray-700 border-gray-300 dark:border-gray-600 text-gray-800 dark:text-gray-200`}
1132
+ rows={4}
1133
+ placeholder="No custom calldata"
1134
+ />
1244
1135
  </div>
1245
- )}
1246
-
1247
- {/* Children content */}
1248
- {children && <div className="mb-0">{children}</div>}
1136
+ </div>
1249
1137
  </div>
1250
- </div>
1138
+ )}
1139
+
1140
+ {/* Children content */}
1141
+ {children && <div className="mb-0">{children}</div>}
1251
1142
  </div>
1252
1143
  </div>
1253
1144
  </div>