0xtrails 0.2.6 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. package/dist/aave.d.ts +2 -0
  2. package/dist/aave.d.ts.map +1 -1
  3. package/dist/{ccip-Xjh9d1gb.js → ccip-BpQGQiWq.js} +7 -7
  4. package/dist/config.d.ts +0 -5
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/constants.d.ts +2 -4
  7. package/dist/constants.d.ts.map +1 -1
  8. package/dist/error.d.ts +4 -1
  9. package/dist/error.d.ts.map +1 -1
  10. package/dist/fees.d.ts +2 -2
  11. package/dist/fees.d.ts.map +1 -1
  12. package/dist/{index-BnhdZ8Ho.js → index-DsJM5F-V.js} +46084 -48697
  13. package/dist/index.d.ts +9 -8
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +741 -923
  16. package/dist/intentReceiptMonitor.d.ts +24 -0
  17. package/dist/intentReceiptMonitor.d.ts.map +1 -0
  18. package/dist/intentReceiptPoller.d.ts +69 -0
  19. package/dist/intentReceiptPoller.d.ts.map +1 -0
  20. package/dist/intents.d.ts +15 -11
  21. package/dist/intents.d.ts.map +1 -1
  22. package/dist/morpho.d.ts +6 -5
  23. package/dist/morpho.d.ts.map +1 -1
  24. package/dist/mutations.d.ts +16 -0
  25. package/dist/mutations.d.ts.map +1 -0
  26. package/dist/preconditions.d.ts +5 -4
  27. package/dist/preconditions.d.ts.map +1 -1
  28. package/dist/prepareSend.d.ts +5 -190
  29. package/dist/prepareSend.d.ts.map +1 -1
  30. package/dist/prices.d.ts +9 -6
  31. package/dist/prices.d.ts.map +1 -1
  32. package/dist/sequenceWallet.d.ts +3 -16
  33. package/dist/sequenceWallet.d.ts.map +1 -1
  34. package/dist/tokenBalances.d.ts +17 -13
  35. package/dist/tokenBalances.d.ts.map +1 -1
  36. package/dist/trails.d.ts +24 -40
  37. package/dist/trails.d.ts.map +1 -1
  38. package/dist/trailsClient.d.ts +5 -6
  39. package/dist/trailsClient.d.ts.map +1 -1
  40. package/dist/transactionIntent/constants.d.ts +7 -0
  41. package/dist/transactionIntent/constants.d.ts.map +1 -0
  42. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +44 -0
  43. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -0
  44. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +30 -0
  45. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -0
  46. package/dist/transactionIntent/deposits/index.d.ts +4 -0
  47. package/dist/transactionIntent/deposits/index.d.ts.map +1 -0
  48. package/dist/transactionIntent/deposits/standardDeposit.d.ts +30 -0
  49. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -0
  50. package/dist/transactionIntent/execution/index.d.ts +2 -0
  51. package/dist/transactionIntent/execution/index.d.ts.map +1 -0
  52. package/dist/transactionIntent/execution/transactionState.d.ts +5 -0
  53. package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -0
  54. package/dist/transactionIntent/handlers/crossChain.d.ts +82 -0
  55. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -0
  56. package/dist/transactionIntent/handlers/index.d.ts +4 -0
  57. package/dist/transactionIntent/handlers/index.d.ts.map +1 -0
  58. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +62 -0
  59. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +1 -0
  60. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +72 -0
  61. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -0
  62. package/dist/transactionIntent/index.d.ts +9 -0
  63. package/dist/transactionIntent/index.d.ts.map +1 -0
  64. package/dist/transactionIntent/quote/feeExtractors.d.ts +17 -0
  65. package/dist/transactionIntent/quote/feeExtractors.d.ts.map +1 -0
  66. package/dist/transactionIntent/quote/index.d.ts +4 -0
  67. package/dist/transactionIntent/quote/index.d.ts.map +1 -0
  68. package/dist/transactionIntent/quote/normalizeQuote.d.ts +34 -0
  69. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -0
  70. package/dist/transactionIntent/quote/quoteHelpers.d.ts +5 -0
  71. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -0
  72. package/dist/transactionIntent/types.d.ts +131 -0
  73. package/dist/transactionIntent/types.d.ts.map +1 -0
  74. package/dist/transactionIntent/utils/balanceChecker.d.ts +18 -0
  75. package/dist/transactionIntent/utils/balanceChecker.d.ts.map +1 -0
  76. package/dist/transactionIntent/utils/index.d.ts +4 -0
  77. package/dist/transactionIntent/utils/index.d.ts.map +1 -0
  78. package/dist/transactionIntent/utils/lifiHelpers.d.ts +10 -0
  79. package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +1 -0
  80. package/dist/transactionIntent/utils/testnetHelpers.d.ts +3 -0
  81. package/dist/transactionIntent/utils/testnetHelpers.d.ts.map +1 -0
  82. package/dist/transactionIntent/validators.d.ts +6 -0
  83. package/dist/transactionIntent/validators.d.ts.map +1 -0
  84. package/dist/transactions.d.ts +2 -1
  85. package/dist/transactions.d.ts.map +1 -1
  86. package/dist/widget/components/AccountSettings.d.ts.map +1 -1
  87. package/dist/widget/components/ClassicSwap.d.ts +0 -1
  88. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  89. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  90. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  91. package/dist/widget/components/DynamicSizeInputField.d.ts +13 -0
  92. package/dist/widget/components/DynamicSizeInputField.d.ts.map +1 -0
  93. package/dist/widget/components/Earn.d.ts +0 -1
  94. package/dist/widget/components/Earn.d.ts.map +1 -1
  95. package/dist/widget/components/FeeOptions.d.ts +5 -13
  96. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  97. package/dist/widget/components/Fund.d.ts +0 -1
  98. package/dist/widget/components/Fund.d.ts.map +1 -1
  99. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  100. package/dist/widget/components/FundSwap.d.ts +0 -1
  101. package/dist/widget/components/FundSwap.d.ts.map +1 -1
  102. package/dist/widget/components/Pay.d.ts +0 -1
  103. package/dist/widget/components/Pay.d.ts.map +1 -1
  104. package/dist/widget/components/PoolDeposit.d.ts +0 -1
  105. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  106. package/dist/widget/components/PoolWithdraw.d.ts +0 -18
  107. package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
  108. package/dist/widget/components/QuoteDetails.d.ts +1 -0
  109. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  110. package/dist/widget/components/Swap.d.ts +0 -1
  111. package/dist/widget/components/Swap.d.ts.map +1 -1
  112. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  113. package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
  114. package/dist/widget/css/compiled.css +2 -2
  115. package/dist/widget/hooks/useCheckout.d.ts +17 -4
  116. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  117. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
  118. package/dist/widget/hooks/useQuote.d.ts +3 -4
  119. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  120. package/dist/widget/hooks/useSelectedFeeToken.d.ts +1 -0
  121. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
  122. package/dist/widget/hooks/useSendForm.d.ts +3 -4
  123. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  124. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  125. package/dist/widget/hooks/useWalletConnectionContext.d.ts +25 -0
  126. package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -0
  127. package/dist/widget/index.js +1 -1
  128. package/dist/widget/widget.d.ts +12 -7
  129. package/dist/widget/widget.d.ts.map +1 -1
  130. package/package.json +21 -23
  131. package/src/aave.ts +54 -1
  132. package/src/config.ts +57 -58
  133. package/src/constants.ts +8 -9
  134. package/src/error.ts +21 -3
  135. package/src/fees.ts +53 -42
  136. package/src/index.ts +35 -13
  137. package/src/intentReceiptMonitor.ts +102 -0
  138. package/src/intentReceiptPoller.ts +299 -0
  139. package/src/intents.ts +206 -172
  140. package/src/morpho.ts +58 -9
  141. package/src/mutations.ts +129 -0
  142. package/src/preconditions.ts +16 -21
  143. package/src/prepareSend.ts +80 -4514
  144. package/src/prices.ts +26 -22
  145. package/src/relaySdk.ts +2 -2
  146. package/src/sequenceWallet.ts +6 -73
  147. package/src/tokenBalances.ts +175 -69
  148. package/src/trails.ts +230 -722
  149. package/src/trailsClient.ts +10 -23
  150. package/src/transactionIntent/constants.ts +11 -0
  151. package/src/transactionIntent/deposits/depositOrchestrator.ts +210 -0
  152. package/src/transactionIntent/deposits/gaslessDeposit.ts +588 -0
  153. package/src/transactionIntent/deposits/index.ts +3 -0
  154. package/src/transactionIntent/deposits/standardDeposit.ts +379 -0
  155. package/src/transactionIntent/execution/index.ts +1 -0
  156. package/src/transactionIntent/execution/transactionState.ts +35 -0
  157. package/src/transactionIntent/handlers/crossChain.ts +1707 -0
  158. package/src/transactionIntent/handlers/index.ts +3 -0
  159. package/src/transactionIntent/handlers/sameChainDifferentToken.ts +323 -0
  160. package/src/transactionIntent/handlers/sameChainSameToken.ts +712 -0
  161. package/src/transactionIntent/index.ts +9 -0
  162. package/src/transactionIntent/quote/feeExtractors.ts +81 -0
  163. package/src/transactionIntent/quote/index.ts +3 -0
  164. package/src/transactionIntent/quote/normalizeQuote.ts +367 -0
  165. package/src/transactionIntent/quote/quoteHelpers.ts +53 -0
  166. package/src/transactionIntent/types.ts +157 -0
  167. package/src/transactionIntent/utils/balanceChecker.ts +96 -0
  168. package/src/transactionIntent/utils/index.ts +3 -0
  169. package/src/transactionIntent/utils/lifiHelpers.ts +68 -0
  170. package/src/transactionIntent/utils/testnetHelpers.ts +10 -0
  171. package/src/transactionIntent/validators.ts +57 -0
  172. package/src/transactions.ts +36 -53
  173. package/src/widget/compiled.css +2 -2
  174. package/src/widget/components/AccountIntentTransactionHistory.tsx +36 -36
  175. package/src/widget/components/AccountSettings.tsx +23 -6
  176. package/src/widget/components/ClassicSwap.tsx +28 -53
  177. package/src/widget/components/ConfigDisplay.tsx +0 -11
  178. package/src/widget/components/ConnectedWallets.tsx +30 -4
  179. package/src/widget/components/DynamicSizeInputField.tsx +109 -0
  180. package/src/widget/components/Earn.tsx +0 -16
  181. package/src/widget/components/FeeBreakdown.tsx +3 -3
  182. package/src/widget/components/FeeOption.tsx +2 -2
  183. package/src/widget/components/FeeOptions.tsx +151 -112
  184. package/src/widget/components/Fund.tsx +0 -3
  185. package/src/widget/components/FundMethods.tsx +4 -3
  186. package/src/widget/components/FundSwap.tsx +0 -1
  187. package/src/widget/components/Pay.tsx +11 -16
  188. package/src/widget/components/PoolDeposit.tsx +35 -32
  189. package/src/widget/components/PoolWithdraw.tsx +153 -256
  190. package/src/widget/components/QuoteDetails.tsx +899 -494
  191. package/src/widget/components/Swap.tsx +0 -1
  192. package/src/widget/components/TransferPendingVertical.tsx +12 -8
  193. package/src/widget/components/WaasFeeOptions.tsx +23 -7
  194. package/src/widget/components/WalletConfirmation.tsx +1 -1
  195. package/src/widget/hooks/useAmountUsd.ts +9 -9
  196. package/src/widget/hooks/useCheckout.ts +97 -9
  197. package/src/widget/hooks/useDefaultTokenSelection.tsx +27 -21
  198. package/src/widget/hooks/useQuote.ts +86 -33
  199. package/src/widget/hooks/useSelectedFeeToken.tsx +32 -37
  200. package/src/widget/hooks/useSendForm.ts +37 -47
  201. package/src/widget/hooks/useTokenList.ts +34 -26
  202. package/src/widget/hooks/useWalletConnectionContext.tsx +128 -0
  203. package/src/widget/widget.tsx +197 -207
  204. package/dist/apiClient.d.ts +0 -9
  205. package/dist/apiClient.d.ts.map +0 -1
  206. package/dist/intentEntrypoint.d.ts +0 -114
  207. package/dist/intentEntrypoint.d.ts.map +0 -1
  208. package/dist/metaTxnMonitor.d.ts +0 -15
  209. package/dist/metaTxnMonitor.d.ts.map +0 -1
  210. package/dist/metaTxns.d.ts +0 -11
  211. package/dist/metaTxns.d.ts.map +0 -1
  212. package/dist/relayer.d.ts +0 -43
  213. package/dist/relayer.d.ts.map +0 -1
  214. package/src/apiClient.ts +0 -35
  215. package/src/intentEntrypoint.ts +0 -203
  216. package/src/metaTxnMonitor.ts +0 -171
  217. package/src/metaTxns.ts +0 -45
  218. package/src/relayer.ts +0 -289
@@ -1,4 +1,5 @@
1
1
  import { TokenImage } from "./TokenImage.js"
2
+ import { ChainImage } from "./ChainImage.js"
2
3
  import { InfoIcon } from "@0xsequence/design-system"
3
4
  import { Tooltip } from "./Tooltip.js"
4
5
  import type React from "react"
@@ -8,7 +9,7 @@ import { useState, useEffect, useRef } from "react"
8
9
  import { truncateAddress } from "../../utils.js"
9
10
  import { PriceImpactWarning } from "./PriceImpactWarning.js"
10
11
  import { usePriceImpactWarning } from "../hooks/usePriceImpactWarning.js"
11
- import { FeeBreakdown } from "./FeeBreakdown.js"
12
+ import { formatUsdAmountDisplay } from "../../tokenBalances.js"
12
13
 
13
14
  interface QuoteDetailsProps {
14
15
  quote?: PrepareSendQuote | null
@@ -17,6 +18,7 @@ interface QuoteDetailsProps {
17
18
  onExpand?: (isExpanded: boolean) => void
18
19
  swapMode?: boolean
19
20
  compact?: boolean
21
+ isRefetching?: boolean
20
22
  }
21
23
 
22
24
  // Helper function to format completion time
@@ -48,12 +50,15 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
48
50
  onExpand,
49
51
  swapMode,
50
52
  compact = false,
53
+ isRefetching = false,
51
54
  }) => {
52
55
  const [showCalldata, setShowCalldata] = useState(false)
53
56
  const [showOriginRate, setShowOriginRate] = useState(true)
54
57
  const [isExpanded, setIsExpanded] = useState(false)
58
+ const [showMoreInfo, setShowMoreInfo] = useState(false)
55
59
  const containerRef = useRef<HTMLDivElement>(null)
56
60
  const calldataRef = useRef<HTMLDivElement>(null)
61
+ const moreInfoRef = useRef<HTMLDivElement>(null)
57
62
 
58
63
  const priceImpactConfig = usePriceImpactWarning()
59
64
 
@@ -76,7 +81,9 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
76
81
  if (!showContent) return null
77
82
 
78
83
  return (
79
- <div className="relative">
84
+ <div
85
+ className={`relative transition-opacity duration-300 ${isRefetching ? "opacity-50" : ""}`}
86
+ >
80
87
  {/* Price Impact Warning - always visible when conditions are met */}
81
88
  <PriceImpactWarning
82
89
  quote={quote}
@@ -85,6 +92,35 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
85
92
  fallbackBridgeUrl={priceImpactConfig.fallbackBridgeUrl}
86
93
  />
87
94
 
95
+ {/* Insufficient Balance Warning - always visible when conditions are met */}
96
+ {quote?.noSufficientBalance && (
97
+ <div className="flex justify-between items-center mb-2 p-2 bg-amber-50 dark:bg-amber-900/20 rounded-lg">
98
+ <span className="text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
99
+ Balance Status:
100
+ <Tooltip message="Your wallet does not have sufficient balance to complete this transaction">
101
+ <InfoIcon className="w-3 h-3 text-amber-500 dark:text-amber-400 cursor-pointer" />
102
+ </Tooltip>
103
+ </span>
104
+ <span className="font-medium text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
105
+ <svg
106
+ className="w-3 h-3"
107
+ fill="none"
108
+ stroke="currentColor"
109
+ viewBox="0 0 24 24"
110
+ aria-hidden="true"
111
+ >
112
+ <path
113
+ strokeLinecap="round"
114
+ strokeLinejoin="round"
115
+ strokeWidth={2}
116
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
117
+ />
118
+ </svg>
119
+ Insufficient Balance
120
+ </span>
121
+ </div>
122
+ )}
123
+
88
124
  {/* More Details Button - only visible when collapsed */}
89
125
  {!isExpanded && (
90
126
  <div className={`flex justify-center`}>
@@ -248,54 +284,7 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
248
284
  )}
249
285
  </div>
250
286
  <div className="space-y-3">
251
- {/* Insufficient Balance Warning */}
252
- {quote?.noSufficientBalance && (
253
- <div className="flex justify-between items-center">
254
- <span className="text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
255
- Balance Status:
256
- <Tooltip message="Your wallet does not have sufficient balance to complete this transaction">
257
- <InfoIcon className="w-3 h-3 text-amber-500 dark:text-amber-400 cursor-pointer" />
258
- </Tooltip>
259
- </span>
260
- <span className="font-medium text-xs text-amber-600 dark:text-amber-400 flex items-center gap-1">
261
- <svg
262
- className="w-3 h-3"
263
- fill="none"
264
- stroke="currentColor"
265
- viewBox="0 0 24 24"
266
- aria-hidden="true"
267
- >
268
- <path
269
- strokeLinecap="round"
270
- strokeLinejoin="round"
271
- strokeWidth={2}
272
- d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
273
- />
274
- </svg>
275
- Insufficient Balance
276
- </span>
277
- </div>
278
- )}
279
-
280
- {quote?.originTokenRate && quote?.destinationTokenRate && (
281
- <div className="flex justify-between items-center">
282
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
283
- Exchange Rate:
284
- <Tooltip message="The current exchange rate between the origin and destination tokens">
285
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
286
- </Tooltip>
287
- </span>
288
- <button
289
- type="button"
290
- onClick={() => setShowOriginRate(!showOriginRate)}
291
- className="font-medium text-xs hover:underline cursor-pointer text-gray-900 hover:text-gray-700 dark:text-white dark:hover:text-gray-300"
292
- >
293
- {showOriginRate
294
- ? quote.originTokenRate
295
- : quote.destinationTokenRate}
296
- </button>
297
- </div>
298
- )}
287
+ {/* Estimated Time */}
299
288
  {quote?.completionEstimateSeconds != null && (
300
289
  <div className="flex justify-between items-center">
301
290
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
@@ -324,480 +313,896 @@ export const QuoteDetails: React.FC<QuoteDetailsProps> = ({
324
313
  </div>
325
314
  )}
326
315
 
327
- {quote?.gasCostUsd != null && quote?.gasCostUsd > 0 && (
328
- <div className="flex justify-between items-center">
329
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
330
- Network Cost:
331
- <Tooltip message="The estimated gas cost for executing this transaction on the origin chain">
332
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
333
- </Tooltip>
334
- </span>
335
- <span className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1">
336
- <svg
337
- aria-hidden="true"
338
- focusable="false"
339
- data-prefix="fas"
340
- data-icon="gas-pump"
341
- className="svg-inline--fa fa-gas-pump "
342
- role="img"
343
- xmlns="http://www.w3.org/2000/svg"
344
- viewBox="0 0 512 512"
345
- width="12"
346
- >
347
- <path
348
- fill="currentColor"
349
- 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"
350
- ></path>
351
- </svg>
352
- {quote.gasCostUsdDisplay}
353
- </span>
354
- </div>
355
- )}
316
+ {/* Spacer */}
317
+ <div className="h-2" />
356
318
 
357
- {quote?.originAmount &&
358
- quote?.originToken.symbol &&
359
- quote?.originChain.id && (
360
- <div className="flex justify-between items-start">
361
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
362
- Origin Transfer Amount:
363
- <Tooltip message="The amount of tokens you will send from the origin chain">
364
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
365
- </Tooltip>
366
- </span>
367
- <div className="text-right">
368
- {quote.originToken.contractAddress ===
369
- "0x0000000000000000000000000000000000000000" ? (
370
- <>
371
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
372
- <TokenImage
373
- imageUrl={quote.originToken.imageUrl}
374
- symbol={quote.originToken.symbol}
375
- chainId={quote.originChain.id}
376
- contractAddress={quote.originToken.contractAddress}
377
- size={16}
319
+ {/* Gas Costs Section */}
320
+ {quote?.trailsFeeBreakdown &&
321
+ (quote?.trailsFeeBreakdown.originRelayFee ||
322
+ quote?.trailsFeeBreakdown.destinationRelayFee) && (
323
+ <>
324
+ {/* Origin Gas */}
325
+ {quote.trailsFeeBreakdown.originRelayFee && (
326
+ <div className="flex justify-between items-center">
327
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
328
+ Origin Gas
329
+ <ChainImage chainId={quote.originChain.id} size={16} />:
330
+ <Tooltip message="Gas fee for executing the transaction on the origin chain">
331
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
332
+ </Tooltip>
333
+ </span>
334
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
335
+ {quote.trailsFeeBreakdown.originRelayFee.usdValue}
336
+ </span>
337
+ </div>
338
+ )}
339
+
340
+ {/* Destination Gas */}
341
+ {quote.trailsFeeBreakdown.destinationRelayFee && (
342
+ <div className="flex justify-between items-center">
343
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
344
+ Destination Gas
345
+ <ChainImage
346
+ chainId={quote.destinationChain.id}
347
+ size={16}
348
+ />
349
+ :
350
+ <Tooltip message="Gas fee for executing the transaction on the destination chain">
351
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
352
+ </Tooltip>
353
+ </span>
354
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
355
+ {quote.trailsFeeBreakdown.destinationRelayFee.usdValue}
356
+ </span>
357
+ </div>
358
+ )}
359
+
360
+ {/* All Gas Costs */}
361
+ {(quote.trailsFeeBreakdown.originRelayFee ||
362
+ quote.trailsFeeBreakdown.destinationRelayFee) && (
363
+ <div className="flex justify-between items-center">
364
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
365
+ All gas costs:
366
+ <Tooltip message="Total gas costs for executing transactions on both origin and destination chains">
367
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
368
+ </Tooltip>
369
+ </span>
370
+ <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">
371
+ <svg
372
+ aria-hidden="true"
373
+ focusable="false"
374
+ data-prefix="fas"
375
+ data-icon="gas-pump"
376
+ className="svg-inline--fa fa-gas-pump"
377
+ role="img"
378
+ xmlns="http://www.w3.org/2000/svg"
379
+ viewBox="0 0 512 512"
380
+ width="12"
381
+ >
382
+ <path
383
+ fill="currentColor"
384
+ 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"
378
385
  />
379
- {quote.originAmountDisplay} {quote.originToken.symbol}
386
+ </svg>
387
+ {(() => {
388
+ const originGasUsd = parseFloat(
389
+ quote.trailsFeeBreakdown.originRelayFee?.usdValue?.replace(
390
+ /[^0-9.-]/g,
391
+ "",
392
+ ) || "0",
393
+ )
394
+ const destGasUsd = parseFloat(
395
+ quote.trailsFeeBreakdown.destinationRelayFee?.usdValue?.replace(
396
+ /[^0-9.-]/g,
397
+ "",
398
+ ) || "0",
399
+ )
400
+ const totalGasUsd = originGasUsd + destGasUsd
401
+ return formatUsdAmountDisplay(totalGasUsd)
402
+ })()}
403
+ </span>
404
+ </div>
405
+ )}
406
+
407
+ {/* Spacer */}
408
+ <div className="h-2" />
409
+ </>
410
+ )}
411
+
412
+ {/* Provider Costs Section */}
413
+ {(() => {
414
+ if (!quote?.trailsFeeBreakdown) return null
415
+
416
+ // Check if provider fee is non-zero
417
+ const hasProviderFee =
418
+ quote.trailsFeeBreakdown.providerFee &&
419
+ parseFloat(
420
+ quote.trailsFeeBreakdown.providerFee.usdValue?.replace(
421
+ /[^0-9.-]/g,
422
+ "",
423
+ ) || "0",
424
+ ) !== 0
425
+
426
+ // Check if trails fee is non-zero
427
+ const hasTrailsFee =
428
+ quote.trailsFeeBreakdown.trailsFee &&
429
+ parseFloat(
430
+ quote.trailsFeeBreakdown.trailsFee.usdValue?.replace(
431
+ /[^0-9.-]/g,
432
+ "",
433
+ ) || "0",
434
+ ) !== 0
435
+
436
+ if (!hasProviderFee && !hasTrailsFee) return null
437
+
438
+ return (
439
+ <>
440
+ {/* Bridge/Swap Provider Fee */}
441
+ {hasProviderFee &&
442
+ quote.trailsFeeBreakdown.providerFee &&
443
+ (() => {
444
+ const providerFee = quote.trailsFeeBreakdown.providerFee
445
+ const isCrossChain =
446
+ quote.originChain.id !== quote.destinationChain.id
447
+ const providerName = quote.quoteProvider?.name || ""
448
+
449
+ return (
450
+ <div className="flex justify-between items-center">
451
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
452
+ {isCrossChain ? (
453
+ providerName ? (
454
+ <>
455
+ Bridge (
456
+ <a
457
+ href={quote.quoteProvider?.url}
458
+ target="_blank"
459
+ rel="noopener noreferrer"
460
+ className="hover:underline flex items-center gap-0.5"
461
+ >
462
+ {providerName}
463
+ <svg
464
+ className="w-3 h-3"
465
+ fill="none"
466
+ stroke="currentColor"
467
+ viewBox="0 0 24 24"
468
+ aria-hidden="true"
469
+ >
470
+ <path
471
+ strokeLinecap="round"
472
+ strokeLinejoin="round"
473
+ strokeWidth={2}
474
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
475
+ />
476
+ </svg>
477
+ </a>
478
+ ):
479
+ </>
480
+ ) : (
481
+ <>Bridge:</>
482
+ )
483
+ ) : providerName ? (
484
+ <>
485
+ Liquidity Provider (
486
+ <a
487
+ href={quote.quoteProvider?.url}
488
+ target="_blank"
489
+ rel="noopener noreferrer"
490
+ className="hover:underline flex items-center gap-0.5"
491
+ >
492
+ {providerName}
493
+ <svg
494
+ className="w-3 h-3"
495
+ fill="none"
496
+ stroke="currentColor"
497
+ viewBox="0 0 24 24"
498
+ aria-hidden="true"
499
+ >
500
+ <path
501
+ strokeLinecap="round"
502
+ strokeLinejoin="round"
503
+ strokeWidth={2}
504
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
505
+ />
506
+ </svg>
507
+ </a>
508
+ ):
509
+ </>
510
+ ) : (
511
+ <>Liquidity Provider:</>
512
+ )}
513
+ <Tooltip message="Fee charged by the bridge/swap provider for executing the transaction">
514
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
515
+ </Tooltip>
516
+ </span>
517
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
518
+ {providerFee.usdValue}
519
+ </span>
380
520
  </div>
381
- {quote.originAmountUsdDisplay && (
382
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
383
- ≈ {quote.originAmountUsdDisplay}
384
- </div>
385
- )}
386
- </>
387
- ) : (
388
- <>
389
- <a
390
- href={getExplorerUrlForAddress({
391
- address: quote.originToken.contractAddress,
392
- chainId: quote.originChain.id,
393
- })}
394
- target="_blank"
395
- rel="noopener noreferrer"
396
- className="hover:underline cursor-pointer"
521
+ )
522
+ })()}
523
+
524
+ {/* Swap Fees (implicit costs) */}
525
+ {(() => {
526
+ // Calculate swap fees: (originAmount - destinationAmount) - totalFees
527
+ const originUsd = parseFloat(
528
+ quote.originAmountUsdDisplay?.replace(/[^0-9.-]/g, "") ||
529
+ "0",
530
+ )
531
+ const destUsd = parseFloat(
532
+ quote.destinationAmountUsdDisplay?.replace(
533
+ /[^0-9.-]/g,
534
+ "",
535
+ ) || "0",
536
+ )
537
+ const totalFeesUsd = parseFloat(
538
+ quote.fees?.totalFeeAmountUsdDisplay?.replace(
539
+ /[^0-9.-]/g,
540
+ "",
541
+ ) || "0",
542
+ )
543
+
544
+ const swapFeesUsd = originUsd - destUsd - totalFeesUsd
545
+
546
+ // Only show if swap fees > 0
547
+ if (swapFeesUsd <= 0) return null
548
+
549
+ return (
550
+ <div className="flex justify-between items-center">
551
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
552
+ Swap:
553
+ <Tooltip message="Implicit costs including DEX fees, liquidity provider fees, and routing costs">
554
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
555
+ </Tooltip>
556
+ </span>
557
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
558
+ {formatUsdAmountDisplay(swapFeesUsd)}
559
+ </span>
560
+ </div>
561
+ )
562
+ })()}
563
+
564
+ {/* Trails Platform Fee */}
565
+ {hasTrailsFee &&
566
+ quote.trailsFeeBreakdown.trailsFee &&
567
+ (() => {
568
+ const trailsFee = quote.trailsFeeBreakdown.trailsFee
569
+
570
+ return (
571
+ <div className="flex justify-between items-center">
572
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
573
+ Trails:
574
+ <Tooltip message="Platform fee for using the Trails service">
575
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
576
+ </Tooltip>
577
+ </span>
578
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
579
+ {trailsFee.usdValue}
580
+ </span>
581
+ </div>
582
+ )
583
+ })()}
584
+
585
+ {/* All Provider Costs */}
586
+ {(hasProviderFee || hasTrailsFee) &&
587
+ (() => {
588
+ const providerUsd = parseFloat(
589
+ quote.trailsFeeBreakdown.providerFee?.usdValue?.replace(
590
+ /[^0-9.-]/g,
591
+ "",
592
+ ) || "0",
593
+ )
594
+ const trailsUsd = parseFloat(
595
+ quote.trailsFeeBreakdown.trailsFee?.usdValue?.replace(
596
+ /[^0-9.-]/g,
597
+ "",
598
+ ) || "0",
599
+ )
600
+
601
+ // Calculate swap fees
602
+ const originUsd = parseFloat(
603
+ quote.originAmountUsdDisplay?.replace(
604
+ /[^0-9.-]/g,
605
+ "",
606
+ ) || "0",
607
+ )
608
+ const destUsd = parseFloat(
609
+ quote.destinationAmountUsdDisplay?.replace(
610
+ /[^0-9.-]/g,
611
+ "",
612
+ ) || "0",
613
+ )
614
+ const totalFeesUsd = parseFloat(
615
+ quote.fees?.totalFeeAmountUsdDisplay?.replace(
616
+ /[^0-9.-]/g,
617
+ "",
618
+ ) || "0",
619
+ )
620
+ const swapFeesUsd = Math.max(
621
+ 0,
622
+ originUsd - destUsd - totalFeesUsd,
623
+ )
624
+
625
+ const totalProviderUsd =
626
+ providerUsd + trailsUsd + swapFeesUsd
627
+
628
+ return (
629
+ <div className="flex justify-between items-center">
630
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
631
+ All provider costs:
632
+ <Tooltip message="Total fees charged by providers, including bridge/swap, platform fees, and implicit swap costs">
633
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
634
+ </Tooltip>
635
+ </span>
636
+ <span className="font-medium text-xs text-gray-900 dark:text-white pt-2 border-t border-gray-200 dark:border-gray-700">
637
+ {formatUsdAmountDisplay(totalProviderUsd)}
638
+ </span>
639
+ </div>
640
+ )
641
+ })()}
642
+
643
+ {/* Spacer */}
644
+ <div className="h-2" />
645
+
646
+ {/* Total Fees */}
647
+ {(() => {
648
+ // Calculate total gas costs
649
+ const originGasUsd = parseFloat(
650
+ quote.trailsFeeBreakdown?.originRelayFee?.usdValue?.replace(
651
+ /[^0-9.-]/g,
652
+ "",
653
+ ) || "0",
654
+ )
655
+ const destGasUsd = parseFloat(
656
+ quote.trailsFeeBreakdown?.destinationRelayFee?.usdValue?.replace(
657
+ /[^0-9.-]/g,
658
+ "",
659
+ ) || "0",
660
+ )
661
+ const totalGasUsd = originGasUsd + destGasUsd
662
+
663
+ // Calculate total provider costs (including swap fees)
664
+ const providerUsd = parseFloat(
665
+ quote.trailsFeeBreakdown?.providerFee?.usdValue?.replace(
666
+ /[^0-9.-]/g,
667
+ "",
668
+ ) || "0",
669
+ )
670
+ const trailsUsd = parseFloat(
671
+ quote.trailsFeeBreakdown?.trailsFee?.usdValue?.replace(
672
+ /[^0-9.-]/g,
673
+ "",
674
+ ) || "0",
675
+ )
676
+ const originUsd = parseFloat(
677
+ quote.originAmountUsdDisplay?.replace(/[^0-9.-]/g, "") ||
678
+ "0",
679
+ )
680
+ const destUsd = parseFloat(
681
+ quote.destinationAmountUsdDisplay?.replace(
682
+ /[^0-9.-]/g,
683
+ "",
684
+ ) || "0",
685
+ )
686
+ const totalFeesUsd = parseFloat(
687
+ quote.fees?.totalFeeAmountUsdDisplay?.replace(
688
+ /[^0-9.-]/g,
689
+ "",
690
+ ) || "0",
691
+ )
692
+ const swapFeesUsd = Math.max(
693
+ 0,
694
+ originUsd - destUsd - totalFeesUsd,
695
+ )
696
+ const totalProviderUsd =
697
+ providerUsd + trailsUsd + swapFeesUsd
698
+
699
+ // Sum of all gas costs and all provider costs
700
+ const grandTotalUsd = totalGasUsd + totalProviderUsd
701
+
702
+ if (grandTotalUsd <= 0) return null
703
+
704
+ return (
705
+ <div className="flex justify-between items-center">
706
+ <span className="text-xs font-semibold text-gray-700 dark:text-gray-300 flex items-center gap-1">
707
+ Total fees:
708
+ <Tooltip message="The total fees for this transaction, including gas costs and all provider fees">
709
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
710
+ </Tooltip>
711
+ </span>
712
+ <span className="font-semibold text-xs text-gray-900 dark:text-white">
713
+ ≈ {formatUsdAmountDisplay(grandTotalUsd)}
714
+ </span>
715
+ </div>
716
+ )
717
+ })()}
718
+
719
+ {/* Spacer */}
720
+ <div className="h-2" />
721
+ </>
722
+ )
723
+ })()}
724
+
725
+ {/* Transaction Details Section */}
726
+ {(() => {
727
+ const hasSlippage =
728
+ quote?.slippageTolerance != null &&
729
+ Number(quote.slippageTolerance) !== 0
730
+ const hasPriceImpact =
731
+ quote?.priceImpact != null && Number(quote.priceImpact) !== 0
732
+ const showSection = hasSlippage || hasPriceImpact
733
+
734
+ if (!showSection) return null
735
+
736
+ return (
737
+ <>
738
+ <div className="text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2 text-center">
739
+ Transaction details
740
+ </div>
741
+
742
+ {/* Max Slippage */}
743
+ {hasSlippage && (
744
+ <div className="flex justify-between items-center">
745
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
746
+ Max slippage:
747
+ <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.">
748
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
749
+ </Tooltip>
750
+ </span>
751
+ <span className="font-medium text-xs text-gray-900 dark:text-white">
752
+ {quote.slippageTolerance}%
753
+ </span>
754
+ </div>
755
+ )}
756
+
757
+ {/* Price Impact */}
758
+ {hasPriceImpact && (
759
+ <div className="space-y-1">
760
+ <div className="flex justify-between items-center">
761
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
762
+ Price impact:
763
+ <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.">
764
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
765
+ </Tooltip>
766
+ </span>
767
+ <span
768
+ className={`font-medium text-xs flex items-center gap-1 ${
769
+ Math.abs(Number(quote.priceImpact)) > 5
770
+ ? "text-red-600 dark:text-red-400"
771
+ : Math.abs(Number(quote.priceImpact)) > 0.5
772
+ ? "text-orange-600 dark:text-orange-400"
773
+ : "text-gray-900 dark:text-white"
774
+ }`}
397
775
  >
398
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
399
- <TokenImage
400
- imageUrl={quote.originToken.imageUrl}
401
- symbol={quote.originToken.symbol}
402
- chainId={quote.originChain.id}
403
- contractAddress={
404
- quote.originToken.contractAddress
405
- }
406
- size={16}
407
- />
408
- {quote.originAmountDisplay}{" "}
409
- {quote.originToken.symbol}
410
- </div>
411
- </a>
412
- {quote.originAmountUsdDisplay && (
413
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
414
- ≈ {quote.originAmountUsdDisplay}
415
- </div>
416
- )}
417
- </>
776
+ {Math.abs(Number(quote.priceImpact)) > 0.5 && (
777
+ <span title="High price impact">
778
+ <svg
779
+ className="w-3 h-3"
780
+ fill="none"
781
+ stroke="currentColor"
782
+ viewBox="0 0 24 24"
783
+ aria-hidden="true"
784
+ >
785
+ <path
786
+ strokeLinecap="round"
787
+ strokeLinejoin="round"
788
+ strokeWidth={2}
789
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
790
+ />
791
+ </svg>
792
+ </span>
793
+ )}
794
+ {quote.priceImpact}%
795
+ </span>
796
+ </div>
797
+ {quote.priceImpactUsdDisplay && (
798
+ <div className="text-right">
799
+ <span className="text-xs text-gray-500 dark:text-gray-400">
800
+ ≈ {quote.priceImpactUsdDisplay}
801
+ </span>
802
+ </div>
803
+ )}
804
+ </div>
805
+ )}
806
+ </>
807
+ )
808
+ })()}
809
+
810
+ {/* More Info Section */}
811
+ <div className="space-y-2">
812
+ <button
813
+ type="button"
814
+ onClick={() => {
815
+ setShowMoreInfo(!showMoreInfo)
816
+ if (!showMoreInfo) {
817
+ setTimeout(() => {
818
+ if (moreInfoRef.current) {
819
+ moreInfoRef.current.scrollIntoView({
820
+ behavior: "smooth",
821
+ block: "nearest",
822
+ })
823
+ }
824
+ }, 150)
825
+ }
826
+ }}
827
+ 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"
828
+ aria-label={showMoreInfo ? "Hide more info" : "Show more info"}
829
+ >
830
+ <span>More</span>
831
+ <svg
832
+ className={`w-3 h-3 transition-transform duration-300 ease-out ${
833
+ showMoreInfo ? "rotate-180" : ""
834
+ }`}
835
+ fill="none"
836
+ stroke="currentColor"
837
+ viewBox="0 0 24 24"
838
+ aria-hidden="true"
839
+ >
840
+ <path
841
+ strokeLinecap="round"
842
+ strokeLinejoin="round"
843
+ strokeWidth={2}
844
+ d="M19 9l-7 7-7-7"
845
+ />
846
+ </svg>
847
+ </button>
848
+
849
+ <div
850
+ ref={moreInfoRef}
851
+ className={`overflow-hidden transition-all duration-300 ease-out ${
852
+ showMoreInfo
853
+ ? "max-h-[500px] opacity-100"
854
+ : "max-h-0 opacity-0"
855
+ }`}
856
+ >
857
+ <div className="space-y-3 pt-2">
858
+ {/* Exchange Rate */}
859
+ {quote?.originTokenRate && quote?.destinationTokenRate && (
860
+ <div className="flex justify-between items-center">
861
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
862
+ Exchange Rate:
863
+ <Tooltip message="The current exchange rate between the origin and destination tokens">
864
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
865
+ </Tooltip>
866
+ </span>
867
+ <button
868
+ type="button"
869
+ onClick={() => setShowOriginRate(!showOriginRate)}
870
+ className="font-medium text-xs hover:underline cursor-pointer text-gray-900 hover:text-gray-700 dark:text-white dark:hover:text-gray-300"
871
+ >
872
+ {showOriginRate
873
+ ? quote.originTokenRate
874
+ : quote.destinationTokenRate}
875
+ </button>
876
+ </div>
877
+ )}
878
+
879
+ {/* Origin Transfer Amount */}
880
+ {quote?.originAmount &&
881
+ quote?.originToken.symbol &&
882
+ quote?.originChain.id && (
883
+ <div className="flex justify-between items-start">
884
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
885
+ Origin Transfer Amount:
886
+ <Tooltip message="The amount of tokens you will send from the origin chain">
887
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
888
+ </Tooltip>
889
+ </span>
890
+ <div className="text-right">
891
+ {quote.originToken.contractAddress ===
892
+ "0x0000000000000000000000000000000000000000" ? (
893
+ <>
894
+ <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
895
+ <TokenImage
896
+ imageUrl={quote.originToken.imageUrl}
897
+ symbol={quote.originToken.symbol}
898
+ chainId={quote.originChain.id}
899
+ contractAddress={
900
+ quote.originToken.contractAddress
901
+ }
902
+ size={16}
903
+ />
904
+ {quote.originAmountDisplay}{" "}
905
+ {quote.originToken.symbol}
906
+ </div>
907
+ {quote.originAmountUsdDisplay && (
908
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
909
+ ≈ {quote.originAmountUsdDisplay}
910
+ </div>
911
+ )}
912
+ </>
913
+ ) : (
914
+ <>
915
+ <a
916
+ href={getExplorerUrlForAddress({
917
+ address: quote.originToken.contractAddress,
918
+ chainId: quote.originChain.id,
919
+ })}
920
+ target="_blank"
921
+ rel="noopener noreferrer"
922
+ className="hover:underline cursor-pointer"
923
+ >
924
+ <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
925
+ <TokenImage
926
+ imageUrl={quote.originToken.imageUrl}
927
+ symbol={quote.originToken.symbol}
928
+ chainId={quote.originChain.id}
929
+ contractAddress={
930
+ quote.originToken.contractAddress
931
+ }
932
+ size={16}
933
+ />
934
+ {quote.originAmountDisplay}{" "}
935
+ {quote.originToken.symbol}
936
+ </div>
937
+ </a>
938
+ {quote.originAmountUsdDisplay && (
939
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
940
+ ≈ {quote.originAmountUsdDisplay}
941
+ </div>
942
+ )}
943
+ </>
944
+ )}
945
+ </div>
946
+ </div>
418
947
  )}
419
- </div>
420
- </div>
421
- )}
422
948
 
423
- {quote?.destinationToken.symbol &&
424
- quote?.destinationAmount &&
425
- quote?.destinationAmountUsdDisplay &&
426
- quote?.destinationChain.id && (
427
- <div className="flex justify-between items-start">
428
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
429
- Destination Target Amount:
430
- <Tooltip message="The amount of tokens you will receive on the destination chain after the swap and/or bridge">
431
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
432
- </Tooltip>
433
- </span>
434
- <div className="text-right">
435
- {quote.destinationToken.contractAddress ===
436
- "0x0000000000000000000000000000000000000000" ? (
437
- <>
438
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
439
- <TokenImage
440
- imageUrl={quote.destinationToken.imageUrl}
441
- symbol={quote.destinationToken.symbol}
442
- chainId={quote.destinationChain.id}
443
- contractAddress={
444
- quote.destinationToken.contractAddress
445
- }
446
- size={16}
447
- />
448
- {quote.destinationAmountDisplay}{" "}
449
- {quote.destinationToken.symbol}
949
+ {/* Destination Target Amount */}
950
+ {quote?.destinationToken.symbol &&
951
+ quote?.destinationAmount &&
952
+ quote?.destinationAmountUsdDisplay &&
953
+ quote?.destinationChain.id && (
954
+ <div className="flex justify-between items-start">
955
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
956
+ Destination Target Amount:
957
+ <Tooltip message="The amount of tokens you will receive on the destination chain after the swap and/or bridge">
958
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
959
+ </Tooltip>
960
+ </span>
961
+ <div className="text-right">
962
+ {quote.destinationToken.contractAddress ===
963
+ "0x0000000000000000000000000000000000000000" ? (
964
+ <>
965
+ <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
966
+ <TokenImage
967
+ imageUrl={quote.destinationToken.imageUrl}
968
+ symbol={quote.destinationToken.symbol}
969
+ chainId={quote.destinationChain.id}
970
+ contractAddress={
971
+ quote.destinationToken.contractAddress
972
+ }
973
+ size={16}
974
+ />
975
+ {quote.destinationAmountDisplay}{" "}
976
+ {quote.destinationToken.symbol}
977
+ </div>
978
+ {quote.destinationAmountUsdDisplay && (
979
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
980
+ ≈ {quote.destinationAmountUsdDisplay}
981
+ </div>
982
+ )}
983
+ </>
984
+ ) : (
985
+ <>
986
+ <a
987
+ href={getExplorerUrlForAddress({
988
+ address:
989
+ quote.destinationToken.contractAddress,
990
+ chainId: quote.destinationChain.id,
991
+ })}
992
+ target="_blank"
993
+ rel="noopener noreferrer"
994
+ className="hover:underline cursor-pointer"
995
+ >
996
+ <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
997
+ <TokenImage
998
+ imageUrl={quote.destinationToken.imageUrl}
999
+ symbol={quote.destinationToken.symbol}
1000
+ chainId={quote.destinationChain.id}
1001
+ contractAddress={
1002
+ quote.destinationToken.contractAddress
1003
+ }
1004
+ size={16}
1005
+ />
1006
+ {quote.destinationAmountDisplay}{" "}
1007
+ {quote.destinationToken.symbol}
1008
+ </div>
1009
+ </a>
1010
+ {quote.destinationAmountUsdDisplay && (
1011
+ <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
1012
+ ≈ {quote.destinationAmountUsdDisplay}
1013
+ </div>
1014
+ )}
1015
+ </>
1016
+ )}
450
1017
  </div>
451
- {quote.destinationAmountUsdDisplay && (
452
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
453
- ≈ {quote.destinationAmountUsdDisplay}
454
- </div>
455
- )}
456
- </>
457
- ) : (
458
- <>
1018
+ </div>
1019
+ )}
1020
+
1021
+ {/* Origin Deposit Address */}
1022
+ {quote?.originDepositAddress && (
1023
+ <div className="flex justify-between items-center">
1024
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1025
+ Origin Deposit Address:
1026
+ <Tooltip message="This is the intent address to deposit to that will then execute the swap and/or bridge">
1027
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1028
+ </Tooltip>
1029
+ </span>
1030
+ <a
1031
+ href={getExplorerUrlForAddress({
1032
+ address: quote.originDepositAddress,
1033
+ chainId: quote.originChain.id,
1034
+ })}
1035
+ target="_blank"
1036
+ rel="noopener noreferrer"
1037
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
1038
+ >
1039
+ {truncateAddress(quote.originDepositAddress)}
1040
+ <svg
1041
+ className="w-3 h-3"
1042
+ fill="none"
1043
+ stroke="currentColor"
1044
+ viewBox="0 0 24 24"
1045
+ aria-hidden="true"
1046
+ >
1047
+ <path
1048
+ strokeLinecap="round"
1049
+ strokeLinejoin="round"
1050
+ strokeWidth={2}
1051
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1052
+ />
1053
+ </svg>
1054
+ </a>
1055
+ </div>
1056
+ )}
1057
+
1058
+ {/* Destination Deposit Address */}
1059
+ {quote?.destinationDepositAddress &&
1060
+ quote?.destinationDepositAddress !==
1061
+ quote?.originDepositAddress && (
1062
+ <div className="flex justify-between items-center">
1063
+ <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
1064
+ Destination Deposit Address:
1065
+ <Tooltip message="This is the address that will receive the tokens after any swap and/or bridge from the origin chain">
1066
+ <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
1067
+ </Tooltip>
1068
+ </span>
459
1069
  <a
460
1070
  href={getExplorerUrlForAddress({
461
- address: quote.destinationToken.contractAddress,
1071
+ address: quote.destinationDepositAddress,
462
1072
  chainId: quote.destinationChain.id,
463
1073
  })}
464
1074
  target="_blank"
465
1075
  rel="noopener noreferrer"
466
- className="hover:underline cursor-pointer"
1076
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
467
1077
  >
468
- <div className="font-medium text-xs text-gray-900 dark:text-white flex items-center gap-1 justify-end">
469
- <TokenImage
470
- imageUrl={quote.destinationToken.imageUrl}
471
- symbol={quote.destinationToken.symbol}
472
- chainId={quote.destinationChain.id}
473
- contractAddress={
474
- quote.destinationToken.contractAddress
475
- }
476
- size={16}
1078
+ {truncateAddress(quote.destinationDepositAddress)}
1079
+ <svg
1080
+ className="w-3 h-3"
1081
+ fill="none"
1082
+ stroke="currentColor"
1083
+ viewBox="0 0 24 24"
1084
+ aria-hidden="true"
1085
+ >
1086
+ <path
1087
+ strokeLinecap="round"
1088
+ strokeLinejoin="round"
1089
+ strokeWidth={2}
1090
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
477
1091
  />
478
- {quote.destinationAmountDisplay}{" "}
479
- {quote.destinationToken.symbol}
480
- </div>
1092
+ </svg>
481
1093
  </a>
482
- {quote.destinationAmountUsdDisplay && (
483
- <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
484
- ≈ {quote.destinationAmountUsdDisplay}
485
- </div>
486
- )}
487
- </>
1094
+ </div>
488
1095
  )}
489
- </div>
490
- </div>
491
- )}
492
-
493
- {quote?.originDepositAddress && (
494
- <div className="flex justify-between items-center">
495
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
496
- Origin Deposit Address:
497
- <Tooltip message="This is the intent address to deposit to that will then execute the swap and/or bridge">
498
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
499
- </Tooltip>
500
- </span>
501
- <a
502
- href={getExplorerUrlForAddress({
503
- address: quote.originDepositAddress,
504
- chainId: quote.originChain.id,
505
- })}
506
- target="_blank"
507
- rel="noopener noreferrer"
508
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
509
- >
510
- {truncateAddress(quote.originDepositAddress)}
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
- </div>
527
- )}
528
-
529
- {quote?.destinationDepositAddress &&
530
- quote?.destinationDepositAddress !==
531
- quote?.originDepositAddress && (
532
- <div className="flex justify-between items-center">
533
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
534
- Destination Deposit Address:
535
- <Tooltip message="This is the address that will receive the tokens after any swap and/or bridge from the origin chain">
536
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
537
- </Tooltip>
538
- </span>
539
- <a
540
- href={getExplorerUrlForAddress({
541
- address: quote.destinationDepositAddress,
542
- chainId: quote.destinationChain.id,
543
- })}
544
- target="_blank"
545
- rel="noopener noreferrer"
546
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
547
- >
548
- {truncateAddress(quote.destinationDepositAddress)}
549
- <svg
550
- className="w-3 h-3"
551
- fill="none"
552
- stroke="currentColor"
553
- viewBox="0 0 24 24"
554
- aria-hidden="true"
555
- >
556
- <path
557
- strokeLinecap="round"
558
- strokeLinejoin="round"
559
- strokeWidth={2}
560
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
561
- />
562
- </svg>
563
- </a>
564
- </div>
565
- )}
566
-
567
- {quote?.destinationAddress && (
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
- Destination Target Address:
571
- <Tooltip message="This is the final execution address or recipient address">
572
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
573
- </Tooltip>
574
- </span>
575
- <a
576
- href={getExplorerUrlForAddress({
577
- address: quote.destinationAddress,
578
- chainId: quote.destinationChain.id,
579
- })}
580
- target="_blank"
581
- rel="noopener noreferrer"
582
- className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
583
- >
584
- {truncateAddress(quote.destinationAddress)}
585
- <svg
586
- className="w-3 h-3"
587
- fill="none"
588
- stroke="currentColor"
589
- viewBox="0 0 24 24"
590
- aria-hidden="true"
591
- >
592
- <path
593
- strokeLinecap="round"
594
- strokeLinejoin="round"
595
- strokeWidth={2}
596
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
597
- />
598
- </svg>
599
- </a>
600
- </div>
601
- )}
602
1096
 
603
- {quote?.slippageTolerance != null && (
604
- <div className="flex justify-between items-center">
605
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
606
- Max Slippage:
607
- <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.">
608
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
609
- </Tooltip>
610
- </span>
611
- <span className="font-medium text-xs text-gray-900 dark:text-white">
612
- {quote.slippageTolerance}%
613
- </span>
614
- </div>
615
- )}
616
-
617
- {quote?.priceImpact != null &&
618
- (() => {
619
- const priceImpactNum = Math.abs(Number(quote.priceImpact))
620
- return (
621
- <div className="space-y-1">
1097
+ {/* Destination Target Address */}
1098
+ {quote?.destinationAddress && (
622
1099
  <div className="flex justify-between items-center">
623
1100
  <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
624
- Price Impact:
625
- <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.">
1101
+ Destination Target Address:
1102
+ <Tooltip message="This is the final execution address or recipient address">
626
1103
  <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
627
1104
  </Tooltip>
628
1105
  </span>
629
- <span
630
- className={`font-medium text-xs flex items-center gap-1 ${
631
- priceImpactNum > 5
632
- ? "text-red-600 dark:text-red-400"
633
- : priceImpactNum > 0.5
634
- ? "text-orange-600 dark:text-orange-400"
635
- : "text-gray-900 dark:text-white"
636
- }`}
1106
+ <a
1107
+ href={getExplorerUrlForAddress({
1108
+ address: quote.destinationAddress,
1109
+ chainId: quote.destinationChain.id,
1110
+ })}
1111
+ target="_blank"
1112
+ rel="noopener noreferrer"
1113
+ className="font-mono text-xs hover:underline flex items-center gap-1 text-gray-700 dark:text-gray-300"
637
1114
  >
638
- {priceImpactNum > 0.5 && (
639
- <span title="High price impact">
640
- <svg
641
- className="w-3 h-3"
642
- fill="none"
643
- stroke="currentColor"
644
- viewBox="0 0 24 24"
645
- aria-hidden="true"
646
- >
647
- <path
648
- strokeLinecap="round"
649
- strokeLinejoin="round"
650
- strokeWidth={2}
651
- d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
652
- />
653
- </svg>
654
- </span>
655
- )}
656
- {quote.priceImpact}%
657
- </span>
1115
+ {truncateAddress(quote.destinationAddress)}
1116
+ <svg
1117
+ className="w-3 h-3"
1118
+ fill="none"
1119
+ stroke="currentColor"
1120
+ viewBox="0 0 24 24"
1121
+ aria-hidden="true"
1122
+ >
1123
+ <path
1124
+ strokeLinecap="round"
1125
+ strokeLinejoin="round"
1126
+ strokeWidth={2}
1127
+ d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
1128
+ />
1129
+ </svg>
1130
+ </a>
658
1131
  </div>
659
- {quote.priceImpactUsdDisplay && (
660
- <div className="text-right">
661
- <span className="text-xs text-gray-500 dark:text-gray-400">
662
- {quote.priceImpactUsdDisplay}
1132
+ )}
1133
+
1134
+ {/* Custom Calldata */}
1135
+ {quote?.destinationCalldata && (
1136
+ <div className="space-y-2">
1137
+ <button
1138
+ type="button"
1139
+ onClick={() => {
1140
+ setShowCalldata(!showCalldata)
1141
+ // Auto-scroll to calldata when expanding
1142
+ if (!showCalldata) {
1143
+ setTimeout(() => {
1144
+ if (calldataRef.current) {
1145
+ calldataRef.current.scrollIntoView({
1146
+ behavior: "smooth",
1147
+ block: "nearest",
1148
+ })
1149
+ }
1150
+ }, 150) // Delay to let the expansion animation start
1151
+ }
1152
+ }}
1153
+ 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"
1154
+ aria-label={
1155
+ showCalldata
1156
+ ? "Hide custom calldata"
1157
+ : "Show custom calldata"
1158
+ }
1159
+ >
1160
+ <span className="text-[10px]">
1161
+ Includes custom destination calldata
663
1162
  </span>
1163
+ <svg
1164
+ className={`w-3 h-3 transition-transform duration-300 ease-out ${
1165
+ showCalldata ? "rotate-180" : ""
1166
+ }`}
1167
+ fill="none"
1168
+ stroke="currentColor"
1169
+ viewBox="0 0 24 24"
1170
+ aria-hidden="true"
1171
+ >
1172
+ <path
1173
+ strokeLinecap="round"
1174
+ strokeLinejoin="round"
1175
+ strokeWidth={2}
1176
+ d="M19 9l-7 7-7-7"
1177
+ />
1178
+ </svg>
1179
+ </button>
1180
+ <div
1181
+ ref={calldataRef}
1182
+ className={`overflow-hidden transition-all duration-300 ease-out ${
1183
+ showCalldata
1184
+ ? "max-h-32 opacity-100"
1185
+ : "max-h-0 opacity-0"
1186
+ }`}
1187
+ >
1188
+ <div className="mt-2">
1189
+ <textarea
1190
+ value={quote.destinationCalldata}
1191
+ readOnly
1192
+ 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`}
1193
+ rows={4}
1194
+ placeholder="No custom calldata"
1195
+ />
1196
+ </div>
664
1197
  </div>
665
- )}
666
- </div>
667
- )
668
- })()}
669
-
670
- {/* Total Fees with optional breakdown */}
671
- {quote?.trailsFeeBreakdown ? (
672
- <FeeBreakdown feeBreakdown={quote.trailsFeeBreakdown}>
673
- <div className="flex justify-between items-center w-full">
674
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1 w-full">
675
- Total Fees:
676
- <Tooltip message="The total fees charged for this transaction, including gas fees, bridge fees, and any platform fees. These fees are deducted from your transaction.">
677
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
678
- </Tooltip>
679
- </span>
680
- <span className="font-medium text-xs text-gray-900 dark:text-white">
681
- {quote.fees.totalFeeAmountUsdDisplay}
682
- </span>
683
- </div>
684
- </FeeBreakdown>
685
- ) : quote?.fees?.totalFeeAmountUsd != null ? (
686
- <div className="flex justify-between items-center">
687
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
688
- Total Fees:
689
- <Tooltip message="The total fees charged for this transaction, including gas fees, bridge fees, and any platform fees. These fees are deducted from your transaction.">
690
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
691
- </Tooltip>
692
- </span>
693
- <span className="font-medium text-xs text-gray-900 dark:text-white">
694
- {quote.fees.totalFeeAmountUsdDisplay}
695
- </span>
696
- </div>
697
- ) : null}
698
-
699
- {quote?.quoteProvider?.name && (
700
- <div className="flex justify-between items-center">
701
- <span className="text-xs text-gray-600 dark:text-gray-400 flex items-center gap-1">
702
- {quote.originChain.id === quote.destinationChain.id
703
- ? "Swap Provider"
704
- : "Bridge"}
705
- :
706
- <Tooltip message="The service that fullfils the swap and/or bridge">
707
- <InfoIcon className="w-3 h-3 text-gray-500 dark:text-gray-400 cursor-pointer" />
708
- </Tooltip>
709
- </span>
710
- <a
711
- href={quote.quoteProvider?.url}
712
- target="_blank"
713
- rel="noopener noreferrer"
714
- className="font-medium text-xs text-gray-900 dark:text-white hover:underline flex items-center gap-1"
715
- >
716
- {quote.quoteProvider?.name}
717
- <svg
718
- className="w-3 h-3"
719
- fill="none"
720
- stroke="currentColor"
721
- viewBox="0 0 24 24"
722
- aria-hidden="true"
723
- >
724
- <path
725
- strokeLinecap="round"
726
- strokeLinejoin="round"
727
- strokeWidth={2}
728
- d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"
729
- />
730
- </svg>
731
- </a>
732
- </div>
733
- )}
1198
+ </div>
1199
+ )}
734
1200
 
735
- {quote?.destinationCalldata && (
736
- <div className="space-y-2">
737
- <button
738
- type="button"
739
- onClick={() => {
740
- setShowCalldata(!showCalldata)
741
- // Auto-scroll to calldata when expanding
742
- if (!showCalldata) {
743
- setTimeout(() => {
744
- if (calldataRef.current) {
745
- calldataRef.current.scrollIntoView({
746
- behavior: "smooth",
747
- block: "nearest",
748
- })
749
- }
750
- }, 150) // Delay to let the expansion animation start
751
- }
752
- }}
753
- 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"
754
- aria-label={
755
- showCalldata
756
- ? "Hide custom calldata"
757
- : "Show custom calldata"
758
- }
759
- >
760
- <span className="text-[10px]">
761
- Includes custom destination calldata
762
- </span>
763
- <svg
764
- className={`w-3 h-3 transition-transform duration-300 ease-out ${
765
- showCalldata ? "rotate-180" : ""
766
- }`}
767
- fill="none"
768
- stroke="currentColor"
769
- viewBox="0 0 24 24"
770
- aria-hidden="true"
771
- >
772
- <path
773
- strokeLinecap="round"
774
- strokeLinejoin="round"
775
- strokeWidth={2}
776
- d="M19 9l-7 7-7-7"
777
- />
778
- </svg>
779
- </button>
780
- <div
781
- ref={calldataRef}
782
- className={`overflow-hidden transition-all duration-300 ease-out ${
783
- showCalldata ? "max-h-32 opacity-100" : "max-h-0 opacity-0"
784
- }`}
785
- >
786
- <div className="mt-2">
787
- <textarea
788
- value={quote.destinationCalldata}
789
- readOnly
790
- 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`}
791
- rows={4}
792
- placeholder="No custom calldata"
793
- />
794
- </div>
1201
+ {/* Children content */}
1202
+ {children && <div className="mb-0">{children}</div>}
795
1203
  </div>
796
1204
  </div>
797
- )}
798
-
799
- {/* Children content */}
800
- {children && <div className="mb-0">{children}</div>}
1205
+ </div>
801
1206
  </div>
802
1207
  </div>
803
1208
  </div>