0xtrails 0.2.5 → 0.3.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 (267) hide show
  1. package/dist/aave.d.ts +2 -0
  2. package/dist/aave.d.ts.map +1 -1
  3. package/dist/abortController.d.ts +8 -0
  4. package/dist/abortController.d.ts.map +1 -0
  5. package/dist/{ccip-CXlshvBY.js → ccip-BMB3uDZt.js} +1 -1
  6. package/dist/config.d.ts +0 -5
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/constants.d.ts +4 -4
  9. package/dist/constants.d.ts.map +1 -1
  10. package/dist/error.d.ts +4 -1
  11. package/dist/error.d.ts.map +1 -1
  12. package/dist/fees.d.ts +19 -0
  13. package/dist/fees.d.ts.map +1 -0
  14. package/dist/{index-_QuyGrjU.js → index-QXPUrZVv.js} +48719 -50852
  15. package/dist/index.d.ts +9 -8
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +811 -784
  18. package/dist/intentReceiptMonitor.d.ts +24 -0
  19. package/dist/intentReceiptMonitor.d.ts.map +1 -0
  20. package/dist/intentReceiptPoller.d.ts +69 -0
  21. package/dist/intentReceiptPoller.d.ts.map +1 -0
  22. package/dist/intents.d.ts +15 -11
  23. package/dist/intents.d.ts.map +1 -1
  24. package/dist/morpho.d.ts +6 -5
  25. package/dist/morpho.d.ts.map +1 -1
  26. package/dist/mutations.d.ts +16 -0
  27. package/dist/mutations.d.ts.map +1 -0
  28. package/dist/preconditions.d.ts +5 -4
  29. package/dist/preconditions.d.ts.map +1 -1
  30. package/dist/prepareSend.d.ts +7 -258
  31. package/dist/prepareSend.d.ts.map +1 -1
  32. package/dist/prices.d.ts +9 -6
  33. package/dist/prices.d.ts.map +1 -1
  34. package/dist/sequenceWallet.d.ts +3 -16
  35. package/dist/sequenceWallet.d.ts.map +1 -1
  36. package/dist/tokenBalances.d.ts +17 -13
  37. package/dist/tokenBalances.d.ts.map +1 -1
  38. package/dist/trails.d.ts +24 -40
  39. package/dist/trails.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 +6 -3
  85. package/dist/transactions.d.ts.map +1 -1
  86. package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts +4 -0
  87. package/dist/widget/components/AccountIntentTransactionHistoryButton.d.ts.map +1 -0
  88. package/dist/widget/components/AccountSettings.d.ts.map +1 -1
  89. package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
  90. package/dist/widget/components/ClassicSwap.d.ts +2 -3
  91. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  92. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  93. package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
  94. package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
  95. package/dist/widget/components/DynamicInputStyles.d.ts +18 -0
  96. package/dist/widget/components/DynamicInputStyles.d.ts.map +1 -0
  97. package/dist/widget/components/DynamicSizeInputField.d.ts +13 -0
  98. package/dist/widget/components/DynamicSizeInputField.d.ts.map +1 -0
  99. package/dist/widget/components/Earn.d.ts +2 -3
  100. package/dist/widget/components/Earn.d.ts.map +1 -1
  101. package/dist/widget/components/ErrorAnimationIcon.d.ts +2 -0
  102. package/dist/widget/components/ErrorAnimationIcon.d.ts.map +1 -0
  103. package/dist/widget/components/FeeBreakdown.d.ts +9 -0
  104. package/dist/widget/components/FeeBreakdown.d.ts.map +1 -0
  105. package/dist/widget/components/FeeOptions.d.ts +5 -13
  106. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  107. package/dist/widget/components/Fund.d.ts +2 -3
  108. package/dist/widget/components/Fund.d.ts.map +1 -1
  109. package/dist/widget/components/FundMethods.d.ts.map +1 -1
  110. package/dist/widget/components/FundSwap.d.ts +2 -3
  111. package/dist/widget/components/FundSwap.d.ts.map +1 -1
  112. package/dist/widget/components/FundingMethodSelectorButton.d.ts.map +1 -1
  113. package/dist/widget/components/Identicon.d.ts.map +1 -1
  114. package/dist/widget/components/MeshConnectExchanges.d.ts +0 -3
  115. package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
  116. package/dist/widget/components/Modal.d.ts.map +1 -1
  117. package/dist/widget/components/Pay.d.ts +2 -3
  118. package/dist/widget/components/Pay.d.ts.map +1 -1
  119. package/dist/widget/components/PoolDeposit.d.ts +3 -3
  120. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  121. package/dist/widget/components/PoolWithdraw.d.ts +3 -20
  122. package/dist/widget/components/PoolWithdraw.d.ts.map +1 -1
  123. package/dist/widget/components/QuoteDetails.d.ts +2 -0
  124. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  125. package/dist/widget/components/Receipt.d.ts.map +1 -1
  126. package/dist/widget/components/RecipientSelectorButton.d.ts.map +1 -1
  127. package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
  128. package/dist/widget/components/Swap.d.ts +2 -3
  129. package/dist/widget/components/Swap.d.ts.map +1 -1
  130. package/dist/widget/components/ThemeProvider.d.ts.map +1 -1
  131. package/dist/widget/components/TokenDisplayNonSelectable.d.ts +11 -0
  132. package/dist/widget/components/TokenDisplayNonSelectable.d.ts.map +1 -0
  133. package/dist/widget/components/TokenSelector.d.ts.map +1 -1
  134. package/dist/widget/components/TokenSelectorButton.d.ts.map +1 -1
  135. package/dist/widget/components/Tooltip.d.ts +9 -0
  136. package/dist/widget/components/Tooltip.d.ts.map +1 -0
  137. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -1
  138. package/dist/widget/components/WaasFeeOptions.d.ts +1 -0
  139. package/dist/widget/components/WaasFeeOptions.d.ts.map +1 -1
  140. package/dist/widget/components/WalletConfirmation.d.ts.map +1 -1
  141. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  142. package/dist/widget/css/compiled.css +2 -2
  143. package/dist/widget/hooks/useCheckout.d.ts +17 -4
  144. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  145. package/dist/widget/hooks/useDefaultTokenSelection.d.ts.map +1 -1
  146. package/dist/widget/hooks/useQuote.d.ts +82 -0
  147. package/dist/widget/hooks/useQuote.d.ts.map +1 -0
  148. package/dist/widget/hooks/useSelectedFeeToken.d.ts +1 -0
  149. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -1
  150. package/dist/widget/hooks/useSendForm.d.ts +5 -6
  151. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  152. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  153. package/dist/widget/hooks/useWalletConnectionContext.d.ts +25 -0
  154. package/dist/widget/hooks/useWalletConnectionContext.d.ts.map +1 -0
  155. package/dist/widget/index.js +2 -2
  156. package/dist/widget/widget.d.ts +17 -7
  157. package/dist/widget/widget.d.ts.map +1 -1
  158. package/package.json +19 -21
  159. package/src/aave.ts +54 -1
  160. package/src/abortController.ts +35 -0
  161. package/src/config.ts +57 -58
  162. package/src/constants.ts +11 -9
  163. package/src/error.ts +21 -3
  164. package/src/fees.ts +210 -0
  165. package/src/index.ts +35 -13
  166. package/src/intentReceiptMonitor.ts +102 -0
  167. package/src/intentReceiptPoller.ts +299 -0
  168. package/src/intents.ts +205 -171
  169. package/src/morpho.ts +58 -9
  170. package/src/mutations.ts +129 -0
  171. package/src/preconditions.ts +16 -21
  172. package/src/prepareSend.ts +92 -4699
  173. package/src/prices.ts +26 -22
  174. package/src/relaySdk.ts +2 -2
  175. package/src/sequenceWallet.ts +6 -73
  176. package/src/tokenBalances.ts +175 -69
  177. package/src/trails.ts +230 -722
  178. package/src/transactionIntent/constants.ts +11 -0
  179. package/src/transactionIntent/deposits/depositOrchestrator.ts +210 -0
  180. package/src/transactionIntent/deposits/gaslessDeposit.ts +588 -0
  181. package/src/transactionIntent/deposits/index.ts +3 -0
  182. package/src/transactionIntent/deposits/standardDeposit.ts +379 -0
  183. package/src/transactionIntent/execution/index.ts +1 -0
  184. package/src/transactionIntent/execution/transactionState.ts +35 -0
  185. package/src/transactionIntent/handlers/crossChain.ts +1707 -0
  186. package/src/transactionIntent/handlers/index.ts +3 -0
  187. package/src/transactionIntent/handlers/sameChainDifferentToken.ts +323 -0
  188. package/src/transactionIntent/handlers/sameChainSameToken.ts +712 -0
  189. package/src/transactionIntent/index.ts +9 -0
  190. package/src/transactionIntent/quote/feeExtractors.ts +81 -0
  191. package/src/transactionIntent/quote/index.ts +3 -0
  192. package/src/transactionIntent/quote/normalizeQuote.ts +367 -0
  193. package/src/transactionIntent/quote/quoteHelpers.ts +53 -0
  194. package/src/transactionIntent/types.ts +157 -0
  195. package/src/transactionIntent/utils/balanceChecker.ts +96 -0
  196. package/src/transactionIntent/utils/index.ts +3 -0
  197. package/src/transactionIntent/utils/lifiHelpers.ts +68 -0
  198. package/src/transactionIntent/utils/testnetHelpers.ts +10 -0
  199. package/src/transactionIntent/validators.ts +57 -0
  200. package/src/transactions.ts +98 -71
  201. package/src/widget/compiled.css +2 -2
  202. package/src/widget/components/AccountIntentTransactionHistory.tsx +36 -36
  203. package/src/widget/components/AccountIntentTransactionHistoryButton.tsx +22 -0
  204. package/src/widget/components/AccountSettings.tsx +70 -41
  205. package/src/widget/components/ChainFilterDropdown.tsx +24 -3
  206. package/src/widget/components/ClassicSwap.tsx +44 -107
  207. package/src/widget/components/ConfigDisplay.tsx +0 -11
  208. package/src/widget/components/ConnectWallet.tsx +4 -1
  209. package/src/widget/components/ConnectedWallets.tsx +51 -25
  210. package/src/widget/components/DynamicInputStyles.tsx +76 -0
  211. package/src/widget/components/DynamicSizeInputField.tsx +109 -0
  212. package/src/widget/components/Earn.tsx +34 -45
  213. package/src/widget/components/ErrorAnimationIcon.tsx +130 -0
  214. package/src/widget/components/FeeBreakdown.tsx +155 -0
  215. package/src/widget/components/FeeOption.tsx +2 -2
  216. package/src/widget/components/FeeOptions.tsx +151 -112
  217. package/src/widget/components/Fund.tsx +10 -29
  218. package/src/widget/components/FundMethods.tsx +4 -3
  219. package/src/widget/components/FundSwap.tsx +2 -3
  220. package/src/widget/components/FundingMethodSelectorButton.tsx +24 -14
  221. package/src/widget/components/Identicon.tsx +164 -95
  222. package/src/widget/components/MeshConnectExchanges.tsx +2 -15
  223. package/src/widget/components/Modal.tsx +0 -12
  224. package/src/widget/components/Pay.tsx +72 -75
  225. package/src/widget/components/PoolDeposit.tsx +221 -242
  226. package/src/widget/components/PoolWithdraw.tsx +347 -469
  227. package/src/widget/components/PriceImpactWarning.tsx +1 -1
  228. package/src/widget/components/QuoteDetails.tsx +906 -484
  229. package/src/widget/components/Receipt.tsx +16 -2
  230. package/src/widget/components/RecipientSelectorButton.tsx +7 -5
  231. package/src/widget/components/Recipients.tsx +1 -1
  232. package/src/widget/components/ScreenHeader.tsx +60 -36
  233. package/src/widget/components/Swap.tsx +2 -3
  234. package/src/widget/components/ThemeProvider.tsx +2 -1
  235. package/src/widget/components/TokenDisplayNonSelectable.tsx +40 -0
  236. package/src/widget/components/TokenImage.tsx +1 -1
  237. package/src/widget/components/TokenSelector.tsx +62 -53
  238. package/src/widget/components/TokenSelectorButton.tsx +38 -15
  239. package/src/widget/components/Tooltip.tsx +51 -0
  240. package/src/widget/components/TransferPendingVertical.tsx +12 -8
  241. package/src/widget/components/WaasFeeOptions.tsx +139 -4
  242. package/src/widget/components/WalletConfirmation.tsx +23 -13
  243. package/src/widget/components/WalletConnect.tsx +93 -29
  244. package/src/widget/hooks/useAmountUsd.ts +9 -9
  245. package/src/widget/hooks/useCheckout.ts +97 -9
  246. package/src/widget/hooks/useDefaultTokenSelection.tsx +27 -21
  247. package/src/widget/hooks/useQuote.ts +466 -0
  248. package/src/widget/hooks/useSelectedFeeToken.tsx +32 -37
  249. package/src/widget/hooks/useSendForm.ts +45 -51
  250. package/src/widget/hooks/useTokenList.ts +34 -26
  251. package/src/widget/hooks/useWalletConnectionContext.tsx +128 -0
  252. package/src/widget/widget.tsx +365 -390
  253. package/dist/apiClient.d.ts +0 -9
  254. package/dist/apiClient.d.ts.map +0 -1
  255. package/dist/intentEntrypoint.d.ts +0 -114
  256. package/dist/intentEntrypoint.d.ts.map +0 -1
  257. package/dist/metaTxnMonitor.d.ts +0 -15
  258. package/dist/metaTxnMonitor.d.ts.map +0 -1
  259. package/dist/metaTxns.d.ts +0 -11
  260. package/dist/metaTxns.d.ts.map +0 -1
  261. package/dist/relayer.d.ts +0 -43
  262. package/dist/relayer.d.ts.map +0 -1
  263. package/src/apiClient.ts +0 -35
  264. package/src/intentEntrypoint.ts +0 -203
  265. package/src/metaTxnMonitor.ts +0 -171
  266. package/src/metaTxns.ts +0 -45
  267. package/src/relayer.ts +0 -289
@@ -1,7 +1,7 @@
1
1
  import { useEffect, useState } from "react"
2
2
  import { useWaasFeeOptions } from "@0xsequence/connect"
3
3
  import { TokenImage } from "./TokenImage.js"
4
- import { ChevronDown, ChevronUp } from "lucide-react"
4
+ import { ChevronDown, ChevronUp, Copy } from "lucide-react"
5
5
  import { formatUnits } from "viem"
6
6
 
7
7
  // Define types based on the @0xsequence/connect documentation
@@ -29,12 +29,14 @@ interface WaasFeeOptionsProps {
29
29
  chainId?: number
30
30
  setIsFeeOptionConfirmed: (isFeeOptionConfirmed: boolean) => void
31
31
  onFeeOptionsLoaded?: () => void
32
+ setIsError?: (isError: boolean) => void
32
33
  }
33
34
 
34
35
  export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
35
36
  chainId,
36
37
  setIsFeeOptionConfirmed,
37
38
  onFeeOptionsLoaded,
39
+ setIsError,
38
40
  }) => {
39
41
  const [
40
42
  pendingFeeOptionConfirmation,
@@ -47,6 +49,7 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
47
49
  const [isExpanded, setIsExpanded] = useState(false)
48
50
  const [isProcessing, setIsProcessing] = useState(false)
49
51
  const [isLoading, setIsLoading] = useState(false)
52
+ const [copiedAddress, setCopiedAddress] = useState<string | null>(null)
50
53
 
51
54
  // Debug logging
52
55
  useEffect(() => {
@@ -97,7 +100,10 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
97
100
  // Notify parent that fee options are loaded
98
101
  if (
99
102
  onFeeOptionsLoaded &&
100
- pendingFeeOptionConfirmation.options?.length > 0
103
+ pendingFeeOptionConfirmation.options?.length > 0 &&
104
+ pendingFeeOptionConfirmation.options.find(
105
+ (option: any) => option.hasEnoughBalanceForFee,
106
+ )
101
107
  ) {
102
108
  onFeeOptionsLoaded()
103
109
  }
@@ -139,6 +145,30 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
139
145
  }
140
146
  }
141
147
 
148
+ // Handle copy address to clipboard
149
+ const handleCopyAddress = async (address: string, e: React.MouseEvent) => {
150
+ e.preventDefault()
151
+ e.stopPropagation()
152
+ try {
153
+ await navigator.clipboard.writeText(address)
154
+ setCopiedAddress(address)
155
+ setTimeout(() => setCopiedAddress(null), 2000)
156
+ } catch (_error) {
157
+ try {
158
+ const textArea = document.createElement("textarea")
159
+ textArea.value = address
160
+ document.body.appendChild(textArea)
161
+ textArea.select()
162
+ document.execCommand("copy")
163
+ document.body.removeChild(textArea)
164
+ setCopiedAddress(address)
165
+ setTimeout(() => setCopiedAddress(null), 2000)
166
+ } catch (fallbackError) {
167
+ console.error("Fallback copy failed:", fallbackError)
168
+ }
169
+ }
170
+ }
171
+
142
172
  // Don't render if no pending fee confirmation
143
173
  if (!pendingFeeOptionConfirmation) {
144
174
  return null
@@ -162,6 +192,111 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
162
192
  | FeeOptionExtended
163
193
  | undefined
164
194
 
195
+ const hasTokenForFee = pendingFeeOptionConfirmation.options.find(
196
+ (option: any) => option.hasEnoughBalanceForFee,
197
+ )
198
+
199
+ if (!hasTokenForFee) {
200
+ setIsError?.(true)
201
+ }
202
+
203
+ if (!hasTokenForFee) {
204
+ return (
205
+ <div className="space-y-4 py-6">
206
+ {/* Warning Message */}
207
+ <div className="p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg">
208
+ <div className="flex items-start space-x-2">
209
+ <svg
210
+ className="w-5 h-5 text-red-600 dark:text-red-400 shrink-0 mt-0.5"
211
+ fill="none"
212
+ viewBox="0 0 24 24"
213
+ stroke="currentColor"
214
+ >
215
+ <path
216
+ strokeLinecap="round"
217
+ strokeLinejoin="round"
218
+ strokeWidth={2}
219
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
220
+ />
221
+ </svg>
222
+ <p className="text-sm text-red-800 dark:text-red-200 font-medium">
223
+ No available tokens for fees, please transfer any of these tokens
224
+ to your wallet.
225
+ </p>
226
+ </div>
227
+ </div>
228
+
229
+ <div className="flex flex-col space-y-2">
230
+ {pendingFeeOptionConfirmation.options.map((option: any) => {
231
+ const contractAddress = option.token.contractAddress
232
+
233
+ return (
234
+ <div
235
+ key={option.token.symbol || contractAddress}
236
+ className="flex items-center space-x-3 p-3 trails-bg-secondary trails-border-radius-container border border-transparent"
237
+ >
238
+ <div className="flex items-center shrink-0">
239
+ <TokenImage
240
+ symbol={option.token.symbol}
241
+ imageUrl={(option.token as any).logoURL}
242
+ chainId={chainId}
243
+ size={32}
244
+ />
245
+ </div>
246
+ <div className="flex-1 min-w-0 flex flex-col items-start">
247
+ <span className="text-sm font-bold trails-text-primary leading-tight">
248
+ {option.token.symbol}
249
+ </span>
250
+ {contractAddress ? (
251
+ <div className="flex items-center space-x-1.5 mt-0.5">
252
+ <span className="text-xs trails-text-muted leading-tight">
253
+ {contractAddress.slice(0, 4)}...
254
+ {contractAddress.slice(-4)}
255
+ </span>
256
+ <button
257
+ type="button"
258
+ onClick={(e) => handleCopyAddress(contractAddress, e)}
259
+ className="shrink-0 p-0.5 rounded transition-colors cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-700 flex items-center justify-center"
260
+ title={
261
+ copiedAddress === contractAddress
262
+ ? "Copied!"
263
+ : "Copy address"
264
+ }
265
+ >
266
+ {copiedAddress === contractAddress ? (
267
+ <svg
268
+ className="w-3 h-3 text-green-600 dark:text-green-400"
269
+ fill="none"
270
+ viewBox="0 0 24 24"
271
+ stroke="currentColor"
272
+ aria-label="Copied"
273
+ >
274
+ <path
275
+ strokeLinecap="round"
276
+ strokeLinejoin="round"
277
+ strokeWidth={2}
278
+ d="M5 13l4 4L19 7"
279
+ />
280
+ </svg>
281
+ ) : (
282
+ <Copy className="w-3 h-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" />
283
+ )}
284
+ </button>
285
+ </div>
286
+ ) : (
287
+ <span className="text-xs trails-text-muted mt-0.5 leading-tight">
288
+ Native Token
289
+ </span>
290
+ )}
291
+ </div>
292
+ </div>
293
+ )
294
+ })}
295
+ </div>
296
+ </div>
297
+ )
298
+ }
299
+
165
300
  return (
166
301
  <div className="space-y-2">
167
302
  {/* Header */}
@@ -208,7 +343,7 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
208
343
  {/* Display balance info if available */}
209
344
  {selectedOption && "balanceFormatted" in selectedOption && (
210
345
  <div className="text-right">
211
- <div className="text-xs trails-text-muted">
346
+ <div className="text-xs text-gray-500 dark:text-gray-400">
212
347
  Balance: {String(selectedOption.balanceFormatted)}
213
348
  </div>
214
349
  {!selectedOption.hasEnoughBalanceForFee && (
@@ -266,7 +401,7 @@ export const WaasFeeOptions: React.FC<WaasFeeOptionsProps> = ({
266
401
  {/* Display balance info if available */}
267
402
  {"balanceFormatted" in option && (
268
403
  <div className="text-right">
269
- <div className="text-xs trails-text-muted">
404
+ <div className="text-xs text-gray-500 dark:text-gray-400">
270
405
  Balance: {String(option.balanceFormatted)}
271
406
  </div>
272
407
  <div className="text-xs trails-text-muted">
@@ -1,4 +1,5 @@
1
1
  import { TokenImage } from "./TokenImage.js"
2
+ import { ErrorAnimationIcon } from "./ErrorAnimationIcon.js"
2
3
  import { ChevronLeft } from "lucide-react"
3
4
  import type React from "react"
4
5
  import { useEffect, useMemo, useState } from "react"
@@ -25,9 +26,11 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
25
26
  const [showTimeoutWarning, setShowTimeoutWarning] = useState(false)
26
27
  const [isFeeOptionConfirmed, setIsFeeOptionConfirmed] = useState(false)
27
28
  const [areFeeOptionsLoaded, setAreFeeOptionsLoaded] = useState(false)
29
+ const [feeOptionsError, setFeeOptionsError] = useState<boolean>(false)
28
30
  const { connector } = useAccount()
29
31
 
30
32
  useEffect(() => {
33
+ setAreFeeOptionsLoaded(false)
31
34
  setShowContent(true)
32
35
  }, [])
33
36
 
@@ -80,21 +83,25 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
80
83
  <div
81
84
  className={`mx-auto flex items-center justify-center transition-all duration-500 ease-out relative mb-4 ${showContent ? "transform -translate-y-8" : ""}`}
82
85
  >
83
- {retryEnabled ? (
86
+ {feeOptionsError ? (
87
+ <ErrorAnimationIcon />
88
+ ) : retryEnabled ? (
84
89
  <div className={`h-24 w-24`} />
85
90
  ) : (
86
91
  <div className="animate-spin rounded-full h-24 w-24 border-solid border-b-2 border-blue-500 dark:border-blue-400" />
87
92
  )}
88
93
 
89
- <div className="absolute">
90
- <TokenImage
91
- imageUrl={quote?.originToken.imageUrl}
92
- symbol={quote?.originToken.symbol}
93
- chainId={quote?.originChain.id}
94
- contractAddress={quote?.originToken.contractAddress}
95
- size={64}
96
- />
97
- </div>
94
+ {!feeOptionsError && (
95
+ <div className="absolute">
96
+ <TokenImage
97
+ imageUrl={quote?.originToken.imageUrl}
98
+ symbol={quote?.originToken.symbol}
99
+ chainId={quote?.originChain.id}
100
+ contractAddress={quote?.originToken.contractAddress}
101
+ size={64}
102
+ />
103
+ </div>
104
+ )}
98
105
  </div>
99
106
 
100
107
  <div
@@ -109,7 +116,9 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
109
116
  ? "Waiting for wallet…"
110
117
  : areFeeOptionsLoaded
111
118
  ? "Waiting for fee selection…"
112
- : "Waiting for fee options…"}
119
+ : feeOptionsError
120
+ ? "No fee token found"
121
+ : "Waiting for fee options…"}
113
122
  </h2>
114
123
  <p className="mt-2 text-sm text-gray-600 dark:text-gray-300">
115
124
  {!isSequenceWaas
@@ -127,6 +136,7 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
127
136
  <WaasFeeOptions
128
137
  chainId={quote?.originChain.id}
129
138
  setIsFeeOptionConfirmed={setIsFeeOptionConfirmed}
139
+ setIsError={setFeeOptionsError}
130
140
  onFeeOptionsLoaded={() => {
131
141
  console.log("[trails-sdk] Fee options loaded callback called")
132
142
  setAreFeeOptionsLoaded(true)
@@ -144,7 +154,7 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
144
154
  <div className="p-4 trails-border-radius-container text-sm bg-yellow-50 border border-solid border-yellow-200 dark:bg-yellow-900/20 dark:border-yellow-700/50">
145
155
  <div className="flex items-start space-x-3">
146
156
  <svg
147
- className="w-5 h-5 mt-0.5 flex-shrink-0 text-yellow-600 dark:text-yellow-400"
157
+ className="w-5 h-5 mt-0.5 shrink-0 text-yellow-600 dark:text-yellow-400"
148
158
  fill="none"
149
159
  viewBox="0 0 24 24"
150
160
  stroke="currentColor"
@@ -187,7 +197,7 @@ export const WalletConfirmation: React.FC<WalletConfirmationProps> = ({
187
197
  )}
188
198
 
189
199
  {/* Transaction Details */}
190
- <QuoteDetails quote={quote} showContent={true} />
200
+ <QuoteDetails quote={quote} showContent={true} compact={true} />
191
201
  </div>
192
202
  </div>
193
203
  )
@@ -44,6 +44,7 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
44
44
  const { isConnected, address, connector } = useAccount()
45
45
  const [wcUri, setWcUri] = React.useState<string | null>(null)
46
46
  const [showUri, setShowUri] = React.useState(false)
47
+ const [copied, setCopied] = React.useState(false)
47
48
  const listenerRef = React.useRef<(() => void) | null>(null)
48
49
  const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null)
49
50
 
@@ -57,6 +58,21 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
57
58
  setWcUri(uri)
58
59
  }, 500) // 300ms debounce delay
59
60
  }, [])
61
+
62
+ // Copy URI to clipboard
63
+ const handleCopyUri = useCallback(async () => {
64
+ if (!wcUri) return
65
+ try {
66
+ await navigator.clipboard.writeText(wcUri)
67
+ setCopied(true)
68
+ setTimeout(() => setCopied(false), 2000)
69
+ } catch (err) {
70
+ logger.console.error(
71
+ "[trails-sdk] [WalletConnect] Failed to copy URI",
72
+ err,
73
+ )
74
+ }
75
+ }, [wcUri])
60
76
  const isWalletConnectConnector = React.useMemo(() => {
61
77
  return connector?.name === "WalletConnect" && isConnected
62
78
  }, [connector, isConnected])
@@ -68,18 +84,13 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
68
84
  (c.id || "").toLowerCase().includes("walletconnect"),
69
85
  )
70
86
 
71
- // Only auto-navigate back if we successfully connect a new wallet
87
+ // Only auto-navigate to home if we successfully connect a new wallet
72
88
  // Don't auto-navigate if user was already connected when they entered this screen
73
89
  useEffect(() => {
74
- if (
75
- isConnected &&
76
- status === "success" &&
77
- !wasConnectedOnMount.current &&
78
- onBack
79
- ) {
80
- onBack()
90
+ if (isConnected && status === "success" && !wasConnectedOnMount.current) {
91
+ onContinue()
81
92
  }
82
- }, [isConnected, status, onBack])
93
+ }, [isConnected, status, onContinue])
83
94
 
84
95
  const handleConnect = useCallback(
85
96
  async (force: boolean = false) => {
@@ -306,29 +317,82 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
306
317
  getWalletIcon("walletconnect")
307
318
  }
308
319
  />
309
- <button
310
- onClick={() => setShowUri(!showUri)}
311
- className="mt-2 text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:underline cursor-pointer flex items-center gap-1"
312
- >
313
- {showUri ? "Hide URI" : "Show URI"}
314
- <svg
315
- className={`w-3 h-3 transition-transform ${showUri ? "rotate-180" : ""}`}
316
- fill="none"
317
- stroke="currentColor"
318
- viewBox="0 0 24 24"
320
+ <div className="flex items-center justify-center gap-2 mt-2">
321
+ <button
322
+ type="button"
323
+ onClick={handleCopyUri}
324
+ className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 cursor-pointer flex items-center gap-1 hover:underline"
325
+ title="Copy URI to clipboard"
319
326
  >
320
- <path
321
- strokeLinecap="round"
322
- strokeLinejoin="round"
323
- strokeWidth={2}
324
- d="M19 9l-7 7-7-7"
325
- />
326
- </svg>
327
- </button>
327
+ {copied ? (
328
+ <>
329
+ <svg
330
+ className="w-3 h-3"
331
+ fill="none"
332
+ stroke="currentColor"
333
+ viewBox="0 0 24 24"
334
+ aria-hidden="true"
335
+ >
336
+ <path
337
+ strokeLinecap="round"
338
+ strokeLinejoin="round"
339
+ strokeWidth={2}
340
+ d="M5 13l4 4L19 7"
341
+ />
342
+ </svg>
343
+ Copied!
344
+ </>
345
+ ) : (
346
+ <>
347
+ <svg
348
+ className="w-3 h-3"
349
+ fill="none"
350
+ stroke="currentColor"
351
+ viewBox="0 0 24 24"
352
+ aria-hidden="true"
353
+ >
354
+ <path
355
+ strokeLinecap="round"
356
+ strokeLinejoin="round"
357
+ strokeWidth={2}
358
+ d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"
359
+ />
360
+ </svg>
361
+ Copy URI
362
+ </>
363
+ )}
364
+ </button>
365
+ <button
366
+ type="button"
367
+ onClick={() => setShowUri(!showUri)}
368
+ className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:underline cursor-pointer flex items-center gap-1"
369
+ >
370
+ {showUri ? "Hide URI" : "Show URI"}
371
+ <svg
372
+ className={`w-3 h-3 transition-transform ${showUri ? "rotate-180" : ""}`}
373
+ fill="none"
374
+ stroke="currentColor"
375
+ viewBox="0 0 24 24"
376
+ aria-hidden="true"
377
+ >
378
+ <path
379
+ strokeLinecap="round"
380
+ strokeLinejoin="round"
381
+ strokeWidth={2}
382
+ d="M19 9l-7 7-7-7"
383
+ />
384
+ </svg>
385
+ </button>
386
+ </div>
328
387
  {showUri && (
329
- <p className="mt-2 text-xs text-gray-600 dark:text-gray-400 break-all">
388
+ <button
389
+ type="button"
390
+ className="mt-2 text-xs text-gray-600 dark:text-gray-400 break-all cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-800 p-2 rounded transition-colors text-left w-full"
391
+ onClick={handleCopyUri}
392
+ title="Click to copy URI"
393
+ >
330
394
  {wcUri}
331
- </p>
395
+ </button>
332
396
  )}
333
397
  </div>
334
398
  ) : (
@@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"
2
2
  import { useTokenPrice } from "../../prices.js"
3
3
  import { formatUsdAmountDisplay } from "../../tokenBalances.js"
4
4
  import { useTokenAddress } from "../../tokens.js"
5
- import { useAPIClient } from "../../apiClient.js"
5
+ import { useTrailsClient } from "../../trailsClient.js"
6
6
 
7
7
  type UseAmountUsdProps = {
8
8
  amount?: string | null
@@ -14,7 +14,7 @@ export function useAmountUsd({ amount, token, chainId }: UseAmountUsdProps): {
14
14
  amountUsd: number | null
15
15
  amountUsdFormatted: string
16
16
  } {
17
- const apiClient = useAPIClient()
17
+ const trailsClient = useTrailsClient()
18
18
  const isTokenAddress = token?.startsWith("0x")
19
19
  const resolvedTokenAddress = useTokenAddress({
20
20
  chainId,
@@ -25,26 +25,26 @@ export function useAmountUsd({ amount, token, chainId }: UseAmountUsdProps): {
25
25
  const { tokenPrice } = useTokenPrice(
26
26
  token && tokenAddress && chainId
27
27
  ? {
28
- tokenId: token,
29
- contractAddress: tokenAddress,
28
+ tokenSymbol: token,
29
+ tokenAddress: tokenAddress,
30
30
  chainId: Number(chainId),
31
31
  }
32
32
  : null,
33
- apiClient,
33
+ trailsClient,
34
34
  )
35
35
 
36
36
  const { data: amountUsd } = useQuery({
37
- queryKey: ["amountUsd", amount, tokenPrice?.price?.value],
37
+ queryKey: ["amountUsd", amount, tokenPrice?.priceUsd],
38
38
  queryFn: () => {
39
- if (!amount || !tokenPrice?.price?.value) {
39
+ if (!amount || !tokenPrice?.priceUsd) {
40
40
  return null
41
41
  }
42
42
 
43
- const tokenPriceValue = tokenPrice.price.value
43
+ const tokenPriceValue = tokenPrice.priceUsd
44
44
  const value = Number(amount) * tokenPriceValue
45
45
  return value
46
46
  },
47
- enabled: !!amount && !!tokenPrice?.price?.value,
47
+ enabled: !!amount && !!tokenPrice?.priceUsd,
48
48
  })
49
49
 
50
50
  return {
@@ -2,13 +2,25 @@ import { useCallback, useRef } from "react"
2
2
  import { getSessionId } from "../../analytics.js"
3
3
  import { logger } from "../../logger.js"
4
4
  import { updatePersistentToast } from "../../toast.js"
5
- import { getPrettifiedErrorMessage } from "../../error.js"
5
+ import {
6
+ getPrettifiedErrorMessage,
7
+ getIsUserRejectionError,
8
+ UserRejectionError,
9
+ getErrorString,
10
+ } from "../../error.js"
11
+ import { invalidateTokenBalancesCache } from "../../tokenBalances.js"
6
12
 
7
13
  export type CheckoutCallbacks = {
8
14
  onCheckoutStart?: (data: { sessionId: string }) => void
9
15
  onCheckoutQuote?: (data: { sessionId: string; quote: any }) => void
16
+ onCheckoutSignatureRequest?: (data: { sessionId: string }) => void
17
+ onCheckoutSignatureConfirmed?: (data: { sessionId: string }) => void
18
+ onCheckoutSignatureRejected?: (data: {
19
+ sessionId: string
20
+ error: unknown
21
+ }) => void
10
22
  onCheckoutComplete?: (data: { sessionId: string }) => void
11
- onCheckoutError?: (data: { sessionId: string; error: string }) => void
23
+ onCheckoutError?: (data: { sessionId: string; error: unknown }) => void
12
24
  onCheckoutStatusUpdate?: (data: {
13
25
  sessionId: string
14
26
  transactionStates: any[]
@@ -18,8 +30,14 @@ export type CheckoutCallbacks = {
18
30
  export type CheckoutOnHandlers = {
19
31
  triggerCheckoutStart: () => void
20
32
  triggerCheckoutQuote: (quote: any) => void
21
- triggerCheckoutComplete: (txStatus: "success" | "fail") => void
22
- triggerCheckoutError: (error: string) => void
33
+ triggerCheckoutSignatureRequest: () => void
34
+ triggerCheckoutSignatureConfirmed: () => void
35
+ triggerCheckoutSignatureRejected: (error: unknown) => void
36
+ triggerCheckoutComplete: (
37
+ txStatus: "success" | "fail",
38
+ accountAddress?: string,
39
+ ) => void
40
+ triggerCheckoutError: (error: unknown) => void
23
41
  triggerCheckoutStatusUpdate: (transactionStates: any[]) => void
24
42
  }
25
43
 
@@ -38,6 +56,9 @@ export type UseCheckoutReturn = {
38
56
  export function useCheckout({
39
57
  onCheckoutStart,
40
58
  onCheckoutQuote,
59
+ onCheckoutSignatureRequest,
60
+ onCheckoutSignatureConfirmed,
61
+ onCheckoutSignatureRejected,
41
62
  onCheckoutComplete,
42
63
  onCheckoutError,
43
64
  onCheckoutStatusUpdate,
@@ -82,8 +103,57 @@ export function useCheckout({
82
103
  [onCheckoutQuote],
83
104
  )
84
105
 
106
+ const triggerCheckoutSignatureRequest = useCallback(() => {
107
+ if (onCheckoutSignatureRequest && sessionIdRef.current) {
108
+ try {
109
+ onCheckoutSignatureRequest({
110
+ sessionId: sessionIdRef.current,
111
+ })
112
+ } catch (error) {
113
+ logger.console.error(
114
+ "[trails-sdk] Error calling onCheckoutSignatureRequest:",
115
+ error,
116
+ )
117
+ }
118
+ }
119
+ }, [onCheckoutSignatureRequest])
120
+
121
+ const triggerCheckoutSignatureConfirmed = useCallback(() => {
122
+ if (onCheckoutSignatureConfirmed && sessionIdRef.current) {
123
+ try {
124
+ onCheckoutSignatureConfirmed({
125
+ sessionId: sessionIdRef.current,
126
+ })
127
+ } catch (error) {
128
+ logger.console.error(
129
+ "[trails-sdk] Error calling onCheckoutSignatureConfirmed:",
130
+ error,
131
+ )
132
+ }
133
+ }
134
+ }, [onCheckoutSignatureConfirmed])
135
+
136
+ const triggerCheckoutSignatureRejected = useCallback(
137
+ (error: unknown) => {
138
+ if (onCheckoutSignatureRejected && sessionIdRef.current) {
139
+ try {
140
+ onCheckoutSignatureRejected({
141
+ sessionId: sessionIdRef.current,
142
+ error,
143
+ })
144
+ } catch (callbackError) {
145
+ logger.console.error(
146
+ "[trails-sdk] Error calling onCheckoutSignatureRejected:",
147
+ callbackError,
148
+ )
149
+ }
150
+ }
151
+ },
152
+ [onCheckoutSignatureRejected],
153
+ )
154
+
85
155
  const triggerCheckoutComplete = useCallback(
86
- (txStatus: "success" | "fail") => {
156
+ (txStatus: "success" | "fail", accountAddress?: string) => {
87
157
  if (onCheckoutComplete && sessionIdRef.current) {
88
158
  try {
89
159
  onCheckoutComplete({
@@ -98,6 +168,9 @@ export function useCheckout({
98
168
  }
99
169
 
100
170
  if (txStatus === "success") {
171
+ // Invalidate token balances cache to trigger a refresh
172
+ invalidateTokenBalancesCache(accountAddress)
173
+
101
174
  updatePersistentToast(
102
175
  "Transaction Complete",
103
176
  "Your transaction has been successfully processed",
@@ -116,12 +189,24 @@ export function useCheckout({
116
189
  )
117
190
 
118
191
  const triggerCheckoutError = useCallback(
119
- (error: string) => {
192
+ (error: unknown) => {
193
+ // Wrap user rejection errors in custom UserRejectionError class
194
+ let processedError = error
195
+ const isUserRejection = getIsUserRejectionError(error)
196
+
197
+ if (isUserRejection) {
198
+ const errorMessage = getErrorString(error)
199
+ processedError = new UserRejectionError(errorMessage)
200
+
201
+ // Trigger signature rejected callback for user rejections
202
+ triggerCheckoutSignatureRejected(processedError)
203
+ }
204
+
120
205
  if (onCheckoutError && sessionIdRef.current) {
121
206
  try {
122
207
  onCheckoutError({
123
208
  sessionId: sessionIdRef.current,
124
- error,
209
+ error: processedError,
125
210
  })
126
211
  } catch (error) {
127
212
  logger.console.error(
@@ -134,13 +219,13 @@ export function useCheckout({
134
219
  updatePersistentToast(
135
220
  "Transaction Failed",
136
221
  getPrettifiedErrorMessage(
137
- error,
222
+ processedError,
138
223
  "An error occurred while processing your transaction",
139
224
  ),
140
225
  "error",
141
226
  )
142
227
  },
143
- [onCheckoutError],
228
+ [onCheckoutError, triggerCheckoutSignatureRejected],
144
229
  )
145
230
 
146
231
  const triggerCheckoutStatusUpdate = useCallback(
@@ -168,6 +253,9 @@ export function useCheckout({
168
253
  checkoutOnHandlers: {
169
254
  triggerCheckoutStart,
170
255
  triggerCheckoutQuote,
256
+ triggerCheckoutSignatureRequest,
257
+ triggerCheckoutSignatureConfirmed,
258
+ triggerCheckoutSignatureRejected,
171
259
  triggerCheckoutComplete,
172
260
  triggerCheckoutError,
173
261
  triggerCheckoutStatusUpdate,