0xtrails 0.1.2 → 0.1.3
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 +68 -1
- package/dist/analytics.d.ts.map +1 -1
- package/dist/{ccip-BmFTEOaB.js → ccip-CWd4g9uZ.js} +1 -1
- package/dist/chains.d.ts +9 -3
- package/dist/chains.d.ts.map +1 -1
- package/dist/ens.d.ts +7 -0
- package/dist/ens.d.ts.map +1 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.d.ts.map +1 -1
- package/dist/{index-BPsVj7zK.js → index-BTUBzx4R.js} +23624 -21770
- package/dist/index.js +2 -2
- package/dist/lifi.d.ts +4 -0
- package/dist/lifi.d.ts.map +1 -0
- package/dist/mode.d.ts +1 -1
- package/dist/mode.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +3 -1
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/prices.d.ts +2 -0
- package/dist/prices.d.ts.map +1 -1
- package/dist/relaySdk.d.ts.map +1 -1
- package/dist/relayer.d.ts.map +1 -1
- package/dist/tokenBalances.d.ts.map +1 -1
- package/dist/tokens.d.ts +2 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/trails.d.ts +3 -3
- package/dist/trails.d.ts.map +1 -1
- package/dist/transactions.d.ts.map +1 -1
- package/dist/wallets.d.ts +247 -5
- package/dist/wallets.d.ts.map +1 -1
- package/dist/widget/components/ChainFilterDropdown.d.ts +2 -0
- package/dist/widget/components/ChainFilterDropdown.d.ts.map +1 -1
- package/dist/widget/components/ConnectWallet.d.ts +1 -0
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/DebugScreensDropdown.d.ts.map +1 -1
- package/dist/widget/components/FundSendForm.d.ts +2 -2
- package/dist/widget/components/FundSendForm.d.ts.map +1 -1
- package/dist/widget/components/PaySendForm.d.ts +2 -2
- package/dist/widget/components/PaySendForm.d.ts.map +1 -1
- package/dist/widget/components/QrCode.d.ts +1 -1
- package/dist/widget/components/QrCode.d.ts.map +1 -1
- package/dist/widget/components/RefundAddressInput.d.ts +13 -0
- package/dist/widget/components/RefundAddressInput.d.ts.map +1 -0
- package/dist/widget/components/Swap.d.ts +43 -0
- package/dist/widget/components/Swap.d.ts.map +1 -0
- package/dist/widget/components/TokenList.d.ts +0 -2
- package/dist/widget/components/TokenList.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts +26 -0
- package/dist/widget/components/TokenSelector.d.ts.map +1 -0
- package/dist/widget/components/WalletConnect.d.ts.map +1 -1
- package/dist/widget/components/WalletConnectionPending.d.ts +12 -0
- package/dist/widget/components/WalletConnectionPending.d.ts.map +1 -0
- package/dist/widget/components/WalletList.d.ts.map +1 -1
- package/dist/widget/hooks/useAmountUsd.d.ts +1 -3
- package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -1
- package/dist/widget/hooks/useCheckout.d.ts.map +1 -1
- package/dist/widget/hooks/useSendForm.d.ts +6 -4
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/hooks/useTokenList.d.ts +2 -3
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +9 -6
- package/src/aave.ts +13 -13
- package/src/analytics.ts +87 -4
- package/src/chains.ts +45 -7
- package/src/constants.ts +4 -4
- package/src/ens.ts +17 -0
- package/src/error.ts +16 -1
- package/src/lifi.ts +58 -0
- package/src/mode.ts +1 -1
- package/src/morpho.ts +3 -3
- package/src/pools.ts +18 -18
- package/src/prepareSend.ts +35 -3
- package/src/prices.ts +21 -0
- package/src/relaySdk.ts +1 -0
- package/src/relayer.ts +8 -0
- package/src/tokenBalances.ts +3 -0
- package/src/tokens.ts +85 -19
- package/src/trails.ts +2 -2
- package/src/transactions.ts +1 -0
- package/src/wallets.ts +275 -35
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/ChainFilterDropdown.tsx +42 -33
- package/src/widget/components/ChainImage.tsx +1 -1
- package/src/widget/components/ConnectWallet.tsx +92 -128
- package/src/widget/components/DebugScreensDropdown.tsx +3 -0
- package/src/widget/components/FundSendForm.tsx +17 -3
- package/src/widget/components/PaySendForm.tsx +16 -2
- package/src/widget/components/QRCodeDeposit.tsx +1 -1
- package/src/widget/components/QrCode.tsx +277 -16
- package/src/widget/components/Receipt.tsx +1 -1
- package/src/widget/components/RefundAddressInput.tsx +149 -0
- package/src/widget/components/Swap.tsx +648 -0
- package/src/widget/components/TokenList.tsx +27 -363
- package/src/widget/components/TokenSelector.tsx +405 -0
- package/src/widget/components/WalletConnect.tsx +9 -7
- package/src/widget/components/WalletConnectionPending.tsx +157 -0
- package/src/widget/components/WalletList.tsx +6 -5
- package/src/widget/hooks/useAmountUsd.ts +3 -8
- package/src/widget/hooks/useCheckout.ts +3 -2
- package/src/widget/hooks/useSendForm.ts +66 -32
- package/src/widget/hooks/useTokenList.ts +158 -106
- package/src/widget/widget.tsx +335 -72
package/src/widget/widget.tsx
CHANGED
|
@@ -15,7 +15,7 @@ import React, {
|
|
|
15
15
|
} from "react"
|
|
16
16
|
import { createPortal } from "react-dom"
|
|
17
17
|
import type { Chain, WalletClient } from "viem"
|
|
18
|
-
import { createWalletClient, custom, http, parseUnits } from "viem"
|
|
18
|
+
import { createWalletClient, custom, http, parseUnits, isAddress } from "viem"
|
|
19
19
|
import * as viemChains from "viem/chains"
|
|
20
20
|
import type { Connector } from "wagmi"
|
|
21
21
|
import {
|
|
@@ -26,10 +26,7 @@ import {
|
|
|
26
26
|
WagmiContext,
|
|
27
27
|
WagmiProvider,
|
|
28
28
|
} from "wagmi"
|
|
29
|
-
import { injected, walletConnect, safe, baseAccount } from "wagmi/connectors"
|
|
30
|
-
import { useAPIClient } from "../apiClient.js"
|
|
31
29
|
import { getChainInfo } from "../chains.js"
|
|
32
|
-
import { useIndexerGatewayClient } from "../indexerClient.js"
|
|
33
30
|
import type { TransactionState } from "../transactions.js"
|
|
34
31
|
import type { RelayerEnv, MetaTxnReceipt } from "../relayer.js"
|
|
35
32
|
import type { Theme } from "../theme.js"
|
|
@@ -45,22 +42,25 @@ import TransferPending from "./components/TransferPendingVertical.js"
|
|
|
45
42
|
import WalletConfirmation from "./components/WalletConfirmation.js"
|
|
46
43
|
import QRCodeDeposit from "./components/QRCodeDeposit.js"
|
|
47
44
|
import { ThemeProvider } from "./components/ThemeProvider.js"
|
|
48
|
-
import {
|
|
49
|
-
getWalletConnectProjectId,
|
|
50
|
-
setWalletConnectProjectId,
|
|
51
|
-
} from "../config.js"
|
|
45
|
+
import { setWalletConnectProjectId } from "../config.js"
|
|
52
46
|
import { useAmountUsd } from "./hooks/useAmountUsd.js"
|
|
53
47
|
import { useRecentTokens } from "./hooks/useRecentTokens.js"
|
|
54
48
|
import { getWethAddress } from "../tokens.js"
|
|
55
49
|
import css from "./compiled.css?inline"
|
|
56
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
getSessionId,
|
|
52
|
+
trackWalletConnected,
|
|
53
|
+
trackWidgetScreen,
|
|
54
|
+
} from "../analytics.js"
|
|
57
55
|
import type { PrepareSendQuote } from "../prepareSend.js"
|
|
58
56
|
import { getNormalizedQuoteObject } from "../prepareSend.js"
|
|
59
57
|
import type { SupportedToken } from "../tokens.js"
|
|
60
58
|
import {
|
|
61
|
-
getErrorString,
|
|
62
59
|
getIsWalletRejectedError,
|
|
63
60
|
getIsBalanceTooLowError,
|
|
61
|
+
getFullErrorMessage,
|
|
62
|
+
getIsApiError,
|
|
63
|
+
getIsRateLimitedError,
|
|
64
64
|
} from "../error.js"
|
|
65
65
|
import {
|
|
66
66
|
setSequenceIndexerUrl,
|
|
@@ -73,11 +73,13 @@ import {
|
|
|
73
73
|
setSlippageTolerance,
|
|
74
74
|
} from "../config.js"
|
|
75
75
|
import { FundSendForm } from "./components/FundSendForm.js"
|
|
76
|
+
import { Swap } from "./components/Swap.js"
|
|
76
77
|
import type { MeshConnectProps } from "./components/MeshConnectIframe.js"
|
|
77
78
|
import { MeshConnectFlow } from "./components/MeshConnectFlow.js"
|
|
78
79
|
import WalletConnectScreen from "./components/WalletConnect.js"
|
|
79
80
|
import FundMethods from "./components/FundMethods.js"
|
|
80
81
|
import EarnPools from "./components/EarnPools.js"
|
|
82
|
+
import WalletConnectionPending from "./components/WalletConnectionPending.js"
|
|
81
83
|
import type { Mode } from "../mode.js"
|
|
82
84
|
import type { OnCompleteProps } from "./hooks/useSendForm.js"
|
|
83
85
|
import type { Pool } from "../pools.js"
|
|
@@ -86,10 +88,24 @@ import { AaveProvider, AaveClient } from "@aave/react"
|
|
|
86
88
|
import { encodeFunctionData } from "viem"
|
|
87
89
|
import { cssObjectToString } from "../cssUtils.js"
|
|
88
90
|
import { useCheckout } from "./hooks/useCheckout.js"
|
|
89
|
-
import {
|
|
91
|
+
import { useWallets, walletConnectConnector, connectors } from "../wallets.js"
|
|
92
|
+
import { isValidNumeric, isValidInteger } from "../prices.js"
|
|
90
93
|
|
|
91
94
|
export const aaveClient = AaveClient.create()
|
|
92
95
|
|
|
96
|
+
// Validate toToken - must be "ETH", "USDC", or a valid hex address
|
|
97
|
+
const isValidToToToken = (toToken: string | null | undefined) => {
|
|
98
|
+
if (toToken === null || toToken === undefined || toToken === "") {
|
|
99
|
+
return true // Empty values are considered valid
|
|
100
|
+
}
|
|
101
|
+
const token = String(toToken).trim()
|
|
102
|
+
if (token === "ETH" || token === "USDC") {
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return isAddress(token)
|
|
107
|
+
}
|
|
108
|
+
|
|
93
109
|
type Screen =
|
|
94
110
|
| "connect"
|
|
95
111
|
| "tokens"
|
|
@@ -97,6 +113,7 @@ type Screen =
|
|
|
97
113
|
| "fund-form"
|
|
98
114
|
| "fund-methods"
|
|
99
115
|
| "earn-pools"
|
|
116
|
+
| "swap"
|
|
100
117
|
| "wallet-confirmation"
|
|
101
118
|
| "qr-code-deposit"
|
|
102
119
|
| "pending"
|
|
@@ -104,6 +121,7 @@ type Screen =
|
|
|
104
121
|
| "mesh-connect"
|
|
105
122
|
| "wallet-connect"
|
|
106
123
|
| "wallet-list"
|
|
124
|
+
| "wallet-connection-pending"
|
|
107
125
|
|
|
108
126
|
export const defaultWalletOptions = ["injected", "walletconnect"]
|
|
109
127
|
|
|
@@ -183,7 +201,7 @@ const useWalletManager = (
|
|
|
183
201
|
const [walletClient, setWalletClient] = useState<WalletClient | null>(null)
|
|
184
202
|
|
|
185
203
|
useEffect(() => {
|
|
186
|
-
const
|
|
204
|
+
const connectWallet = async () => {
|
|
187
205
|
try {
|
|
188
206
|
if (!connector) {
|
|
189
207
|
return
|
|
@@ -208,7 +226,7 @@ const useWalletManager = (
|
|
|
208
226
|
console.error("[trails-sdk] Failed to connect wallet", error)
|
|
209
227
|
}
|
|
210
228
|
}
|
|
211
|
-
|
|
229
|
+
connectWallet().catch(console.error)
|
|
212
230
|
}, [address, chainId, connector])
|
|
213
231
|
|
|
214
232
|
return walletClient
|
|
@@ -243,7 +261,7 @@ const useTransactionState = (
|
|
|
243
261
|
onOriginConfirmation({
|
|
244
262
|
txHash: originTxHash,
|
|
245
263
|
chainId: originChainId,
|
|
246
|
-
sessionId:
|
|
264
|
+
sessionId: getSessionId(),
|
|
247
265
|
})
|
|
248
266
|
}
|
|
249
267
|
}, [originTxHash, onOriginConfirmation, originChainId])
|
|
@@ -253,7 +271,7 @@ const useTransactionState = (
|
|
|
253
271
|
onDestinationConfirmation({
|
|
254
272
|
txHash: destinationTxHash,
|
|
255
273
|
chainId: destinationChainId,
|
|
256
|
-
sessionId:
|
|
274
|
+
sessionId: getSessionId(),
|
|
257
275
|
})
|
|
258
276
|
}
|
|
259
277
|
}, [destinationTxHash, onDestinationConfirmation, destinationChainId])
|
|
@@ -308,9 +326,6 @@ const useTransactionState = (
|
|
|
308
326
|
const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
309
327
|
(
|
|
310
328
|
{
|
|
311
|
-
appId: sequenceProjectAccessKey,
|
|
312
|
-
sequenceIndexerUrl,
|
|
313
|
-
sequenceApiUrl,
|
|
314
329
|
toAddress,
|
|
315
330
|
toAmount,
|
|
316
331
|
toChainId,
|
|
@@ -335,20 +350,37 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
335
350
|
ref,
|
|
336
351
|
) => {
|
|
337
352
|
const { address, isConnected, chainId, connector } = useAccount()
|
|
338
|
-
const {
|
|
353
|
+
const { disconnectAsync } = useDisconnect()
|
|
339
354
|
const { recentTokens, addRecentToken } = useRecentTokens(address)
|
|
355
|
+
const { wallets: allWallets } = useWallets()
|
|
340
356
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
341
357
|
const [currentScreen, setCurrentScreen] = useState<Screen>(
|
|
342
|
-
isConnected ? "tokens" : "connect",
|
|
358
|
+
isConnected ? (mode === "swap" ? "swap" : "tokens") : "connect",
|
|
343
359
|
)
|
|
344
360
|
const [selectedToken, setSelectedToken] = useState<Token | null>(null)
|
|
345
|
-
const [selectedFundMethod, setSelectedFundMethod] =
|
|
346
|
-
|
|
347
|
-
)
|
|
361
|
+
const [selectedFundMethod, setSelectedFundMethod] =
|
|
362
|
+
useState<string>("wallet")
|
|
348
363
|
const [selectedPool, setSelectedPool] = useState<Pool | null>(null)
|
|
349
364
|
const [selectedWalletId, setSelectedWalletId] = useState<string | null>(
|
|
350
|
-
|
|
365
|
+
() => {
|
|
366
|
+
// Initialize from localStorage if available
|
|
367
|
+
if (typeof window !== "undefined") {
|
|
368
|
+
try {
|
|
369
|
+
return localStorage.getItem("trails-last-wallet") || null
|
|
370
|
+
} catch (error) {
|
|
371
|
+
console.error(
|
|
372
|
+
"[trails-sdk] Failed to read from localStorage:",
|
|
373
|
+
error,
|
|
374
|
+
)
|
|
375
|
+
return null
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return null
|
|
379
|
+
},
|
|
351
380
|
)
|
|
381
|
+
const [isConnecting, setIsConnecting] = useState(false)
|
|
382
|
+
const [showWalletConnectionRetry, setShowWalletConnectionRetry] =
|
|
383
|
+
useState(false)
|
|
352
384
|
const [generatedCalldata, setGeneratedCalldata] = useState<
|
|
353
385
|
string | undefined
|
|
354
386
|
>(undefined)
|
|
@@ -364,10 +396,105 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
364
396
|
const [totalCompletionSeconds, setTotalCompletionSeconds] = useState<
|
|
365
397
|
number | null
|
|
366
398
|
>(null)
|
|
367
|
-
const {
|
|
399
|
+
const { connectAsync } = useConnect()
|
|
400
|
+
|
|
401
|
+
// Validate widget props
|
|
402
|
+
useEffect(() => {
|
|
403
|
+
const isValidToAmount = isValidNumeric(toAmount)
|
|
404
|
+
const isValidToChainId = isValidInteger(toChainId)
|
|
405
|
+
const isValidToToken = isValidToToToken(toToken)
|
|
406
|
+
const isValidToAddress = toAddress ? isAddress(toAddress) : true
|
|
407
|
+
|
|
408
|
+
if (
|
|
409
|
+
isValidToAmount &&
|
|
410
|
+
isValidToChainId &&
|
|
411
|
+
isValidToToken &&
|
|
412
|
+
isValidToAddress
|
|
413
|
+
) {
|
|
414
|
+
setError(null)
|
|
415
|
+
return
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Validate toAmount - must be numeric if provided
|
|
419
|
+
if (!isValidToAmount) {
|
|
420
|
+
console.error(
|
|
421
|
+
"[trails-sdk] Invalid toAmount prop: must be numeric. Received:",
|
|
422
|
+
toAmount,
|
|
423
|
+
)
|
|
424
|
+
setError("Invalid toAmount: must be a numeric value")
|
|
425
|
+
return
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Validate toChainId - must be numeric if provided
|
|
429
|
+
if (!isValidToChainId) {
|
|
430
|
+
console.error(
|
|
431
|
+
"[trails-sdk] Invalid toChainId prop: must be numeric. Received:",
|
|
432
|
+
toChainId,
|
|
433
|
+
)
|
|
434
|
+
setError("Invalid toChainId: must be a numeric value")
|
|
435
|
+
return
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Validate toToken - must be "ETH", "USDC", or a valid hex address
|
|
439
|
+
if (!isValidToToken) {
|
|
440
|
+
console.error(
|
|
441
|
+
"[trails-sdk] Invalid toToken prop: must be 'ETH', 'USDC', or a valid hex address. Received:",
|
|
442
|
+
toToken,
|
|
443
|
+
)
|
|
444
|
+
setError(
|
|
445
|
+
"Invalid toToken: must be 'ETH', 'USDC', or a valid hex address",
|
|
446
|
+
)
|
|
447
|
+
return
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (!isValidToAddress) {
|
|
451
|
+
console.error(
|
|
452
|
+
"[trails-sdk] Invalid toAddress prop: must be a valid hex address. Received:",
|
|
453
|
+
toAddress,
|
|
454
|
+
)
|
|
455
|
+
setError("Invalid toAddress: must be a valid hex address")
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (mode === "fund") {
|
|
459
|
+
if (toAmount) {
|
|
460
|
+
setError("toAmount is not allowed in fund mode")
|
|
461
|
+
return
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (mode === "swap") {
|
|
466
|
+
if (toAmount) {
|
|
467
|
+
setError("toAmount is not allowed in swap mode")
|
|
468
|
+
return
|
|
469
|
+
}
|
|
470
|
+
if (toChainId) {
|
|
471
|
+
setError("toChainId is not allowed in swap mode")
|
|
472
|
+
return
|
|
473
|
+
}
|
|
474
|
+
if (toToken) {
|
|
475
|
+
setError("toToken is not allowed in swap mode")
|
|
476
|
+
}
|
|
477
|
+
if (toAddress) {
|
|
478
|
+
setError("toAddress is not allowed in swap mode")
|
|
479
|
+
return
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}, [toAmount, toChainId, toToken, mode, toAddress])
|
|
368
483
|
|
|
369
484
|
const walletClient = useWalletManager(address, chainId, connector)
|
|
370
485
|
|
|
486
|
+
// Function to save wallet ID to localStorage
|
|
487
|
+
const saveLastClickedWallet = (walletId: string) => {
|
|
488
|
+
setSelectedWalletId(walletId)
|
|
489
|
+
if (typeof window !== "undefined") {
|
|
490
|
+
try {
|
|
491
|
+
localStorage.setItem("trails-last-wallet", walletId)
|
|
492
|
+
} catch (error) {
|
|
493
|
+
console.error("[trails-sdk] Failed to save to localStorage:", error)
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
371
498
|
const [meshConnectProps, setMeshConnectProps] =
|
|
372
499
|
useState<Partial<MeshConnectProps> | null>(null)
|
|
373
500
|
|
|
@@ -434,7 +561,7 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
434
561
|
|
|
435
562
|
if (matchingPool) {
|
|
436
563
|
console.log(
|
|
437
|
-
|
|
564
|
+
`[trails-sdk] Auto-selected pool for ${mode} mode toAddress:`,
|
|
438
565
|
toAddress,
|
|
439
566
|
"toChainId:",
|
|
440
567
|
targetChainId,
|
|
@@ -445,7 +572,7 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
445
572
|
setSelectedPool(matchingPool)
|
|
446
573
|
} else {
|
|
447
574
|
console.log(
|
|
448
|
-
|
|
575
|
+
`[trails-sdk] No matching pool found for ${mode} mode toAddress:`,
|
|
449
576
|
toAddress,
|
|
450
577
|
"toChainId:",
|
|
451
578
|
targetChainId,
|
|
@@ -489,24 +616,43 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
489
616
|
// Update screen based on connection state and mode
|
|
490
617
|
useEffect(() => {
|
|
491
618
|
if (isConnected) {
|
|
492
|
-
if (
|
|
619
|
+
if (
|
|
620
|
+
currentScreen === "connect" ||
|
|
621
|
+
currentScreen === "wallet-list" ||
|
|
622
|
+
currentScreen === "wallet-connection-pending"
|
|
623
|
+
) {
|
|
493
624
|
if (!alreadyRedirectedToTokens) {
|
|
494
625
|
setAlreadyRedirectedToTokens(true)
|
|
495
|
-
|
|
626
|
+
// For swap mode, go directly to swap screen, otherwise go to tokens
|
|
627
|
+
if (mode === "swap") {
|
|
628
|
+
setCurrentScreen("swap")
|
|
629
|
+
} else {
|
|
630
|
+
setCurrentScreen("tokens")
|
|
631
|
+
}
|
|
496
632
|
}
|
|
497
633
|
}
|
|
498
634
|
} else {
|
|
499
635
|
if (
|
|
500
636
|
currentScreen !== "connect" &&
|
|
501
637
|
currentScreen !== "wallet-connect" &&
|
|
502
|
-
currentScreen !== "wallet-list"
|
|
638
|
+
currentScreen !== "wallet-list" &&
|
|
639
|
+
currentScreen !== "wallet-connection-pending"
|
|
503
640
|
) {
|
|
504
641
|
setTimeout(() => {
|
|
505
642
|
setCurrentScreen("connect")
|
|
506
643
|
}, 0)
|
|
507
644
|
}
|
|
508
645
|
}
|
|
509
|
-
}, [isConnected, currentScreen, alreadyRedirectedToTokens])
|
|
646
|
+
}, [isConnected, currentScreen, alreadyRedirectedToTokens, mode])
|
|
647
|
+
|
|
648
|
+
useEffect(() => {
|
|
649
|
+
if (
|
|
650
|
+
currentScreen === "wallet-connection-pending" &&
|
|
651
|
+
alreadyRedirectedToTokens
|
|
652
|
+
) {
|
|
653
|
+
setAlreadyRedirectedToTokens(false)
|
|
654
|
+
}
|
|
655
|
+
}, [currentScreen, alreadyRedirectedToTokens])
|
|
510
656
|
|
|
511
657
|
// Auto-detect mode changes and switch screens accordingly
|
|
512
658
|
useEffect(() => {
|
|
@@ -532,6 +678,7 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
532
678
|
if (!address || !chainId || !connector?.name) {
|
|
533
679
|
return
|
|
534
680
|
}
|
|
681
|
+
|
|
535
682
|
trackWalletConnected({
|
|
536
683
|
walletType: connector?.name || "",
|
|
537
684
|
address,
|
|
@@ -550,34 +697,34 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
550
697
|
}
|
|
551
698
|
}, [selectedPool, mode, generatedCalldata])
|
|
552
699
|
|
|
553
|
-
const indexerGatewayClient = useIndexerGatewayClient({
|
|
554
|
-
indexerGatewayUrl: sequenceIndexerUrl || undefined,
|
|
555
|
-
projectAccessKey: sequenceProjectAccessKey,
|
|
556
|
-
})
|
|
557
|
-
|
|
558
|
-
const apiClient = useAPIClient({
|
|
559
|
-
apiUrl: sequenceApiUrl || undefined,
|
|
560
|
-
projectAccessKey: sequenceProjectAccessKey,
|
|
561
|
-
})
|
|
562
|
-
|
|
563
700
|
const handleWalletConnect = async (walletId: string) => {
|
|
564
701
|
try {
|
|
565
702
|
setError(null)
|
|
703
|
+
setIsConnecting(true)
|
|
566
704
|
|
|
567
705
|
// Handle special case for wallet-list screen
|
|
568
706
|
if (walletId === "wallet-list") {
|
|
569
707
|
setCurrentScreen("wallet-list")
|
|
708
|
+
setIsConnecting(false)
|
|
570
709
|
return
|
|
571
710
|
}
|
|
572
711
|
|
|
573
|
-
const config =
|
|
712
|
+
const config = allWallets.find((w) => w.id === walletId)
|
|
574
713
|
if (!config) {
|
|
575
714
|
setError(`No configuration found for wallet: ${walletId}`)
|
|
715
|
+
setIsConnecting(false)
|
|
576
716
|
return
|
|
577
717
|
}
|
|
578
|
-
console.log("[trails-sdk]
|
|
718
|
+
console.log("[trails-sdk] Initiating connection to wallet", walletId)
|
|
579
719
|
if (config.connector !== walletConnectConnector) {
|
|
580
|
-
|
|
720
|
+
console.log(
|
|
721
|
+
"[trails-sdk] Initiating connection to walletId",
|
|
722
|
+
walletId,
|
|
723
|
+
)
|
|
724
|
+
await connectAsync({ connector: config.connector })
|
|
725
|
+
console.log(`[trails-sdk] Successfully connected to ${config.name}`)
|
|
726
|
+
// Set the last clicked wallet after successful connection
|
|
727
|
+
saveLastClickedWallet(walletId)
|
|
581
728
|
} else if (config.connector === walletConnectConnector) {
|
|
582
729
|
// Store the current connector as previous before switching to WalletConnect
|
|
583
730
|
if (connector && connector.name !== "WalletConnect") {
|
|
@@ -585,14 +732,16 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
585
732
|
}
|
|
586
733
|
// Route to dedicated WalletConnect screen where we show our own QR
|
|
587
734
|
setCurrentScreen("wallet-connect")
|
|
735
|
+
setIsConnecting(false)
|
|
588
736
|
return
|
|
589
737
|
}
|
|
590
|
-
|
|
738
|
+
setIsConnecting(false)
|
|
591
739
|
} catch (error) {
|
|
592
740
|
console.error("[trails-sdk] Failed to connect:", error)
|
|
593
741
|
setError(
|
|
594
742
|
error instanceof Error ? error.message : "Failed to connect wallet",
|
|
595
743
|
)
|
|
744
|
+
setIsConnecting(false)
|
|
596
745
|
}
|
|
597
746
|
}
|
|
598
747
|
|
|
@@ -600,7 +749,7 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
600
749
|
setError(null)
|
|
601
750
|
|
|
602
751
|
try {
|
|
603
|
-
await
|
|
752
|
+
await disconnectAsync()
|
|
604
753
|
setAlreadyRedirectedToTokens(false)
|
|
605
754
|
} catch (error) {
|
|
606
755
|
console.error("[trails-sdk] Failed to disconnect:", error)
|
|
@@ -610,15 +759,19 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
610
759
|
}
|
|
611
760
|
|
|
612
761
|
const handleContinue = () => {
|
|
613
|
-
|
|
762
|
+
if (mode === "swap") {
|
|
763
|
+
setCurrentScreen("swap")
|
|
764
|
+
} else {
|
|
765
|
+
setCurrentScreen("tokens")
|
|
766
|
+
}
|
|
614
767
|
}
|
|
615
768
|
|
|
616
769
|
const getAvailableWallets = (): WalletOption[] => {
|
|
617
770
|
const requestedWallets = walletOptions || defaultWalletOptions
|
|
618
771
|
const availableWallets = requestedWallets
|
|
619
|
-
.filter((id) =>
|
|
772
|
+
.filter((id) => allWallets.find((w) => w.id === id))
|
|
620
773
|
.map((id) => {
|
|
621
|
-
const config =
|
|
774
|
+
const config = allWallets.find((w) => w.id === id)
|
|
622
775
|
if (!config) return null
|
|
623
776
|
return {
|
|
624
777
|
id: config.id,
|
|
@@ -647,6 +800,8 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
647
800
|
// Go to earn-pools for pool selection when no specific destination is set
|
|
648
801
|
setCurrentScreen("earn-pools")
|
|
649
802
|
}
|
|
803
|
+
} else if (mode === "swap") {
|
|
804
|
+
setCurrentScreen("swap")
|
|
650
805
|
} else {
|
|
651
806
|
setCurrentScreen(mode === "fund" ? "fund-form" : "send-form")
|
|
652
807
|
}
|
|
@@ -696,15 +851,22 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
696
851
|
}
|
|
697
852
|
|
|
698
853
|
const handleSendAnother = () => {
|
|
699
|
-
|
|
854
|
+
if (mode === "swap") {
|
|
855
|
+
setCurrentScreen("swap")
|
|
856
|
+
} else {
|
|
857
|
+
setCurrentScreen("tokens")
|
|
858
|
+
}
|
|
700
859
|
resetState()
|
|
701
860
|
}
|
|
702
861
|
|
|
703
862
|
const resetState = useCallback(() => {
|
|
704
|
-
setSelectedFundMethod(
|
|
863
|
+
setSelectedFundMethod("wallet")
|
|
705
864
|
setCurrentScreen("connect")
|
|
706
865
|
setSelectedToken(null)
|
|
707
866
|
setSelectedPool(null)
|
|
867
|
+
setSelectedWalletId(null)
|
|
868
|
+
setIsConnecting(false)
|
|
869
|
+
setShowWalletConnectionRetry(false)
|
|
708
870
|
setGeneratedCalldata(undefined)
|
|
709
871
|
setOriginTxHash("")
|
|
710
872
|
setOriginChainId(null)
|
|
@@ -755,6 +917,10 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
755
917
|
setCurrentScreen("tokens")
|
|
756
918
|
setSelectedToken(null)
|
|
757
919
|
break
|
|
920
|
+
case "swap":
|
|
921
|
+
setCurrentScreen("connect")
|
|
922
|
+
setSelectedToken(null)
|
|
923
|
+
break
|
|
758
924
|
case "send-form":
|
|
759
925
|
if (mode === "earn" && !toAddress && !toChainId) {
|
|
760
926
|
setCurrentScreen("earn-pools")
|
|
@@ -770,6 +936,9 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
770
936
|
case "wallet-confirmation":
|
|
771
937
|
setCurrentScreen(mode === "fund" ? "fund-form" : "send-form")
|
|
772
938
|
break
|
|
939
|
+
case "qr-code-deposit":
|
|
940
|
+
setCurrentScreen(mode === "fund" ? "fund-form" : "send-form")
|
|
941
|
+
break
|
|
773
942
|
case "receipt":
|
|
774
943
|
setCurrentScreen("tokens")
|
|
775
944
|
setSelectedToken(null)
|
|
@@ -783,10 +952,18 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
783
952
|
break
|
|
784
953
|
case "wallet-connect":
|
|
785
954
|
setCurrentScreen("wallet-list")
|
|
955
|
+
setSelectedWalletId(null)
|
|
786
956
|
break
|
|
787
957
|
case "wallet-list":
|
|
788
958
|
setCurrentScreen("connect")
|
|
789
959
|
break
|
|
960
|
+
case "wallet-connection-pending":
|
|
961
|
+
setCurrentScreen("wallet-list")
|
|
962
|
+
setSelectedWalletId(null)
|
|
963
|
+
setError(null)
|
|
964
|
+
setIsConnecting(false)
|
|
965
|
+
setShowWalletConnectionRetry(false)
|
|
966
|
+
break
|
|
790
967
|
default:
|
|
791
968
|
break
|
|
792
969
|
}
|
|
@@ -1240,12 +1417,26 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1240
1417
|
case "wallet-list":
|
|
1241
1418
|
setCurrentScreen("wallet-list")
|
|
1242
1419
|
break
|
|
1420
|
+
case "wallet-connection-pending":
|
|
1421
|
+
setSelectedWalletId("metamask")
|
|
1422
|
+
setCurrentScreen("wallet-connection-pending")
|
|
1423
|
+
break
|
|
1424
|
+
case "wallet-connection-pending-retry":
|
|
1425
|
+
setSelectedWalletId("metamask")
|
|
1426
|
+
setShowWalletConnectionRetry(true)
|
|
1427
|
+
setCurrentScreen("wallet-connection-pending")
|
|
1428
|
+
break
|
|
1243
1429
|
case "fund-methods":
|
|
1244
1430
|
setCurrentScreen("fund-methods")
|
|
1245
1431
|
break
|
|
1246
1432
|
case "earn-pools":
|
|
1247
1433
|
setCurrentScreen("earn-pools")
|
|
1248
1434
|
break
|
|
1435
|
+
case "swap":
|
|
1436
|
+
setSelectedToken(null)
|
|
1437
|
+
setTransactionStates([])
|
|
1438
|
+
setCurrentScreen("swap")
|
|
1439
|
+
break
|
|
1249
1440
|
}
|
|
1250
1441
|
}
|
|
1251
1442
|
|
|
@@ -1266,7 +1457,7 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1266
1457
|
)
|
|
1267
1458
|
|
|
1268
1459
|
try {
|
|
1269
|
-
await
|
|
1460
|
+
await connectAsync({ connector: previousConnector })
|
|
1270
1461
|
} catch (error) {
|
|
1271
1462
|
console.error(
|
|
1272
1463
|
"[trails-sdk] Failed to reconnect to previous wallet:",
|
|
@@ -1430,12 +1621,17 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1430
1621
|
if (error) {
|
|
1431
1622
|
console.error("[trails-sdk] Error sending transaction", error)
|
|
1432
1623
|
}
|
|
1433
|
-
const errorMessage =
|
|
1624
|
+
const errorMessage = getFullErrorMessage(error)
|
|
1434
1625
|
const isRejected = getIsWalletRejectedError(error)
|
|
1435
1626
|
const isBalanceTooLow = getIsBalanceTooLowError(error)
|
|
1436
|
-
|
|
1627
|
+
const isApiError = getIsApiError(error)
|
|
1628
|
+
const isRateLimited = getIsRateLimitedError(error)
|
|
1629
|
+
|
|
1630
|
+
if (isRateLimited) {
|
|
1631
|
+
// no-op
|
|
1632
|
+
} else if (isRejected) {
|
|
1437
1633
|
setShowWalletConfirmRetry(true)
|
|
1438
|
-
} else if (isBalanceTooLow) {
|
|
1634
|
+
} else if (isBalanceTooLow || isApiError) {
|
|
1439
1635
|
setShowWalletConfirmRetry(true)
|
|
1440
1636
|
setError(errorMessage)
|
|
1441
1637
|
} else {
|
|
@@ -1489,7 +1685,6 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1489
1685
|
amount: toAmount,
|
|
1490
1686
|
token: toToken,
|
|
1491
1687
|
chainId: Number(toChainId),
|
|
1492
|
-
apiClient: apiClient,
|
|
1493
1688
|
})
|
|
1494
1689
|
|
|
1495
1690
|
const renderScreenContent = () => {
|
|
@@ -1497,11 +1692,27 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1497
1692
|
case "connect":
|
|
1498
1693
|
return (
|
|
1499
1694
|
<ConnectWallet
|
|
1500
|
-
onConnect={
|
|
1695
|
+
onConnect={(walletId) => {
|
|
1696
|
+
if (
|
|
1697
|
+
allWallets.find((w) => w.id === walletId)?.connector ===
|
|
1698
|
+
walletConnectConnector
|
|
1699
|
+
) {
|
|
1700
|
+
saveLastClickedWallet(walletId)
|
|
1701
|
+
setCurrentScreen("wallet-connect")
|
|
1702
|
+
} else {
|
|
1703
|
+
saveLastClickedWallet(walletId)
|
|
1704
|
+
setCurrentScreen("wallet-connection-pending")
|
|
1705
|
+
// Auto-trigger connection
|
|
1706
|
+
setTimeout(() => {
|
|
1707
|
+
handleWalletConnect(walletId)
|
|
1708
|
+
}, 100)
|
|
1709
|
+
}
|
|
1710
|
+
}}
|
|
1501
1711
|
onDisconnect={handleWalletDisconnect}
|
|
1502
1712
|
onContinue={handleContinue}
|
|
1503
1713
|
walletOptions={getAvailableWallets()}
|
|
1504
1714
|
onError={handleConnectError}
|
|
1715
|
+
lastClickedWallet={selectedWalletId}
|
|
1505
1716
|
/>
|
|
1506
1717
|
)
|
|
1507
1718
|
case "fund-methods":
|
|
@@ -1525,7 +1736,6 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1525
1736
|
<TokenList
|
|
1526
1737
|
onContinue={handleTokenSelect}
|
|
1527
1738
|
onBack={handleBack}
|
|
1528
|
-
indexerGatewayClient={indexerGatewayClient}
|
|
1529
1739
|
targetAmountUsd={targetAmountUsd}
|
|
1530
1740
|
targetAmountUsdFormatted={targetAmountUsdFormatted}
|
|
1531
1741
|
onError={handleTokenListError}
|
|
@@ -1694,15 +1904,26 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1694
1904
|
onBack={handleBack}
|
|
1695
1905
|
onWalletSelect={(walletId) => {
|
|
1696
1906
|
if (
|
|
1697
|
-
|
|
1907
|
+
allWallets.find((w) => w.id === walletId)?.connector ===
|
|
1908
|
+
walletConnectConnector
|
|
1698
1909
|
) {
|
|
1699
|
-
|
|
1910
|
+
saveLastClickedWallet(walletId)
|
|
1700
1911
|
setCurrentScreen("wallet-connect")
|
|
1701
1912
|
} else {
|
|
1702
|
-
|
|
1913
|
+
saveLastClickedWallet(walletId)
|
|
1914
|
+
setCurrentScreen("wallet-connection-pending")
|
|
1915
|
+
// Auto-trigger connection
|
|
1916
|
+
setTimeout(() => {
|
|
1917
|
+
handleWalletConnect(walletId)
|
|
1918
|
+
}, 100)
|
|
1703
1919
|
}
|
|
1704
1920
|
}}
|
|
1705
|
-
walletOptions={
|
|
1921
|
+
walletOptions={allWallets.map((wallet) => ({
|
|
1922
|
+
id: wallet.id,
|
|
1923
|
+
name: wallet.name,
|
|
1924
|
+
icon: wallet.icon,
|
|
1925
|
+
connector: wallet.connector,
|
|
1926
|
+
}))}
|
|
1706
1927
|
/>
|
|
1707
1928
|
)
|
|
1708
1929
|
case "earn-pools":
|
|
@@ -1716,6 +1937,55 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1716
1937
|
}}
|
|
1717
1938
|
/>
|
|
1718
1939
|
)
|
|
1940
|
+
case "swap":
|
|
1941
|
+
return walletClient?.account ? (
|
|
1942
|
+
<Swap
|
|
1943
|
+
onSend={handleOnSend}
|
|
1944
|
+
onBack={handleBack}
|
|
1945
|
+
onWaitingForWalletConfirm={handleWaitingForWalletConfirm}
|
|
1946
|
+
onConfirm={() => setCurrentScreen("pending")}
|
|
1947
|
+
onComplete={handleTransferComplete}
|
|
1948
|
+
selectedToken={selectedToken}
|
|
1949
|
+
account={walletClient.account}
|
|
1950
|
+
toRecipient={toAddress || undefined}
|
|
1951
|
+
toAmount={toAmount || undefined}
|
|
1952
|
+
toChainId={toChainId ? Number(toChainId) : undefined}
|
|
1953
|
+
toToken={toToken || undefined}
|
|
1954
|
+
toCalldata={toCalldata || undefined}
|
|
1955
|
+
walletClient={walletClient}
|
|
1956
|
+
onTransactionStateChange={handleTransactionStateChange}
|
|
1957
|
+
onError={handleSendError}
|
|
1958
|
+
paymasterUrls={paymasterUrls}
|
|
1959
|
+
gasless={gasless}
|
|
1960
|
+
setWalletConfirmRetryHandler={setWalletConfirmRetryHandler}
|
|
1961
|
+
quoteProvider={quoteProvider}
|
|
1962
|
+
fundMethod={selectedFundMethod}
|
|
1963
|
+
onNavigateToMeshConnect={handleNavigateToMeshConnect}
|
|
1964
|
+
onAmountUpdate={undefined}
|
|
1965
|
+
mode={mode}
|
|
1966
|
+
checkoutOnHandlers={checkoutOnHandlers}
|
|
1967
|
+
/>
|
|
1968
|
+
) : (
|
|
1969
|
+
<div className="text-center p-4 rounded-lg text-gray-600 bg-gray-50 dark:text-gray-300 dark:bg-gray-800">
|
|
1970
|
+
Please connect wallet
|
|
1971
|
+
</div>
|
|
1972
|
+
)
|
|
1973
|
+
case "wallet-connection-pending":
|
|
1974
|
+
return (
|
|
1975
|
+
<WalletConnectionPending
|
|
1976
|
+
onBack={handleBack}
|
|
1977
|
+
onRetry={() => {
|
|
1978
|
+
if (selectedWalletId) {
|
|
1979
|
+
setShowWalletConnectionRetry(false)
|
|
1980
|
+
handleWalletConnect(selectedWalletId)
|
|
1981
|
+
}
|
|
1982
|
+
}}
|
|
1983
|
+
selectedWalletId={selectedWalletId || ""}
|
|
1984
|
+
isConnecting={isConnecting}
|
|
1985
|
+
error={error}
|
|
1986
|
+
showRetry={showWalletConnectionRetry}
|
|
1987
|
+
/>
|
|
1988
|
+
)
|
|
1719
1989
|
default:
|
|
1720
1990
|
return null
|
|
1721
1991
|
}
|
|
@@ -1781,7 +2051,8 @@ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1781
2051
|
onClick={() => setIsModalOpen(true)}
|
|
1782
2052
|
className="trails-modal-button cursor-pointer font-semibold py-3 px-6 trails-font"
|
|
1783
2053
|
>
|
|
1784
|
-
{buttonText ||
|
|
2054
|
+
{buttonText ||
|
|
2055
|
+
(mode === "fund" ? "Fund" : mode === "swap" ? "Swap" : "Pay")}
|
|
1785
2056
|
</motion.button>
|
|
1786
2057
|
) : (
|
|
1787
2058
|
<motion.div
|
|
@@ -1858,15 +2129,7 @@ export const TrailsWidget = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
|
|
|
1858
2129
|
|
|
1859
2130
|
return createConfig({
|
|
1860
2131
|
...baseConfig,
|
|
1861
|
-
connectors:
|
|
1862
|
-
injected(),
|
|
1863
|
-
walletConnect({
|
|
1864
|
-
projectId: getWalletConnectProjectId(),
|
|
1865
|
-
showQrModal: false,
|
|
1866
|
-
}),
|
|
1867
|
-
safe(),
|
|
1868
|
-
baseAccount(),
|
|
1869
|
-
],
|
|
2132
|
+
connectors: connectors,
|
|
1870
2133
|
})
|
|
1871
2134
|
}, [])
|
|
1872
2135
|
|