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.
- package/dist/analytics.d.ts +8 -3
- package/dist/analytics.d.ts.map +1 -1
- package/dist/{ccip-C9CA3tIi.js → ccip-Dw5AN7oU.js} +27 -27
- package/dist/cctp.d.ts +0 -149
- package/dist/cctp.d.ts.map +1 -1
- package/dist/chains.d.ts +31 -4
- package/dist/chains.d.ts.map +1 -1
- package/dist/config.d.ts +28 -52
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -7
- package/dist/constants.d.ts.map +1 -1
- package/dist/contractUtils.d.ts.map +1 -1
- package/dist/estimate.d.ts.map +1 -1
- package/dist/fees.d.ts.map +1 -1
- package/dist/gasless.d.ts +12 -0
- package/dist/gasless.d.ts.map +1 -1
- package/dist/{index-CNB57v0n.js → index-BtVUTbEZ.js} +32255 -40547
- package/dist/index.d.ts +13 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +320 -944
- package/dist/indexerClient.d.ts +9 -6
- package/dist/indexerClient.d.ts.map +1 -1
- package/dist/intents.d.ts +0 -18
- package/dist/intents.d.ts.map +1 -1
- package/dist/mutations.d.ts.map +1 -1
- package/dist/paymasterSend.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +1 -1
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/sendUserOp.d.ts +0 -18
- package/dist/sendUserOp.d.ts.map +1 -1
- package/dist/sequenceWallet.d.ts +1 -1
- package/dist/sequenceWallet.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/tokens.d.ts +10 -8
- package/dist/tokens.d.ts.map +1 -1
- package/dist/trailsClient.d.ts +3 -3
- package/dist/trailsClient.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts +4 -5
- package/dist/transactionIntent/deposits/depositOrchestrator.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts +4 -5
- package/dist/transactionIntent/deposits/gaslessDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/deposits/standardDeposit.d.ts +2 -2
- package/dist/transactionIntent/deposits/standardDeposit.d.ts.map +1 -1
- package/dist/transactionIntent/execution/transactionState.d.ts +2 -2
- package/dist/transactionIntent/execution/transactionState.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/crossChain.d.ts +6 -4
- package/dist/transactionIntent/handlers/crossChain.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/index.d.ts +0 -1
- package/dist/transactionIntent/handlers/index.d.ts.map +1 -1
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts +4 -34
- package/dist/transactionIntent/handlers/sameChainSameToken.d.ts.map +1 -1
- package/dist/transactionIntent/quote/normalizeQuote.d.ts.map +1 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts +2 -1
- package/dist/transactionIntent/quote/quoteHelpers.d.ts.map +1 -1
- package/dist/transactionIntent/types.d.ts +7 -19
- package/dist/transactionIntent/types.d.ts.map +1 -1
- package/dist/transactionIntent/utils/index.d.ts +0 -1
- package/dist/transactionIntent/utils/index.d.ts.map +1 -1
- package/dist/transactions.d.ts +6 -18
- package/dist/transactions.d.ts.map +1 -1
- package/dist/utils.d.ts +8 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/walletUtils.d.ts +21 -0
- package/dist/walletUtils.d.ts.map +1 -0
- package/dist/wallets.d.ts +33 -240
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/AccountIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/components/ClassicSwap.d.ts.map +1 -1
- package/dist/widget/components/ConfigDisplay.d.ts.map +1 -1
- package/dist/widget/components/FeeOption.d.ts +8 -13
- package/dist/widget/components/FeeOption.d.ts.map +1 -1
- package/dist/widget/components/FeeOptions.d.ts +11 -5
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/NativeGasOption.d.ts.map +1 -1
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PoolDeposit.d.ts.map +1 -1
- package/dist/widget/components/QRCodeDeposit.d.ts +5 -0
- package/dist/widget/components/QRCodeDeposit.d.ts.map +1 -1
- package/dist/widget/components/QRCodeWalletSelect.d.ts +13 -0
- package/dist/widget/components/QRCodeWalletSelect.d.ts.map +1 -0
- package/dist/widget/components/QrCode.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/Receipt.d.ts.map +1 -1
- package/dist/widget/components/ScreenHeader.d.ts +1 -1
- package/dist/widget/components/ScreenHeader.d.ts.map +1 -1
- package/dist/widget/components/SlippageToleranceSettings.d.ts +1 -0
- package/dist/widget/components/SlippageToleranceSettings.d.ts.map +1 -1
- package/dist/widget/components/Toast.d.ts.map +1 -1
- package/dist/widget/components/TokenImage.d.ts.map +1 -1
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/css/compiled.css +1 -1
- package/dist/widget/hooks/useCheckout.d.ts +15 -1
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts +1 -1
- package/dist/widget/hooks/useCurrentScreen.d.ts.map +1 -1
- package/dist/widget/hooks/useDebugScreens.d.ts +1 -1
- package/dist/widget/hooks/useDebugScreens.d.ts.map +1 -1
- package/dist/widget/hooks/useIntentTransactionHistory.d.ts.map +1 -1
- package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts +7 -0
- package/dist/widget/hooks/useIsConnectedWalletSmartContract.d.ts.map +1 -0
- package/dist/widget/hooks/useIsSequenceWallet.d.ts +6 -0
- package/dist/widget/hooks/useIsSequenceWallet.d.ts.map +1 -0
- package/dist/widget/hooks/useQuote.d.ts +6 -11
- package/dist/widget/hooks/useQuote.d.ts.map +1 -1
- package/dist/widget/hooks/useRecentTokens.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFeeOption.d.ts +30 -0
- package/dist/widget/hooks/useSelectedFeeOption.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +6 -15
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/index.d.ts +1 -0
- package/dist/widget/index.d.ts.map +1 -1
- package/dist/widget/index.js +4 -2
- package/dist/widget/providers/TrailsProvider.d.ts +29 -0
- package/dist/widget/providers/TrailsProvider.d.ts.map +1 -0
- package/dist/widget/widget.d.ts +14 -3
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +9 -8
- package/src/analytics.ts +53 -21
- package/src/cctp.ts +0 -1016
- package/src/chains.ts +155 -68
- package/src/config.ts +51 -207
- package/src/constants.ts +1 -13
- package/src/contractUtils.ts +6 -6
- package/src/estimate.ts +3 -6
- package/src/fees.ts +5 -10
- package/src/gasless.ts +45 -0
- package/src/index.ts +18 -40
- package/src/indexerClient.ts +39 -48
- package/src/intents.ts +51 -226
- package/src/mutations.ts +3 -2
- package/src/paymasterSend.ts +2 -5
- package/src/prepareSend.ts +21 -14
- package/src/sendUserOp.ts +3 -64
- package/src/sequenceWallet.ts +1 -2
- package/src/tokenBalances.ts +2 -1
- package/src/tokens.ts +62 -133
- package/src/trailsClient.ts +17 -12
- package/src/transactionIntent/deposits/depositOrchestrator.ts +14 -15
- package/src/transactionIntent/deposits/gaslessDeposit.ts +70 -100
- package/src/transactionIntent/deposits/standardDeposit.ts +22 -28
- package/src/transactionIntent/execution/transactionState.ts +2 -2
- package/src/transactionIntent/handlers/crossChain.ts +179 -381
- package/src/transactionIntent/handlers/index.ts +0 -1
- package/src/transactionIntent/handlers/sameChainSameToken.ts +228 -94
- package/src/transactionIntent/quote/normalizeQuote.ts +4 -6
- package/src/transactionIntent/quote/quoteHelpers.ts +35 -3
- package/src/transactionIntent/types.ts +7 -27
- package/src/transactionIntent/utils/index.ts +0 -1
- package/src/transactions.ts +19 -118
- package/src/umd.tsx +1 -3
- package/src/utils.ts +28 -8
- package/src/walletUtils.ts +42 -0
- package/src/wallets.ts +365 -208
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountIntentTransactionHistory.tsx +78 -4
- package/src/widget/components/AccountSettings.tsx +17 -17
- package/src/widget/components/ChainList.tsx +3 -3
- package/src/widget/components/ClassicSwap.tsx +19 -10
- package/src/widget/components/ConfigDisplay.tsx +19 -59
- package/src/widget/components/FeeOption.tsx +63 -20
- package/src/widget/components/FeeOptions.tsx +54 -123
- package/src/widget/components/NativeGasOption.tsx +3 -1
- package/src/widget/components/Pay.tsx +18 -11
- package/src/widget/components/PoolDeposit.tsx +23 -10
- package/src/widget/components/QRCodeDeposit.tsx +50 -30
- package/src/widget/components/QRCodeWalletSelect.tsx +77 -0
- package/src/widget/components/QrCode.tsx +188 -233
- package/src/widget/components/QuoteDetails.tsx +48 -2
- package/src/widget/components/Receipt.tsx +5 -2
- package/src/widget/components/ScreenHeader.tsx +10 -8
- package/src/widget/components/SlippageToleranceSettings.tsx +63 -14
- package/src/widget/components/Toast.tsx +10 -0
- package/src/widget/components/TokenImage.tsx +56 -13
- package/src/widget/components/WalletConnect.tsx +37 -99
- package/src/widget/hooks/useCheckout.ts +71 -0
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDebugScreens.ts +5 -0
- package/src/widget/hooks/useIntentTransactionHistory.ts +790 -412
- package/src/widget/hooks/useIsConnectedWalletSmartContract.ts +43 -0
- package/src/widget/hooks/useIsSequenceWallet.ts +17 -0
- package/src/widget/hooks/useQuote.ts +27 -34
- package/src/widget/hooks/useRecentTokens.ts +2 -1
- package/src/widget/hooks/useSelectedFeeOption.tsx +257 -0
- package/src/widget/hooks/useSendForm.ts +175 -46
- package/src/widget/hooks/useTokenList.ts +15 -2
- package/src/widget/index.tsx +8 -0
- package/src/widget/providers/TrailsProvider.tsx +123 -0
- package/src/widget/widget.tsx +165 -143
- package/dist/cctpqueue.d.ts +0 -18
- package/dist/cctpqueue.d.ts.map +0 -1
- package/dist/preconditions.d.ts +0 -12
- package/dist/preconditions.d.ts.map +0 -1
- package/dist/trails.d.ts +0 -110
- package/dist/trails.d.ts.map +0 -1
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts +0 -62
- package/dist/transactionIntent/handlers/sameChainDifferentToken.d.ts.map +0 -1
- package/dist/transactionIntent/utils/lifiHelpers.d.ts +0 -10
- package/dist/transactionIntent/utils/lifiHelpers.d.ts.map +0 -1
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +0 -33
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +0 -1
- package/src/cctpqueue.ts +0 -66
- package/src/preconditions.ts +0 -47
- package/src/trails.ts +0 -1303
- package/src/transactionIntent/handlers/sameChainDifferentToken.ts +0 -323
- package/src/transactionIntent/utils/lifiHelpers.ts +0 -68
- 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 {
|
|
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
|
|
45
|
+
// Initialize display value from local storage or config
|
|
31
46
|
useEffect(() => {
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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] =
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
|
25
|
+
projectId,
|
|
26
26
|
)
|
|
27
27
|
wcConnectorSingleton = walletConnect({
|
|
28
|
-
projectId: projectId
|
|
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
|
|
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 (
|
|
91
|
-
|
|
76
|
+
if (
|
|
77
|
+
isConnected &&
|
|
78
|
+
status === "success" &&
|
|
79
|
+
!wasConnectedOnMount.current &&
|
|
80
|
+
onBack
|
|
81
|
+
) {
|
|
82
|
+
onBack()
|
|
92
83
|
}
|
|
93
|
-
}, [isConnected, status,
|
|
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
|
-
<
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
<
|
|
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
|
-
</
|
|
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,
|
|
@@ -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)
|