0xtrails 0.4.3 → 0.6.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 (207) hide show
  1. package/dist/analytics.d.ts +8 -3
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/{ccip-C9CA3tIi.js → ccip-Dw5AN7oU.js} +27 -27
  4. package/dist/cctp.d.ts +0 -149
  5. package/dist/cctp.d.ts.map +1 -1
  6. package/dist/chains.d.ts +31 -4
  7. package/dist/chains.d.ts.map +1 -1
  8. package/dist/config.d.ts +28 -52
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/constants.d.ts +1 -7
  11. package/dist/constants.d.ts.map +1 -1
  12. package/dist/contractUtils.d.ts.map +1 -1
  13. package/dist/estimate.d.ts.map +1 -1
  14. package/dist/fees.d.ts.map +1 -1
  15. package/dist/gasless.d.ts +12 -0
  16. package/dist/gasless.d.ts.map +1 -1
  17. package/dist/{index-CNB57v0n.js → index-BtVUTbEZ.js} +32255 -40547
  18. package/dist/index.d.ts +13 -11
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +320 -944
  21. package/dist/indexerClient.d.ts +9 -6
  22. package/dist/indexerClient.d.ts.map +1 -1
  23. package/dist/intents.d.ts +0 -18
  24. package/dist/intents.d.ts.map +1 -1
  25. package/dist/mutations.d.ts.map +1 -1
  26. package/dist/paymasterSend.d.ts.map +1 -1
  27. package/dist/prepareSend.d.ts +1 -1
  28. package/dist/prepareSend.d.ts.map +1 -1
  29. package/dist/sendUserOp.d.ts +0 -18
  30. package/dist/sendUserOp.d.ts.map +1 -1
  31. package/dist/sequenceWallet.d.ts +1 -1
  32. package/dist/sequenceWallet.d.ts.map +1 -1
  33. package/dist/tokenBalances.d.ts.map +1 -1
  34. package/dist/tokens.d.ts +10 -8
  35. package/dist/tokens.d.ts.map +1 -1
  36. package/dist/trailsClient.d.ts +3 -3
  37. package/dist/trailsClient.d.ts.map +1 -1
  38. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +4 -5
  39. package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
  40. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +4 -5
  41. package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
  42. package/dist/transactionIntent/deposits/standardDeposit.d.ts +2 -2
  43. package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
  44. package/dist/transactionIntent/execution/transactionState.d.ts +2 -2
  45. package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -1
  46. package/dist/transactionIntent/handlers/crossChain.d.ts +6 -4
  47. package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
  48. package/dist/transactionIntent/handlers/index.d.ts +0 -1
  49. package/dist/transactionIntent/handlers/index.d.ts.map +1 -1
  50. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +4 -34
  51. package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
  52. package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
  53. package/dist/transactionIntent/quote/quoteHelpers.d.ts +2 -1
  54. package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
  55. package/dist/transactionIntent/types.d.ts +7 -19
  56. package/dist/transactionIntent/types.d.ts.map +1 -1
  57. package/dist/transactionIntent/utils/index.d.ts +0 -1
  58. package/dist/transactionIntent/utils/index.d.ts.map +1 -1
  59. package/dist/transactions.d.ts +6 -18
  60. package/dist/transactions.d.ts.map +1 -1
  61. package/dist/utils.d.ts +8 -2
  62. package/dist/utils.d.ts.map +1 -1
  63. package/dist/walletUtils.d.ts +21 -0
  64. package/dist/walletUtils.d.ts.map +1 -0
  65. package/dist/wallets.d.ts +33 -240
  66. package/dist/wallets.d.ts.map +1 -1
  67. package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
  68. package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
  69. package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
  70. package/dist/widget/components/FeeOption.d.ts +8 -13
  71. package/dist/widget/components/FeeOption.d.ts.map +1 -1
  72. package/dist/widget/components/FeeOptions.d.ts +11 -5
  73. package/dist/widget/components/FeeOptions.d.ts.map +1 -1
  74. package/dist/widget/components/NativeGasOption.d.ts.map +1 -1
  75. package/dist/widget/components/Pay.d.ts.map +1 -1
  76. package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
  77. package/dist/widget/components/QRCodeDeposit.d.ts +5 -0
  78. package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
  79. package/dist/widget/components/QRCodeWalletSelect.d.ts +13 -0
  80. package/dist/widget/components/QRCodeWalletSelect.d.ts.map +1 -0
  81. package/dist/widget/components/QrCode.d.ts.map +1 -1
  82. package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
  83. package/dist/widget/components/Receipt.d.ts.map +1 -1
  84. package/dist/widget/components/ScreenHeader.d.ts +1 -1
  85. package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
  86. package/dist/widget/components/SlippageToleranceSettings.d.ts +1 -0
  87. package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
  88. package/dist/widget/components/Toast.d.ts.map +1 -1
  89. package/dist/widget/components/TokenImage.d.ts.map +1 -1
  90. package/dist/widget/components/WalletConnect.d.ts.map +1 -1
  91. package/dist/widget/css/compiled.css +1 -1
  92. package/dist/widget/hooks/useCheckout.d.ts +15 -1
  93. package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
  94. package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
  95. package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
  96. package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
  97. package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
  98. package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
  99. package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts +7 -0
  100. package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts.map +1 -0
  101. package/dist/widget/hooks/useIsSequenceWallet.d.ts +6 -0
  102. package/dist/widget/hooks/useIsSequenceWallet.d.ts.map +1 -0
  103. package/dist/widget/hooks/useQuote.d.ts +6 -11
  104. package/dist/widget/hooks/useQuote.d.ts.map +1 -1
  105. package/dist/widget/hooks/useRecentTokens.d.ts.map +1 -1
  106. package/dist/widget/hooks/useSelectedFeeOption.d.ts +30 -0
  107. package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -0
  108. package/dist/widget/hooks/useSendForm.d.ts +6 -15
  109. package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
  110. package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
  111. package/dist/widget/index.d.ts +1 -0
  112. package/dist/widget/index.d.ts.map +1 -1
  113. package/dist/widget/index.js +4 -2
  114. package/dist/widget/providers/TrailsProvider.d.ts +29 -0
  115. package/dist/widget/providers/TrailsProvider.d.ts.map +1 -0
  116. package/dist/widget/widget.d.ts +14 -3
  117. package/dist/widget/widget.d.ts.map +1 -1
  118. package/package.json +9 -8
  119. package/src/analytics.ts +53 -21
  120. package/src/cctp.ts +0 -1016
  121. package/src/chains.ts +155 -68
  122. package/src/config.ts +51 -207
  123. package/src/constants.ts +1 -13
  124. package/src/contractUtils.ts +6 -6
  125. package/src/estimate.ts +3 -6
  126. package/src/fees.ts +5 -10
  127. package/src/gasless.ts +45 -0
  128. package/src/index.ts +18 -40
  129. package/src/indexerClient.ts +39 -48
  130. package/src/intents.ts +51 -226
  131. package/src/mutations.ts +3 -2
  132. package/src/paymasterSend.ts +2 -5
  133. package/src/prepareSend.ts +21 -14
  134. package/src/sendUserOp.ts +3 -64
  135. package/src/sequenceWallet.ts +1 -2
  136. package/src/tokenBalances.ts +2 -1
  137. package/src/tokens.ts +62 -133
  138. package/src/trailsClient.ts +17 -12
  139. package/src/transactionIntent/deposits/depositOrchestrator.ts +14 -15
  140. package/src/transactionIntent/deposits/gaslessDeposit.ts +70 -100
  141. package/src/transactionIntent/deposits/standardDeposit.ts +22 -28
  142. package/src/transactionIntent/execution/transactionState.ts +2 -2
  143. package/src/transactionIntent/handlers/crossChain.ts +179 -381
  144. package/src/transactionIntent/handlers/index.ts +0 -1
  145. package/src/transactionIntent/handlers/sameChainSameToken.ts +228 -94
  146. package/src/transactionIntent/quote/normalizeQuote.ts +4 -6
  147. package/src/transactionIntent/quote/quoteHelpers.ts +35 -3
  148. package/src/transactionIntent/types.ts +7 -27
  149. package/src/transactionIntent/utils/index.ts +0 -1
  150. package/src/transactions.ts +19 -118
  151. package/src/umd.tsx +1 -3
  152. package/src/utils.ts +28 -8
  153. package/src/walletUtils.ts +42 -0
  154. package/src/wallets.ts +365 -208
  155. package/src/widget/compiled.css +1 -1
  156. package/src/widget/components/AccountIntentTransactionHistory.tsx +78 -4
  157. package/src/widget/components/AccountSettings.tsx +17 -17
  158. package/src/widget/components/ChainList.tsx +3 -3
  159. package/src/widget/components/ClassicSwap.tsx +19 -10
  160. package/src/widget/components/ConfigDisplay.tsx +19 -59
  161. package/src/widget/components/FeeOption.tsx +63 -20
  162. package/src/widget/components/FeeOptions.tsx +54 -123
  163. package/src/widget/components/NativeGasOption.tsx +3 -1
  164. package/src/widget/components/Pay.tsx +18 -11
  165. package/src/widget/components/PoolDeposit.tsx +23 -10
  166. package/src/widget/components/QRCodeDeposit.tsx +50 -30
  167. package/src/widget/components/QRCodeWalletSelect.tsx +77 -0
  168. package/src/widget/components/QrCode.tsx +188 -233
  169. package/src/widget/components/QuoteDetails.tsx +48 -2
  170. package/src/widget/components/Receipt.tsx +5 -2
  171. package/src/widget/components/ScreenHeader.tsx +10 -8
  172. package/src/widget/components/SlippageToleranceSettings.tsx +63 -14
  173. package/src/widget/components/Toast.tsx +10 -0
  174. package/src/widget/components/TokenImage.tsx +56 -13
  175. package/src/widget/components/WalletConnect.tsx +37 -99
  176. package/src/widget/hooks/useCheckout.ts +71 -0
  177. package/src/widget/hooks/useCurrentScreen.tsx +1 -0
  178. package/src/widget/hooks/useDebugScreens.ts +5 -0
  179. package/src/widget/hooks/useIntentTransactionHistory.ts +790 -412
  180. package/src/widget/hooks/useIsConnectedWalletSmartContract.ts +43 -0
  181. package/src/widget/hooks/useIsSequenceWallet.ts +17 -0
  182. package/src/widget/hooks/useQuote.ts +27 -34
  183. package/src/widget/hooks/useRecentTokens.ts +2 -1
  184. package/src/widget/hooks/useSelectedFeeOption.tsx +257 -0
  185. package/src/widget/hooks/useSendForm.ts +175 -46
  186. package/src/widget/hooks/useTokenList.ts +15 -2
  187. package/src/widget/index.tsx +8 -0
  188. package/src/widget/providers/TrailsProvider.tsx +123 -0
  189. package/src/widget/widget.tsx +165 -143
  190. package/dist/cctpqueue.d.ts +0 -18
  191. package/dist/cctpqueue.d.ts.map +0 -1
  192. package/dist/preconditions.d.ts +0 -12
  193. package/dist/preconditions.d.ts.map +0 -1
  194. package/dist/trails.d.ts +0 -110
  195. package/dist/trails.d.ts.map +0 -1
  196. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +0 -62
  197. package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +0 -1
  198. package/dist/transactionIntent/utils/lifiHelpers.d.ts +0 -10
  199. package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +0 -1
  200. package/dist/widget/hooks/useSelectedFeeToken.d.ts +0 -33
  201. package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +0 -1
  202. package/src/cctpqueue.ts +0 -66
  203. package/src/preconditions.ts +0 -47
  204. package/src/trails.ts +0 -1303
  205. package/src/transactionIntent/handlers/sameChainDifferentToken.ts +0 -323
  206. package/src/transactionIntent/utils/lifiHelpers.ts +0 -68
  207. package/src/widget/hooks/useSelectedFeeToken.tsx +0 -288
@@ -1,7 +1,7 @@
1
1
  import type React from "react"
2
2
  import { useState, useEffect } from "react"
3
3
  import { HelpCircle } from "lucide-react"
4
- import { getSlippageTolerance, setSlippageTolerance } from "../../config.js"
4
+ import { useTrails } from "../providers/TrailsProvider.js"
5
5
 
6
6
  // Convert decimal format to percentage for display
7
7
  // Format: "0.05" (5%) -> "5"
@@ -17,6 +17,20 @@ const percentageToDecimal = (percentage: string): string => {
17
17
  return (num / 100).toString()
18
18
  }
19
19
 
20
+ // Local storage key for user's slippage preference
21
+ const SLIPPAGE_STORAGE_KEY = "trails-slippage-tolerance"
22
+
23
+ // Helper function to get current slippage tolerance (for use in SDK functions)
24
+ // Returns the user's stored preference or falls back to the provided default
25
+ export const getSlippageToleranceValue = (defaultValue: string): string => {
26
+ try {
27
+ const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
28
+ return stored || defaultValue
29
+ } catch (_error) {
30
+ return defaultValue
31
+ }
32
+ }
33
+
20
34
  interface SlippageToleranceSettingsProps {
21
35
  className?: string
22
36
  }
@@ -24,14 +38,25 @@ interface SlippageToleranceSettingsProps {
24
38
  export const SlippageToleranceSettings: React.FC<
25
39
  SlippageToleranceSettingsProps
26
40
  > = ({ className = "" }) => {
41
+ const config = useTrails()
27
42
  const [displayValue, setDisplayValue] = useState("")
28
43
  const [showTooltip, setShowTooltip] = useState(false)
29
44
 
30
- // Initialize display value from current config
45
+ // Initialize display value from local storage or config
31
46
  useEffect(() => {
32
- const currentSlippage = getSlippageTolerance()
33
- setDisplayValue(decimalToPercentage(currentSlippage))
34
- }, [])
47
+ try {
48
+ const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
49
+ if (stored) {
50
+ setDisplayValue(decimalToPercentage(stored))
51
+ } else {
52
+ // Default to config value
53
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
54
+ }
55
+ } catch (_error) {
56
+ // Fallback to config if localStorage fails
57
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
58
+ }
59
+ }, [config.slippageTolerance])
35
60
 
36
61
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
37
62
  const value = e.target.value
@@ -49,9 +74,17 @@ export const SlippageToleranceSettings: React.FC<
49
74
 
50
75
  const handleInputBlur = () => {
51
76
  if (displayValue === "") {
52
- // Reset to current value if empty
53
- const currentSlippage = getSlippageTolerance()
54
- setDisplayValue(decimalToPercentage(currentSlippage))
77
+ // Reset to stored value or config default
78
+ try {
79
+ const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
80
+ if (stored) {
81
+ setDisplayValue(decimalToPercentage(stored))
82
+ } else {
83
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
84
+ }
85
+ } catch (_error) {
86
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
87
+ }
55
88
  return
56
89
  }
57
90
 
@@ -59,15 +92,27 @@ export const SlippageToleranceSettings: React.FC<
59
92
 
60
93
  // Validate range (0.01% to 50%)
61
94
  if (percentage < 0.01 || percentage > 50) {
62
- // Reset to current value if invalid
63
- const currentSlippage = getSlippageTolerance()
64
- setDisplayValue(decimalToPercentage(currentSlippage))
95
+ // Reset to stored value or config default
96
+ try {
97
+ const stored = localStorage.getItem(SLIPPAGE_STORAGE_KEY)
98
+ if (stored) {
99
+ setDisplayValue(decimalToPercentage(stored))
100
+ } else {
101
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
102
+ }
103
+ } catch (_error) {
104
+ setDisplayValue(decimalToPercentage(String(config.slippageTolerance)))
105
+ }
65
106
  return
66
107
  }
67
108
 
68
- // Convert to decimal format and save
109
+ // Convert to decimal format and save to localStorage
69
110
  const decimalValue = percentageToDecimal(displayValue)
70
- setSlippageTolerance(decimalValue)
111
+ try {
112
+ localStorage.setItem(SLIPPAGE_STORAGE_KEY, decimalValue)
113
+ } catch (error) {
114
+ console.warn("Failed to save slippage tolerance to localStorage:", error)
115
+ }
71
116
 
72
117
  // Update display to show formatted value
73
118
  setDisplayValue(percentage.toString())
@@ -83,7 +128,11 @@ export const SlippageToleranceSettings: React.FC<
83
128
  const percentageStr = percentage.toString()
84
129
  setDisplayValue(percentageStr)
85
130
  const decimalValue = percentageToDecimal(percentageStr)
86
- setSlippageTolerance(decimalValue)
131
+ try {
132
+ localStorage.setItem(SLIPPAGE_STORAGE_KEY, decimalValue)
133
+ } catch (error) {
134
+ console.warn("Failed to save slippage tolerance to localStorage:", error)
135
+ }
87
136
  }
88
137
 
89
138
  return (
@@ -298,6 +298,16 @@ function ToastItem({ toast, onRemove }: ToastItemProps) {
298
298
  <p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">
299
299
  {toast.message}
300
300
  </p>
301
+ {toast.type === "error" && (
302
+ <a
303
+ href="https://support.trails.build/en/"
304
+ target="_blank"
305
+ rel="noopener noreferrer"
306
+ className="mt-2 text-xs text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 underline inline-block"
307
+ >
308
+ Visit support
309
+ </a>
310
+ )}
301
311
  </div>
302
312
  <button
303
313
  type="button"
@@ -1,16 +1,18 @@
1
- import React, { useMemo } from "react"
1
+ import { useMemo, useState, useEffect, useRef } from "react"
2
+ import type React from "react"
2
3
  import { ChainImage } from "./ChainImage.js"
3
4
  import { getCommonTokenImageUrl } from "../../tokens.js"
4
5
  import { logger } from "../../logger.js"
6
+ import { commonTokenImages } from "../../tokens.js"
5
7
 
6
8
  function normalizeImageUrl(
7
9
  imageUrl?: string | null,
8
10
  symbol?: string | null,
9
11
  chainId?: number | null,
10
12
  contractAddress?: string | null,
11
- ) {
13
+ ): string | null {
12
14
  if (symbol === "ETH") {
13
- return "https://assets.sequence.info/images/tokens/large/1/0x0000000000000000000000000000000000000000.webp"
15
+ return commonTokenImages.ETH!
14
16
  }
15
17
  const commonImageUrl = getCommonTokenImageUrl({
16
18
  symbol,
@@ -43,24 +45,64 @@ export const TokenImage: React.FC<TokenImageProps> = ({
43
45
  contractAddress,
44
46
  size = 24,
45
47
  }) => {
46
- const [imageError, setImageError] = React.useState(false)
47
- const effectiveImageUrl = useMemo(() => {
48
- logger.console.log("[TokenImage] normalizeImageUrl", {
49
- imageUrl,
50
- symbol,
51
- chainId,
52
- contractAddress,
53
- })
48
+ const [imageError, setImageError] = useState(false)
49
+ const [imageSize, setImageSize] = useState<{
50
+ width: number
51
+ height: number
52
+ } | null>(null)
53
+ const previousUrlRef = useRef<string | null>(null)
54
+
55
+ const effectiveImageUrl = useMemo<string | null>(() => {
54
56
  return normalizeImageUrl(imageUrl, symbol, chainId, contractAddress)
55
57
  }, [imageUrl, symbol, chainId, contractAddress])
56
58
 
59
+ // Reset image size and error when URL changes
60
+ useEffect(() => {
61
+ if (previousUrlRef.current !== effectiveImageUrl) {
62
+ setImageSize(null)
63
+ setImageError(false)
64
+ previousUrlRef.current = effectiveImageUrl
65
+ }
66
+ }, [effectiveImageUrl])
67
+
57
68
  const displaySymbol = symbol?.[0]?.toUpperCase() || "?"
58
69
 
70
+ const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {
71
+ const img = e.currentTarget
72
+ const size = {
73
+ width: img.naturalWidth,
74
+ height: img.naturalHeight,
75
+ }
76
+ setImageSize(size)
77
+ logger.console.log("[TokenImage] Image loaded", {
78
+ effectiveImageUrl,
79
+ naturalWidth: img.naturalWidth,
80
+ naturalHeight: img.naturalHeight,
81
+ symbol,
82
+ chainId,
83
+ contractAddress,
84
+ })
85
+ }
86
+
59
87
  const handleImageError = () => {
60
- setImageError(true)
88
+ // Only set error if we haven't already determined it's invalid
89
+ // This prevents unnecessary state updates
90
+ if (!imageError) {
91
+ logger.console.error("[TokenImage] Image load error", {
92
+ effectiveImageUrl,
93
+ imageUrl,
94
+ symbol,
95
+ chainId,
96
+ contractAddress,
97
+ })
98
+ setImageError(true)
99
+ }
61
100
  }
62
101
 
63
- const shouldShowText = !effectiveImageUrl || imageError
102
+ // Show text if no URL, error, or image is 1x1 or less (transparent pixel)
103
+ const isTransparentPixel =
104
+ imageSize !== null && imageSize.width <= 1 && imageSize.height <= 1
105
+ const shouldShowText = !effectiveImageUrl || imageError || isTransparentPixel
64
106
 
65
107
  return (
66
108
  <div
@@ -92,6 +134,7 @@ export const TokenImage: React.FC<TokenImageProps> = ({
92
134
  src={effectiveImageUrl}
93
135
  alt={symbol || "Token"}
94
136
  className="absolute w-full h-full rounded-full object-contain"
137
+ onLoad={handleImageLoad}
95
138
  onError={handleImageError}
96
139
  title={`Token: ${symbol}`}
97
140
  style={{
@@ -3,7 +3,7 @@ import { useAccount, useConnect, useDisconnect } from "wagmi"
3
3
  import { walletConnect } from "wagmi/connectors"
4
4
  import { QrCode } from "./QrCode.js"
5
5
  import { TruncatedAddress } from "./TruncatedAddress.js"
6
- import { getWalletConnectProjectId } from "../../config.js"
6
+ import { useTrails } from "../providers/TrailsProvider.js"
7
7
  import { ScreenHeader } from "./ScreenHeader.js"
8
8
  import { getWalletIcon, getWalletName } from "../../wallets.js"
9
9
  import { logger } from "../../logger.js"
@@ -18,14 +18,14 @@ export interface WalletConnectProps {
18
18
 
19
19
  // Local singleton to avoid multiple Core initializations from this screen
20
20
  let wcConnectorSingleton: ReturnType<typeof walletConnect> | null = null
21
- function getWalletConnectConnector(projectId?: string) {
21
+ function getWalletConnectConnector(projectId: string) {
22
22
  if (!wcConnectorSingleton) {
23
23
  logger.console.log(
24
24
  "[trails-sdk] [WalletConnect] Creating new connector with projectId:",
25
- projectId || getWalletConnectProjectId(),
25
+ projectId,
26
26
  )
27
27
  wcConnectorSingleton = walletConnect({
28
- projectId: projectId || getWalletConnectProjectId(),
28
+ projectId: projectId,
29
29
  showQrModal: false,
30
30
  })
31
31
  }
@@ -35,16 +35,17 @@ function getWalletConnectConnector(projectId?: string) {
35
35
  export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
36
36
  onBack,
37
37
  onContinue,
38
- projectId,
38
+ projectId: projectIdProp,
39
39
  onReconnectPreviousWallet,
40
40
  selectedWalletId,
41
41
  }) => {
42
+ const config = useTrails()
43
+ const projectId = projectIdProp || config.walletConnectProjectId
42
44
  const { connect, connectors, status } = useConnect() as any
43
45
  const { disconnect } = useDisconnect()
44
46
  const { isConnected, address, connector } = useAccount()
45
47
  const [wcUri, setWcUri] = React.useState<string | null>(null)
46
48
  const [showUri, setShowUri] = React.useState(false)
47
- const [copied, setCopied] = React.useState(false)
48
49
  const listenerRef = React.useRef<(() => void) | null>(null)
49
50
  const debounceTimeoutRef = useRef<NodeJS.Timeout | null>(null)
50
51
 
@@ -58,21 +59,6 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
58
59
  setWcUri(uri)
59
60
  }, 500) // 300ms debounce delay
60
61
  }, [])
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])
76
62
  const isWalletConnectConnector = React.useMemo(() => {
77
63
  return connector?.name === "WalletConnect" && isConnected
78
64
  }, [connector, isConnected])
@@ -84,13 +70,18 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
84
70
  (c.id || "").toLowerCase().includes("walletconnect"),
85
71
  )
86
72
 
87
- // Only auto-navigate to home if we successfully connect a new wallet
73
+ // Only auto-navigate back if we successfully connect a new wallet
88
74
  // Don't auto-navigate if user was already connected when they entered this screen
89
75
  useEffect(() => {
90
- if (isConnected && status === "success" && !wasConnectedOnMount.current) {
91
- onContinue()
76
+ if (
77
+ isConnected &&
78
+ status === "success" &&
79
+ !wasConnectedOnMount.current &&
80
+ onBack
81
+ ) {
82
+ onBack()
92
83
  }
93
- }, [isConnected, status, onContinue])
84
+ }, [isConnected, status, onBack])
94
85
 
95
86
  const handleConnect = useCallback(
96
87
  async (force: boolean = false) => {
@@ -101,7 +92,7 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
101
92
  })
102
93
  if ((status === "pending" || status === "success") && !force) return
103
94
 
104
- const makeConnector = () => getWalletConnectConnector(projectId)
95
+ const makeConnector = () => getWalletConnectConnector(projectId!)
105
96
  const connector = wcConnectorFromConfig || makeConnector()
106
97
 
107
98
  logger.console.log(
@@ -317,82 +308,29 @@ export const WalletConnectScreen: React.FC<WalletConnectProps> = ({
317
308
  getWalletIcon("walletconnect")
318
309
  }
319
310
  />
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"
311
+ <button
312
+ onClick={() => setShowUri(!showUri)}
313
+ 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"
314
+ >
315
+ {showUri ? "Hide URI" : "Show URI"}
316
+ <svg
317
+ className={`w-3 h-3 transition-transform ${showUri ? "rotate-180" : ""}`}
318
+ fill="none"
319
+ stroke="currentColor"
320
+ viewBox="0 0 24 24"
326
321
  >
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>
322
+ <path
323
+ strokeLinecap="round"
324
+ strokeLinejoin="round"
325
+ strokeWidth={2}
326
+ d="M19 9l-7 7-7-7"
327
+ />
328
+ </svg>
329
+ </button>
387
330
  {showUri && (
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
- >
331
+ <p className="mt-2 text-xs text-gray-600 dark:text-gray-400 break-all">
394
332
  {wcUri}
395
- </button>
333
+ </p>
396
334
  )}
397
335
  </div>
398
336
  ) : (
@@ -19,6 +19,15 @@ export type CheckoutCallbacks = {
19
19
  sessionId: string
20
20
  error: unknown
21
21
  }) => void
22
+ onCheckoutApprovalRequest?: (data: { sessionId: string }) => void
23
+ onCheckoutApprovalConfirmed?: (data: {
24
+ sessionId: string
25
+ transactionHash: `0x${string}`
26
+ }) => void
27
+ onCheckoutApprovalRejected?: (data: {
28
+ sessionId: string
29
+ error: unknown
30
+ }) => void
22
31
  onCheckoutComplete?: (data: { sessionId: string }) => void
23
32
  onCheckoutError?: (data: { sessionId: string; error: unknown }) => void
24
33
  onCheckoutStatusUpdate?: (data: {
@@ -33,6 +42,9 @@ export type CheckoutOnHandlers = {
33
42
  triggerCheckoutSignatureRequest: () => void
34
43
  triggerCheckoutSignatureConfirmed: () => void
35
44
  triggerCheckoutSignatureRejected: (error: unknown) => void
45
+ triggerCheckoutApprovalRequest: () => void
46
+ triggerCheckoutApprovalConfirmed: (transactionHash: `0x${string}`) => void
47
+ triggerCheckoutApprovalRejected: (error: unknown) => void
36
48
  triggerCheckoutComplete: (
37
49
  txStatus: "success" | "fail",
38
50
  accountAddress?: string,
@@ -59,6 +71,9 @@ export function useCheckout({
59
71
  onCheckoutSignatureRequest,
60
72
  onCheckoutSignatureConfirmed,
61
73
  onCheckoutSignatureRejected,
74
+ onCheckoutApprovalRequest,
75
+ onCheckoutApprovalConfirmed,
76
+ onCheckoutApprovalRejected,
62
77
  onCheckoutComplete,
63
78
  onCheckoutError,
64
79
  onCheckoutStatusUpdate,
@@ -152,6 +167,59 @@ export function useCheckout({
152
167
  [onCheckoutSignatureRejected],
153
168
  )
154
169
 
170
+ const triggerCheckoutApprovalRequest = useCallback(() => {
171
+ if (onCheckoutApprovalRequest && sessionIdRef.current) {
172
+ try {
173
+ onCheckoutApprovalRequest({
174
+ sessionId: sessionIdRef.current,
175
+ })
176
+ } catch (error) {
177
+ logger.console.error(
178
+ "[trails-sdk] Error calling onCheckoutApprovalRequest:",
179
+ error,
180
+ )
181
+ }
182
+ }
183
+ }, [onCheckoutApprovalRequest])
184
+
185
+ const triggerCheckoutApprovalConfirmed = useCallback(
186
+ (transactionHash: `0x${string}`) => {
187
+ if (onCheckoutApprovalConfirmed && sessionIdRef.current) {
188
+ try {
189
+ onCheckoutApprovalConfirmed({
190
+ sessionId: sessionIdRef.current,
191
+ transactionHash,
192
+ })
193
+ } catch (error) {
194
+ logger.console.error(
195
+ "[trails-sdk] Error calling onCheckoutApprovalConfirmed:",
196
+ error,
197
+ )
198
+ }
199
+ }
200
+ },
201
+ [onCheckoutApprovalConfirmed],
202
+ )
203
+
204
+ const triggerCheckoutApprovalRejected = useCallback(
205
+ (error: unknown) => {
206
+ if (onCheckoutApprovalRejected && sessionIdRef.current) {
207
+ try {
208
+ onCheckoutApprovalRejected({
209
+ sessionId: sessionIdRef.current,
210
+ error,
211
+ })
212
+ } catch (callbackError) {
213
+ logger.console.error(
214
+ "[trails-sdk] Error calling onCheckoutApprovalRejected:",
215
+ callbackError,
216
+ )
217
+ }
218
+ }
219
+ },
220
+ [onCheckoutApprovalRejected],
221
+ )
222
+
155
223
  const triggerCheckoutComplete = useCallback(
156
224
  (txStatus: "success" | "fail", accountAddress?: string) => {
157
225
  if (onCheckoutComplete && sessionIdRef.current) {
@@ -256,6 +324,9 @@ export function useCheckout({
256
324
  triggerCheckoutSignatureRequest,
257
325
  triggerCheckoutSignatureConfirmed,
258
326
  triggerCheckoutSignatureRejected,
327
+ triggerCheckoutApprovalRequest,
328
+ triggerCheckoutApprovalConfirmed,
329
+ triggerCheckoutApprovalRejected,
259
330
  triggerCheckoutComplete,
260
331
  triggerCheckoutError,
261
332
  triggerCheckoutStatusUpdate,
@@ -12,6 +12,7 @@ export type Screen =
12
12
  | "swap"
13
13
  | "receive"
14
14
  | "wallet-confirmation"
15
+ | "qr-code-wallet-select"
15
16
  | "qr-code-deposit"
16
17
  | "pending"
17
18
  | "receipt"
@@ -16,6 +16,7 @@ type Screen =
16
16
  | "swap"
17
17
  | "receive"
18
18
  | "wallet-confirmation"
19
+ | "qr-code-wallet-select"
19
20
  | "qr-code-deposit"
20
21
  | "pending"
21
22
  | "receipt"
@@ -132,6 +133,10 @@ export const useDebugScreens = ({
132
133
  setShowWalletConfirmRetry(false)
133
134
  setCurrentScreen("wallet-confirmation")
134
135
  break
136
+ case "qr-code-wallet-select":
137
+ setPrepareSendQuote(dummyQuote)
138
+ setCurrentScreen("qr-code-wallet-select")
139
+ break
135
140
  case "wallet-confirmation-retry":
136
141
  // Set dummy USDC token for debug mode
137
142
  setSelectedToken(dummySelectedToken)