@solana/connector 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +685 -1071
  3. package/dist/chunk-3STZXVXD.mjs +2185 -0
  4. package/dist/chunk-3STZXVXD.mjs.map +1 -0
  5. package/dist/chunk-I64FD2EH.js +312 -0
  6. package/dist/chunk-I64FD2EH.js.map +1 -0
  7. package/dist/{chunk-TIW3EQPC.js → chunk-JUZVCBAI.js} +127 -104
  8. package/dist/chunk-JUZVCBAI.js.map +1 -0
  9. package/dist/{chunk-7CKCRY25.js → chunk-NQXK7PGX.js} +75 -79
  10. package/dist/chunk-NQXK7PGX.js.map +1 -0
  11. package/dist/{chunk-HPENTIPE.mjs → chunk-QKVL45F6.mjs} +57 -57
  12. package/dist/chunk-QKVL45F6.mjs.map +1 -0
  13. package/dist/chunk-QL3IT3TS.mjs +299 -0
  14. package/dist/chunk-QL3IT3TS.mjs.map +1 -0
  15. package/dist/chunk-ULUYX23Q.js +2213 -0
  16. package/dist/chunk-ULUYX23Q.js.map +1 -0
  17. package/dist/{chunk-TKJSKXSA.mjs → chunk-VMSZJPR5.mjs} +42 -20
  18. package/dist/chunk-VMSZJPR5.mjs.map +1 -0
  19. package/dist/compat.d.mts +4 -2
  20. package/dist/compat.d.ts +4 -2
  21. package/dist/compat.js +3 -3
  22. package/dist/compat.mjs +1 -1
  23. package/dist/headless.d.mts +146 -18
  24. package/dist/headless.d.ts +146 -18
  25. package/dist/headless.js +144 -111
  26. package/dist/headless.mjs +3 -2
  27. package/dist/index.d.mts +6 -5
  28. package/dist/index.d.ts +6 -5
  29. package/dist/index.js +207 -126
  30. package/dist/index.mjs +4 -3
  31. package/dist/react.d.mts +707 -67
  32. package/dist/react.d.ts +707 -67
  33. package/dist/react.js +64 -16
  34. package/dist/react.mjs +2 -2
  35. package/dist/{transaction-signer-D3csM_Mf.d.mts → transaction-signer-D9d8nxwb.d.mts} +3 -1
  36. package/dist/{transaction-signer-D3csM_Mf.d.ts → transaction-signer-D9d8nxwb.d.ts} +3 -1
  37. package/dist/{wallet-standard-shim-Cg0GVGwu.d.mts → wallet-standard-shim--YcrQNRt.d.ts} +216 -6
  38. package/dist/{wallet-standard-shim-C1tisl9S.d.ts → wallet-standard-shim-Dx7H8Ctf.d.mts} +216 -6
  39. package/package.json +16 -12
  40. package/dist/chunk-5ZUVZZWU.mjs +0 -180
  41. package/dist/chunk-5ZUVZZWU.mjs.map +0 -1
  42. package/dist/chunk-7CKCRY25.js.map +0 -1
  43. package/dist/chunk-FTD7F7CS.js +0 -314
  44. package/dist/chunk-FTD7F7CS.js.map +0 -1
  45. package/dist/chunk-HPENTIPE.mjs.map +0 -1
  46. package/dist/chunk-MPZFJEJK.mjs +0 -298
  47. package/dist/chunk-MPZFJEJK.mjs.map +0 -1
  48. package/dist/chunk-SMUUAKC3.js +0 -186
  49. package/dist/chunk-SMUUAKC3.js.map +0 -1
  50. package/dist/chunk-TIW3EQPC.js.map +0 -1
  51. package/dist/chunk-TKJSKXSA.mjs.map +0 -1
@@ -0,0 +1,2185 @@
1
+ import { installPolyfills, ConnectorErrorBoundary, isMainnetCluster, isDevnetCluster, isTestnetCluster, isLocalCluster, getClusterExplorerUrl, getClusterType, formatAddress, copyAddressToClipboard, createTransactionSigner, createKitTransactionSigner, NetworkError, getTransactionUrl, ConnectorClient } from './chunk-VMSZJPR5.mjs';
2
+ import { createLogger, __publicField, createSolanaClient, prepareTransaction } from './chunk-QL3IT3TS.mjs';
3
+ import React, { createContext, useContext, useSyncExternalStore, useMemo, useState, useCallback, useRef, useEffect } from 'react';
4
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
5
+ import { address } from '@solana/addresses';
6
+ import { signature } from '@solana/keys';
7
+
8
+ var logger = createLogger("ConnectorProvider");
9
+ installPolyfills();
10
+ var ConnectorContext = createContext(null);
11
+ ConnectorContext.displayName = "ConnectorContext";
12
+ function ConnectorProviderInternal({
13
+ children,
14
+ config,
15
+ mobile
16
+ }) {
17
+ let clientRef = useRef(null), client = React.useCallback(() => {
18
+ if (!clientRef.current)
19
+ try {
20
+ clientRef.current = new ConnectorClient(config), typeof window < "u" && (window.__connectorClient = clientRef.current), config?.debug && logger.info("Client initialized successfully");
21
+ } catch (error) {
22
+ let err = error;
23
+ logger.error("Failed to initialize client", { error: err });
24
+ let extendedConfig = config;
25
+ return extendedConfig?.errorBoundary?.onError && extendedConfig.errorBoundary.onError(err, {
26
+ componentStack: "client-initialization",
27
+ digest: `constructor-${(/* @__PURE__ */ new Date()).toISOString()}`
28
+ }), null;
29
+ }
30
+ return clientRef.current;
31
+ }, [config])();
32
+ return React.useEffect(() => {
33
+ let currentClient = clientRef.current;
34
+ if (currentClient) {
35
+ let privateClient = currentClient;
36
+ privateClient.initialize && typeof privateClient.initialize == "function" && privateClient.initialize();
37
+ }
38
+ return () => {
39
+ typeof window < "u" && (window.__connectorClient = void 0), currentClient && typeof currentClient.destroy == "function" && currentClient.destroy();
40
+ };
41
+ }, []), React.useEffect(() => {
42
+ if (!mobile) return;
43
+ let cancelled = false;
44
+ return (async () => {
45
+ try {
46
+ let mod = await import('@solana-mobile/wallet-standard-mobile');
47
+ if (cancelled) return;
48
+ let {
49
+ registerMwa,
50
+ createDefaultAuthorizationCache,
51
+ createDefaultChainSelector,
52
+ createDefaultWalletNotFoundHandler
53
+ } = mod, defaultChains = [
54
+ "solana:mainnet",
55
+ "solana:devnet",
56
+ "solana:testnet"
57
+ ];
58
+ registerMwa({
59
+ appIdentity: mobile.appIdentity,
60
+ authorizationCache: mobile.authorizationCache ?? createDefaultAuthorizationCache(),
61
+ chains: mobile.chains ?? defaultChains,
62
+ chainSelector: mobile.chainSelector ?? createDefaultChainSelector(),
63
+ remoteHostAuthority: mobile.remoteHostAuthority,
64
+ onWalletNotFound: mobile.onWalletNotFound ?? createDefaultWalletNotFoundHandler()
65
+ });
66
+ } catch {
67
+ }
68
+ })(), () => {
69
+ cancelled = true;
70
+ };
71
+ }, [mobile]), /* @__PURE__ */ jsx(ConnectorContext.Provider, { value: client, children });
72
+ }
73
+ function ConnectorProvider({
74
+ children,
75
+ config,
76
+ mobile
77
+ }) {
78
+ let errorBoundaryConfig = config?.errorBoundary;
79
+ return errorBoundaryConfig?.enabled ? /* @__PURE__ */ jsx(
80
+ ConnectorErrorBoundary,
81
+ {
82
+ maxRetries: errorBoundaryConfig.maxRetries ?? 3,
83
+ onError: errorBoundaryConfig.onError,
84
+ fallback: errorBoundaryConfig.fallback,
85
+ children: /* @__PURE__ */ jsx(ConnectorProviderInternal, { config, mobile, children })
86
+ }
87
+ ) : /* @__PURE__ */ jsx(ConnectorProviderInternal, { config, mobile, children });
88
+ }
89
+ function useConnector() {
90
+ let client = useContext(ConnectorContext);
91
+ if (!client)
92
+ throw new Error(
93
+ "useConnector must be used within ConnectorProvider. Wrap your app with <ConnectorProvider> or <UnifiedProvider> to use connector hooks."
94
+ );
95
+ let state = useSyncExternalStore(
96
+ React.useCallback((cb) => client.subscribe(cb), [client]),
97
+ React.useCallback(() => client.getSnapshot(), [client]),
98
+ React.useCallback(() => client.getSnapshot(), [client])
99
+ ), methods = useMemo(
100
+ () => ({
101
+ select: client.select.bind(client),
102
+ disconnect: client.disconnect.bind(client),
103
+ selectAccount: client.selectAccount.bind(client)
104
+ }),
105
+ [client]
106
+ );
107
+ return useMemo(
108
+ () => ({
109
+ ...state,
110
+ ...methods
111
+ }),
112
+ [state, methods]
113
+ );
114
+ }
115
+ function useConnectorClient() {
116
+ return useContext(ConnectorContext);
117
+ }
118
+ function UnifiedProvider({ children, config, connectorConfig, mobile, providers = [] }) {
119
+ let actualConnectorConfig = config?.connectorConfig ?? connectorConfig, actualMobile = config?.mobile ?? mobile, content = /* @__PURE__ */ jsx(ConnectorProvider, { config: actualConnectorConfig, mobile: actualMobile, children });
120
+ for (let i = providers.length - 1; i >= 0; i--) {
121
+ let { component: Provider, props = {} } = providers[i];
122
+ content = /* @__PURE__ */ jsx(Provider, { ...props, children: content });
123
+ }
124
+ return content;
125
+ }
126
+ function useCluster() {
127
+ let { cluster, clusters } = useConnector(), client = useConnectorClient();
128
+ if (!client)
129
+ throw new Error("useCluster must be used within ConnectorProvider");
130
+ let setCluster = useMemo(
131
+ () => async (id) => {
132
+ await client.setCluster(id);
133
+ },
134
+ [client]
135
+ );
136
+ return useMemo(() => {
137
+ let isMainnet = cluster ? isMainnetCluster(cluster) : false, isDevnet = cluster ? isDevnetCluster(cluster) : false, isTestnet = cluster ? isTestnetCluster(cluster) : false, isLocal = cluster ? isLocalCluster(cluster) : false, explorerUrl = cluster ? getClusterExplorerUrl(cluster) : "", type = cluster ? getClusterType(cluster) : null;
138
+ return {
139
+ cluster,
140
+ clusters,
141
+ setCluster,
142
+ isMainnet,
143
+ isDevnet,
144
+ isTestnet,
145
+ isLocal,
146
+ explorerUrl,
147
+ type
148
+ };
149
+ }, [cluster, clusters, setCluster]);
150
+ }
151
+ function useAccount() {
152
+ let { selectedAccount, accounts, connected, selectAccount } = useConnector(), [copied, setCopied] = useState(false), copyTimeoutRef = React.useRef(void 0), account = useMemo(
153
+ () => accounts.find((a) => a.address === selectedAccount) ?? null,
154
+ [accounts, selectedAccount]
155
+ ), formatted = useMemo(() => selectedAccount ? formatAddress(selectedAccount) : "", [selectedAccount]), copy = useCallback(async () => selectedAccount ? (copyTimeoutRef.current && clearTimeout(copyTimeoutRef.current), await copyAddressToClipboard(selectedAccount, {
156
+ onSuccess: () => {
157
+ setCopied(true), copyTimeoutRef.current = setTimeout(() => setCopied(false), 2e3);
158
+ }
159
+ })) : {
160
+ success: false,
161
+ error: "empty_value" /* EMPTY_VALUE */,
162
+ errorMessage: "No account selected"
163
+ }, [selectedAccount]);
164
+ return React.useEffect(() => () => {
165
+ copyTimeoutRef.current && clearTimeout(copyTimeoutRef.current);
166
+ }, []), useMemo(
167
+ () => ({
168
+ address: selectedAccount,
169
+ account,
170
+ connected,
171
+ formatted,
172
+ copy,
173
+ copied,
174
+ accounts,
175
+ selectAccount
176
+ }),
177
+ [selectedAccount, account, connected, formatted, copy, copied, accounts, selectAccount]
178
+ );
179
+ }
180
+ function useWalletInfo() {
181
+ let { selectedWallet, wallets, connected, connecting } = useConnector(), mappedWallets = useMemo(
182
+ () => wallets.map(
183
+ (walletInfo) => ({
184
+ name: walletInfo.wallet.name,
185
+ icon: walletInfo.wallet.icon,
186
+ installed: walletInfo.installed,
187
+ connectable: walletInfo.connectable
188
+ })
189
+ ),
190
+ [wallets]
191
+ ), selectedWalletInfo = useMemo(() => {
192
+ if (!selectedWallet)
193
+ return {
194
+ name: null,
195
+ icon: null,
196
+ installed: false,
197
+ connectable: false
198
+ };
199
+ let walletInfo = wallets.find((w) => w.wallet.name === selectedWallet.name);
200
+ return {
201
+ name: selectedWallet.name,
202
+ icon: selectedWallet.icon ?? null,
203
+ installed: walletInfo?.installed ?? false,
204
+ connectable: walletInfo?.connectable ?? false
205
+ };
206
+ }, [selectedWallet, wallets]);
207
+ return useMemo(
208
+ () => ({
209
+ ...selectedWalletInfo,
210
+ connected,
211
+ connecting,
212
+ wallets: mappedWallets
213
+ }),
214
+ [selectedWalletInfo, connected, connecting, mappedWallets]
215
+ );
216
+ }
217
+ function useTransactionSigner() {
218
+ let { selectedWallet, selectedAccount, accounts, cluster, connected } = useConnector(), client = useConnectorClient(), account = useMemo(
219
+ () => accounts.find((a) => a.address === selectedAccount)?.raw ?? null,
220
+ [accounts, selectedAccount]
221
+ ), signer = useMemo(() => !connected || !selectedWallet || !account ? null : createTransactionSigner({
222
+ wallet: selectedWallet,
223
+ account,
224
+ cluster: cluster ?? void 0,
225
+ eventEmitter: client ? {
226
+ emit: (event) => {
227
+ client.emitEvent(event);
228
+ }
229
+ } : void 0
230
+ }), [connected, selectedWallet, account, cluster, client]), capabilities = useMemo(
231
+ () => signer?.getCapabilities() ?? {
232
+ canSign: false,
233
+ canSend: false,
234
+ canSignMessage: false,
235
+ supportsBatchSigning: false
236
+ },
237
+ [signer]
238
+ );
239
+ return {
240
+ signer,
241
+ ready: !!signer,
242
+ address: selectedAccount,
243
+ capabilities
244
+ };
245
+ }
246
+ function useKitTransactionSigner() {
247
+ let { signer: connectorSigner, ready } = useTransactionSigner();
248
+ return {
249
+ signer: useMemo(() => connectorSigner ? createKitTransactionSigner(connectorSigner) : null, [connectorSigner]),
250
+ ready
251
+ };
252
+ }
253
+ var useGillTransactionSigner = useKitTransactionSigner;
254
+ var logger2 = createLogger("useSolanaClient");
255
+ function useSolanaClient() {
256
+ let { type } = useCluster(), connectorClient = useConnectorClient(), client = useMemo(() => {
257
+ if (!type || !connectorClient) return null;
258
+ try {
259
+ let rpcUrl = connectorClient.getRpcUrl();
260
+ return rpcUrl ? createSolanaClient({
261
+ urlOrMoniker: rpcUrl
262
+ }) : type !== "custom" ? createSolanaClient({
263
+ urlOrMoniker: type
264
+ }) : null;
265
+ } catch (error) {
266
+ return logger2.error("Failed to create Solana client", { error }), null;
267
+ }
268
+ }, [type, connectorClient]);
269
+ return useMemo(
270
+ () => ({
271
+ client,
272
+ ready: !!client,
273
+ clusterType: type
274
+ }),
275
+ [client, type]
276
+ );
277
+ }
278
+ var useGillSolanaClient = useSolanaClient;
279
+ function useTransactionPreparer() {
280
+ let { client, ready } = useSolanaClient(), prepare = useCallback(
281
+ async (transaction, options = {}) => {
282
+ if (!client)
283
+ throw new NetworkError("RPC_ERROR", "Solana client not available. Cannot prepare transaction.");
284
+ return prepareTransaction({
285
+ transaction,
286
+ rpc: client.rpc,
287
+ computeUnitLimitMultiplier: options.computeUnitLimitMultiplier,
288
+ computeUnitLimitReset: options.computeUnitLimitReset,
289
+ blockhashReset: options.blockhashReset
290
+ });
291
+ },
292
+ [client]
293
+ );
294
+ return useMemo(
295
+ () => ({
296
+ prepare,
297
+ ready
298
+ }),
299
+ [prepare, ready]
300
+ );
301
+ }
302
+ var LAMPORTS_PER_SOL2 = 1000000000n;
303
+ function formatSol(lamports, decimals = 4) {
304
+ return (Number(lamports) / Number(LAMPORTS_PER_SOL2)).toLocaleString(void 0, {
305
+ minimumFractionDigits: 0,
306
+ maximumFractionDigits: decimals
307
+ }) + " SOL";
308
+ }
309
+ function useBalance() {
310
+ let { address: address$1, connected } = useAccount(); useCluster(); let client = useSolanaClient(), [lamports, setLamports] = useState(0n), [tokens, setTokens] = useState([]), [isLoading, setIsLoading] = useState(false), [error, setError] = useState(null), [lastUpdated, setLastUpdated] = useState(null), hasDataRef = useRef(false), rpcClient = client?.client ?? null, fetchBalance = useCallback(async () => {
311
+ if (!connected || !address$1 || !rpcClient) {
312
+ setLamports(0n), setTokens([]), hasDataRef.current = false;
313
+ return;
314
+ }
315
+ setIsLoading(true), setError(null);
316
+ try {
317
+ let rpc = rpcClient.rpc, walletAddress = address(address$1), balanceResult = await rpc.getBalance(walletAddress).send();
318
+ setLamports(balanceResult.value);
319
+ try {
320
+ let tokenProgramId = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), tokenAccountsResult = await rpc.getTokenAccountsByOwner(walletAddress, { programId: tokenProgramId }, { encoding: "jsonParsed" }).send(), tokenBalances = [];
321
+ for (let account of tokenAccountsResult.value) {
322
+ let parsed = account.account.data;
323
+ if (parsed?.parsed?.info) {
324
+ let info = parsed.parsed.info, amount = BigInt(info.tokenAmount?.amount || "0"), decimals = info.tokenAmount?.decimals || 0, formatted = (Number(amount) / Math.pow(10, decimals)).toLocaleString(void 0, {
325
+ minimumFractionDigits: 0,
326
+ maximumFractionDigits: Math.min(decimals, 6)
327
+ });
328
+ amount > 0n && tokenBalances.push({
329
+ mint: info.mint,
330
+ amount,
331
+ decimals,
332
+ formatted
333
+ });
334
+ }
335
+ }
336
+ setTokens(tokenBalances);
337
+ } catch (tokenError) {
338
+ console.warn("Failed to fetch token balances:", tokenError), setTokens([]);
339
+ }
340
+ hasDataRef.current = true, setLastUpdated(/* @__PURE__ */ new Date());
341
+ } catch (err) {
342
+ hasDataRef.current || (setError(err), console.error("Failed to fetch balance:", err));
343
+ } finally {
344
+ setIsLoading(false);
345
+ }
346
+ }, [connected, address$1, rpcClient]);
347
+ useEffect(() => {
348
+ fetchBalance();
349
+ }, [fetchBalance]), useEffect(() => {
350
+ if (!connected) return;
351
+ let interval = setInterval(fetchBalance, 3e4);
352
+ return () => clearInterval(interval);
353
+ }, [connected, fetchBalance]);
354
+ let solBalance = useMemo(() => Number(lamports) / Number(LAMPORTS_PER_SOL2), [lamports]), formattedSol = useMemo(() => formatSol(lamports), [lamports]);
355
+ return useMemo(
356
+ () => ({
357
+ solBalance,
358
+ lamports,
359
+ formattedSol,
360
+ tokens,
361
+ isLoading,
362
+ error,
363
+ refetch: fetchBalance,
364
+ lastUpdated
365
+ }),
366
+ [solBalance, lamports, formattedSol, tokens, isLoading, error, fetchBalance, lastUpdated]
367
+ );
368
+ }
369
+ function formatDate(timestamp) {
370
+ if (!timestamp)
371
+ return { date: "Unknown", time: "" };
372
+ let date = new Date(timestamp * 1e3), diffDays = Math.floor(((/* @__PURE__ */ new Date()).getTime() - date.getTime()) / (1e3 * 60 * 60 * 24)), formattedDate;
373
+ diffDays === 0 ? formattedDate = "Today" : diffDays === 1 ? formattedDate = "Yesterday" : diffDays < 7 ? formattedDate = `${diffDays} days ago` : formattedDate = date.toLocaleDateString();
374
+ let formattedTime = date.toLocaleTimeString(void 0, {
375
+ hour: "2-digit",
376
+ minute: "2-digit"
377
+ });
378
+ return { date: formattedDate, time: formattedTime };
379
+ }
380
+ function isAccountKey(value) {
381
+ return typeof value == "object" && value !== null && "pubkey" in value && typeof value.pubkey == "string";
382
+ }
383
+ function isTransactionMeta(value) {
384
+ if (typeof value != "object" || value === null || !("preBalances" in value) || !("postBalances" in value))
385
+ return false;
386
+ let meta = value;
387
+ if (!Array.isArray(meta.preBalances) || !Array.isArray(meta.postBalances))
388
+ return false;
389
+ let isValidBalance = (b) => typeof b == "number" || typeof b == "bigint";
390
+ return meta.preBalances.every(isValidBalance) && meta.postBalances.every(isValidBalance);
391
+ }
392
+ function isTokenBalance(value) {
393
+ return typeof value == "object" && value !== null && "accountIndex" in value && "mint" in value && "uiTokenAmount" in value && typeof value.accountIndex == "number" && typeof value.mint == "string" && typeof value.uiTokenAmount == "object" && value.uiTokenAmount !== null;
394
+ }
395
+ function isUiTokenAmount(value) {
396
+ return typeof value == "object" && value !== null && "amount" in value && "decimals" in value && typeof value.amount == "string" && typeof value.decimals == "number";
397
+ }
398
+ function isTransactionWithMeta(value) {
399
+ return typeof value == "object" && value !== null && "meta" in value && "transaction" in value && value.meta !== null && typeof value.transaction == "object" && value.transaction !== null && "message" in value.transaction;
400
+ }
401
+ function isTransactionMessage(value) {
402
+ return typeof value == "object" && value !== null && "accountKeys" in value && Array.isArray(value.accountKeys);
403
+ }
404
+ function getAccountKeys(message) {
405
+ return Array.isArray(message.accountKeys) ? message.accountKeys.map((key) => typeof key == "string" ? key : isAccountKey(key) ? key.pubkey : "").filter(Boolean) : [];
406
+ }
407
+ function detectProgramIds(message, accountKeys) {
408
+ let programIds = /* @__PURE__ */ new Set();
409
+ if (!Array.isArray(message.instructions))
410
+ return programIds;
411
+ for (let instruction of message.instructions)
412
+ if (typeof instruction == "object" && instruction !== null) {
413
+ if (typeof instruction.programIdIndex == "number" && accountKeys[instruction.programIdIndex])
414
+ programIds.add(accountKeys[instruction.programIdIndex]);
415
+ else if (typeof instruction.programId == "string")
416
+ programIds.add(instruction.programId);
417
+ else if (instruction.programId && typeof instruction.programId == "object") {
418
+ let programIdStr = String(instruction.programId);
419
+ programIdStr && programIdStr !== "[object Object]" && programIds.add(programIdStr);
420
+ }
421
+ }
422
+ return programIds;
423
+ }
424
+ function parseSolChange(meta, walletIndex) {
425
+ if (!isTransactionMeta(meta) || !Array.isArray(meta.preBalances) || !Array.isArray(meta.postBalances))
426
+ return { balanceChange: 0, solChange: 0 };
427
+ let preBalanceRaw = meta.preBalances[walletIndex], postBalanceRaw = meta.postBalances[walletIndex], preBalance = typeof preBalanceRaw == "number" ? preBalanceRaw : typeof preBalanceRaw == "bigint" ? Number(preBalanceRaw) : 0, balanceChange = (typeof postBalanceRaw == "number" ? postBalanceRaw : typeof postBalanceRaw == "bigint" ? Number(postBalanceRaw) : 0) - preBalance, solChange = balanceChange / 1e9;
428
+ return { balanceChange, solChange };
429
+ }
430
+ function parseTokenTransfers(meta, accountKeys, walletAddress) {
431
+ if (!isTransactionMeta(meta))
432
+ return null;
433
+ let preTokenBalances = Array.isArray(meta.preTokenBalances) ? meta.preTokenBalances : [], postTokenBalances = Array.isArray(meta.postTokenBalances) ? meta.postTokenBalances : [], ourPreTokens = preTokenBalances.filter((balance) => {
434
+ if (!isTokenBalance(balance)) return false;
435
+ let accountKey = accountKeys[balance.accountIndex];
436
+ return accountKey && accountKey.trim() === walletAddress.trim() || balance.owner && balance.owner.trim() === walletAddress.trim();
437
+ }), ourPostTokens = postTokenBalances.filter((balance) => {
438
+ if (!isTokenBalance(balance)) return false;
439
+ let accountKey = accountKeys[balance.accountIndex];
440
+ return accountKey && accountKey.trim() === walletAddress.trim() || balance.owner && balance.owner.trim() === walletAddress.trim();
441
+ }), allMints = /* @__PURE__ */ new Set();
442
+ for (let token of ourPreTokens)
443
+ isTokenBalance(token) && allMints.add(token.mint);
444
+ for (let token of ourPostTokens)
445
+ isTokenBalance(token) && allMints.add(token.mint);
446
+ for (let mint of allMints) {
447
+ let preBal = ourPreTokens.find((b) => isTokenBalance(b) && b.mint === mint), postBal = ourPostTokens.find((b) => isTokenBalance(b) && b.mint === mint);
448
+ if (!isTokenBalance(preBal) && !isTokenBalance(postBal))
449
+ continue;
450
+ let preAmount = isTokenBalance(preBal) && isUiTokenAmount(preBal.uiTokenAmount) ? Number(preBal.uiTokenAmount.amount) : 0, change = (isTokenBalance(postBal) && isUiTokenAmount(postBal.uiTokenAmount) ? Number(postBal.uiTokenAmount.amount) : 0) - preAmount;
451
+ if (change !== 0) {
452
+ let decimals = isTokenBalance(postBal) && isUiTokenAmount(postBal.uiTokenAmount) ? postBal.uiTokenAmount.decimals : isTokenBalance(preBal) && isUiTokenAmount(preBal.uiTokenAmount) ? preBal.uiTokenAmount.decimals : 0;
453
+ if (typeof decimals != "number" || decimals < 0)
454
+ continue;
455
+ return {
456
+ tokenMint: mint,
457
+ tokenAmount: Math.abs(change) / Math.pow(10, decimals),
458
+ tokenDecimals: decimals,
459
+ direction: change > 0 ? "in" : "out",
460
+ type: change > 0 ? "received" : "sent"
461
+ };
462
+ }
463
+ }
464
+ if (ourPostTokens.length > ourPreTokens.length) {
465
+ let newToken = ourPostTokens.find(
466
+ (b) => isTokenBalance(b) && !ourPreTokens.some((p) => isTokenBalance(p) && p.mint === b.mint)
467
+ );
468
+ if (isTokenBalance(newToken) && isUiTokenAmount(newToken.uiTokenAmount)) {
469
+ let decimals = newToken.uiTokenAmount.decimals;
470
+ if (typeof decimals == "number" && decimals >= 0) {
471
+ let amount = Number(newToken.uiTokenAmount.amount) / Math.pow(10, decimals);
472
+ return {
473
+ tokenMint: newToken.mint,
474
+ tokenAmount: amount,
475
+ tokenDecimals: decimals,
476
+ direction: "in",
477
+ type: "received"
478
+ };
479
+ }
480
+ }
481
+ }
482
+ return null;
483
+ }
484
+ function formatAmount(tokenAmount, tokenDecimals, direction, solChange) {
485
+ if (tokenAmount !== void 0 && tokenDecimals !== void 0 && direction !== void 0) {
486
+ let sign = direction === "in" ? "+" : "-", maxDecimals = Math.min(tokenDecimals, 6);
487
+ return `${sign}${tokenAmount.toLocaleString(void 0, { maximumFractionDigits: maxDecimals })}`;
488
+ }
489
+ if (solChange !== 0)
490
+ return `${solChange > 0 ? "+" : ""}${solChange.toFixed(4)} SOL`;
491
+ }
492
+ var tokenMetadataCache = /* @__PURE__ */ new Map();
493
+ function transformImageUrl(url, imageProxy) {
494
+ if (url)
495
+ return imageProxy ? `${imageProxy}${encodeURIComponent(url)}` : url;
496
+ }
497
+ async function fetchTokenMetadata(mints) {
498
+ let results = /* @__PURE__ */ new Map();
499
+ if (mints.length === 0) return results;
500
+ let uncachedMints = [];
501
+ for (let mint of mints) {
502
+ let cached = tokenMetadataCache.get(mint);
503
+ cached ? results.set(mint, cached) : uncachedMints.push(mint);
504
+ }
505
+ if (uncachedMints.length === 0) return results;
506
+ try {
507
+ let response = await fetch("https://token-list-api.solana.cloud/v1/mints?chainId=101", {
508
+ method: "POST",
509
+ headers: { "Content-Type": "application/json" },
510
+ body: JSON.stringify({ addresses: uncachedMints }),
511
+ signal: AbortSignal.timeout(5e3)
512
+ });
513
+ if (!response.ok) return results;
514
+ let data = await response.json();
515
+ for (let item of data.content) {
516
+ let metadata = { symbol: item.symbol, icon: item.logoURI };
517
+ results.set(item.address, metadata), tokenMetadataCache.set(item.address, metadata);
518
+ }
519
+ } catch (error) {
520
+ console.warn("[useTransactions] Failed to fetch token metadata:", error);
521
+ }
522
+ return results;
523
+ }
524
+ function useTransactions(options = {}) {
525
+ let { limit = 10, autoRefresh = false, refreshInterval = 6e4, fetchDetails = true } = options, { address: address$1, connected } = useAccount(), { cluster } = useCluster(), client = useSolanaClient(), connectorClient = useConnectorClient(), [transactions, setTransactions] = useState([]), [isLoading, setIsLoading] = useState(false), [error, setError] = useState(null), [hasMore, setHasMore] = useState(true), [lastUpdated, setLastUpdated] = useState(null), beforeSignatureRef = useRef(void 0), prevDepsRef = useRef(
526
+ null
527
+ ), rpcClient = client?.client ?? null, imageProxy = connectorClient?.getConfig().imageProxy, parseTransaction = useCallback(
528
+ (tx, walletAddress, sig, blockTime, slot, err, explorerUrl) => {
529
+ let { date, time } = formatDate(blockTime), baseInfo = {
530
+ signature: sig,
531
+ blockTime,
532
+ slot,
533
+ status: err ? "failed" : "success",
534
+ error: err ? JSON.stringify(
535
+ err,
536
+ (_key, value) => typeof value == "bigint" ? value.toString() : value
537
+ ) : void 0,
538
+ type: "unknown",
539
+ formattedDate: date,
540
+ formattedTime: time,
541
+ explorerUrl
542
+ };
543
+ if (!isTransactionWithMeta(tx))
544
+ return baseInfo;
545
+ try {
546
+ let { meta, transaction } = tx;
547
+ if (!isTransactionMeta(meta))
548
+ return baseInfo;
549
+ let { message } = transaction;
550
+ if (!isTransactionMessage(message))
551
+ return baseInfo;
552
+ let accountKeys = getAccountKeys(message), walletIndex = accountKeys.findIndex((key) => key.trim() === walletAddress.trim());
553
+ if (walletIndex === -1)
554
+ return baseInfo;
555
+ let { balanceChange, solChange } = parseSolChange(meta, walletIndex), programIds = detectProgramIds(message, accountKeys), hasJupiter = programIds.has("JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"), hasOrca = programIds.has("whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc"), hasRaydium = programIds.has("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"), hasStake = programIds.has("Stake11111111111111111111111111111111111111"), hasMetaplex = programIds.has("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"), hasSystemProgram = programIds.has("11111111111111111111111111111111"), hasTokenProgram = programIds.has("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), type = "unknown", direction, counterparty, tokenMint, tokenAmount, tokenDecimals;
556
+ if (hasJupiter || hasOrca || hasRaydium)
557
+ type = "swap";
558
+ else if (hasStake)
559
+ type = "stake";
560
+ else if (hasMetaplex)
561
+ type = "nft";
562
+ else if (hasSystemProgram && Math.abs(balanceChange) > 0)
563
+ type = balanceChange > 0 ? "received" : "sent", direction = balanceChange > 0 ? "in" : "out", tokenMint = "So11111111111111111111111111111111111111112", accountKeys.length >= 2 && (counterparty = accountKeys.find(
564
+ (key, idx) => idx !== walletIndex && key !== "11111111111111111111111111111111"
565
+ ));
566
+ else if (hasTokenProgram) {
567
+ let tokenTransfer = parseTokenTransfers(meta, accountKeys, walletAddress);
568
+ tokenTransfer && (type = tokenTransfer.type, direction = tokenTransfer.direction, tokenMint = tokenTransfer.tokenMint, tokenAmount = tokenTransfer.tokenAmount, tokenDecimals = tokenTransfer.tokenDecimals);
569
+ } else programIds.size > 0 && (type = "program");
570
+ let formattedAmount = formatAmount(tokenAmount, tokenDecimals, direction, solChange);
571
+ return {
572
+ ...baseInfo,
573
+ type,
574
+ direction,
575
+ amount: tokenAmount ?? Math.abs(solChange),
576
+ formattedAmount,
577
+ tokenMint,
578
+ counterparty: counterparty ? `${counterparty.slice(0, 4)}...${counterparty.slice(-4)}` : void 0
579
+ };
580
+ } catch (parseError) {
581
+ return console.warn("Failed to parse transaction:", parseError), baseInfo;
582
+ }
583
+ },
584
+ []
585
+ ), fetchTransactions = useCallback(
586
+ async (loadMore = false) => {
587
+ if (!connected || !address$1 || !rpcClient || !cluster) {
588
+ setTransactions([]);
589
+ return;
590
+ }
591
+ setIsLoading(true), setError(null);
592
+ try {
593
+ let rpc = rpcClient.rpc, walletAddress = address(address$1), signaturesResult = await rpc.getSignaturesForAddress(walletAddress, {
594
+ limit,
595
+ ...loadMore && beforeSignatureRef.current ? { before: signature(beforeSignatureRef.current) } : {}
596
+ }).send(), newTransactions;
597
+ if (fetchDetails && signaturesResult.length > 0) {
598
+ let txPromises = signaturesResult.map(
599
+ (s) => rpc.getTransaction(signature(String(s.signature)), {
600
+ encoding: "jsonParsed",
601
+ maxSupportedTransactionVersion: 0
602
+ }).send().catch(() => null)
603
+ ), txDetails = await Promise.all(txPromises);
604
+ newTransactions = signaturesResult.map((sig, idx) => {
605
+ let blockTimeNum = sig.blockTime ? Number(sig.blockTime) : null, tx = txDetails[idx];
606
+ return parseTransaction(
607
+ tx,
608
+ address$1,
609
+ String(sig.signature),
610
+ blockTimeNum,
611
+ Number(sig.slot),
612
+ sig.err,
613
+ getTransactionUrl(String(sig.signature), cluster)
614
+ );
615
+ });
616
+ } else
617
+ newTransactions = signaturesResult.map((sig) => {
618
+ let blockTimeNum = sig.blockTime ? Number(sig.blockTime) : null, { date, time } = formatDate(blockTimeNum);
619
+ return {
620
+ signature: String(sig.signature),
621
+ blockTime: blockTimeNum,
622
+ slot: Number(sig.slot),
623
+ status: sig.err ? "failed" : "success",
624
+ error: sig.err ? JSON.stringify(sig.err) : void 0,
625
+ type: "unknown",
626
+ formattedDate: date,
627
+ formattedTime: time,
628
+ explorerUrl: getTransactionUrl(String(sig.signature), cluster)
629
+ };
630
+ });
631
+ setTransactions(loadMore ? (prev) => [...prev, ...newTransactions] : newTransactions);
632
+ let mintsToFetch = [...new Set(newTransactions.filter((tx) => tx.tokenMint).map((tx) => tx.tokenMint))];
633
+ if (mintsToFetch.length > 0) {
634
+ let tokenMetadata = await fetchTokenMetadata(mintsToFetch);
635
+ if (tokenMetadata.size > 0) {
636
+ let enrichedTransactions = newTransactions.map((tx) => {
637
+ if (tx.tokenMint && tokenMetadata.has(tx.tokenMint)) {
638
+ let meta = tokenMetadata.get(tx.tokenMint);
639
+ return {
640
+ ...tx,
641
+ tokenSymbol: meta.symbol,
642
+ tokenIcon: transformImageUrl(meta.icon, imageProxy),
643
+ // Update formatted amount with symbol
644
+ formattedAmount: tx.formattedAmount ? `${tx.formattedAmount} ${meta.symbol}` : tx.formattedAmount
645
+ };
646
+ }
647
+ return tx;
648
+ });
649
+ setTransactions(loadMore ? (prev) => [...prev.slice(0, -newTransactions.length), ...enrichedTransactions] : enrichedTransactions);
650
+ }
651
+ }
652
+ if (typeof newTransactions < "u" && Array.isArray(newTransactions)) {
653
+ if (newTransactions.length > 0) {
654
+ let newBeforeSignature = newTransactions[newTransactions.length - 1].signature;
655
+ beforeSignatureRef.current = newBeforeSignature;
656
+ }
657
+ setHasMore(newTransactions.length === limit);
658
+ }
659
+ setLastUpdated(/* @__PURE__ */ new Date());
660
+ } catch (err) {
661
+ setError(err), console.error("Failed to fetch transactions:", err);
662
+ } finally {
663
+ setIsLoading(false);
664
+ }
665
+ },
666
+ [connected, address$1, rpcClient, cluster, limit, fetchDetails, parseTransaction, imageProxy]
667
+ ), refetch = useCallback(async () => {
668
+ beforeSignatureRef.current = void 0, await fetchTransactions(false);
669
+ }, [fetchTransactions]), loadMoreFn = useCallback(async () => {
670
+ hasMore && !isLoading && await fetchTransactions(true);
671
+ }, [hasMore, isLoading, fetchTransactions]);
672
+ return useEffect(() => {
673
+ let prevDeps = prevDepsRef.current, currentDeps = { connected, address: address$1, cluster };
674
+ (!prevDeps || prevDeps.connected !== connected || prevDeps.address !== address$1 || prevDeps.cluster !== cluster) && (prevDepsRef.current = currentDeps, beforeSignatureRef.current = void 0, fetchTransactions(false));
675
+ }, [connected, address$1, cluster, fetchTransactions]), useEffect(() => {
676
+ if (!connected || !autoRefresh) return;
677
+ let interval = setInterval(refetch, refreshInterval);
678
+ return () => clearInterval(interval);
679
+ }, [connected, autoRefresh, refreshInterval, refetch]), useMemo(
680
+ () => ({
681
+ transactions,
682
+ isLoading,
683
+ error,
684
+ hasMore,
685
+ loadMore: loadMoreFn,
686
+ refetch,
687
+ lastUpdated
688
+ }),
689
+ [transactions, isLoading, error, hasMore, loadMoreFn, refetch, lastUpdated]
690
+ );
691
+ }
692
+ function createTimeoutSignal(ms) {
693
+ if (typeof AbortSignal.timeout == "function")
694
+ return { signal: AbortSignal.timeout(ms), cleanup: () => {
695
+ } };
696
+ let controller = new AbortController(), timeoutId = setTimeout(() => controller.abort(), ms);
697
+ return {
698
+ signal: controller.signal,
699
+ cleanup: () => clearTimeout(timeoutId)
700
+ };
701
+ }
702
+ var NATIVE_MINT = "So11111111111111111111111111111111111111112", CACHE_MAX_SIZE = 500, PRICE_CACHE_TTL = 6e4, STALE_CLEANUP_INTERVAL = 12e4, COINGECKO_DEFAULT_MAX_RETRIES = 3, COINGECKO_DEFAULT_BASE_DELAY = 1e3, COINGECKO_DEFAULT_MAX_TIMEOUT = 3e4, COINGECKO_API_BASE_URL = "https://api.coingecko.com/api/v3", LRUCache = class {
703
+ constructor(maxSize, options) {
704
+ __publicField(this, "cache", /* @__PURE__ */ new Map());
705
+ __publicField(this, "maxSize");
706
+ __publicField(this, "getTtl");
707
+ __publicField(this, "getTimestamp");
708
+ this.maxSize = maxSize, this.getTtl = options?.getTtl, this.getTimestamp = options?.getTimestamp;
709
+ }
710
+ get(key) {
711
+ let value = this.cache.get(key);
712
+ if (value !== void 0) {
713
+ if (this.getTtl && this.getTimestamp) {
714
+ let ttl = this.getTtl(value), timestamp = this.getTimestamp(value);
715
+ if (ttl !== void 0 && timestamp !== void 0 && Date.now() - timestamp >= ttl) {
716
+ this.cache.delete(key);
717
+ return;
718
+ }
719
+ }
720
+ return this.cache.delete(key), this.cache.set(key, value), value;
721
+ }
722
+ }
723
+ set(key, value) {
724
+ if (this.cache.has(key) && this.cache.delete(key), this.cache.size >= this.maxSize) {
725
+ let oldestKey = this.cache.keys().next().value;
726
+ oldestKey !== void 0 && this.cache.delete(oldestKey);
727
+ }
728
+ this.cache.set(key, value);
729
+ }
730
+ has(key) {
731
+ return this.cache.has(key);
732
+ }
733
+ delete(key) {
734
+ return this.cache.delete(key);
735
+ }
736
+ clear() {
737
+ this.cache.clear();
738
+ }
739
+ get size() {
740
+ return this.cache.size;
741
+ }
742
+ /**
743
+ * Prune stale entries based on TTL.
744
+ * Only works if getTtl and getTimestamp are provided.
745
+ */
746
+ pruneStale() {
747
+ if (!this.getTtl || !this.getTimestamp) return 0;
748
+ let now = Date.now(), pruned = 0;
749
+ for (let [key, value] of this.cache) {
750
+ let ttl = this.getTtl(value), timestamp = this.getTimestamp(value);
751
+ ttl !== void 0 && timestamp !== void 0 && now - timestamp >= ttl && (this.cache.delete(key), pruned++);
752
+ }
753
+ return pruned;
754
+ }
755
+ }, metadataCache = new LRUCache(CACHE_MAX_SIZE), priceCache = new LRUCache(CACHE_MAX_SIZE, {
756
+ getTtl: () => PRICE_CACHE_TTL,
757
+ getTimestamp: (entry) => entry.timestamp
758
+ }), cleanupIntervalId = null, cleanupRefCount = 0;
759
+ function startCacheCleanup() {
760
+ cleanupRefCount++, cleanupIntervalId === null && (cleanupIntervalId = setInterval(() => {
761
+ priceCache.pruneStale();
762
+ }, STALE_CLEANUP_INTERVAL));
763
+ }
764
+ function stopCacheCleanup() {
765
+ cleanupRefCount = Math.max(0, cleanupRefCount - 1), cleanupRefCount === 0 && cleanupIntervalId !== null && (clearInterval(cleanupIntervalId), cleanupIntervalId = null);
766
+ }
767
+ function clearTokenCaches() {
768
+ metadataCache.clear(), priceCache.clear();
769
+ }
770
+ async function fetchSolanaTokenMetadata(mints) {
771
+ let results = /* @__PURE__ */ new Map();
772
+ if (mints.length === 0) return results;
773
+ let { signal, cleanup } = createTimeoutSignal(1e4);
774
+ try {
775
+ let response = await fetch("https://token-list-api.solana.cloud/v1/mints?chainId=101", {
776
+ method: "POST",
777
+ headers: { "Content-Type": "application/json" },
778
+ body: JSON.stringify({ addresses: mints }),
779
+ signal
780
+ });
781
+ if (cleanup(), !response.ok)
782
+ throw new Error(`Solana Token List API error: ${response.status}`);
783
+ let data = await response.json();
784
+ for (let item of data.content)
785
+ results.set(item.address, item);
786
+ } catch (error) {
787
+ cleanup(), console.warn("[useTokens] Solana Token List API failed:", error);
788
+ }
789
+ return results;
790
+ }
791
+ function calculateBackoffDelay(attempt, baseDelay, retryAfter) {
792
+ if (retryAfter !== void 0 && retryAfter > 0) {
793
+ let jitter2 = Math.random() * 500;
794
+ return retryAfter * 1e3 + jitter2;
795
+ }
796
+ let exponentialDelay = baseDelay * Math.pow(2, attempt), jitter = Math.random() * 500;
797
+ return exponentialDelay + jitter;
798
+ }
799
+ function parseRetryAfter(retryAfterHeader) {
800
+ if (!retryAfterHeader) return;
801
+ let seconds = parseInt(retryAfterHeader, 10);
802
+ if (!isNaN(seconds) && seconds >= 0)
803
+ return seconds;
804
+ let date = Date.parse(retryAfterHeader);
805
+ if (!isNaN(date)) {
806
+ let waitMs = date - Date.now();
807
+ return waitMs > 0 ? Math.ceil(waitMs / 1e3) : 0;
808
+ }
809
+ }
810
+ async function fetchCoinGeckoPrices(coingeckoIds, config) {
811
+ let results = /* @__PURE__ */ new Map();
812
+ if (coingeckoIds.length === 0) return results;
813
+ let now = Date.now(), uncachedIds = [];
814
+ for (let id of coingeckoIds) {
815
+ let cached = priceCache.get(id);
816
+ cached && now - cached.timestamp < PRICE_CACHE_TTL ? results.set(id, cached.price) : uncachedIds.push(id);
817
+ }
818
+ if (uncachedIds.length === 0) return results;
819
+ let maxRetries = config?.maxRetries ?? COINGECKO_DEFAULT_MAX_RETRIES, baseDelay = config?.baseDelay ?? COINGECKO_DEFAULT_BASE_DELAY, maxTimeout = config?.maxTimeout ?? COINGECKO_DEFAULT_MAX_TIMEOUT, apiKey = config?.apiKey, isPro = config?.isPro ?? false, url = `${COINGECKO_API_BASE_URL}/simple/price?ids=${uncachedIds.join(",")}&vs_currencies=usd`, headers = {};
820
+ apiKey && (headers[isPro ? "x-cg-pro-api-key" : "x-cg-demo-api-key"] = apiKey);
821
+ let startTime = Date.now(), attempt = 0, lastError = null;
822
+ for (; attempt <= maxRetries; ) {
823
+ let elapsedTime = Date.now() - startTime;
824
+ if (elapsedTime >= maxTimeout) {
825
+ console.warn(
826
+ `[useTokens] CoinGecko API: Total timeout (${maxTimeout}ms) exceeded after ${attempt} attempts. Returning cached/partial results.`
827
+ );
828
+ break;
829
+ }
830
+ let remainingTimeout = maxTimeout - elapsedTime, requestTimeout = Math.min(1e4, remainingTimeout), { signal, cleanup } = createTimeoutSignal(requestTimeout);
831
+ try {
832
+ let response = await fetch(url, {
833
+ headers,
834
+ signal
835
+ });
836
+ if (cleanup(), response.status === 429) {
837
+ let retryAfter = parseRetryAfter(response.headers.get("Retry-After")), delay = calculateBackoffDelay(attempt, baseDelay, retryAfter);
838
+ if (console.warn(
839
+ `[useTokens] CoinGecko API rate limited (429). Attempt ${attempt + 1}/${maxRetries + 1}. Retry-After: ${retryAfter ?? "not specified"}s. Waiting ${Math.round(delay)}ms before retry. Consider adding an API key for higher limits: https://www.coingecko.com/en/api/pricing`
840
+ ), Date.now() - startTime + delay >= maxTimeout) {
841
+ console.warn(
842
+ `[useTokens] CoinGecko API: Skipping retry - would exceed total timeout (${maxTimeout}ms). Returning cached/partial results.`
843
+ );
844
+ break;
845
+ }
846
+ await new Promise((resolve) => setTimeout(resolve, delay)), attempt++;
847
+ continue;
848
+ }
849
+ if (!response.ok)
850
+ throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
851
+ let data = await response.json(), fetchTime = Date.now();
852
+ for (let [id, priceData] of Object.entries(data))
853
+ priceData?.usd !== void 0 && (results.set(id, priceData.usd), priceCache.set(id, { price: priceData.usd, timestamp: fetchTime }));
854
+ return results;
855
+ } catch (error) {
856
+ if (cleanup(), lastError = error, error instanceof DOMException && error.name === "AbortError" ? console.warn(
857
+ `[useTokens] CoinGecko API request timed out. Attempt ${attempt + 1}/${maxRetries + 1}.`
858
+ ) : console.warn(
859
+ `[useTokens] CoinGecko API request failed. Attempt ${attempt + 1}/${maxRetries + 1}:`,
860
+ error
861
+ ), attempt < maxRetries) {
862
+ let delay = calculateBackoffDelay(attempt, baseDelay);
863
+ Date.now() - startTime + delay < maxTimeout && await new Promise((resolve) => setTimeout(resolve, delay));
864
+ }
865
+ attempt++;
866
+ }
867
+ }
868
+ return attempt > maxRetries && console.warn(
869
+ `[useTokens] CoinGecko API: All ${maxRetries + 1} attempts failed. Returning cached/partial results. Last error: ${lastError?.message ?? "Unknown error"}. If you are frequently rate limited, consider adding an API key: https://www.coingecko.com/en/api/pricing`
870
+ ), results;
871
+ }
872
+ async function fetchTokenMetadataHybrid(mints, coingeckoConfig) {
873
+ let results = /* @__PURE__ */ new Map();
874
+ if (mints.length === 0) return results;
875
+ let uncachedMints = [], now = Date.now();
876
+ for (let mint of mints) {
877
+ let cached = metadataCache.get(mint);
878
+ cached ? (cached.coingeckoId && (!priceCache.get(cached.coingeckoId) || now - (priceCache.get(cached.coingeckoId)?.timestamp ?? 0) >= PRICE_CACHE_TTL) && cached.coingeckoId && uncachedMints.push(mint), results.set(mint, cached)) : uncachedMints.push(mint);
879
+ }
880
+ if (uncachedMints.length === 0) return results;
881
+ let solanaMetadata = await fetchSolanaTokenMetadata(uncachedMints), coingeckoIdToMint = /* @__PURE__ */ new Map();
882
+ for (let [mint, meta] of solanaMetadata)
883
+ meta.extensions?.coingeckoId && coingeckoIdToMint.set(meta.extensions.coingeckoId, mint);
884
+ for (let mint of mints) {
885
+ let cached = metadataCache.get(mint);
886
+ cached?.coingeckoId && !coingeckoIdToMint.has(cached.coingeckoId) && coingeckoIdToMint.set(cached.coingeckoId, mint);
887
+ }
888
+ let prices = await fetchCoinGeckoPrices([...coingeckoIdToMint.keys()], coingeckoConfig);
889
+ for (let [mint, meta] of solanaMetadata) {
890
+ let coingeckoId = meta.extensions?.coingeckoId, usdPrice = coingeckoId ? prices.get(coingeckoId) : void 0, combined = {
891
+ address: meta.address,
892
+ name: meta.address === NATIVE_MINT ? "Solana" : meta.name,
893
+ symbol: meta.symbol,
894
+ decimals: meta.decimals,
895
+ logoURI: meta.logoURI,
896
+ coingeckoId,
897
+ usdPrice
898
+ };
899
+ results.set(mint, combined), metadataCache.set(mint, combined);
900
+ }
901
+ for (let [coingeckoId, mint] of coingeckoIdToMint) {
902
+ let cached = results.get(mint) ?? metadataCache.get(mint);
903
+ if (cached) {
904
+ let usdPrice = prices.get(coingeckoId);
905
+ usdPrice !== void 0 && (cached.usdPrice = usdPrice, results.set(mint, cached), metadataCache.set(mint, cached));
906
+ }
907
+ }
908
+ return results;
909
+ }
910
+ function formatBalance(amount, decimals) {
911
+ return (Number(amount) / Math.pow(10, decimals)).toLocaleString(void 0, {
912
+ minimumFractionDigits: 0,
913
+ maximumFractionDigits: Math.min(decimals, 6)
914
+ });
915
+ }
916
+ function formatUsd(amount, decimals, usdPrice) {
917
+ return (Number(amount) / Math.pow(10, decimals) * usdPrice).toLocaleString(void 0, {
918
+ style: "currency",
919
+ currency: "USD",
920
+ minimumFractionDigits: 2,
921
+ maximumFractionDigits: 2
922
+ });
923
+ }
924
+ function transformImageUrl2(url, imageProxy) {
925
+ if (!url) return;
926
+ if (!imageProxy) return url;
927
+ let encodedUrl = encodeURIComponent(url);
928
+ return imageProxy.endsWith("/") ? imageProxy + encodedUrl : imageProxy + "/" + encodedUrl;
929
+ }
930
+ function useTokens(options = {}) {
931
+ let {
932
+ includeZeroBalance = false,
933
+ autoRefresh = false,
934
+ refreshInterval = 6e4,
935
+ fetchMetadata = true,
936
+ includeNativeSol = true
937
+ } = options, { address: address$1, connected } = useAccount(), client = useSolanaClient(), connectorClient = useConnectorClient(), [tokens, setTokens] = useState([]), [isLoading, setIsLoading] = useState(false), [error, setError] = useState(null), [lastUpdated, setLastUpdated] = useState(null), [totalAccounts, setTotalAccounts] = useState(0), rpcClient = client?.client ?? null, connectorConfig = connectorClient?.getConfig(), imageProxy = connectorConfig?.imageProxy, coingeckoConfig = connectorConfig?.coingecko, fetchTokens = useCallback(async () => {
938
+ if (!connected || !address$1 || !rpcClient) {
939
+ setTokens([]), setTotalAccounts(0);
940
+ return;
941
+ }
942
+ setIsLoading(true), setError(null);
943
+ try {
944
+ let rpc = rpcClient.rpc, walletAddress = address(address$1), tokenProgramId = address("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"), [balanceResult, tokenAccountsResult] = await Promise.all([
945
+ includeNativeSol ? rpc.getBalance(walletAddress).send() : Promise.resolve(null),
946
+ rpc.getTokenAccountsByOwner(walletAddress, { programId: tokenProgramId }, { encoding: "jsonParsed" }).send()
947
+ ]), tokenList = [], mints = [];
948
+ if (includeNativeSol && balanceResult !== null) {
949
+ let solBalance = balanceResult.value;
950
+ (includeZeroBalance || solBalance > 0n) && (tokenList.push({
951
+ mint: NATIVE_MINT,
952
+ tokenAccount: address$1,
953
+ // SOL uses wallet address
954
+ amount: solBalance,
955
+ decimals: 9,
956
+ formatted: formatBalance(solBalance, 9),
957
+ isFrozen: false,
958
+ owner: address$1
959
+ }), mints.push(NATIVE_MINT));
960
+ }
961
+ for (let account of tokenAccountsResult.value) {
962
+ let parsed = account.account.data;
963
+ if (parsed?.parsed?.info) {
964
+ let info = parsed.parsed.info, amount = BigInt(info.tokenAmount?.amount || "0"), decimals = info.tokenAmount?.decimals || 0;
965
+ if (!includeZeroBalance && amount === 0n)
966
+ continue;
967
+ tokenList.push({
968
+ mint: info.mint,
969
+ tokenAccount: account.pubkey,
970
+ amount,
971
+ decimals,
972
+ formatted: formatBalance(amount, decimals),
973
+ isFrozen: info.state === "frozen",
974
+ owner: info.owner
975
+ }), mints.push(info.mint);
976
+ }
977
+ }
978
+ if (setTokens([...tokenList]), setTotalAccounts(tokenAccountsResult.value.length + (includeNativeSol ? 1 : 0)), setLastUpdated(/* @__PURE__ */ new Date()), fetchMetadata && mints.length > 0) {
979
+ let metadata = await fetchTokenMetadataHybrid(mints, coingeckoConfig);
980
+ for (let i = 0; i < tokenList.length; i++) {
981
+ let meta = metadata.get(tokenList[i].mint);
982
+ meta && (tokenList[i] = {
983
+ ...tokenList[i],
984
+ name: meta.name,
985
+ symbol: meta.symbol,
986
+ logo: transformImageUrl2(meta.logoURI, imageProxy),
987
+ usdPrice: meta.usdPrice,
988
+ formattedUsd: meta.usdPrice ? formatUsd(tokenList[i].amount, tokenList[i].decimals, meta.usdPrice) : void 0
989
+ });
990
+ }
991
+ tokenList.sort((a, b) => {
992
+ let metadataSort = (b.logo ? 1 : 0) - (a.logo ? 1 : 0);
993
+ if (metadataSort !== 0) return metadataSort;
994
+ let aValue = Number(a.amount) / Math.pow(10, a.decimals) * (a.usdPrice ?? 0);
995
+ return Number(b.amount) / Math.pow(10, b.decimals) * (b.usdPrice ?? 0) - aValue;
996
+ }), setTokens([...tokenList]);
997
+ }
998
+ } catch (err) {
999
+ setError(err), console.error("[useTokens] Failed to fetch tokens:", err);
1000
+ } finally {
1001
+ setIsLoading(false);
1002
+ }
1003
+ }, [connected, address$1, rpcClient, includeZeroBalance, fetchMetadata, includeNativeSol, imageProxy, coingeckoConfig]);
1004
+ useEffect(() => {
1005
+ fetchTokens();
1006
+ }, [fetchTokens]), useEffect(() => {
1007
+ if (!connected || !autoRefresh) return;
1008
+ let interval = setInterval(fetchTokens, refreshInterval);
1009
+ return () => clearInterval(interval);
1010
+ }, [connected, autoRefresh, refreshInterval, fetchTokens]), useEffect(() => (startCacheCleanup(), () => stopCacheCleanup()), []);
1011
+ let wasConnectedRef = useRef(connected);
1012
+ return useEffect(() => {
1013
+ wasConnectedRef.current && !connected && clearTokenCaches(), wasConnectedRef.current = connected;
1014
+ }, [connected]), useMemo(
1015
+ () => ({
1016
+ tokens,
1017
+ isLoading,
1018
+ error,
1019
+ refetch: fetchTokens,
1020
+ lastUpdated,
1021
+ totalAccounts
1022
+ }),
1023
+ [tokens, isLoading, error, fetchTokens, lastUpdated, totalAccounts]
1024
+ );
1025
+ }
1026
+ function DisconnectElement({
1027
+ variant = "menuitem",
1028
+ className,
1029
+ label = "Disconnect",
1030
+ icon,
1031
+ showIcon = true,
1032
+ onDisconnect,
1033
+ render
1034
+ }) {
1035
+ let { disconnect, connecting } = useConnector(), [disconnecting, setDisconnecting] = React.useState(false), handleDisconnect = async () => {
1036
+ setDisconnecting(true);
1037
+ try {
1038
+ await disconnect(), onDisconnect?.();
1039
+ } finally {
1040
+ setDisconnecting(false);
1041
+ }
1042
+ };
1043
+ if (render)
1044
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ disconnect: handleDisconnect, disconnecting }) });
1045
+ let isDisabled = connecting || disconnecting, content = /* @__PURE__ */ jsxs(Fragment, { children: [
1046
+ showIcon && (icon || showIcon && !icon && /* @__PURE__ */ jsxs(
1047
+ "svg",
1048
+ {
1049
+ width: "16",
1050
+ height: "16",
1051
+ viewBox: "0 0 24 24",
1052
+ fill: "none",
1053
+ stroke: "currentColor",
1054
+ strokeWidth: "2",
1055
+ strokeLinecap: "round",
1056
+ strokeLinejoin: "round",
1057
+ className: "ck-block-icon",
1058
+ "data-slot": "disconnect-element-icon",
1059
+ children: [
1060
+ /* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
1061
+ /* @__PURE__ */ jsx("polyline", { points: "16 17 21 12 16 7" }),
1062
+ /* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
1063
+ ]
1064
+ }
1065
+ )),
1066
+ /* @__PURE__ */ jsx("span", { "data-slot": "disconnect-element-label", children: label })
1067
+ ] });
1068
+ return variant === "button" ? /* @__PURE__ */ jsx(
1069
+ "button",
1070
+ {
1071
+ type: "button",
1072
+ className: `ck-disconnect-block ck-disconnect-block--button ${className || ""}`,
1073
+ onClick: handleDisconnect,
1074
+ disabled: isDisabled,
1075
+ "data-slot": "disconnect-element",
1076
+ "data-variant": "button",
1077
+ "data-disconnecting": disconnecting,
1078
+ children: content
1079
+ }
1080
+ ) : variant === "link" ? /* @__PURE__ */ jsx(
1081
+ "button",
1082
+ {
1083
+ type: "button",
1084
+ className: `ck-disconnect-block ck-disconnect-block--link ${className || ""}`,
1085
+ onClick: handleDisconnect,
1086
+ disabled: isDisabled,
1087
+ "data-slot": "disconnect-element",
1088
+ "data-variant": "link",
1089
+ "data-disconnecting": disconnecting,
1090
+ children: content
1091
+ }
1092
+ ) : /* @__PURE__ */ jsx(
1093
+ "button",
1094
+ {
1095
+ type: "button",
1096
+ role: "menuitem",
1097
+ className: `ck-disconnect-block ck-disconnect-block--menuitem ${className || ""}`,
1098
+ onClick: handleDisconnect,
1099
+ disabled: isDisabled,
1100
+ "data-slot": "disconnect-element",
1101
+ "data-variant": "menuitem",
1102
+ "data-disconnecting": disconnecting,
1103
+ children: content
1104
+ }
1105
+ );
1106
+ }
1107
+ DisconnectElement.displayName = "DisconnectElement";
1108
+ function AccountElement({
1109
+ showAvatar = true,
1110
+ showCopy = true,
1111
+ showFullAddress = false,
1112
+ className,
1113
+ avatarSize = 32,
1114
+ variant = "compact",
1115
+ render
1116
+ }) {
1117
+ let { address, formatted, copy, copied } = useAccount(), { name: walletName, icon: walletIcon } = useWalletInfo();
1118
+ if (render)
1119
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ address, formatted, walletName, walletIcon, copy, copied }) });
1120
+ if (!address) return null;
1121
+ let displayAddress = showFullAddress ? address : formatted, handleCopy = async (e) => {
1122
+ e.stopPropagation(), await copy();
1123
+ }, copyIcon = /* @__PURE__ */ jsx(
1124
+ "svg",
1125
+ {
1126
+ width: "14",
1127
+ height: "14",
1128
+ viewBox: "0 0 24 24",
1129
+ fill: "none",
1130
+ stroke: "currentColor",
1131
+ strokeWidth: "2",
1132
+ strokeLinecap: "round",
1133
+ strokeLinejoin: "round",
1134
+ className: "ck-block-icon",
1135
+ "data-slot": "account-element-copy-icon",
1136
+ children: copied ? /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1137
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
1138
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
1139
+ ] })
1140
+ }
1141
+ );
1142
+ return variant === "inline" ? /* @__PURE__ */ jsxs(
1143
+ "div",
1144
+ {
1145
+ className: `ck-account-block ck-account-block--inline ${className || ""}`,
1146
+ "data-slot": "account-element",
1147
+ "data-variant": "inline",
1148
+ children: [
1149
+ showAvatar && walletIcon && /* @__PURE__ */ jsx(
1150
+ "img",
1151
+ {
1152
+ src: walletIcon,
1153
+ alt: walletName || "Wallet",
1154
+ className: "ck-account-block-avatar",
1155
+ style: { width: avatarSize, height: avatarSize },
1156
+ "data-slot": "account-element-avatar"
1157
+ }
1158
+ ),
1159
+ /* @__PURE__ */ jsx("span", { className: "ck-account-block-address", "data-slot": "account-element-address", children: displayAddress }),
1160
+ showCopy && /* @__PURE__ */ jsx(
1161
+ "button",
1162
+ {
1163
+ type: "button",
1164
+ className: "ck-account-block-copy",
1165
+ onClick: handleCopy,
1166
+ title: copied ? "Copied!" : "Copy address",
1167
+ "data-slot": "account-element-copy",
1168
+ "data-copied": copied,
1169
+ children: copyIcon
1170
+ }
1171
+ )
1172
+ ]
1173
+ }
1174
+ ) : variant === "expanded" ? /* @__PURE__ */ jsxs(
1175
+ "div",
1176
+ {
1177
+ className: `ck-account-block ck-account-block--expanded ${className || ""}`,
1178
+ "data-slot": "account-element",
1179
+ "data-variant": "expanded",
1180
+ children: [
1181
+ /* @__PURE__ */ jsxs("div", { className: "ck-account-block-header", "data-slot": "account-element-header", children: [
1182
+ showAvatar && walletIcon && /* @__PURE__ */ jsx(
1183
+ "img",
1184
+ {
1185
+ src: walletIcon,
1186
+ alt: walletName || "Wallet",
1187
+ className: "ck-account-block-avatar",
1188
+ style: { width: avatarSize, height: avatarSize },
1189
+ "data-slot": "account-element-avatar"
1190
+ }
1191
+ ),
1192
+ /* @__PURE__ */ jsxs("div", { className: "ck-account-block-info", "data-slot": "account-element-info", children: [
1193
+ walletName && /* @__PURE__ */ jsx("span", { className: "ck-account-block-wallet-name", "data-slot": "account-element-wallet-name", children: walletName }),
1194
+ /* @__PURE__ */ jsx("span", { className: "ck-account-block-address", "data-slot": "account-element-address", children: displayAddress })
1195
+ ] })
1196
+ ] }),
1197
+ showCopy && /* @__PURE__ */ jsxs(
1198
+ "button",
1199
+ {
1200
+ type: "button",
1201
+ className: "ck-account-block-copy",
1202
+ onClick: handleCopy,
1203
+ "data-slot": "account-element-copy",
1204
+ "data-copied": copied,
1205
+ children: [
1206
+ copyIcon,
1207
+ /* @__PURE__ */ jsx("span", { children: copied ? "Copied!" : "Copy" })
1208
+ ]
1209
+ }
1210
+ )
1211
+ ]
1212
+ }
1213
+ ) : /* @__PURE__ */ jsxs(
1214
+ "div",
1215
+ {
1216
+ className: `ck-account-block ck-account-block--compact ${className || ""}`,
1217
+ "data-slot": "account-element",
1218
+ "data-variant": "compact",
1219
+ children: [
1220
+ showAvatar && walletIcon && /* @__PURE__ */ jsx(
1221
+ "img",
1222
+ {
1223
+ src: walletIcon,
1224
+ alt: walletName || "Wallet",
1225
+ className: "ck-account-block-avatar",
1226
+ style: { width: avatarSize, height: avatarSize },
1227
+ "data-slot": "account-element-avatar"
1228
+ }
1229
+ ),
1230
+ /* @__PURE__ */ jsxs("div", { className: "ck-account-block-content", "data-slot": "account-element-content", children: [
1231
+ walletName && /* @__PURE__ */ jsx("span", { className: "ck-account-block-wallet-name", "data-slot": "account-element-wallet-name", children: walletName }),
1232
+ /* @__PURE__ */ jsx("span", { className: "ck-account-block-address", "data-slot": "account-element-address", children: displayAddress })
1233
+ ] }),
1234
+ showCopy && /* @__PURE__ */ jsx(
1235
+ "button",
1236
+ {
1237
+ type: "button",
1238
+ className: "ck-account-block-copy",
1239
+ onClick: handleCopy,
1240
+ title: copied ? "Copied!" : "Copy address",
1241
+ "data-slot": "account-element-copy",
1242
+ "data-copied": copied,
1243
+ children: copyIcon
1244
+ }
1245
+ )
1246
+ ]
1247
+ }
1248
+ );
1249
+ }
1250
+ AccountElement.displayName = "AccountElement";
1251
+ var DEFAULT_LABELS = {
1252
+ "mainnet-beta": "Mainnet",
1253
+ devnet: "Devnet",
1254
+ testnet: "Testnet",
1255
+ localnet: "Localnet"
1256
+ };
1257
+ function getClusterColor(clusterId) {
1258
+ switch (clusterId) {
1259
+ case "mainnet-beta":
1260
+ return "var(--ck-cluster-mainnet, #22c55e)";
1261
+ case "devnet":
1262
+ return "var(--ck-cluster-devnet, #3b82f6)";
1263
+ case "testnet":
1264
+ return "var(--ck-cluster-testnet, #eab308)";
1265
+ case "localnet":
1266
+ return "var(--ck-cluster-localnet, #ef4444)";
1267
+ default:
1268
+ return "var(--ck-cluster-custom, #8b5cf6)";
1269
+ }
1270
+ }
1271
+ function ClusterElement({
1272
+ variant = "badge",
1273
+ className,
1274
+ allowChange = false,
1275
+ showIndicator = true,
1276
+ labels = {},
1277
+ render
1278
+ }) {
1279
+ let { cluster, clusters, setCluster, isMainnet, isDevnet, isTestnet, isLocal } = useCluster(), [isOpen, setIsOpen] = React.useState(false);
1280
+ if (render)
1281
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ cluster, clusters, setCluster, isMainnet, isDevnet, isTestnet, isLocal }) });
1282
+ if (!cluster) return null;
1283
+ let allLabels = { ...DEFAULT_LABELS, ...labels }, displayLabel = allLabels[cluster.id] || cluster.label || cluster.id, color = getClusterColor(cluster.id), indicator = showIndicator && /* @__PURE__ */ jsx(
1284
+ "span",
1285
+ {
1286
+ className: "ck-cluster-indicator",
1287
+ style: { backgroundColor: color },
1288
+ "data-slot": "cluster-element-indicator",
1289
+ "aria-hidden": "true"
1290
+ }
1291
+ );
1292
+ return variant === "badge" ? /* @__PURE__ */ jsxs(
1293
+ "span",
1294
+ {
1295
+ className: `ck-cluster-block ck-cluster-block--badge ${className || ""}`,
1296
+ "data-slot": "cluster-element",
1297
+ "data-variant": "badge",
1298
+ "data-cluster": cluster.id,
1299
+ children: [
1300
+ indicator,
1301
+ /* @__PURE__ */ jsx("span", { "data-slot": "cluster-element-label", children: displayLabel })
1302
+ ]
1303
+ }
1304
+ ) : variant === "menuitem" ? allowChange ? /* @__PURE__ */ jsxs(
1305
+ "div",
1306
+ {
1307
+ className: `ck-cluster-block ck-cluster-block--menuitem ${className || ""}`,
1308
+ "data-slot": "cluster-element",
1309
+ "data-variant": "menuitem",
1310
+ "data-cluster": cluster.id,
1311
+ children: [
1312
+ /* @__PURE__ */ jsxs(
1313
+ "button",
1314
+ {
1315
+ type: "button",
1316
+ className: "ck-cluster-block-trigger",
1317
+ onClick: () => setIsOpen(!isOpen),
1318
+ "data-slot": "cluster-element-trigger",
1319
+ children: [
1320
+ indicator,
1321
+ /* @__PURE__ */ jsx("span", { "data-slot": "cluster-element-label", children: displayLabel }),
1322
+ /* @__PURE__ */ jsx(
1323
+ "svg",
1324
+ {
1325
+ width: "12",
1326
+ height: "12",
1327
+ viewBox: "0 0 24 24",
1328
+ fill: "none",
1329
+ stroke: "currentColor",
1330
+ strokeWidth: "2",
1331
+ className: `ck-cluster-block-chevron ${isOpen ? "ck-cluster-block-chevron--open" : ""}`,
1332
+ "data-slot": "cluster-element-chevron",
1333
+ children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
1334
+ }
1335
+ )
1336
+ ]
1337
+ }
1338
+ ),
1339
+ isOpen && /* @__PURE__ */ jsx("div", { className: "ck-cluster-block-options", "data-slot": "cluster-element-options", children: clusters.map((c) => {
1340
+ let cLabel = allLabels[c.id] || c.label || c.id, cColor = getClusterColor(c.id), isSelected = c.id === cluster.id;
1341
+ return /* @__PURE__ */ jsxs(
1342
+ "button",
1343
+ {
1344
+ type: "button",
1345
+ className: `ck-cluster-block-option ${isSelected ? "ck-cluster-block-option--selected" : ""}`,
1346
+ onClick: () => {
1347
+ setCluster(c.id), setIsOpen(false);
1348
+ },
1349
+ "data-slot": "cluster-element-option",
1350
+ "data-selected": isSelected,
1351
+ children: [
1352
+ /* @__PURE__ */ jsx(
1353
+ "span",
1354
+ {
1355
+ className: "ck-cluster-indicator",
1356
+ style: { backgroundColor: cColor },
1357
+ "data-slot": "cluster-element-indicator"
1358
+ }
1359
+ ),
1360
+ /* @__PURE__ */ jsx("span", { children: cLabel }),
1361
+ isSelected && /* @__PURE__ */ jsx(
1362
+ "svg",
1363
+ {
1364
+ width: "12",
1365
+ height: "12",
1366
+ viewBox: "0 0 24 24",
1367
+ fill: "none",
1368
+ stroke: "currentColor",
1369
+ strokeWidth: "3",
1370
+ className: "ck-cluster-block-check",
1371
+ "data-slot": "cluster-element-check",
1372
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
1373
+ }
1374
+ )
1375
+ ]
1376
+ },
1377
+ c.id
1378
+ );
1379
+ }) })
1380
+ ]
1381
+ }
1382
+ ) : /* @__PURE__ */ jsxs(
1383
+ "div",
1384
+ {
1385
+ className: `ck-cluster-block ck-cluster-block--menuitem ${className || ""}`,
1386
+ role: "menuitem",
1387
+ "data-slot": "cluster-element",
1388
+ "data-variant": "menuitem",
1389
+ "data-cluster": cluster.id,
1390
+ children: [
1391
+ indicator,
1392
+ /* @__PURE__ */ jsx("span", { "data-slot": "cluster-element-label", children: displayLabel })
1393
+ ]
1394
+ }
1395
+ ) : /* @__PURE__ */ jsxs(
1396
+ "div",
1397
+ {
1398
+ className: `ck-cluster-block ck-cluster-block--select ${className || ""}`,
1399
+ "data-slot": "cluster-element",
1400
+ "data-variant": "select",
1401
+ "data-cluster": cluster.id,
1402
+ children: [
1403
+ /* @__PURE__ */ jsxs(
1404
+ "button",
1405
+ {
1406
+ type: "button",
1407
+ className: "ck-cluster-block-trigger",
1408
+ onClick: () => setIsOpen(!isOpen),
1409
+ disabled: !allowChange,
1410
+ "data-slot": "cluster-element-trigger",
1411
+ children: [
1412
+ indicator,
1413
+ /* @__PURE__ */ jsx("span", { "data-slot": "cluster-element-label", children: displayLabel }),
1414
+ allowChange && /* @__PURE__ */ jsx(
1415
+ "svg",
1416
+ {
1417
+ width: "12",
1418
+ height: "12",
1419
+ viewBox: "0 0 24 24",
1420
+ fill: "none",
1421
+ stroke: "currentColor",
1422
+ strokeWidth: "2",
1423
+ className: `ck-cluster-block-chevron ${isOpen ? "ck-cluster-block-chevron--open" : ""}`,
1424
+ "data-slot": "cluster-element-chevron",
1425
+ children: /* @__PURE__ */ jsx("polyline", { points: "6 9 12 15 18 9" })
1426
+ }
1427
+ )
1428
+ ]
1429
+ }
1430
+ ),
1431
+ isOpen && allowChange && /* @__PURE__ */ jsxs(Fragment, { children: [
1432
+ /* @__PURE__ */ jsx("div", { className: "ck-cluster-block-backdrop", onClick: () => setIsOpen(false), "aria-hidden": "true" }),
1433
+ /* @__PURE__ */ jsx("div", { className: "ck-cluster-block-options", "data-slot": "cluster-element-options", children: clusters.map((c) => {
1434
+ let cLabel = allLabels[c.id] || c.label || c.id, cColor = getClusterColor(c.id), isSelected = c.id === cluster.id;
1435
+ return /* @__PURE__ */ jsxs(
1436
+ "button",
1437
+ {
1438
+ type: "button",
1439
+ className: `ck-cluster-block-option ${isSelected ? "ck-cluster-block-option--selected" : ""}`,
1440
+ onClick: () => {
1441
+ setCluster(c.id), setIsOpen(false);
1442
+ },
1443
+ "data-slot": "cluster-element-option",
1444
+ "data-selected": isSelected,
1445
+ children: [
1446
+ /* @__PURE__ */ jsx(
1447
+ "span",
1448
+ {
1449
+ className: "ck-cluster-indicator",
1450
+ style: { backgroundColor: cColor },
1451
+ "data-slot": "cluster-element-indicator"
1452
+ }
1453
+ ),
1454
+ /* @__PURE__ */ jsx("span", { children: cLabel }),
1455
+ isSelected && /* @__PURE__ */ jsx(
1456
+ "svg",
1457
+ {
1458
+ width: "12",
1459
+ height: "12",
1460
+ viewBox: "0 0 24 24",
1461
+ fill: "none",
1462
+ stroke: "currentColor",
1463
+ strokeWidth: "3",
1464
+ className: "ck-cluster-block-check",
1465
+ "data-slot": "cluster-element-check",
1466
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
1467
+ }
1468
+ )
1469
+ ]
1470
+ },
1471
+ c.id
1472
+ );
1473
+ }) })
1474
+ ] })
1475
+ ]
1476
+ }
1477
+ );
1478
+ }
1479
+ ClusterElement.displayName = "ClusterElement";
1480
+ function WalletListElement({
1481
+ installedOnly = false,
1482
+ className,
1483
+ variant = "list",
1484
+ showStatus = true,
1485
+ onSelect,
1486
+ render,
1487
+ renderWallet
1488
+ }) {
1489
+ let { wallets, connecting } = useWalletInfo(), { select } = useConnector(), installedWallets = wallets.filter((w) => w.installed), displayWallets = installedOnly ? installedWallets : wallets, handleSelect = async (walletName) => {
1490
+ await select(walletName), onSelect?.(walletName);
1491
+ };
1492
+ if (render)
1493
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ wallets, installedWallets, select: handleSelect, connecting }) });
1494
+ if (displayWallets.length === 0)
1495
+ return /* @__PURE__ */ jsx(
1496
+ "div",
1497
+ {
1498
+ className: `ck-wallet-list-block ck-wallet-list-block--empty ${className || ""}`,
1499
+ "data-slot": "wallet-list-element",
1500
+ "data-empty": "true",
1501
+ children: /* @__PURE__ */ jsxs("div", { className: "ck-wallet-list-empty", "data-slot": "wallet-list-empty", children: [
1502
+ /* @__PURE__ */ jsxs(
1503
+ "svg",
1504
+ {
1505
+ width: "48",
1506
+ height: "48",
1507
+ viewBox: "0 0 24 24",
1508
+ fill: "none",
1509
+ stroke: "currentColor",
1510
+ strokeWidth: "1.5",
1511
+ strokeLinecap: "round",
1512
+ strokeLinejoin: "round",
1513
+ className: "ck-wallet-list-empty-icon",
1514
+ "data-slot": "wallet-list-empty-icon",
1515
+ children: [
1516
+ /* @__PURE__ */ jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }),
1517
+ /* @__PURE__ */ jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })
1518
+ ]
1519
+ }
1520
+ ),
1521
+ /* @__PURE__ */ jsx("p", { className: "ck-wallet-list-empty-text", "data-slot": "wallet-list-empty-text", children: installedOnly ? "No wallets detected" : "No wallets available" }),
1522
+ /* @__PURE__ */ jsx("p", { className: "ck-wallet-list-empty-hint", "data-slot": "wallet-list-empty-hint", children: "Install a Solana wallet extension to continue" })
1523
+ ] })
1524
+ }
1525
+ );
1526
+ let walletIcon = /* @__PURE__ */ jsxs(
1527
+ "svg",
1528
+ {
1529
+ width: "20",
1530
+ height: "20",
1531
+ viewBox: "0 0 24 24",
1532
+ fill: "none",
1533
+ stroke: "currentColor",
1534
+ strokeWidth: "2",
1535
+ strokeLinecap: "round",
1536
+ strokeLinejoin: "round",
1537
+ className: "ck-wallet-list-item-fallback-icon",
1538
+ "data-slot": "wallet-list-item-fallback-icon",
1539
+ children: [
1540
+ /* @__PURE__ */ jsx("path", { d: "M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1" }),
1541
+ /* @__PURE__ */ jsx("path", { d: "M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4" })
1542
+ ]
1543
+ }
1544
+ );
1545
+ return variant === "grid" ? /* @__PURE__ */ jsx(
1546
+ "div",
1547
+ {
1548
+ className: `ck-wallet-list-block ck-wallet-list-block--grid ${className || ""}`,
1549
+ "data-slot": "wallet-list-element",
1550
+ "data-variant": "grid",
1551
+ children: displayWallets.map((wallet) => renderWallet ? /* @__PURE__ */ jsx(React.Fragment, { children: renderWallet({
1552
+ wallet,
1553
+ select: () => handleSelect(wallet.name),
1554
+ connecting
1555
+ }) }, wallet.name) : /* @__PURE__ */ jsxs(
1556
+ "button",
1557
+ {
1558
+ type: "button",
1559
+ className: "ck-wallet-list-item ck-wallet-list-item--grid",
1560
+ onClick: () => handleSelect(wallet.name),
1561
+ disabled: connecting || !wallet.installed && installedOnly,
1562
+ "data-slot": "wallet-list-item",
1563
+ "data-wallet": wallet.name,
1564
+ "data-installed": wallet.installed,
1565
+ children: [
1566
+ /* @__PURE__ */ jsx("div", { className: "ck-wallet-list-item-icon", "data-slot": "wallet-list-item-icon", children: wallet.icon ? /* @__PURE__ */ jsx("img", { src: wallet.icon, alt: wallet.name }) : walletIcon }),
1567
+ /* @__PURE__ */ jsx("span", { className: "ck-wallet-list-item-name", "data-slot": "wallet-list-item-name", children: wallet.name }),
1568
+ showStatus && !wallet.installed && /* @__PURE__ */ jsx("span", { className: "ck-wallet-list-item-status", "data-slot": "wallet-list-item-status", children: "Not installed" })
1569
+ ]
1570
+ },
1571
+ wallet.name
1572
+ ))
1573
+ }
1574
+ ) : variant === "compact" ? /* @__PURE__ */ jsx(
1575
+ "div",
1576
+ {
1577
+ className: `ck-wallet-list-block ck-wallet-list-block--compact ${className || ""}`,
1578
+ "data-slot": "wallet-list-element",
1579
+ "data-variant": "compact",
1580
+ children: displayWallets.map((wallet) => renderWallet ? /* @__PURE__ */ jsx(React.Fragment, { children: renderWallet({
1581
+ wallet,
1582
+ select: () => handleSelect(wallet.name),
1583
+ connecting
1584
+ }) }, wallet.name) : /* @__PURE__ */ jsxs(
1585
+ "button",
1586
+ {
1587
+ type: "button",
1588
+ className: "ck-wallet-list-item ck-wallet-list-item--compact",
1589
+ onClick: () => handleSelect(wallet.name),
1590
+ disabled: connecting || !wallet.installed && installedOnly,
1591
+ "data-slot": "wallet-list-item",
1592
+ "data-wallet": wallet.name,
1593
+ "data-installed": wallet.installed,
1594
+ children: [
1595
+ /* @__PURE__ */ jsx("div", { className: "ck-wallet-list-item-icon", "data-slot": "wallet-list-item-icon", children: wallet.icon ? /* @__PURE__ */ jsx("img", { src: wallet.icon, alt: wallet.name }) : walletIcon }),
1596
+ /* @__PURE__ */ jsx("span", { className: "ck-wallet-list-item-name", "data-slot": "wallet-list-item-name", children: wallet.name })
1597
+ ]
1598
+ },
1599
+ wallet.name
1600
+ ))
1601
+ }
1602
+ ) : /* @__PURE__ */ jsx(
1603
+ "div",
1604
+ {
1605
+ className: `ck-wallet-list-block ck-wallet-list-block--list ${className || ""}`,
1606
+ "data-slot": "wallet-list-element",
1607
+ "data-variant": "list",
1608
+ children: displayWallets.map((wallet) => renderWallet ? /* @__PURE__ */ jsx(React.Fragment, { children: renderWallet({
1609
+ wallet,
1610
+ select: () => handleSelect(wallet.name),
1611
+ connecting
1612
+ }) }, wallet.name) : /* @__PURE__ */ jsxs(
1613
+ "button",
1614
+ {
1615
+ type: "button",
1616
+ className: "ck-wallet-list-item ck-wallet-list-item--list",
1617
+ onClick: () => handleSelect(wallet.name),
1618
+ disabled: connecting || !wallet.installed && installedOnly,
1619
+ "data-slot": "wallet-list-item",
1620
+ "data-wallet": wallet.name,
1621
+ "data-installed": wallet.installed,
1622
+ children: [
1623
+ /* @__PURE__ */ jsx("div", { className: "ck-wallet-list-item-icon", "data-slot": "wallet-list-item-icon", children: wallet.icon ? /* @__PURE__ */ jsx("img", { src: wallet.icon, alt: wallet.name }) : walletIcon }),
1624
+ /* @__PURE__ */ jsxs("div", { className: "ck-wallet-list-item-info", "data-slot": "wallet-list-item-info", children: [
1625
+ /* @__PURE__ */ jsx("span", { className: "ck-wallet-list-item-name", "data-slot": "wallet-list-item-name", children: wallet.name }),
1626
+ showStatus && /* @__PURE__ */ jsx(
1627
+ "span",
1628
+ {
1629
+ className: "ck-wallet-list-item-status",
1630
+ "data-slot": "wallet-list-item-status",
1631
+ "data-installed": wallet.installed,
1632
+ children: wallet.installed ? "Detected" : "Not installed"
1633
+ }
1634
+ )
1635
+ ] }),
1636
+ /* @__PURE__ */ jsx(
1637
+ "svg",
1638
+ {
1639
+ width: "16",
1640
+ height: "16",
1641
+ viewBox: "0 0 24 24",
1642
+ fill: "none",
1643
+ stroke: "currentColor",
1644
+ strokeWidth: "2",
1645
+ strokeLinecap: "round",
1646
+ strokeLinejoin: "round",
1647
+ className: "ck-wallet-list-item-arrow",
1648
+ "data-slot": "wallet-list-item-arrow",
1649
+ children: /* @__PURE__ */ jsx("polyline", { points: "9 18 15 12 9 6" })
1650
+ }
1651
+ )
1652
+ ]
1653
+ },
1654
+ wallet.name
1655
+ ))
1656
+ }
1657
+ );
1658
+ }
1659
+ WalletListElement.displayName = "WalletListElement";
1660
+ function BalanceElement({
1661
+ showSol = true,
1662
+ showTokens = false,
1663
+ tokenCount = 3,
1664
+ className,
1665
+ variant = "compact",
1666
+ showRefresh = false,
1667
+ showSkeleton = true,
1668
+ render
1669
+ }) {
1670
+ let { solBalance, formattedSol, tokens, isLoading, error, refetch } = useBalance();
1671
+ if (render)
1672
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ solBalance, formattedSol, tokens, isLoading, error, refetch }) });
1673
+ let displayTokens = tokens.slice(0, tokenCount), refreshIcon = /* @__PURE__ */ jsxs(
1674
+ "svg",
1675
+ {
1676
+ width: "14",
1677
+ height: "14",
1678
+ viewBox: "0 0 24 24",
1679
+ fill: "none",
1680
+ stroke: "currentColor",
1681
+ strokeWidth: "2",
1682
+ strokeLinecap: "round",
1683
+ strokeLinejoin: "round",
1684
+ className: `ck-block-icon ${isLoading ? "ck-block-icon--spinning" : ""}`,
1685
+ "data-slot": "balance-element-refresh-icon",
1686
+ children: [
1687
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
1688
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
1689
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
1690
+ /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
1691
+ ]
1692
+ }
1693
+ );
1694
+ return isLoading && showSkeleton && solBalance === 0 ? /* @__PURE__ */ jsx(
1695
+ "div",
1696
+ {
1697
+ className: `ck-balance-block ck-balance-block--${variant} ck-balance-block--loading ${className || ""}`,
1698
+ "data-slot": "balance-element",
1699
+ "data-variant": variant,
1700
+ "data-loading": "true",
1701
+ children: /* @__PURE__ */ jsxs("div", { className: "ck-balance-block-skeleton", "data-slot": "balance-element-skeleton", children: [
1702
+ /* @__PURE__ */ jsx("div", { className: "ck-skeleton ck-skeleton--text" }),
1703
+ showTokens && /* @__PURE__ */ jsxs(Fragment, { children: [
1704
+ /* @__PURE__ */ jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short" }),
1705
+ /* @__PURE__ */ jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short" })
1706
+ ] })
1707
+ ] })
1708
+ }
1709
+ ) : error ? /* @__PURE__ */ jsxs(
1710
+ "div",
1711
+ {
1712
+ className: `ck-balance-block ck-balance-block--${variant} ck-balance-block--error ${className || ""}`,
1713
+ "data-slot": "balance-element",
1714
+ "data-variant": variant,
1715
+ "data-error": "true",
1716
+ children: [
1717
+ /* @__PURE__ */ jsx("span", { className: "ck-balance-block-error", "data-slot": "balance-element-error", children: "Failed to load balance" }),
1718
+ showRefresh && /* @__PURE__ */ jsx(
1719
+ "button",
1720
+ {
1721
+ type: "button",
1722
+ className: "ck-balance-block-refresh",
1723
+ onClick: () => refetch(),
1724
+ "data-slot": "balance-element-refresh",
1725
+ children: refreshIcon
1726
+ }
1727
+ )
1728
+ ]
1729
+ }
1730
+ ) : variant === "inline" ? /* @__PURE__ */ jsxs(
1731
+ "div",
1732
+ {
1733
+ className: `ck-balance-block ck-balance-block--inline ${className || ""}`,
1734
+ "data-slot": "balance-element",
1735
+ "data-variant": "inline",
1736
+ children: [
1737
+ showSol && /* @__PURE__ */ jsx("span", { className: "ck-balance-block-sol", "data-slot": "balance-element-sol", children: formattedSol }),
1738
+ showRefresh && /* @__PURE__ */ jsx(
1739
+ "button",
1740
+ {
1741
+ type: "button",
1742
+ className: "ck-balance-block-refresh",
1743
+ onClick: () => refetch(),
1744
+ disabled: isLoading,
1745
+ "data-slot": "balance-element-refresh",
1746
+ children: refreshIcon
1747
+ }
1748
+ )
1749
+ ]
1750
+ }
1751
+ ) : variant === "expanded" ? /* @__PURE__ */ jsxs(
1752
+ "div",
1753
+ {
1754
+ className: `ck-balance-block ck-balance-block--expanded ${className || ""}`,
1755
+ "data-slot": "balance-element",
1756
+ "data-variant": "expanded",
1757
+ children: [
1758
+ showSol && /* @__PURE__ */ jsxs("div", { className: "ck-balance-block-sol-section", "data-slot": "balance-element-sol-section", children: [
1759
+ /* @__PURE__ */ jsx("span", { className: "ck-balance-block-label", "data-slot": "balance-element-label", children: "SOL Balance" }),
1760
+ /* @__PURE__ */ jsx("span", { className: "ck-balance-block-sol", "data-slot": "balance-element-sol", children: formattedSol })
1761
+ ] }),
1762
+ showTokens && displayTokens.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ck-balance-block-tokens-section", "data-slot": "balance-element-tokens-section", children: [
1763
+ /* @__PURE__ */ jsxs("span", { className: "ck-balance-block-label", "data-slot": "balance-element-label", children: [
1764
+ "Tokens (",
1765
+ tokens.length,
1766
+ ")"
1767
+ ] }),
1768
+ /* @__PURE__ */ jsxs("div", { className: "ck-balance-block-tokens", "data-slot": "balance-element-tokens", children: [
1769
+ displayTokens.map((token) => /* @__PURE__ */ jsxs(
1770
+ "div",
1771
+ {
1772
+ className: "ck-balance-block-token",
1773
+ "data-slot": "balance-element-token",
1774
+ children: [
1775
+ token.logo && /* @__PURE__ */ jsx(
1776
+ "img",
1777
+ {
1778
+ src: token.logo,
1779
+ alt: token.symbol || "Token",
1780
+ className: "ck-balance-block-token-logo",
1781
+ "data-slot": "balance-element-token-logo"
1782
+ }
1783
+ ),
1784
+ /* @__PURE__ */ jsxs(
1785
+ "span",
1786
+ {
1787
+ className: "ck-balance-block-token-info",
1788
+ "data-slot": "balance-element-token-info",
1789
+ children: [
1790
+ /* @__PURE__ */ jsx(
1791
+ "span",
1792
+ {
1793
+ className: "ck-balance-block-token-symbol",
1794
+ "data-slot": "balance-element-token-symbol",
1795
+ children: token.symbol || token.mint.slice(0, 4) + "..." + token.mint.slice(-4)
1796
+ }
1797
+ ),
1798
+ /* @__PURE__ */ jsx(
1799
+ "span",
1800
+ {
1801
+ className: "ck-balance-block-token-amount",
1802
+ "data-slot": "balance-element-token-amount",
1803
+ children: token.formatted
1804
+ }
1805
+ )
1806
+ ]
1807
+ }
1808
+ )
1809
+ ]
1810
+ },
1811
+ token.mint
1812
+ )),
1813
+ tokens.length > tokenCount && /* @__PURE__ */ jsxs("div", { className: "ck-balance-block-more", "data-slot": "balance-element-more", children: [
1814
+ "+",
1815
+ tokens.length - tokenCount,
1816
+ " more"
1817
+ ] })
1818
+ ] })
1819
+ ] }),
1820
+ showRefresh && /* @__PURE__ */ jsxs(
1821
+ "button",
1822
+ {
1823
+ type: "button",
1824
+ className: "ck-balance-block-refresh",
1825
+ onClick: () => refetch(),
1826
+ disabled: isLoading,
1827
+ "data-slot": "balance-element-refresh",
1828
+ children: [
1829
+ refreshIcon,
1830
+ /* @__PURE__ */ jsx("span", { children: "Refresh" })
1831
+ ]
1832
+ }
1833
+ )
1834
+ ]
1835
+ }
1836
+ ) : /* @__PURE__ */ jsxs(
1837
+ "div",
1838
+ {
1839
+ className: `ck-balance-block ck-balance-block--compact ${className || ""}`,
1840
+ "data-slot": "balance-element",
1841
+ "data-variant": "compact",
1842
+ children: [
1843
+ showSol && /* @__PURE__ */ jsx("span", { className: "ck-balance-block-sol", "data-slot": "balance-element-sol", children: formattedSol }),
1844
+ showTokens && displayTokens.length > 0 && /* @__PURE__ */ jsxs("span", { className: "ck-balance-block-token-count", "data-slot": "balance-element-token-count", children: [
1845
+ "+",
1846
+ tokens.length,
1847
+ " tokens"
1848
+ ] }),
1849
+ showRefresh && /* @__PURE__ */ jsx(
1850
+ "button",
1851
+ {
1852
+ type: "button",
1853
+ className: "ck-balance-block-refresh",
1854
+ onClick: () => refetch(),
1855
+ disabled: isLoading,
1856
+ "data-slot": "balance-element-refresh",
1857
+ children: refreshIcon
1858
+ }
1859
+ )
1860
+ ]
1861
+ }
1862
+ );
1863
+ }
1864
+ BalanceElement.displayName = "BalanceElement";
1865
+ function TransactionHistoryElement({
1866
+ limit = 5,
1867
+ showStatus = true,
1868
+ showTime = true,
1869
+ className,
1870
+ variant = "list",
1871
+ showLoadMore = false,
1872
+ showSkeleton = true,
1873
+ render,
1874
+ renderItem
1875
+ }) {
1876
+ let { transactions, isLoading, error, hasMore, loadMore, refetch } = useTransactions({ limit });
1877
+ if (render)
1878
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ transactions, isLoading, error, hasMore, loadMore, refetch }) });
1879
+ let statusIcon = (status) => /* @__PURE__ */ jsx(
1880
+ "svg",
1881
+ {
1882
+ width: "12",
1883
+ height: "12",
1884
+ viewBox: "0 0 24 24",
1885
+ fill: "none",
1886
+ stroke: "currentColor",
1887
+ strokeWidth: "2",
1888
+ strokeLinecap: "round",
1889
+ strokeLinejoin: "round",
1890
+ className: `ck-tx-status-icon ck-tx-status-icon--${status}`,
1891
+ "data-slot": "tx-status-icon",
1892
+ "data-status": status,
1893
+ children: status === "success" ? /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1894
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1895
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1896
+ ] })
1897
+ }
1898
+ ), externalLinkIcon = /* @__PURE__ */ jsxs(
1899
+ "svg",
1900
+ {
1901
+ width: "12",
1902
+ height: "12",
1903
+ viewBox: "0 0 24 24",
1904
+ fill: "none",
1905
+ stroke: "currentColor",
1906
+ strokeWidth: "2",
1907
+ strokeLinecap: "round",
1908
+ strokeLinejoin: "round",
1909
+ className: "ck-block-icon",
1910
+ "data-slot": "tx-external-link-icon",
1911
+ children: [
1912
+ /* @__PURE__ */ jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
1913
+ /* @__PURE__ */ jsx("polyline", { points: "15 3 21 3 21 9" }),
1914
+ /* @__PURE__ */ jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
1915
+ ]
1916
+ }
1917
+ );
1918
+ if (isLoading && showSkeleton && transactions.length === 0)
1919
+ return /* @__PURE__ */ jsx(
1920
+ "div",
1921
+ {
1922
+ className: `ck-tx-history-block ck-tx-history-block--${variant} ck-tx-history-block--loading ${className || ""}`,
1923
+ "data-slot": "tx-history-element",
1924
+ "data-variant": variant,
1925
+ "data-loading": "true",
1926
+ children: /* @__PURE__ */ jsx("div", { className: "ck-tx-history-skeleton", "data-slot": "tx-history-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "ck-skeleton ck-skeleton--tx" }, i)) })
1927
+ }
1928
+ );
1929
+ if (error)
1930
+ return /* @__PURE__ */ jsxs(
1931
+ "div",
1932
+ {
1933
+ className: `ck-tx-history-block ck-tx-history-block--${variant} ck-tx-history-block--error ${className || ""}`,
1934
+ "data-slot": "tx-history-element",
1935
+ "data-variant": variant,
1936
+ "data-error": "true",
1937
+ children: [
1938
+ /* @__PURE__ */ jsx("span", { className: "ck-tx-history-error", "data-slot": "tx-history-error", children: "Failed to load transactions" }),
1939
+ /* @__PURE__ */ jsx(
1940
+ "button",
1941
+ {
1942
+ type: "button",
1943
+ className: "ck-tx-history-retry",
1944
+ onClick: () => refetch(),
1945
+ "data-slot": "tx-history-retry",
1946
+ children: "Retry"
1947
+ }
1948
+ )
1949
+ ]
1950
+ }
1951
+ );
1952
+ if (transactions.length === 0)
1953
+ return /* @__PURE__ */ jsx(
1954
+ "div",
1955
+ {
1956
+ className: `ck-tx-history-block ck-tx-history-block--${variant} ck-tx-history-block--empty ${className || ""}`,
1957
+ "data-slot": "tx-history-element",
1958
+ "data-variant": variant,
1959
+ "data-empty": "true",
1960
+ children: /* @__PURE__ */ jsx("span", { className: "ck-tx-history-empty", "data-slot": "tx-history-empty", children: "No transactions yet" })
1961
+ }
1962
+ );
1963
+ let itemRenderer = renderItem || ((tx) => /* @__PURE__ */ jsxs(
1964
+ "a",
1965
+ {
1966
+ href: tx.explorerUrl,
1967
+ target: "_blank",
1968
+ rel: "noopener noreferrer",
1969
+ className: "ck-tx-item",
1970
+ "data-slot": "tx-item",
1971
+ "data-status": tx.status,
1972
+ children: [
1973
+ /* @__PURE__ */ jsxs("div", { className: "ck-tx-item-main", "data-slot": "tx-item-main", children: [
1974
+ showStatus && /* @__PURE__ */ jsx(
1975
+ "span",
1976
+ {
1977
+ className: `ck-tx-status ck-tx-status--${tx.status}`,
1978
+ "data-slot": "tx-status",
1979
+ "data-status": tx.status,
1980
+ children: statusIcon(tx.status)
1981
+ }
1982
+ ),
1983
+ /* @__PURE__ */ jsxs("span", { className: "ck-tx-signature", "data-slot": "tx-signature", children: [
1984
+ tx.signature.slice(0, 8),
1985
+ "...",
1986
+ tx.signature.slice(-8)
1987
+ ] })
1988
+ ] }),
1989
+ /* @__PURE__ */ jsxs("div", { className: "ck-tx-item-meta", "data-slot": "tx-item-meta", children: [
1990
+ showTime && /* @__PURE__ */ jsxs("span", { className: "ck-tx-time", "data-slot": "tx-time", children: [
1991
+ tx.formattedDate,
1992
+ " ",
1993
+ tx.formattedTime
1994
+ ] }),
1995
+ externalLinkIcon
1996
+ ] })
1997
+ ]
1998
+ },
1999
+ tx.signature
2000
+ ));
2001
+ return /* @__PURE__ */ jsxs(
2002
+ "div",
2003
+ {
2004
+ className: `ck-tx-history-block ck-tx-history-block--${variant} ${className || ""}`,
2005
+ "data-slot": "tx-history-element",
2006
+ "data-variant": variant,
2007
+ children: [
2008
+ variant === "expanded" && /* @__PURE__ */ jsxs("div", { className: "ck-tx-history-header", "data-slot": "tx-history-header", children: [
2009
+ /* @__PURE__ */ jsx("span", { className: "ck-tx-history-title", "data-slot": "tx-history-title", children: "Recent Transactions" }),
2010
+ /* @__PURE__ */ jsx("span", { className: "ck-tx-history-count", "data-slot": "tx-history-count", children: transactions.length })
2011
+ ] }),
2012
+ /* @__PURE__ */ jsx("div", { className: "ck-tx-history-list", "data-slot": "tx-history-list", children: transactions.map(itemRenderer) }),
2013
+ showLoadMore && hasMore && /* @__PURE__ */ jsx(
2014
+ "button",
2015
+ {
2016
+ type: "button",
2017
+ className: "ck-tx-history-load-more",
2018
+ onClick: () => loadMore(),
2019
+ disabled: isLoading,
2020
+ "data-slot": "tx-history-load-more",
2021
+ children: isLoading ? "Loading..." : "Load more"
2022
+ }
2023
+ )
2024
+ ]
2025
+ }
2026
+ );
2027
+ }
2028
+ TransactionHistoryElement.displayName = "TransactionHistoryElement";
2029
+ function TokenListElement({
2030
+ limit = 10,
2031
+ showValue = false,
2032
+ className,
2033
+ variant = "compact",
2034
+ showRefresh = false,
2035
+ showSkeleton = true,
2036
+ render,
2037
+ renderItem
2038
+ }) {
2039
+ let { tokens, isLoading, error, refetch, totalAccounts } = useTokens();
2040
+ if (render)
2041
+ return /* @__PURE__ */ jsx(Fragment, { children: render({ tokens, isLoading, error, refetch, totalAccounts }) });
2042
+ let displayTokens = tokens.slice(0, limit), refreshIcon = /* @__PURE__ */ jsxs(
2043
+ "svg",
2044
+ {
2045
+ width: "14",
2046
+ height: "14",
2047
+ viewBox: "0 0 24 24",
2048
+ fill: "none",
2049
+ stroke: "currentColor",
2050
+ strokeWidth: "2",
2051
+ strokeLinecap: "round",
2052
+ strokeLinejoin: "round",
2053
+ className: `ck-block-icon ${isLoading ? "ck-block-icon--spinning" : ""}`,
2054
+ "data-slot": "token-list-refresh-icon",
2055
+ children: [
2056
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
2057
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" }),
2058
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16" }),
2059
+ /* @__PURE__ */ jsx("path", { d: "M16 16h5v5" })
2060
+ ]
2061
+ }
2062
+ ), tokenIcon = /* @__PURE__ */ jsxs(
2063
+ "svg",
2064
+ {
2065
+ width: "20",
2066
+ height: "20",
2067
+ viewBox: "0 0 24 24",
2068
+ fill: "none",
2069
+ stroke: "currentColor",
2070
+ strokeWidth: "2",
2071
+ strokeLinecap: "round",
2072
+ strokeLinejoin: "round",
2073
+ className: "ck-token-placeholder-icon",
2074
+ "data-slot": "token-placeholder-icon",
2075
+ children: [
2076
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
2077
+ /* @__PURE__ */ jsx("path", { d: "M12 6v12" }),
2078
+ /* @__PURE__ */ jsx("path", { d: "M6 12h12" })
2079
+ ]
2080
+ }
2081
+ );
2082
+ if (isLoading && showSkeleton && tokens.length === 0)
2083
+ return /* @__PURE__ */ jsx(
2084
+ "div",
2085
+ {
2086
+ className: `ck-token-list-block ck-token-list-block--${variant} ck-token-list-block--loading ${className || ""}`,
2087
+ "data-slot": "token-list-element",
2088
+ "data-variant": variant,
2089
+ "data-loading": "true",
2090
+ children: /* @__PURE__ */ jsx("div", { className: "ck-token-list-skeleton", "data-slot": "token-list-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "ck-skeleton ck-skeleton--token" }, i)) })
2091
+ }
2092
+ );
2093
+ if (error)
2094
+ return /* @__PURE__ */ jsxs(
2095
+ "div",
2096
+ {
2097
+ className: `ck-token-list-block ck-token-list-block--${variant} ck-token-list-block--error ${className || ""}`,
2098
+ "data-slot": "token-list-element",
2099
+ "data-variant": variant,
2100
+ "data-error": "true",
2101
+ children: [
2102
+ /* @__PURE__ */ jsx("span", { className: "ck-token-list-error", "data-slot": "token-list-error", children: "Failed to load tokens" }),
2103
+ /* @__PURE__ */ jsx(
2104
+ "button",
2105
+ {
2106
+ type: "button",
2107
+ className: "ck-token-list-retry",
2108
+ onClick: () => refetch(),
2109
+ "data-slot": "token-list-retry",
2110
+ children: "Retry"
2111
+ }
2112
+ )
2113
+ ]
2114
+ }
2115
+ );
2116
+ if (tokens.length === 0)
2117
+ return /* @__PURE__ */ jsx(
2118
+ "div",
2119
+ {
2120
+ className: `ck-token-list-block ck-token-list-block--${variant} ck-token-list-block--empty ${className || ""}`,
2121
+ "data-slot": "token-list-element",
2122
+ "data-variant": variant,
2123
+ "data-empty": "true",
2124
+ children: /* @__PURE__ */ jsx("span", { className: "ck-token-list-empty", "data-slot": "token-list-empty", children: "No tokens found" })
2125
+ }
2126
+ );
2127
+ let itemRenderer = renderItem || ((token) => /* @__PURE__ */ jsxs("div", { className: "ck-token-item", "data-slot": "token-item", children: [
2128
+ /* @__PURE__ */ jsx("div", { className: "ck-token-item-icon", "data-slot": "token-item-icon", children: token.logo ? /* @__PURE__ */ jsx(
2129
+ "img",
2130
+ {
2131
+ src: token.logo,
2132
+ alt: token.symbol || "Token",
2133
+ className: "ck-token-logo",
2134
+ "data-slot": "token-logo",
2135
+ onError: (e) => {
2136
+ e.currentTarget.style.display = "none";
2137
+ }
2138
+ }
2139
+ ) : tokenIcon }),
2140
+ /* @__PURE__ */ jsxs("div", { className: "ck-token-item-info", "data-slot": "token-item-info", children: [
2141
+ /* @__PURE__ */ jsx("span", { className: "ck-token-symbol", "data-slot": "token-symbol", children: token.symbol || token.mint.slice(0, 4) + "..." + token.mint.slice(-4) }),
2142
+ token.name && /* @__PURE__ */ jsx("span", { className: "ck-token-name", "data-slot": "token-name", children: token.name })
2143
+ ] }),
2144
+ /* @__PURE__ */ jsxs("div", { className: "ck-token-item-balance", "data-slot": "token-item-balance", children: [
2145
+ /* @__PURE__ */ jsx("span", { className: "ck-token-amount", "data-slot": "token-amount", children: token.formatted }),
2146
+ showValue && /* @__PURE__ */ jsx("span", { className: "ck-token-value", "data-slot": "token-value", children: "-" })
2147
+ ] })
2148
+ ] }, token.mint));
2149
+ return /* @__PURE__ */ jsxs(
2150
+ "div",
2151
+ {
2152
+ className: `ck-token-list-block ck-token-list-block--${variant} ${className || ""}`,
2153
+ "data-slot": "token-list-element",
2154
+ "data-variant": variant,
2155
+ children: [
2156
+ variant === "expanded" && /* @__PURE__ */ jsxs("div", { className: "ck-token-list-header", "data-slot": "token-list-header", children: [
2157
+ /* @__PURE__ */ jsx("span", { className: "ck-token-list-title", "data-slot": "token-list-title", children: "Tokens" }),
2158
+ /* @__PURE__ */ jsx("span", { className: "ck-token-list-count", "data-slot": "token-list-count", children: totalAccounts }),
2159
+ showRefresh && /* @__PURE__ */ jsx(
2160
+ "button",
2161
+ {
2162
+ type: "button",
2163
+ className: "ck-token-list-refresh",
2164
+ onClick: () => refetch(),
2165
+ disabled: isLoading,
2166
+ "data-slot": "token-list-refresh",
2167
+ children: refreshIcon
2168
+ }
2169
+ )
2170
+ ] }),
2171
+ /* @__PURE__ */ jsx("div", { className: `ck-token-list ${variant === "grid" ? "ck-token-list--grid" : ""}`, "data-slot": "token-list", children: displayTokens.map(itemRenderer) }),
2172
+ tokens.length > limit && /* @__PURE__ */ jsxs("div", { className: "ck-token-list-more", "data-slot": "token-list-more", children: [
2173
+ "+",
2174
+ tokens.length - limit,
2175
+ " more tokens"
2176
+ ] })
2177
+ ]
2178
+ }
2179
+ );
2180
+ }
2181
+ TokenListElement.displayName = "TokenListElement";
2182
+
2183
+ export { AccountElement, BalanceElement, ClusterElement, ConnectorProvider, DisconnectElement, TokenListElement, TransactionHistoryElement, UnifiedProvider, WalletListElement, useAccount, useBalance, useCluster, useConnector, useConnectorClient, useGillSolanaClient, useGillTransactionSigner, useKitTransactionSigner, useSolanaClient, useTokens, useTransactionPreparer, useTransactionSigner, useTransactions, useWalletInfo };
2184
+ //# sourceMappingURL=chunk-3STZXVXD.mjs.map
2185
+ //# sourceMappingURL=chunk-3STZXVXD.mjs.map