0xtrails 0.1.13 → 0.2.1

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 (256) hide show
  1. package/dist/aave.d.ts.map +1 -1
  2. package/dist/analytics.d.ts +12 -2
  3. package/dist/analytics.d.ts.map +1 -1
  4. package/dist/apiClient.d.ts +1 -1
  5. package/dist/apiClient.d.ts.map +1 -1
  6. package/dist/{ccip-D3gTQONK.js → ccip-BbfANth7.js} +12 -12
  7. package/dist/cctp.d.ts.map +1 -1
  8. package/dist/cctpqueue.d.ts +3 -3
  9. package/dist/cctpqueue.d.ts.map +1 -1
  10. package/dist/chains.d.ts.map +1 -1
  11. package/dist/config.d.ts +18 -5
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/constants.d.ts +6 -5
  14. package/dist/constants.d.ts.map +1 -1
  15. package/dist/contractUtils.d.ts +2 -0
  16. package/dist/contractUtils.d.ts.map +1 -1
  17. package/dist/customChains.d.ts +24 -0
  18. package/dist/customChains.d.ts.map +1 -0
  19. package/dist/gasless.d.ts +19 -7
  20. package/dist/gasless.d.ts.map +1 -1
  21. package/dist/{index-CnUM7lKf.js → index-WpIVoh3X.js} +36741 -31761
  22. package/dist/index.d.ts +5 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +405 -394
  25. package/dist/indexerClient.d.ts +10 -0
  26. package/dist/indexerClient.d.ts.map +1 -1
  27. package/dist/intentEntrypoint.d.ts +122 -0
  28. package/dist/intentEntrypoint.d.ts.map +1 -0
  29. package/dist/intents.d.ts +5 -3
  30. package/dist/intents.d.ts.map +1 -1
  31. package/dist/metaTxnMonitor.d.ts.map +1 -1
  32. package/dist/morpho.d.ts.map +1 -1
  33. package/dist/pools.d.ts +3 -1
  34. package/dist/pools.d.ts.map +1 -1
  35. package/dist/prepareSend.d.ts +18 -9
  36. package/dist/prepareSend.d.ts.map +1 -1
  37. package/dist/prices.d.ts +1 -1
  38. package/dist/prices.d.ts.map +1 -1
  39. package/dist/relaySdk.d.ts.map +1 -1
  40. package/dist/relayer.d.ts.map +1 -1
  41. package/dist/toast.d.ts +9 -0
  42. package/dist/toast.d.ts.map +1 -0
  43. package/dist/tokenBalances.d.ts +6 -2
  44. package/dist/tokenBalances.d.ts.map +1 -1
  45. package/dist/tokens.d.ts.map +1 -1
  46. package/dist/trails.d.ts +6 -5
  47. package/dist/trails.d.ts.map +1 -1
  48. package/dist/trailsClient.d.ts +12 -0
  49. package/dist/trailsClient.d.ts.map +1 -0
  50. package/dist/trailsRouter.d.ts +22 -0
  51. package/dist/trailsRouter.d.ts.map +1 -0
  52. package/dist/transactions.d.ts +8 -1
  53. package/dist/transactions.d.ts.map +1 -1
  54. package/dist/wallets.d.ts.map +1 -1
  55. package/dist/widget/components/AccountActionsDropdown.d.ts.map +1 -1
  56. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  57. package/dist/widget/components/AccountSettings.d.ts +7 -0
  58. package/dist/widget/components/AccountSettings.d.ts.map +1 -0
  59. package/dist/widget/components/ChainList.d.ts +0 -1
  60. package/dist/widget/components/ChainList.d.ts.map +1 -1
  61. package/dist/widget/components/ClassicSwap.d.ts +46 -0
  62. package/dist/widget/components/ClassicSwap.d.ts.map +1 -0
  63. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  64. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  65. package/dist/widget/components/ConnectedWallets.d.ts +9 -0
  66. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -0
  67. package/dist/widget/components/DebugMenu.d.ts.map +1 -1
  68. package/dist/widget/components/DebugScreensList.d.ts.map +1 -1
  69. package/dist/widget/components/DebugToast.d.ts +3 -0
  70. package/dist/widget/components/DebugToast.d.ts.map +1 -0
  71. package/dist/widget/components/Earn.d.ts.map +1 -1
  72. package/dist/widget/components/EarnPools.d.ts.map +1 -1
  73. package/dist/widget/components/FeeOption.d.ts +22 -0
  74. package/dist/widget/components/FeeOption.d.ts.map +1 -0
  75. package/dist/widget/components/FeeOptions.d.ts +13 -17
  76. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  77. package/dist/widget/components/Fund.d.ts +44 -0
  78. package/dist/widget/components/Fund.d.ts.map +1 -0
  79. package/dist/widget/components/FundMethods.d.ts +1 -1
  80. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  81. package/dist/widget/components/FundSendForm.d.ts.map +1 -1
  82. package/dist/widget/components/Identicon.d.ts +9 -0
  83. package/dist/widget/components/Identicon.d.ts.map +1 -0
  84. package/dist/widget/components/MeshConnectExchanges.d.ts +5 -2
  85. package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
  86. package/dist/widget/components/MeshConnectFlow.d.ts +2 -0
  87. package/dist/widget/components/MeshConnectFlow.d.ts.map +1 -1
  88. package/dist/widget/components/NativeGasOption.d.ts +12 -0
  89. package/dist/widget/components/NativeGasOption.d.ts.map +1 -0
  90. package/dist/widget/components/Pay.d.ts +46 -0
  91. package/dist/widget/components/Pay.d.ts.map +1 -0
  92. package/dist/widget/components/PaySendForm.d.ts.map +1 -1
  93. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  94. package/dist/widget/components/Receive.d.ts.map +1 -1
  95. package/dist/widget/components/RecentTokens.d.ts.map +1 -1
  96. package/dist/widget/components/Recipients.d.ts +9 -0
  97. package/dist/widget/components/Recipients.d.ts.map +1 -0
  98. package/dist/widget/components/RefundWarning.d.ts +9 -0
  99. package/dist/widget/components/RefundWarning.d.ts.map +1 -0
  100. package/dist/widget/components/SimpleSwap.d.ts.map +1 -1
  101. package/dist/widget/components/Swap.d.ts.map +1 -1
  102. package/dist/widget/components/SwapSettings.d.ts +1 -5
  103. package/dist/widget/components/SwapSettings.d.ts.map +1 -1
  104. package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
  105. package/dist/widget/components/ThemeSyncer.d.ts +6 -0
  106. package/dist/widget/components/ThemeSyncer.d.ts.map +1 -0
  107. package/dist/widget/components/Toast.d.ts +24 -0
  108. package/dist/widget/components/Toast.d.ts.map +1 -0
  109. package/dist/widget/components/TokenList.d.ts.map +1 -1
  110. package/dist/widget/components/TokenSelector.d.ts.map +1 -1
  111. package/dist/widget/components/TransactionDetails.d.ts.map +1 -1
  112. package/dist/widget/components/TruncatedAddress.d.ts +2 -0
  113. package/dist/widget/components/TruncatedAddress.d.ts.map +1 -1
  114. package/dist/widget/components/UserPreferences.d.ts +7 -0
  115. package/dist/widget/components/UserPreferences.d.ts.map +1 -0
  116. package/dist/widget/hooks/useBack.d.ts +2 -0
  117. package/dist/widget/hooks/useBack.d.ts.map +1 -1
  118. package/dist/widget/hooks/useBalanceVisible.d.ts +1 -0
  119. package/dist/widget/hooks/useBalanceVisible.d.ts.map +1 -1
  120. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  121. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  122. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  123. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  124. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  125. package/dist/widget/hooks/useDefaultTokenSelection.d.ts +54 -0
  126. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -0
  127. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  128. package/dist/widget/hooks/usePayMessage.d.ts +34 -0
  129. package/dist/widget/hooks/usePayMessage.d.ts.map +1 -0
  130. package/dist/widget/hooks/useRecipients.d.ts +17 -0
  131. package/dist/widget/hooks/useRecipients.d.ts.map +1 -0
  132. package/dist/widget/hooks/useSelectedFeeToken.d.ts +32 -0
  133. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -0
  134. package/dist/widget/hooks/useSelectedMeshExchange.d.ts +14 -0
  135. package/dist/widget/hooks/useSelectedMeshExchange.d.ts.map +1 -0
  136. package/dist/widget/hooks/useSelectedRecipient.d.ts +12 -0
  137. package/dist/widget/hooks/useSelectedRecipient.d.ts.map +1 -0
  138. package/dist/widget/hooks/useSendForm.d.ts +10 -13
  139. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  140. package/dist/widget/hooks/useSwapAmount.d.ts +13 -0
  141. package/dist/widget/hooks/useSwapAmount.d.ts.map +1 -0
  142. package/dist/widget/hooks/useSwapSettings.d.ts +16 -0
  143. package/dist/widget/hooks/useSwapSettings.d.ts.map +1 -0
  144. package/dist/widget/hooks/useTargetAmount.d.ts +5 -0
  145. package/dist/widget/hooks/useTargetAmount.d.ts.map +1 -0
  146. package/dist/widget/hooks/useTheme.d.ts +14 -0
  147. package/dist/widget/hooks/useTheme.d.ts.map +1 -0
  148. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  149. package/dist/widget/index.js +2 -2
  150. package/dist/widget/widget.d.ts +9 -0
  151. package/dist/widget/widget.d.ts.map +1 -1
  152. package/package.json +38 -36
  153. package/src/aave.ts +6 -1
  154. package/src/analytics.ts +109 -53
  155. package/src/apiClient.ts +1 -1
  156. package/src/cctp.ts +6 -2
  157. package/src/cctpqueue.ts +7 -7
  158. package/src/chains.ts +18 -0
  159. package/src/config.ts +63 -17
  160. package/src/constants.ts +20 -16
  161. package/src/contractUtils.ts +33 -2
  162. package/src/customChains.ts +24 -0
  163. package/src/gasless.ts +162 -109
  164. package/src/index.ts +11 -1
  165. package/src/indexerClient.ts +73 -1
  166. package/src/intentEntrypoint.ts +218 -0
  167. package/src/intents.ts +85 -54
  168. package/src/metaTxnMonitor.ts +1 -0
  169. package/src/morpho.ts +13 -2
  170. package/src/pools.ts +68 -86
  171. package/src/prepareSend.ts +1719 -967
  172. package/src/prices.ts +51 -7
  173. package/src/relaySdk.ts +6 -4
  174. package/src/relayer.ts +6 -3
  175. package/src/toast.ts +110 -0
  176. package/src/tokenBalances.ts +112 -20
  177. package/src/tokens.ts +70 -7
  178. package/src/trails.ts +81 -80
  179. package/src/trailsClient.ts +48 -0
  180. package/src/{proxyCaller.ts → trailsRouter.ts} +25 -20
  181. package/src/transactions.ts +30 -88
  182. package/src/umd.tsx +1 -1
  183. package/src/wallets.ts +2 -1
  184. package/src/widget/assets/sequence-logo.svg +15 -0
  185. package/src/widget/compiled.css +2 -2
  186. package/src/widget/components/AccountActionsDropdown.tsx +18 -159
  187. package/src/widget/components/AccountIntentTransactionHistory.tsx +346 -63
  188. package/src/widget/components/AccountSettings.tsx +102 -0
  189. package/src/widget/components/ChainFilterDropdown.tsx +1 -1
  190. package/src/widget/components/ChainList.tsx +10 -20
  191. package/src/widget/components/ClassicSwap.tsx +921 -0
  192. package/src/widget/components/ConfigDisplay.tsx +41 -5
  193. package/src/widget/components/ConnectWallet.tsx +168 -11
  194. package/src/widget/components/ConnectedWallets.tsx +342 -0
  195. package/src/widget/components/DebugMenu.tsx +2 -0
  196. package/src/widget/components/DebugScreensList.tsx +3 -0
  197. package/src/widget/components/DebugToast.tsx +63 -0
  198. package/src/widget/components/Earn.tsx +112 -143
  199. package/src/widget/components/EarnPools.tsx +2 -4
  200. package/src/widget/components/EarnPoolsFilters.tsx +6 -6
  201. package/src/widget/components/FeeOption.tsx +78 -0
  202. package/src/widget/components/FeeOptions.tsx +192 -127
  203. package/src/widget/components/Fund.tsx +1236 -0
  204. package/src/widget/components/FundMethods.tsx +4 -4
  205. package/src/widget/components/FundSendForm.tsx +1 -34
  206. package/src/widget/components/Identicon.tsx +158 -0
  207. package/src/widget/components/MeshConnectExchanges.tsx +32 -3
  208. package/src/widget/components/MeshConnectFlow.tsx +23 -4
  209. package/src/widget/components/NativeGasOption.tsx +99 -0
  210. package/src/widget/components/Pay.tsx +1092 -0
  211. package/src/widget/components/PaySendForm.tsx +1 -38
  212. package/src/widget/components/QuoteDetails.tsx +1 -30
  213. package/src/widget/components/Receipt.tsx +1 -1
  214. package/src/widget/components/Receive.tsx +4 -2
  215. package/src/widget/components/RecentTokens.tsx +2 -1
  216. package/src/widget/components/Recipients.tsx +448 -0
  217. package/src/widget/components/RefundWarning.tsx +61 -0
  218. package/src/widget/components/ScreenHeader.tsx +1 -1
  219. package/src/widget/components/SimpleSwap.tsx +74 -58
  220. package/src/widget/components/Swap.tsx +35 -853
  221. package/src/widget/components/SwapSettings.tsx +5 -11
  222. package/src/widget/components/ThemeProvider.tsx +32 -0
  223. package/src/widget/components/ThemeSyncer.tsx +47 -0
  224. package/src/widget/components/Toast.tsx +315 -0
  225. package/src/widget/components/TokenList.tsx +2 -34
  226. package/src/widget/components/TokenSelector.tsx +14 -3
  227. package/src/widget/components/TransactionDetails.tsx +153 -13
  228. package/src/widget/components/TransferPendingVertical.tsx +1 -1
  229. package/src/widget/components/TruncatedAddress.tsx +5 -1
  230. package/src/widget/components/UserPreferences.tsx +155 -0
  231. package/src/widget/components/WalletList.tsx +1 -1
  232. package/src/widget/hooks/useBack.tsx +4 -0
  233. package/src/widget/hooks/useBalanceVisible.tsx +40 -2
  234. package/src/widget/hooks/useCheckout.ts +13 -0
  235. package/src/widget/hooks/useCurrentScreen.tsx +4 -0
  236. package/src/widget/hooks/useDebugScreens.ts +12 -2
  237. package/src/widget/hooks/useDefaultTokenSelection.tsx +471 -0
  238. package/src/widget/hooks/useIntentTransactionHistory.ts +212 -0
  239. package/src/widget/hooks/usePayMessage.tsx +370 -0
  240. package/src/widget/hooks/useRecipients.ts +168 -0
  241. package/src/widget/hooks/useSelectedFeeToken.tsx +299 -0
  242. package/src/widget/hooks/useSelectedMeshExchange.tsx +46 -0
  243. package/src/widget/hooks/useSelectedRecipient.tsx +48 -0
  244. package/src/widget/hooks/useSendForm.ts +257 -49
  245. package/src/widget/hooks/useSwapAmount.tsx +50 -0
  246. package/src/widget/hooks/useSwapSettings.tsx +100 -0
  247. package/src/widget/hooks/useTargetAmount.ts +23 -0
  248. package/src/widget/hooks/useTheme.tsx +80 -0
  249. package/src/widget/hooks/useTokenList.ts +20 -11
  250. package/src/widget/index.css +45 -21
  251. package/src/widget/widget.tsx +294 -136
  252. package/dist/address.d.ts +0 -2
  253. package/dist/address.d.ts.map +0 -1
  254. package/dist/proxyCaller.d.ts +0 -21
  255. package/dist/proxyCaller.d.ts.map +0 -1
  256. package/src/address.ts +0 -6
@@ -1,30 +1,14 @@
1
- import { ChevronDown, Loader2, ArrowDown } from "lucide-react"
2
1
  import type React from "react"
3
- import { useCallback, useEffect, useRef, useState } from "react"
2
+ import { useEffect } from "react"
4
3
  import type { Account, WalletClient } from "viem"
5
4
  import type { TransactionState } from "../../transactions.js"
6
5
  import type { OnCompleteProps, Token } from "../hooks/useSendForm.js"
7
6
  import type { SupportedToken } from "../../tokens.js"
8
- import { useSendForm } from "../hooks/useSendForm.js"
9
- import { useTokenList } from "../hooks/useTokenList.js"
10
7
  import type { CheckoutOnHandlers } from "../hooks/useCheckout.js"
11
- import { FeeOptions } from "./FeeOptions.js"
12
- import { TokenImage } from "./TokenImage.js"
13
- import { QuoteDetails } from "./QuoteDetails.js"
14
- import { type PrepareSendQuote, TradeType } from "../../prepareSend.js"
15
- import { getChainInfo } from "../../chains.js"
16
- import { formatUsdAmountDisplay } from "../../tokenBalances.js"
17
- import { MINIMUM_USD_AMOUNT_FOR_SWAP } from "../../constants.js"
18
- import { ScreenHeader } from "./ScreenHeader.js"
19
- import { TokenSelector } from "./TokenSelector.js"
20
- import { ErrorDisplay } from "./ErrorDisplay.js"
21
- import { useMode } from "../hooks/useMode.js"
22
- import { logger } from "../../logger.js"
8
+ import type { PrepareSendQuote } from "../../prepareSend.js"
23
9
  import { SimpleSwap } from "./SimpleSwap.js"
24
- import { SwapSettings } from "./SwapSettings.js"
25
- import { useOriginSelectedToken } from "../hooks/useOriginSelectedToken.js"
26
- import { useDestinationSelectedToken } from "../hooks/useDestinationSelectedToken.js"
27
- import { useBalanceVisible } from "../hooks/useBalanceVisible.js"
10
+ import { ClassicSwap } from "./ClassicSwap.js"
11
+ import { useSwapSettings } from "../hooks/useSwapSettings.js"
28
12
  import { useWidgetProps } from "../hooks/useWidgetProps.js"
29
13
 
30
14
  interface SwapProps {
@@ -64,849 +48,47 @@ interface SwapProps {
64
48
  onTrackToken?: (token: any) => void
65
49
  }
66
50
 
67
- export const Swap: React.FC<SwapProps> = ({
68
- selectedToken: initialSelectedToken,
69
- onSend,
70
- onBack,
71
- onConfirm,
72
- onComplete,
73
- account,
74
- toAmount,
75
- toChainId,
76
- toToken,
77
- toCalldata,
78
- walletClient,
79
- onTransactionStateChange,
80
- onError,
81
- onWaitingForWalletConfirm,
82
- paymasterUrls,
83
- gasless,
84
- setWalletConfirmRetryHandler,
85
- quoteProvider,
86
- fundMethod,
87
- onNavigateToMeshConnect,
88
- onAmountUpdate,
89
- checkoutOnHandlers,
90
- recentTokens,
91
- onRecentTokenSelect,
92
- onTrackToken,
93
- }) => {
94
- const { mode } = useMode()
51
+ export const Swap: React.FC<SwapProps> = (props) => {
95
52
  const { swapMode } = useWidgetProps()
96
- const { isBalanceVisible } = useBalanceVisible()
97
- const { selectedToken: originToken, setSelectedToken: setOriginToken } =
98
- useOriginSelectedToken()
99
53
  const {
100
- selectedToken: destinationToken,
101
- setSelectedToken: setDestinationToken,
102
- } = useDestinationSelectedToken()
103
- const [isFlipped, setIsFlipped] = useState(false)
104
- const [isSimpleMode, setIsSimpleMode] = useState(swapMode === "simple")
54
+ isSimpleSwapMode: isSimpleMode,
55
+ setIsSimpleSwapMode: setIsSimpleMode,
56
+ } = useSwapSettings()
105
57
 
106
58
  // Update isSimpleMode when swapMode changes
107
59
  useEffect(() => {
108
60
  if (swapMode === "simple") {
109
61
  setIsSimpleMode(true)
110
62
  }
111
- }, [swapMode])
112
-
113
- // Handle mode changes
114
- const handleModeChange = useCallback((newMode: boolean) => {
115
- setIsSimpleMode(newMode)
116
- }, [])
117
- const [
118
- isSimpleModeTokenSelectorVisible,
119
- setIsSimpleModeTokenSelectorVisible,
120
- ] = useState(false)
121
- const [originChainId, setOriginChainId] = useState<number | null | undefined>(
122
- initialSelectedToken?.chainId || originToken?.chainId,
123
- )
124
- const [tradeType, setTradeType] = useState<TradeType>(TradeType.EXACT_INPUT)
125
- const [sellAmount, setSellAmount] = useState("")
126
- const [buyAmount, setBuyAmount] = useState("")
127
- const [lastInputType, setLastInputType] = useState<"sell" | "buy">("sell")
128
-
129
- // Get sorted tokens to auto-select the highest USD value token
130
- const { filteredTokensFormatted, isLoadingTokens } = useTokenList({
131
- onContinue: () => {}, // Not used for auto-selection
132
- onError: () => {}, // Not used for auto-selection
133
- fundMethod: undefined,
134
- allSupportedTokens: false,
135
- })
136
-
137
- const {
138
- amount,
139
- amountRaw,
140
- amountUsdDisplay,
141
- balanceFormatted,
142
- handleSubmit,
143
- isSubmitting,
144
- isLoadingQuote,
145
- isTokenDropdownOpen,
146
- selectedDestinationChain,
147
- selectedDestToken,
148
- setAmount,
149
- setSelectedDestinationChain,
150
- setSelectedDestToken,
151
- buttonText,
152
- selectedFeeToken,
153
- setSelectedFeeToken,
154
- feeOptions,
155
- setIsTokenDropdownOpen,
156
- toAmountDisplay,
157
- destinationTokenAddress,
158
- isValidCustomToken,
159
- prepareSendQuote,
160
- quoteError,
161
- quoteErrorPrettified,
162
- isSameTokenWithoutCustomCalldata,
163
- } = useSendForm({
164
- account,
165
- toAmount: tradeType === TradeType.EXACT_OUTPUT ? buyAmount : toAmount,
166
- toRecipient: account.address,
167
- toChainId,
168
- toToken,
169
- toCalldata,
170
- walletClient,
171
- onTransactionStateChange,
172
- onError,
173
- onWaitingForWalletConfirm,
174
- paymasterUrls,
175
- gasless,
176
- onConfirm,
177
- onComplete,
178
- onSend,
179
- selectedToken: originToken as any,
180
- setWalletConfirmRetryHandler,
181
- tradeType: tradeType,
182
- quoteProvider,
183
- fundMethod,
184
- mode,
185
- onNavigateToMeshConnect,
186
- checkoutOnHandlers,
187
- })
188
-
189
- // Update amount based on last input type
190
- useEffect(() => {
191
- if (lastInputType === "sell") {
192
- setAmount(sellAmount)
193
- } else {
194
- setAmount(buyAmount)
195
- }
196
- }, [sellAmount, buyAmount, lastInputType, setAmount])
197
-
198
- // Handle sell amount input changes with decimal validation
199
- const handleSellAmountChange = useCallback((value: string) => {
200
- // Validate decimal places (max 8 decimals)
201
- const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
202
- if (!decimalMatch && value !== "") {
203
- return // Don't update if more than 8 decimals
204
- }
205
- setTradeType(TradeType.EXACT_INPUT)
206
- setSellAmount(value)
207
- setBuyAmount("")
208
- setLastInputType("sell")
209
- }, [])
210
-
211
- // Handle buy amount input changes with decimal validation
212
- const handleBuyAmountChange = useCallback((value: string) => {
213
- // Validate decimal places (max 8 decimals)
214
- const decimalMatch = value.match(/^\d*\.?\d{0,8}$/)
215
- if (!decimalMatch && value !== "") {
216
- return // Don't update if more than 8 decimals
217
- }
218
- setTradeType(TradeType.EXACT_OUTPUT)
219
- setBuyAmount(value)
220
- setSellAmount("")
221
- setLastInputType("buy")
222
- }, [])
223
-
224
- // Handle buy input focus - clear field when user wants to type
225
- const handleBuyInputFocus = useCallback(() => {
226
- // When focusing on buy field and it's in EXACT_INPUT mode (showing calculated value), switch to EXACT_OUTPUT mode
227
- if (tradeType === TradeType.EXACT_INPUT && !buyAmount) {
228
- setBuyAmount("")
229
- setTradeType(TradeType.EXACT_OUTPUT)
230
- setLastInputType("buy")
231
- }
232
- }, [tradeType, buyAmount])
233
-
234
- // Update amounts when quote is received
235
- useEffect(() => {
236
- if (!prepareSendQuote) return
237
-
238
- if (
239
- tradeType === TradeType.EXACT_OUTPUT &&
240
- prepareSendQuote.originAmountDisplay
241
- ) {
242
- setSellAmount(prepareSendQuote.originAmountDisplay)
243
- } else if (
244
- tradeType === TradeType.EXACT_INPUT &&
245
- prepareSendQuote.destinationAmountDisplay
246
- ) {
247
- setBuyAmount(prepareSendQuote.destinationAmountDisplay)
248
- }
249
- }, [prepareSendQuote, tradeType])
250
-
251
- // Handle percentage button clicks
252
- const handlePercentageClick = useCallback(
253
- (percentage: number) => {
254
- if (!originToken || !balanceFormatted) return
255
-
256
- // Parse the balance and calculate percentage
257
- const balance = parseFloat(balanceFormatted)
258
- if (Number.isNaN(balance)) return
259
-
260
- const amount = (balance * percentage) / 100
261
- setTradeType(TradeType.EXACT_INPUT)
262
- setSellAmount(amount.toFixed(6))
263
- setBuyAmount("")
264
- setLastInputType("sell")
265
- },
266
- [originToken, balanceFormatted],
267
- )
268
-
269
- // Call onAmountUpdate when amountRaw changes
270
- useEffect(() => {
271
- if (onAmountUpdate) {
272
- onAmountUpdate(amountRaw)
273
- }
274
- }, [amountRaw, onAmountUpdate])
275
-
276
- // Auto-select the highest USD value token as origin token
277
- useEffect(() => {
278
- if (
279
- !originToken &&
280
- !isLoadingTokens &&
281
- filteredTokensFormatted?.length > 0
282
- ) {
283
- const highestValueToken = filteredTokensFormatted[0] // First token is highest USD value
284
- if (highestValueToken && Number(highestValueToken.balanceUsd) > 0) {
285
- setOriginToken({
286
- ...highestValueToken,
287
- contractInfo: {
288
- decimals: highestValueToken.contractInfo?.decimals || 18,
289
- contractAddress: highestValueToken.contractAddress,
290
- symbol: highestValueToken.symbol,
291
- name: highestValueToken.name,
292
- },
293
- } as any)
294
- setOriginChainId(highestValueToken.chainId)
295
- }
296
- }
297
- }, [originToken, isLoadingTokens, filteredTokensFormatted, setOriginToken])
298
-
299
- // Auto-focus the input field when component mounts
300
- useEffect(() => {
301
- if (inputRef.current) {
302
- inputRef.current.focus()
303
- }
304
- }, [])
305
-
306
- const originTokenDropdownRef = useRef<HTMLDivElement>(null)
307
- const tokenDropdownRef = useRef<HTMLInputElement>(null)
308
- const inputRef = useRef<HTMLInputElement>(null)
309
-
310
- const [isOriginTokenDropdownOpen, setIsOriginTokenDropdownOpen] =
311
- useState(false)
312
-
313
- useEffect(() => {
314
- if (selectedDestToken) {
315
- setSelectedDestinationChain(
316
- getChainInfo((selectedDestToken as any)?.chainId as any) as any,
317
- )
318
- }
319
- }, [selectedDestToken, setSelectedDestinationChain])
320
-
321
- // Sync destination token from hook with useSendForm
322
- useEffect(() => {
323
- if (destinationToken && !selectedDestToken) {
324
- setSelectedDestToken(destinationToken as any)
325
- }
326
- }, [destinationToken, selectedDestToken, setSelectedDestToken])
327
-
328
- useEffect(() => {
329
- const handleClickOutside = (event: MouseEvent) => {
330
- if (
331
- tokenDropdownRef.current &&
332
- !tokenDropdownRef.current.contains(event.target as Node)
333
- ) {
334
- setIsTokenDropdownOpen(false)
335
- }
336
- if (
337
- originTokenDropdownRef.current &&
338
- !originTokenDropdownRef.current.contains(event.target as Node)
339
- ) {
340
- setIsOriginTokenDropdownOpen(false)
341
- }
342
- }
343
-
344
- if (isTokenDropdownOpen || isOriginTokenDropdownOpen) {
345
- document.addEventListener("click", handleClickOutside)
346
- return () => document.removeEventListener("click", handleClickOutside)
347
- }
348
- }, [isTokenDropdownOpen, isOriginTokenDropdownOpen, setIsTokenDropdownOpen])
349
-
350
- // Handle flip functionality
351
- const handleFlip = () => {
352
- if (!selectedDestinationChain || !originToken || !selectedDestToken) return
353
-
354
- setIsFlipped(!isFlipped)
355
-
356
- // Store current values
357
- const tempOriginToken = originToken
358
- const tempOriginChainId = originChainId
359
- const tempBuyAmount = buyAmount || toAmountDisplay || ""
360
-
361
- // Swap origin and destination using hooks
362
- setOriginToken(selectedDestToken as any)
363
- setDestinationToken(tempOriginToken as any)
364
- setOriginChainId((selectedDestToken as any)?.chainId as any)
365
- setSelectedDestToken(tempOriginToken as any)
366
-
367
- // Update destination chain
368
- const newChain = getChainInfo(tempOriginChainId as any)
369
- if (newChain) {
370
- setSelectedDestinationChain(newChain)
371
- }
372
-
373
- // When flipping, always set the current visible amount as the new sell amount
374
- if (tradeType === TradeType.EXACT_INPUT) {
375
- // If we were in EXACT_INPUT, use the buy amount (from quote) as the new sell amount
376
- setSellAmount(tempBuyAmount)
377
- setBuyAmount("")
378
- setTradeType(TradeType.EXACT_INPUT)
379
- setLastInputType("sell")
380
- } else {
381
- // If we were in EXACT_OUTPUT, use the current buy amount as the new sell amount
382
- setSellAmount(tempBuyAmount)
383
- setBuyAmount("")
384
- setTradeType(TradeType.EXACT_INPUT)
385
- setLastInputType("sell")
386
- }
63
+ }, [swapMode, setIsSimpleMode])
64
+
65
+ // Render SimpleSwap or ClassicSwap based on mode
66
+ if (isSimpleMode) {
67
+ return (
68
+ <SimpleSwap
69
+ onBack={props.onBack}
70
+ account={props.account}
71
+ walletClient={props.walletClient}
72
+ onTransactionStateChange={props.onTransactionStateChange}
73
+ onError={props.onError}
74
+ onWaitingForWalletConfirm={props.onWaitingForWalletConfirm}
75
+ onConfirm={props.onConfirm}
76
+ onComplete={props.onComplete}
77
+ onSend={props.onSend}
78
+ paymasterUrls={props.paymasterUrls}
79
+ gasless={props.gasless}
80
+ setWalletConfirmRetryHandler={props.setWalletConfirmRetryHandler}
81
+ quoteProvider={props.quoteProvider}
82
+ fundMethod={props.fundMethod}
83
+ checkoutOnHandlers={props.checkoutOnHandlers}
84
+ showHeader={true}
85
+ onTokenSelectorVisibilityChange={() => {}}
86
+ />
87
+ )
387
88
  }
388
89
 
389
- return (
390
- <div className="space-y-2">
391
- {!isSimpleMode && (
392
- <ScreenHeader
393
- onBack={onBack}
394
- headerContent="Swap"
395
- headerContentAlign="left"
396
- showAccountActions={true}
397
- rightSideContent={
398
- <SwapSettings
399
- isSimpleMode={isSimpleMode}
400
- onModeChange={handleModeChange}
401
- />
402
- }
403
- />
404
- )}
405
-
406
- {isSimpleMode && !isSimpleModeTokenSelectorVisible && (
407
- <ScreenHeader
408
- onBack={onBack}
409
- headerContent="Swap"
410
- headerContentAlign="left"
411
- showAccountActions={true}
412
- rightSideContent={
413
- <SwapSettings
414
- isSimpleMode={isSimpleMode}
415
- onModeChange={handleModeChange}
416
- />
417
- }
418
- />
419
- )}
420
-
421
- {isSimpleMode ? (
422
- <SimpleSwap
423
- onBack={onBack}
424
- account={account}
425
- walletClient={walletClient}
426
- onTransactionStateChange={onTransactionStateChange}
427
- onError={onError}
428
- onWaitingForWalletConfirm={onWaitingForWalletConfirm}
429
- onConfirm={onConfirm}
430
- onComplete={onComplete}
431
- onSend={onSend}
432
- paymasterUrls={paymasterUrls}
433
- gasless={gasless}
434
- setWalletConfirmRetryHandler={setWalletConfirmRetryHandler}
435
- quoteProvider={quoteProvider}
436
- fundMethod={fundMethod}
437
- checkoutOnHandlers={checkoutOnHandlers}
438
- showHeader={isSimpleModeTokenSelectorVisible}
439
- onTokenSelectorVisibilityChange={setIsSimpleModeTokenSelectorVisible}
440
- />
441
- ) : (
442
- <form onSubmit={handleSubmit} className="space-y-1">
443
- {/* Input Section - Amount + Token Selection */}
444
- <div className="trails-bg-secondary trails-border-radius-container p-3 group transition-all duration-200 border border-transparent hover:!bg-white dark:hover:!bg-white hover:border-gray-400 dark:hover:border-gray-500">
445
- {/* Sell Label and Percentage Buttons */}
446
- <div className="flex justify-between items-center mb-2">
447
- <div className="text-sm font-medium trails-text-secondary text-left">
448
- Sell
449
- </div>
450
-
451
- {/* Percentage Buttons */}
452
- {originToken && (
453
- <div className="flex space-x-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
454
- <button
455
- type="button"
456
- onClick={() => handlePercentageClick(25)}
457
- className="py-1 px-2 text-xs font-medium trails-border-radius-container border border-solid transition-colors cursor-pointer border-gray-300 text-gray-600 dark:border-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:trails-hover-bg hover:border-gray-400 dark:hover:border-gray-500"
458
- >
459
- 25%
460
- </button>
461
- <button
462
- type="button"
463
- onClick={() => handlePercentageClick(50)}
464
- className="py-1 px-2 text-xs font-medium trails-border-radius-container border border-solid transition-colors cursor-pointer border-gray-300 text-gray-600 dark:border-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:trails-hover-bg hover:border-gray-400 dark:hover:border-gray-500"
465
- >
466
- 50%
467
- </button>
468
- <button
469
- type="button"
470
- onClick={() => handlePercentageClick(75)}
471
- className="py-1 px-2 text-xs font-medium trails-border-radius-container border border-solid transition-colors cursor-pointer border-gray-300 text-gray-600 dark:border-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:trails-hover-bg hover:border-gray-400 dark:hover:border-gray-500"
472
- >
473
- 75%
474
- </button>
475
- <button
476
- type="button"
477
- onClick={() => handlePercentageClick(100)}
478
- className="py-1 px-2 text-xs font-medium trails-border-radius-container border border-solid transition-colors cursor-pointer border-gray-300 text-gray-600 dark:border-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700 hover:trails-hover-bg hover:border-gray-400 dark:hover:border-gray-500"
479
- >
480
- Max
481
- </button>
482
- </div>
483
- )}
484
- </div>
485
-
486
- <div className="flex items-center space-x-2">
487
- {/* Amount Input */}
488
- <div className="flex-1">
489
- <div className="flex items-center space-x-2">
490
- <input
491
- ref={inputRef}
492
- id="amount"
493
- type="text"
494
- value={sellAmount}
495
- onChange={(e) => handleSellAmountChange(e.target.value)}
496
- placeholder="0.00"
497
- className={`w-full bg-transparent text-xl font-medium trails-text-primary placeholder:trails-text-muted border-none outline-none ${
498
- isLoadingQuote && tradeType === TradeType.EXACT_OUTPUT
499
- ? "animate-pulse"
500
- : ""
501
- }`}
502
- readOnly={
503
- tradeType === TradeType.EXACT_OUTPUT && isLoadingQuote
504
- }
505
- />
506
- {isLoadingQuote && tradeType === TradeType.EXACT_OUTPUT && (
507
- <div className="animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
508
- )}
509
- </div>
510
- </div>
511
-
512
- {/* Token Selection Button */}
513
- <div className="relative" ref={originTokenDropdownRef}>
514
- <button
515
- type="button"
516
- onClick={() =>
517
- setIsOriginTokenDropdownOpen(!isOriginTokenDropdownOpen)
518
- }
519
- className="flex items-center space-x-2 trails-bg-card hover:trails-hover-bg trails-border-radius-input px-2.5 py-1.5 border trails-border-primary transition-colors cursor-pointer"
520
- >
521
- {originToken ? (
522
- <>
523
- <TokenImage
524
- symbol={originToken.symbol}
525
- imageUrl={originToken.imageUrl}
526
- chainId={originChainId}
527
- size={20}
528
- />
529
- <span className="font-medium trails-text-primary text-sm">
530
- {originToken.symbol}
531
- </span>
532
- <ChevronDown className="w-3.5 h-3.5 trails-text-muted" />
533
- </>
534
- ) : (
535
- <>
536
- <span className="font-medium trails-text-muted text-sm">
537
- Select Token
538
- </span>
539
- <ChevronDown className="w-3.5 h-3.5 trails-text-muted" />
540
- </>
541
- )}
542
- </button>
543
-
544
- {/* Token Selector Modal */}
545
- {isOriginTokenDropdownOpen && (
546
- <div className="absolute right-0 top-full mt-2 w-80 trails-bg-card rounded-lg shadow-lg border trails-border-primary max-h-80 overflow-hidden z-10 -translate-y-28">
547
- <div className="p-2">
548
- <TokenSelector
549
- onTokenSelect={(token: any) => {
550
- const formattedToken = {
551
- ...token,
552
- decimals:
553
- token.contractInfo?.decimals || token.decimals,
554
- contractInfo: {
555
- decimals:
556
- token.contractInfo?.decimals || token.decimals,
557
- contractAddress: token.contractAddress,
558
- symbol: token.symbol,
559
- name: token.name,
560
- },
561
- } as any
562
- setOriginToken(formattedToken)
563
- logger.console.log(
564
- "[trails-sdk] selected origin token",
565
- token,
566
- )
567
- setOriginChainId(token.chainId)
568
- setIsOriginTokenDropdownOpen(false)
569
- // Track the token selection
570
- onTrackToken?.(token)
571
- }}
572
- onError={onError}
573
- fundMethod={fundMethod}
574
- showContinueButton={false}
575
- compactMode={false}
576
- recentTokens={recentTokens}
577
- onRecentTokenSelect={(token) => {
578
- const formattedToken = {
579
- ...token,
580
- decimals: token.decimals,
581
- contractInfo: {
582
- decimals: token.decimals,
583
- contractAddress: token.contractAddress,
584
- symbol: token.symbol,
585
- name: token.name,
586
- },
587
- } as any
588
- setOriginToken(formattedToken)
589
- setOriginChainId(token.chainId)
590
- setIsOriginTokenDropdownOpen(false)
591
- onRecentTokenSelect?.(token)
592
- }}
593
- />
594
- </div>
595
- </div>
596
- )}
597
- </div>
598
- </div>
599
-
600
- {/* Bottom Info Row for sell */}
601
- <div className="mt-2 flex justify-between items-center">
602
- {/* USD Amount */}
603
- {originToken?.symbol && (
604
- <div className="text-xs trails-text-muted">
605
- ≈{" "}
606
- {tradeType === TradeType.EXACT_INPUT
607
- ? amountUsdDisplay || "$0.00"
608
- : isLoadingQuote
609
- ? "$0.00"
610
- : prepareSendQuote?.originAmountUsdDisplay || "$0.00"}
611
- </div>
612
- )}
613
-
614
- {/* Origin Token Balance */}
615
- {originToken && (
616
- <button
617
- type="button"
618
- className="text-xs trails-text-muted cursor-pointer hover:trails-hover-text transition-colors bg-transparent border-none p-0"
619
- onClick={() => {
620
- if (balanceFormatted) {
621
- const balance = parseFloat(balanceFormatted)
622
- if (!Number.isNaN(balance)) {
623
- setTradeType(TradeType.EXACT_INPUT)
624
- setSellAmount(balance.toFixed(6))
625
- setBuyAmount("")
626
- setLastInputType("sell")
627
- }
628
- }
629
- }}
630
- onKeyDown={(e) => {
631
- if (e.key === "Enter" || e.key === " ") {
632
- e.preventDefault()
633
- if (balanceFormatted) {
634
- const balance = parseFloat(balanceFormatted)
635
- if (!Number.isNaN(balance)) {
636
- setTradeType(TradeType.EXACT_INPUT)
637
- setSellAmount(balance.toFixed(6))
638
- setBuyAmount("")
639
- setLastInputType("sell")
640
- }
641
- }
642
- }
643
- }}
644
- title="Click to use full balance"
645
- >
646
- Balance:{" "}
647
- {isBalanceVisible
648
- ? `${balanceFormatted || "0.00"} ${originToken.symbol}`
649
- : "••••••"}
650
- </button>
651
- )}
652
- </div>
653
- </div>
654
-
655
- {/* Flip Button - Absolutely Positioned */}
656
- <div className="relative">
657
- <button
658
- type="button"
659
- onClick={handleFlip}
660
- className="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 p-1.5 trails-border-radius-button trails-bg-tertiary hover:trails-hover-bg transition-colors cursor-pointer border-2 border-white dark:border-gray-800"
661
- >
662
- <ArrowDown className="w-4 h-4 trails-text-secondary" />
663
- </button>
664
- </div>
665
-
666
- {/* Output Section - Amount + Token Selection */}
667
- <div className="trails-bg-secondary trails-border-radius-container p-3 transition-all duration-200 border border-transparent hover:!bg-white dark:hover:!bg-white hover:border-gray-400 dark:hover:border-gray-500">
668
- {/* Buy Label */}
669
- <div className="text-sm font-medium trails-text-secondary mb-2 text-left">
670
- Buy
671
- </div>
672
-
673
- <div className="flex items-center space-x-2">
674
- {/* Output Amount */}
675
- <div className="flex-1">
676
- <div className="flex items-center space-x-2">
677
- <input
678
- type="text"
679
- value={
680
- tradeType === TradeType.EXACT_OUTPUT
681
- ? buyAmount
682
- : toAmountDisplay || ""
683
- }
684
- onChange={(e) => handleBuyAmountChange(e.target.value)}
685
- onFocus={handleBuyInputFocus}
686
- placeholder="0.00"
687
- className={`w-full bg-transparent text-xl font-medium placeholder:trails-text-muted border-none outline-none ${
688
- !amount
689
- ? "text-gray-400 dark:text-gray-500"
690
- : "trails-text-primary"
691
- } ${isLoadingQuote && tradeType === TradeType.EXACT_INPUT ? "animate-pulse" : ""}`}
692
- readOnly={
693
- tradeType === TradeType.EXACT_INPUT && isLoadingQuote
694
- }
695
- />
696
- {isLoadingQuote && tradeType === TradeType.EXACT_INPUT && (
697
- <div className="animate-spin rounded-full h-4 w-4 border-solid border-b-2 trails-primary" />
698
- )}
699
- </div>
700
- </div>
701
-
702
- {/* Destination Token Selection */}
703
- <div className="relative" ref={tokenDropdownRef}>
704
- <button
705
- type="button"
706
- onClick={() => setIsTokenDropdownOpen(!isTokenDropdownOpen)}
707
- className="flex items-center space-x-2 trails-bg-card hover:trails-hover-bg trails-border-radius-input px-2.5 py-1.5 border trails-border-primary transition-colors cursor-pointer"
708
- >
709
- {selectedDestToken ? (
710
- <>
711
- <TokenImage
712
- symbol={selectedDestToken.symbol}
713
- imageUrl={selectedDestToken.imageUrl}
714
- chainId={(selectedDestToken as any)?.chainId}
715
- size={20}
716
- />
717
- <span className="font-medium trails-text-primary text-sm">
718
- {selectedDestToken.symbol}
719
- </span>
720
- <ChevronDown className="w-3.5 h-3.5 trails-text-muted" />
721
- </>
722
- ) : (
723
- <>
724
- <span className="font-medium trails-text-muted text-sm">
725
- Select Token
726
- </span>
727
- <ChevronDown className="w-3.5 h-3.5 trails-text-muted" />
728
- </>
729
- )}
730
- </button>
731
-
732
- {/* Token Selector Modal */}
733
- {isTokenDropdownOpen && (
734
- <div className="absolute right-0 bottom-full mb-1 w-80 trails-bg-card rounded-lg shadow-lg border trails-border-primary max-h-80 overflow-hidden z-10 translate-y-32">
735
- <div className="p-2">
736
- <TokenSelector
737
- onTokenSelect={(token: any) => {
738
- const formattedToken = {
739
- ...token,
740
- decimals:
741
- token.contractInfo?.decimals || token.decimals,
742
- contractInfo: {
743
- decimals:
744
- token.contractInfo?.decimals || token.decimals,
745
- },
746
- } as any
747
- setDestinationToken(formattedToken)
748
- setSelectedDestToken(formattedToken)
749
- logger.console.log(
750
- "[trails-sdk] selected destination token",
751
- token,
752
- )
753
-
754
- setIsTokenDropdownOpen(false)
755
- // Track the token selection
756
- onTrackToken?.(token)
757
- }}
758
- onError={onError}
759
- fundMethod={fundMethod}
760
- allSupportedTokens={true}
761
- showContinueButton={false}
762
- compactMode={false}
763
- recentTokens={recentTokens}
764
- onRecentTokenSelect={(token) => {
765
- const formattedToken = {
766
- ...token,
767
- decimals: token.decimals,
768
- contractInfo: {
769
- decimals: token.decimals,
770
- },
771
- } as any
772
- setDestinationToken(formattedToken)
773
- setSelectedDestToken(formattedToken)
774
- setIsTokenDropdownOpen(false)
775
- onRecentTokenSelect?.(token)
776
- }}
777
- />
778
- </div>
779
- </div>
780
- )}
781
- </div>
782
- </div>
783
-
784
- {/* Bottom Info Row */}
785
- <div className="mt-2 flex justify-between items-center">
786
- {/* Destination Amount USD from Quote */}
787
- {(prepareSendQuote?.destinationAmountUsdDisplay ||
788
- (isLoadingQuote && tradeType === TradeType.EXACT_INPUT)) && (
789
- <div className="text-xs trails-text-muted">
790
- ≈{" "}
791
- {isLoadingQuote && tradeType === TradeType.EXACT_INPUT
792
- ? "$0.00"
793
- : prepareSendQuote?.destinationAmountUsdDisplay}
794
- </div>
795
- )}
796
- </div>
797
- </div>
798
-
799
- {/* Fee Options */}
800
- <FeeOptions
801
- options={feeOptions}
802
- selectedOption={selectedFeeToken ?? undefined}
803
- onSelect={setSelectedFeeToken}
804
- />
805
-
806
- {/* Warning Messages - Show only one at a time */}
807
- {isSameTokenWithoutCustomCalldata ? (
808
- <ErrorDisplay
809
- errorPrettified="Cannot swap to the same token on the same chain without custom calldata. Please select a different destination token."
810
- severity="error"
811
- />
812
- ) : (
813
- <ErrorDisplay
814
- errorPrettified={quoteErrorPrettified}
815
- error={quoteError}
816
- severity="warning"
817
- />
818
- )}
819
- {prepareSendQuote?.noSufficientBalance ? (
820
- <div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
821
- <div className="flex items-center space-x-2">
822
- <svg
823
- className="w-4 h-4 text-amber-500 flex-shrink-0"
824
- fill="none"
825
- stroke="currentColor"
826
- viewBox="0 0 24 24"
827
- aria-hidden="true"
828
- >
829
- <path
830
- strokeLinecap="round"
831
- strokeLinejoin="round"
832
- strokeWidth={2}
833
- 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"
834
- />
835
- </svg>
836
- <p className="text-sm text-amber-600 dark:text-amber-400">
837
- Insufficient balance to complete this transaction. Required{" "}
838
- {prepareSendQuote?.originAmountDisplay} {originToken?.symbol}
839
- </p>
840
- </div>
841
- </div>
842
- ) : prepareSendQuote?.minimumNotMet ? (
843
- <div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
844
- <div className="flex items-center space-x-2">
845
- <svg
846
- className="w-4 h-4 text-amber-500 flex-shrink-0"
847
- fill="none"
848
- stroke="currentColor"
849
- viewBox="0 0 24 24"
850
- aria-hidden="true"
851
- >
852
- <path
853
- strokeLinecap="round"
854
- strokeLinejoin="round"
855
- strokeWidth={2}
856
- 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"
857
- />
858
- </svg>
859
- <p className="text-sm text-amber-600 dark:text-amber-400">
860
- Please enter an amount above{" "}
861
- {formatUsdAmountDisplay(MINIMUM_USD_AMOUNT_FOR_SWAP)}{" "}
862
- otherwise transfer may fail
863
- </p>
864
- </div>
865
- </div>
866
- ) : null}
867
-
868
- {/* Quote Details */}
869
- {prepareSendQuote && (
870
- <div className="space-y-2">
871
- <QuoteDetails
872
- quote={prepareSendQuote}
873
- showContent={true}
874
- swapMode={true}
875
- />
876
- </div>
877
- )}
878
-
879
- <button
880
- type="submit"
881
- disabled={
882
- !amount ||
883
- isSubmitting ||
884
- !destinationTokenAddress ||
885
- !isValidCustomToken ||
886
- isLoadingQuote ||
887
- !prepareSendQuote ||
888
- prepareSendQuote?.noSufficientBalance ||
889
- isSameTokenWithoutCustomCalldata
890
- }
891
- className="w-full font-semibold py-4 px-4 trails-border-radius-button transition-colors bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white disabled:text-gray-500 disabled:cursor-not-allowed cursor-pointer relative"
892
- >
893
- {isSubmitting ? (
894
- <div className="flex items-center justify-center">
895
- <Loader2 className="w-5 h-5 animate-spin mr-2 trails-text-muted" />
896
- <span>{buttonText}</span>
897
- </div>
898
- ) : isSameTokenWithoutCustomCalldata ? (
899
- "Select Different Tokens"
900
- ) : prepareSendQuote?.noSufficientBalance ? (
901
- "Insufficient Balance"
902
- ) : (
903
- buttonText
904
- )}
905
- </button>
906
- </form>
907
- )}
908
- </div>
909
- )
90
+ // Default to ClassicSwap
91
+ return <ClassicSwap {...props} />
910
92
  }
911
93
 
912
94
  export default Swap