0xtrails 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.d.ts +1 -0
- package/dist/analytics.d.ts.map +1 -1
- package/dist/{ccip-D6ToCrWc.js → ccip-BbfANth7.js} +1 -1
- package/dist/chains.d.ts.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/gasless.d.ts +19 -7
- package/dist/gasless.d.ts.map +1 -1
- package/dist/{index-BqgeTLL8.js → index-WpIVoh3X.js} +27626 -26572
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -68
- package/dist/indexerClient.d.ts +10 -0
- package/dist/indexerClient.d.ts.map +1 -1
- package/dist/intentEntrypoint.d.ts +40 -14
- package/dist/intentEntrypoint.d.ts.map +1 -1
- package/dist/intents.d.ts.map +1 -1
- package/dist/prepareSend.d.ts +11 -8
- package/dist/prepareSend.d.ts.map +1 -1
- package/dist/relayer.d.ts.map +1 -1
- package/dist/trails.d.ts.map +1 -1
- package/dist/trailsClient.d.ts.map +1 -1
- package/dist/trailsRouter.d.ts +22 -0
- package/dist/trailsRouter.d.ts.map +1 -0
- package/dist/transactions.d.ts +0 -1
- package/dist/transactions.d.ts.map +1 -1
- package/dist/widget/components/AccountSettings.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/ConnectWallet.d.ts.map +1 -1
- package/dist/widget/components/ConnectedWallets.d.ts.map +1 -1
- package/dist/widget/components/Earn.d.ts.map +1 -1
- package/dist/widget/components/FeeOption.d.ts +22 -0
- package/dist/widget/components/FeeOption.d.ts.map +1 -0
- package/dist/widget/components/FeeOptions.d.ts +13 -17
- package/dist/widget/components/FeeOptions.d.ts.map +1 -1
- package/dist/widget/components/Fund.d.ts.map +1 -1
- package/dist/widget/components/FundMethods.d.ts +1 -1
- package/dist/widget/components/FundMethods.d.ts.map +1 -1
- package/dist/widget/components/FundSendForm.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectExchanges.d.ts +5 -2
- package/dist/widget/components/MeshConnectExchanges.d.ts.map +1 -1
- package/dist/widget/components/MeshConnectFlow.d.ts +2 -0
- package/dist/widget/components/MeshConnectFlow.d.ts.map +1 -1
- package/dist/widget/components/NativeGasOption.d.ts +12 -0
- package/dist/widget/components/NativeGasOption.d.ts.map +1 -0
- package/dist/widget/components/Pay.d.ts.map +1 -1
- package/dist/widget/components/PaySendForm.d.ts.map +1 -1
- package/dist/widget/components/QuoteDetails.d.ts.map +1 -1
- package/dist/widget/components/TokenSelector.d.ts.map +1 -1
- package/dist/widget/components/UserPreferences.d.ts.map +1 -1
- package/dist/widget/hooks/useBack.d.ts +2 -0
- package/dist/widget/hooks/useBack.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/useDefaultTokenSelection.d.ts.map +1 -1
- package/dist/widget/hooks/useSelectedFeeToken.d.ts +32 -0
- package/dist/widget/hooks/useSelectedFeeToken.d.ts.map +1 -0
- package/dist/widget/hooks/useSelectedMeshExchange.d.ts +14 -0
- package/dist/widget/hooks/useSelectedMeshExchange.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.d.ts +8 -13
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -1
- package/dist/widget/index.js +1 -1
- package/dist/widget/widget.d.ts.map +1 -1
- package/package.json +29 -28
- package/src/analytics.ts +6 -0
- package/src/chains.ts +10 -0
- package/src/config.ts +25 -10
- package/src/constants.ts +11 -10
- package/src/gasless.ts +162 -109
- package/src/index.ts +1 -1
- package/src/indexerClient.ts +73 -1
- package/src/intentEntrypoint.ts +66 -101
- package/src/intents.ts +0 -2
- package/src/prepareSend.ts +1409 -887
- package/src/relayer.ts +4 -3
- package/src/trails.ts +1 -3
- package/src/trailsClient.ts +4 -1
- package/src/{balanceInjector.ts → trailsRouter.ts} +14 -14
- package/src/transactions.ts +4 -54
- package/src/widget/compiled.css +1 -1
- package/src/widget/components/AccountSettings.tsx +7 -1
- package/src/widget/components/ClassicSwap.tsx +173 -175
- package/src/widget/components/ConfigDisplay.tsx +34 -1
- package/src/widget/components/ConnectWallet.tsx +168 -11
- package/src/widget/components/ConnectedWallets.tsx +184 -102
- package/src/widget/components/DebugToast.tsx +3 -3
- package/src/widget/components/Earn.tsx +4 -27
- package/src/widget/components/FeeOption.tsx +78 -0
- package/src/widget/components/FeeOptions.tsx +192 -127
- package/src/widget/components/Fund.tsx +18 -27
- package/src/widget/components/FundMethods.tsx +3 -3
- package/src/widget/components/FundSendForm.tsx +0 -33
- package/src/widget/components/MeshConnectExchanges.tsx +32 -3
- package/src/widget/components/MeshConnectFlow.tsx +23 -4
- package/src/widget/components/NativeGasOption.tsx +99 -0
- package/src/widget/components/Pay.tsx +36 -32
- package/src/widget/components/PaySendForm.tsx +0 -37
- package/src/widget/components/QuoteDetails.tsx +0 -29
- package/src/widget/components/TokenSelector.tsx +11 -0
- package/src/widget/components/TransferPendingVertical.tsx +1 -1
- package/src/widget/components/UserPreferences.tsx +3 -4
- package/src/widget/hooks/useBack.tsx +4 -0
- package/src/widget/hooks/useCurrentScreen.tsx +1 -0
- package/src/widget/hooks/useDefaultTokenSelection.tsx +3 -7
- package/src/widget/hooks/useSelectedFeeToken.tsx +299 -0
- package/src/widget/hooks/useSelectedMeshExchange.tsx +46 -0
- package/src/widget/hooks/useSendForm.ts +78 -23
- package/src/widget/widget.tsx +173 -111
- package/dist/balanceInjector.d.ts +0 -22
- package/dist/balanceInjector.d.ts.map +0 -1
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React, { useEffect, useState } from "react"
|
|
2
2
|
import { ChevronRight, LogOut } from "lucide-react"
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useAccount,
|
|
5
|
+
useConnections,
|
|
6
|
+
useSwitchAccount,
|
|
7
|
+
useConnectors,
|
|
8
|
+
} from "wagmi"
|
|
4
9
|
import { AlignJustify, Wallet } from "lucide-react"
|
|
5
10
|
import { ScreenHeader } from "./ScreenHeader.js"
|
|
6
11
|
import { useWallets, wagmiConnectorToWalletId } from "../../wallets.js"
|
|
@@ -35,6 +40,7 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
35
40
|
const { switchAccount } = useSwitchAccount()
|
|
36
41
|
const { setCurrentScreen } = useCurrentScreen()
|
|
37
42
|
const { wallets: allWallets } = useWallets()
|
|
43
|
+
const connectors = useConnectors()
|
|
38
44
|
const [error, setError] = useState<string | null>(null)
|
|
39
45
|
|
|
40
46
|
useEffect(() => {
|
|
@@ -96,6 +102,87 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
96
102
|
|
|
97
103
|
const connectedWallets = getConnectedWallets()
|
|
98
104
|
|
|
105
|
+
// Get available browser wallets using EIP-6963 and injected providers
|
|
106
|
+
const getAvailableBrowserWallets = (): Array<{
|
|
107
|
+
connector: any
|
|
108
|
+
walletId: string
|
|
109
|
+
walletConfig: any
|
|
110
|
+
name: string
|
|
111
|
+
icon?: string
|
|
112
|
+
}> => {
|
|
113
|
+
const filteredConnectors = connectors
|
|
114
|
+
.filter((connector) => {
|
|
115
|
+
// EIP-6963 compliant wallets will have type "injected" and be ready when installed
|
|
116
|
+
// Filter for connectors that are:
|
|
117
|
+
// 1. Injected type (browser extensions, including EIP-6963)
|
|
118
|
+
// 2. Not WalletConnect (which is a protocol, not a browser wallet)
|
|
119
|
+
// 3. Not Privy wallet (should not appear in detected wallets)
|
|
120
|
+
// 4. Not already connected
|
|
121
|
+
const isInjected = connector.type === "injected"
|
|
122
|
+
const isNotWalletConnect = connector.id !== "walletConnect"
|
|
123
|
+
const isNotPrivy =
|
|
124
|
+
connector.id !== "privy" &&
|
|
125
|
+
!connector.name?.toLowerCase().includes("privy") &&
|
|
126
|
+
!connector.id?.toLowerCase().includes("privy")
|
|
127
|
+
const isNotAlreadyConnected = !connections.some(
|
|
128
|
+
(conn) => conn.connector.id === connector.id,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
// Log for debugging EIP-6963 detection
|
|
132
|
+
if (isInjected && isNotWalletConnect) {
|
|
133
|
+
logger.console.log(
|
|
134
|
+
"[trails-sdk] Detected browser wallet via EIP-6963:",
|
|
135
|
+
{
|
|
136
|
+
id: connector.id,
|
|
137
|
+
name: connector.name,
|
|
138
|
+
type: connector.type,
|
|
139
|
+
uid: connector.uid,
|
|
140
|
+
hasIcon: !!connector.icon,
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Log all connectors for debugging
|
|
146
|
+
logger.console.log("[trails-sdk] All connector:", {
|
|
147
|
+
id: connector.id,
|
|
148
|
+
name: connector.name,
|
|
149
|
+
type: connector.type,
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
isInjected &&
|
|
154
|
+
isNotWalletConnect &&
|
|
155
|
+
isNotPrivy &&
|
|
156
|
+
isNotAlreadyConnected
|
|
157
|
+
)
|
|
158
|
+
})
|
|
159
|
+
.map((connector) => {
|
|
160
|
+
const walletId = wagmiConnectorToWalletId(connector)
|
|
161
|
+
const walletConfig = allWallets.find((wallet) => wallet.id === walletId)
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
connector,
|
|
165
|
+
walletId,
|
|
166
|
+
walletConfig,
|
|
167
|
+
name: connector.name,
|
|
168
|
+
// EIP-6963 providers may have additional metadata including icon
|
|
169
|
+
icon: connector.icon || walletConfig?.icon,
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
// Deduplicate by walletId, keeping the first occurrence
|
|
174
|
+
const seenWalletIds = new Set<string>()
|
|
175
|
+
return filteredConnectors.filter((wallet) => {
|
|
176
|
+
if (seenWalletIds.has(wallet.walletId)) {
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
179
|
+
seenWalletIds.add(wallet.walletId)
|
|
180
|
+
return true
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const allAvailableBrowserWallets = getAvailableBrowserWallets()
|
|
185
|
+
|
|
99
186
|
// Handle switching to a different connected wallet
|
|
100
187
|
const handleWalletSwitch = async (
|
|
101
188
|
walletAddress: string,
|
|
@@ -160,6 +247,14 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
160
247
|
return filteredWallets
|
|
161
248
|
}, [lastClickedWallet, allWallets])
|
|
162
249
|
|
|
250
|
+
// Filter out browser wallets that are already in the main wallet options to avoid showing same wallet twice
|
|
251
|
+
const availableBrowserWallets = React.useMemo(() => {
|
|
252
|
+
const mainWalletIds = new Set(orderedWalletOptions.map((w) => w.id))
|
|
253
|
+
return allAvailableBrowserWallets.filter(
|
|
254
|
+
(wallet) => !mainWalletIds.has(wallet.walletId),
|
|
255
|
+
)
|
|
256
|
+
}, [allAvailableBrowserWallets, orderedWalletOptions])
|
|
257
|
+
|
|
163
258
|
return (
|
|
164
259
|
<div className="space-y-6">
|
|
165
260
|
<ScreenHeader
|
|
@@ -171,14 +266,6 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
171
266
|
{isConnected ? (
|
|
172
267
|
<div className="space-y-4">
|
|
173
268
|
<div className="flex flex-col gap-3">
|
|
174
|
-
{error && (
|
|
175
|
-
<div className="border rounded-lg p-4 bg-red-50 border-red-200 dark:bg-red-900/20 dark:border-red-800">
|
|
176
|
-
<p className="text-sm break-words text-red-600 dark:text-red-200">
|
|
177
|
-
{error}
|
|
178
|
-
</p>
|
|
179
|
-
</div>
|
|
180
|
-
)}
|
|
181
|
-
|
|
182
269
|
{/* Connected Wallets List */}
|
|
183
270
|
{connectedWallets.map((wallet) => (
|
|
184
271
|
<div key={wallet.address} className="space-y-2">
|
|
@@ -242,6 +329,39 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
242
329
|
</div>
|
|
243
330
|
))}
|
|
244
331
|
|
|
332
|
+
{/* Available Browser Wallets Section */}
|
|
333
|
+
{availableBrowserWallets.length > 0 && (
|
|
334
|
+
<div className="pt-2 space-y-2">
|
|
335
|
+
{availableBrowserWallets.map((wallet) => (
|
|
336
|
+
<button
|
|
337
|
+
key={wallet.connector.uid || wallet.connector.id}
|
|
338
|
+
type="button"
|
|
339
|
+
onClick={() => handleWalletConnect(wallet.walletId)}
|
|
340
|
+
className="w-full flex items-center justify-between cursor-pointer font-semibold py-4 px-6 trails-border-radius-large-button transition-all duration-200 trails-bg-secondary trails-hover-bg trails-text-primary"
|
|
341
|
+
>
|
|
342
|
+
<div className="flex items-center space-x-3">
|
|
343
|
+
{typeof wallet.icon === "string" ? (
|
|
344
|
+
<img
|
|
345
|
+
src={wallet.icon}
|
|
346
|
+
alt={wallet.name}
|
|
347
|
+
className="h-6 w-6"
|
|
348
|
+
/>
|
|
349
|
+
) : (
|
|
350
|
+
<Wallet className="h-6 w-6 text-gray-600 dark:text-gray-400" />
|
|
351
|
+
)}
|
|
352
|
+
<div className="flex items-center space-x-2">
|
|
353
|
+
<span>{wallet.walletConfig?.name || wallet.name}</span>
|
|
354
|
+
<span className="text-xs bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300 px-2 py-1 trails-border-radius-container font-normal">
|
|
355
|
+
Detected
|
|
356
|
+
</span>
|
|
357
|
+
</div>
|
|
358
|
+
</div>
|
|
359
|
+
<ChevronRight className="h-5 w-5 text-gray-400" />
|
|
360
|
+
</button>
|
|
361
|
+
))}
|
|
362
|
+
</div>
|
|
363
|
+
)}
|
|
364
|
+
|
|
245
365
|
{/* Connect Another Wallet Button */}
|
|
246
366
|
<button
|
|
247
367
|
type="button"
|
|
@@ -273,6 +393,36 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
273
393
|
</div>
|
|
274
394
|
) : (
|
|
275
395
|
<div className="flex flex-col gap-3">
|
|
396
|
+
{/* Available Browser Wallets Section - Not Connected */}
|
|
397
|
+
{availableBrowserWallets.length > 0 &&
|
|
398
|
+
availableBrowserWallets.map((wallet) => (
|
|
399
|
+
<button
|
|
400
|
+
key={wallet.connector.uid || wallet.connector.id}
|
|
401
|
+
type="button"
|
|
402
|
+
onClick={() => handleWalletConnect(wallet.walletId)}
|
|
403
|
+
className="w-full flex items-center justify-between cursor-pointer font-semibold py-4 px-6 trails-border-radius-large-button transition-all duration-200 trails-bg-secondary trails-hover-bg trails-text-primary"
|
|
404
|
+
>
|
|
405
|
+
<div className="flex items-center space-x-3">
|
|
406
|
+
{typeof wallet.icon === "string" ? (
|
|
407
|
+
<img
|
|
408
|
+
src={wallet.icon}
|
|
409
|
+
alt={wallet.name}
|
|
410
|
+
className="h-6 w-6"
|
|
411
|
+
/>
|
|
412
|
+
) : (
|
|
413
|
+
<Wallet className="h-6 w-6 text-gray-600 dark:text-gray-400" />
|
|
414
|
+
)}
|
|
415
|
+
<div className="flex items-center space-x-2">
|
|
416
|
+
<span>{wallet.walletConfig?.name || wallet.name}</span>
|
|
417
|
+
<span className="text-xs bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300 px-2 py-1 trails-border-radius-container font-normal">
|
|
418
|
+
Detected
|
|
419
|
+
</span>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
<ChevronRight className="h-5 w-5 text-gray-400" />
|
|
423
|
+
</button>
|
|
424
|
+
))}
|
|
425
|
+
|
|
276
426
|
{orderedWalletOptions.length > 0 ? (
|
|
277
427
|
<>
|
|
278
428
|
{orderedWalletOptions.map((wallet) => (
|
|
@@ -301,11 +451,18 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
|
|
301
451
|
)}
|
|
302
452
|
<div className="flex items-center space-x-2">
|
|
303
453
|
<span>{walletConfig?.name || wallet.name}</span>
|
|
304
|
-
{lastClickedWallet === wallet.id
|
|
454
|
+
{lastClickedWallet === wallet.id ? (
|
|
305
455
|
<span className="text-xs bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300 px-2 py-1 trails-border-radius-container font-normal">
|
|
306
456
|
Recent
|
|
307
457
|
</span>
|
|
308
|
-
)
|
|
458
|
+
) : allAvailableBrowserWallets.some(
|
|
459
|
+
(detectedWallet) =>
|
|
460
|
+
detectedWallet.walletId === wallet.id,
|
|
461
|
+
) ? (
|
|
462
|
+
<span className="text-xs bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300 px-2 py-1 trails-border-radius-container font-normal">
|
|
463
|
+
Detected
|
|
464
|
+
</span>
|
|
465
|
+
) : null}
|
|
309
466
|
</div>
|
|
310
467
|
</>
|
|
311
468
|
)
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { useState } from "react"
|
|
2
2
|
import type React from "react"
|
|
3
|
-
import { Wallet, Copy } from "lucide-react"
|
|
4
|
-
import {
|
|
3
|
+
import { Wallet, Copy, X } from "lucide-react"
|
|
4
|
+
import {
|
|
5
|
+
useAccount,
|
|
6
|
+
useConnections,
|
|
7
|
+
useSwitchAccount,
|
|
8
|
+
useDisconnect,
|
|
9
|
+
} from "wagmi"
|
|
5
10
|
import { useWallets, wagmiConnectorToWalletId } from "../../wallets.js"
|
|
6
11
|
import { logger } from "../../logger.js"
|
|
7
12
|
import { truncateAddress } from "../../utils.js"
|
|
13
|
+
import { useAccountTotalBalanceUsd } from "../../tokenBalances.js"
|
|
14
|
+
import { Identicon } from "./Identicon.js"
|
|
8
15
|
|
|
9
16
|
export interface ConnectedWalletsProps {
|
|
10
17
|
onWalletSwitch?: (address: string) => void
|
|
@@ -12,6 +19,153 @@ export interface ConnectedWalletsProps {
|
|
|
12
19
|
className?: string
|
|
13
20
|
}
|
|
14
21
|
|
|
22
|
+
interface WalletItemProps {
|
|
23
|
+
wallet: {
|
|
24
|
+
address: string
|
|
25
|
+
connector: any
|
|
26
|
+
walletConfig: any
|
|
27
|
+
walletId: string
|
|
28
|
+
isActive: boolean
|
|
29
|
+
}
|
|
30
|
+
onWalletSwitch: (address: string, connector: any) => void
|
|
31
|
+
onDisconnect: (connector: any, e: React.MouseEvent) => void
|
|
32
|
+
onCopyAddress: (address: string, e: React.MouseEvent) => void
|
|
33
|
+
copiedAddress: string | null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const WalletItem: React.FC<WalletItemProps> = ({
|
|
37
|
+
wallet,
|
|
38
|
+
onWalletSwitch,
|
|
39
|
+
onDisconnect,
|
|
40
|
+
onCopyAddress,
|
|
41
|
+
copiedAddress,
|
|
42
|
+
}) => {
|
|
43
|
+
const { totalBalanceUsdFormatted, isLoadingTotalBalanceUsd } =
|
|
44
|
+
useAccountTotalBalanceUsd(wallet.address)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="space-y-1">
|
|
48
|
+
{/* Wallet Button */}
|
|
49
|
+
<div
|
|
50
|
+
onClick={() => {
|
|
51
|
+
if (!wallet.isActive) {
|
|
52
|
+
onWalletSwitch(wallet.address, wallet.connector)
|
|
53
|
+
}
|
|
54
|
+
}}
|
|
55
|
+
onKeyDown={(e) => {
|
|
56
|
+
if ((e.key === "Enter" || e.key === " ") && !wallet.isActive) {
|
|
57
|
+
e.preventDefault()
|
|
58
|
+
onWalletSwitch(wallet.address, wallet.connector)
|
|
59
|
+
}
|
|
60
|
+
}}
|
|
61
|
+
tabIndex={wallet.isActive ? -1 : 0}
|
|
62
|
+
className={`group w-full flex items-center justify-between font-medium py-2 px-3 rounded-lg transition-all duration-200 ${
|
|
63
|
+
wallet.isActive
|
|
64
|
+
? "bg-blue-50 dark:bg-blue-900/20 text-gray-700 dark:text-gray-300 cursor-default"
|
|
65
|
+
: "bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-300 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600"
|
|
66
|
+
}`}
|
|
67
|
+
>
|
|
68
|
+
<div className="flex items-center space-x-3">
|
|
69
|
+
{/* Identicon */}
|
|
70
|
+
<Identicon value={wallet.address} size={32} />
|
|
71
|
+
<div className="flex flex-col items-start space-y-1">
|
|
72
|
+
<div className="flex items-center space-x-2">
|
|
73
|
+
{/* Wallet Icon */}
|
|
74
|
+
{typeof wallet.walletConfig?.icon === "string" ? (
|
|
75
|
+
<img
|
|
76
|
+
src={wallet.walletConfig.icon}
|
|
77
|
+
alt={wallet.walletConfig.name}
|
|
78
|
+
className="h-4 w-4"
|
|
79
|
+
/>
|
|
80
|
+
) : (
|
|
81
|
+
<Wallet className="h-4 w-4 text-gray-600 dark:text-gray-400" />
|
|
82
|
+
)}
|
|
83
|
+
<span className="text-sm">
|
|
84
|
+
{wallet.walletConfig?.name ||
|
|
85
|
+
wallet.connector?.name ||
|
|
86
|
+
"Wallet"}
|
|
87
|
+
</span>
|
|
88
|
+
{!isLoadingTotalBalanceUsd && totalBalanceUsdFormatted && (
|
|
89
|
+
<span className="text-xs text-gray-400 dark:text-gray-500">
|
|
90
|
+
{totalBalanceUsdFormatted}
|
|
91
|
+
</span>
|
|
92
|
+
)}
|
|
93
|
+
</div>
|
|
94
|
+
<div className="flex items-center space-x-1">
|
|
95
|
+
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono">
|
|
96
|
+
{truncateAddress(wallet.address)}
|
|
97
|
+
</span>
|
|
98
|
+
<button
|
|
99
|
+
type="button"
|
|
100
|
+
onClick={(e) => {
|
|
101
|
+
e.preventDefault()
|
|
102
|
+
e.stopPropagation()
|
|
103
|
+
onCopyAddress(wallet.address, e)
|
|
104
|
+
}}
|
|
105
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
106
|
+
onMouseUp={(e) => e.stopPropagation()}
|
|
107
|
+
className={`p-0.5 rounded transition-all duration-200 cursor-pointer z-10 relative ${
|
|
108
|
+
copiedAddress === wallet.address
|
|
109
|
+
? "bg-green-100 dark:bg-green-900/30"
|
|
110
|
+
: "hover:bg-gray-200 dark:hover:bg-gray-600"
|
|
111
|
+
}`}
|
|
112
|
+
title={
|
|
113
|
+
copiedAddress === wallet.address
|
|
114
|
+
? "Copied!"
|
|
115
|
+
: "Copy full address"
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
{copiedAddress === wallet.address ? (
|
|
119
|
+
<svg
|
|
120
|
+
className="w-3 h-3 text-green-600 dark:text-green-400"
|
|
121
|
+
fill="none"
|
|
122
|
+
viewBox="0 0 24 24"
|
|
123
|
+
stroke="currentColor"
|
|
124
|
+
aria-label="Copied"
|
|
125
|
+
>
|
|
126
|
+
<title>Copied</title>
|
|
127
|
+
<path
|
|
128
|
+
strokeLinecap="round"
|
|
129
|
+
strokeLinejoin="round"
|
|
130
|
+
strokeWidth={2}
|
|
131
|
+
d="M5 13l4 4L19 7"
|
|
132
|
+
/>
|
|
133
|
+
</svg>
|
|
134
|
+
) : (
|
|
135
|
+
<Copy className="w-3 h-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" />
|
|
136
|
+
)}
|
|
137
|
+
</button>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
|
|
142
|
+
<div className="flex items-center gap-2">
|
|
143
|
+
{wallet.isActive ? (
|
|
144
|
+
<span className="text-xs px-2 py-1 rounded font-medium bg-blue-500 text-white">
|
|
145
|
+
Active
|
|
146
|
+
</span>
|
|
147
|
+
) : (
|
|
148
|
+
<span className="text-xs px-2 py-1 rounded font-medium bg-gray-200 text-gray-700 dark:bg-gray-600 dark:text-gray-300 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
|
149
|
+
Set as active
|
|
150
|
+
</span>
|
|
151
|
+
)}
|
|
152
|
+
<button
|
|
153
|
+
type="button"
|
|
154
|
+
onClick={(e) => onDisconnect(wallet.connector, e)}
|
|
155
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
156
|
+
onMouseUp={(e) => e.stopPropagation()}
|
|
157
|
+
className="p-1 rounded-full hover:bg-gray-200 dark:hover:bg-gray-600 opacity-0 group-hover:opacity-100 transition-all duration-200 cursor-pointer"
|
|
158
|
+
title="Disconnect wallet"
|
|
159
|
+
aria-label="Disconnect wallet"
|
|
160
|
+
>
|
|
161
|
+
<X className="w-4 h-4 text-gray-500 dark:text-gray-400" />
|
|
162
|
+
</button>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
|
|
15
169
|
export const ConnectedWallets: React.FC<ConnectedWalletsProps> = ({
|
|
16
170
|
onWalletSwitch,
|
|
17
171
|
showActiveWallet = true,
|
|
@@ -20,6 +174,7 @@ export const ConnectedWallets: React.FC<ConnectedWalletsProps> = ({
|
|
|
20
174
|
const { address, connector } = useAccount()
|
|
21
175
|
const connections = useConnections()
|
|
22
176
|
const { switchAccount } = useSwitchAccount()
|
|
177
|
+
const { disconnect } = useDisconnect()
|
|
23
178
|
const { wallets: allWallets } = useWallets()
|
|
24
179
|
const [error, setError] = useState<string | null>(null)
|
|
25
180
|
const [copiedAddress, setCopiedAddress] = useState<string | null>(null)
|
|
@@ -87,6 +242,25 @@ export const ConnectedWallets: React.FC<ConnectedWalletsProps> = ({
|
|
|
87
242
|
}
|
|
88
243
|
}
|
|
89
244
|
|
|
245
|
+
// Handle disconnecting a specific wallet
|
|
246
|
+
const handleDisconnect = async (
|
|
247
|
+
walletConnector: any,
|
|
248
|
+
e: React.MouseEvent,
|
|
249
|
+
) => {
|
|
250
|
+
e.preventDefault()
|
|
251
|
+
e.stopPropagation()
|
|
252
|
+
try {
|
|
253
|
+
setError(null)
|
|
254
|
+
await disconnect({ connector: walletConnector })
|
|
255
|
+
logger.console.log("[trails-sdk] Disconnected wallet")
|
|
256
|
+
} catch (error) {
|
|
257
|
+
logger.console.error("[trails-sdk] Failed to disconnect wallet:", error)
|
|
258
|
+
setError(
|
|
259
|
+
error instanceof Error ? error.message : "Failed to disconnect wallet",
|
|
260
|
+
)
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
90
264
|
// Handle copy to clipboard with success indication
|
|
91
265
|
const handleCopyAddress = async (address: string, e: React.MouseEvent) => {
|
|
92
266
|
e.preventDefault()
|
|
@@ -151,106 +325,14 @@ export const ConnectedWallets: React.FC<ConnectedWalletsProps> = ({
|
|
|
151
325
|
}
|
|
152
326
|
|
|
153
327
|
return (
|
|
154
|
-
<
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
onKeyDown={(e) => {
|
|
163
|
-
if ((e.key === "Enter" || e.key === " ") && !wallet.isActive) {
|
|
164
|
-
e.preventDefault()
|
|
165
|
-
handleWalletSwitch(wallet.address, wallet.connector)
|
|
166
|
-
}
|
|
167
|
-
}}
|
|
168
|
-
tabIndex={wallet.isActive ? -1 : 0}
|
|
169
|
-
className={`group w-full flex items-center justify-between font-medium py-2 px-3 rounded-lg transition-all duration-200 ${
|
|
170
|
-
wallet.isActive
|
|
171
|
-
? "bg-blue-50 dark:bg-blue-900/20 text-gray-700 dark:text-gray-300 cursor-default"
|
|
172
|
-
: "bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-300 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600"
|
|
173
|
-
}`}
|
|
174
|
-
>
|
|
175
|
-
<div className="flex items-center space-x-3">
|
|
176
|
-
{typeof wallet.walletConfig?.icon === "string" ? (
|
|
177
|
-
<img
|
|
178
|
-
src={wallet.walletConfig.icon}
|
|
179
|
-
alt={wallet.walletConfig.name}
|
|
180
|
-
className="h-5 w-5"
|
|
181
|
-
/>
|
|
182
|
-
) : (
|
|
183
|
-
<Wallet className="h-5 w-5 text-gray-600 dark:text-gray-400" />
|
|
184
|
-
)}
|
|
185
|
-
<div className="flex flex-col items-start space-y-1">
|
|
186
|
-
<div className="flex items-center space-x-2">
|
|
187
|
-
<span className="text-sm">
|
|
188
|
-
{wallet.walletConfig?.name ||
|
|
189
|
-
wallet.connector?.name ||
|
|
190
|
-
"Wallet"}
|
|
191
|
-
</span>
|
|
192
|
-
</div>
|
|
193
|
-
<div className="flex items-center space-x-1">
|
|
194
|
-
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono">
|
|
195
|
-
{truncateAddress(wallet.address)}
|
|
196
|
-
</span>
|
|
197
|
-
<button
|
|
198
|
-
type="button"
|
|
199
|
-
onClick={(e) => {
|
|
200
|
-
e.preventDefault()
|
|
201
|
-
e.stopPropagation()
|
|
202
|
-
handleCopyAddress(wallet.address, e)
|
|
203
|
-
}}
|
|
204
|
-
onMouseDown={(e) => e.stopPropagation()}
|
|
205
|
-
onMouseUp={(e) => e.stopPropagation()}
|
|
206
|
-
className={`p-0.5 rounded transition-all duration-200 cursor-pointer z-10 relative ${
|
|
207
|
-
copiedAddress === wallet.address
|
|
208
|
-
? "bg-green-100 dark:bg-green-900/30"
|
|
209
|
-
: "hover:bg-gray-200 dark:hover:bg-gray-600"
|
|
210
|
-
}`}
|
|
211
|
-
title={
|
|
212
|
-
copiedAddress === wallet.address
|
|
213
|
-
? "Copied!"
|
|
214
|
-
: "Copy full address"
|
|
215
|
-
}
|
|
216
|
-
>
|
|
217
|
-
{copiedAddress === wallet.address ? (
|
|
218
|
-
<svg
|
|
219
|
-
className="w-3 h-3 text-green-600 dark:text-green-400"
|
|
220
|
-
fill="none"
|
|
221
|
-
viewBox="0 0 24 24"
|
|
222
|
-
stroke="currentColor"
|
|
223
|
-
aria-label="Copied"
|
|
224
|
-
>
|
|
225
|
-
<title>Copied</title>
|
|
226
|
-
<path
|
|
227
|
-
strokeLinecap="round"
|
|
228
|
-
strokeLinejoin="round"
|
|
229
|
-
strokeWidth={2}
|
|
230
|
-
d="M5 13l4 4L19 7"
|
|
231
|
-
/>
|
|
232
|
-
</svg>
|
|
233
|
-
) : (
|
|
234
|
-
<Copy className="w-3 h-3 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" />
|
|
235
|
-
)}
|
|
236
|
-
</button>
|
|
237
|
-
</div>
|
|
238
|
-
</div>
|
|
239
|
-
</div>
|
|
240
|
-
|
|
241
|
-
<div className="flex items-center">
|
|
242
|
-
{wallet.isActive ? (
|
|
243
|
-
<span className="text-xs px-2 py-1 rounded font-medium bg-blue-500 text-white">
|
|
244
|
-
Active
|
|
245
|
-
</span>
|
|
246
|
-
) : (
|
|
247
|
-
<span className="text-xs px-2 py-1 rounded font-medium bg-gray-200 text-gray-700 dark:bg-gray-600 dark:text-gray-300 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
|
248
|
-
Set as active
|
|
249
|
-
</span>
|
|
250
|
-
)}
|
|
251
|
-
</div>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
328
|
+
<WalletItem
|
|
329
|
+
key={wallet.address}
|
|
330
|
+
wallet={wallet}
|
|
331
|
+
onWalletSwitch={handleWalletSwitch}
|
|
332
|
+
onDisconnect={handleDisconnect}
|
|
333
|
+
onCopyAddress={handleCopyAddress}
|
|
334
|
+
copiedAddress={copiedAddress}
|
|
335
|
+
/>
|
|
254
336
|
)
|
|
255
337
|
})}
|
|
256
338
|
</div>
|
|
@@ -38,21 +38,21 @@ export const DebugToast: React.FC = () => {
|
|
|
38
38
|
<button
|
|
39
39
|
type="button"
|
|
40
40
|
onClick={handleShowInfo}
|
|
41
|
-
className="px-2 py-1 text-xs font-medium rounded bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:hover:bg-blue-900/50 transition-colors"
|
|
41
|
+
className="px-2 py-1 text-xs font-medium rounded bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:hover:bg-blue-900/50 transition-colors cursor-pointer"
|
|
42
42
|
>
|
|
43
43
|
info
|
|
44
44
|
</button>
|
|
45
45
|
<button
|
|
46
46
|
type="button"
|
|
47
47
|
onClick={handleShowSuccess}
|
|
48
|
-
className="px-2 py-1 text-xs font-medium rounded bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400 dark:hover:bg-green-900/50 transition-colors"
|
|
48
|
+
className="px-2 py-1 text-xs font-medium rounded bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400 dark:hover:bg-green-900/50 transition-colors cursor-pointer"
|
|
49
49
|
>
|
|
50
50
|
success
|
|
51
51
|
</button>
|
|
52
52
|
<button
|
|
53
53
|
type="button"
|
|
54
54
|
onClick={handleShowError}
|
|
55
|
-
className="px-2 py-1 text-xs font-medium rounded bg-red-100 text-red-700 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50 transition-colors"
|
|
55
|
+
className="px-2 py-1 text-xs font-medium rounded bg-red-100 text-red-700 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50 transition-colors cursor-pointer"
|
|
56
56
|
>
|
|
57
57
|
error
|
|
58
58
|
</button>
|
|
@@ -27,8 +27,6 @@ import { ChainList } from "./ChainList.js"
|
|
|
27
27
|
import { QuoteDetails } from "./QuoteDetails.js"
|
|
28
28
|
import { formatTvl } from "../../prices.js"
|
|
29
29
|
import { getExplorerUrlForAddress } from "../../explorer.js"
|
|
30
|
-
import { formatUsdAmountDisplay } from "../../tokenBalances.js"
|
|
31
|
-
import { MINIMUM_USD_AMOUNT_FOR_SWAP } from "../../constants.js"
|
|
32
30
|
import aaveLogo from "../assets/aave.svg"
|
|
33
31
|
import morphoLogo from "../assets/morpho.svg"
|
|
34
32
|
import type { PrepareSendQuote } from "../../prepareSend.js"
|
|
@@ -340,7 +338,10 @@ export const Earn: React.FC<EarnProps> = ({
|
|
|
340
338
|
<div className="flex items-center space-x-2">
|
|
341
339
|
{/* Amount Input */}
|
|
342
340
|
<div className="flex-1">
|
|
343
|
-
<div
|
|
341
|
+
<div
|
|
342
|
+
className="flex items-center justify-start cursor-text"
|
|
343
|
+
onClick={() => inputRef.current?.focus()}
|
|
344
|
+
>
|
|
344
345
|
<div className="flex items-center">
|
|
345
346
|
<input
|
|
346
347
|
ref={inputRef}
|
|
@@ -623,30 +624,6 @@ export const Earn: React.FC<EarnProps> = ({
|
|
|
623
624
|
</p>
|
|
624
625
|
</div>
|
|
625
626
|
</div>
|
|
626
|
-
) : prepareSendQuote?.minimumNotMet ? (
|
|
627
|
-
<div className="px-2 py-3 rounded-lg bg-amber-500/10 border border-solid border-amber-500/30">
|
|
628
|
-
<div className="flex items-center space-x-2">
|
|
629
|
-
<svg
|
|
630
|
-
className="w-4 h-4 text-amber-500 flex-shrink-0"
|
|
631
|
-
fill="none"
|
|
632
|
-
stroke="currentColor"
|
|
633
|
-
viewBox="0 0 24 24"
|
|
634
|
-
aria-hidden="true"
|
|
635
|
-
>
|
|
636
|
-
<path
|
|
637
|
-
strokeLinecap="round"
|
|
638
|
-
strokeLinejoin="round"
|
|
639
|
-
strokeWidth={2}
|
|
640
|
-
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
|
|
641
|
-
/>
|
|
642
|
-
</svg>
|
|
643
|
-
<p className="text-sm text-amber-600 dark:text-amber-400">
|
|
644
|
-
Please enter an amount above{" "}
|
|
645
|
-
{formatUsdAmountDisplay(MINIMUM_USD_AMOUNT_FOR_SWAP)} otherwise
|
|
646
|
-
transfer may fail
|
|
647
|
-
</p>
|
|
648
|
-
</div>
|
|
649
|
-
</div>
|
|
650
627
|
) : null}
|
|
651
628
|
|
|
652
629
|
<form onSubmit={handleSubmit}>
|