@solana/connector 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -44
- package/dist/{chunk-VMSZJPR5.mjs → chunk-6F6M6L7R.mjs} +152 -173
- package/dist/chunk-6F6M6L7R.mjs.map +1 -0
- package/dist/{chunk-NQXK7PGX.js → chunk-AOIXHVRH.js} +82 -235
- package/dist/chunk-AOIXHVRH.js.map +1 -0
- package/dist/chunk-DSUCH44G.js +678 -0
- package/dist/chunk-DSUCH44G.js.map +1 -0
- package/dist/{chunk-JUZVCBAI.js → chunk-FTXIXM43.js} +240 -271
- package/dist/chunk-FTXIXM43.js.map +1 -0
- package/dist/{chunk-QKVL45F6.mjs → chunk-G575OAT4.mjs} +73 -218
- package/dist/chunk-G575OAT4.mjs.map +1 -0
- package/dist/chunk-J7DHGLW6.mjs +638 -0
- package/dist/chunk-J7DHGLW6.mjs.map +1 -0
- package/dist/{chunk-ULUYX23Q.js → chunk-K3BNIGPX.js} +1023 -404
- package/dist/chunk-K3BNIGPX.js.map +1 -0
- package/dist/{chunk-3STZXVXD.mjs → chunk-TTOKQAPX.mjs} +998 -388
- package/dist/chunk-TTOKQAPX.mjs.map +1 -0
- package/dist/compat.d.mts +1 -1
- package/dist/compat.d.ts +1 -1
- package/dist/compat.js +40 -39
- package/dist/compat.js.map +1 -1
- package/dist/compat.mjs +39 -38
- package/dist/compat.mjs.map +1 -1
- package/dist/headless.d.mts +540 -152
- package/dist/headless.d.ts +540 -152
- package/dist/headless.js +226 -190
- package/dist/headless.mjs +3 -3
- package/dist/index.d.mts +8 -6
- package/dist/index.d.ts +8 -6
- package/dist/index.js +286 -218
- package/dist/index.mjs +4 -4
- package/dist/react.d.mts +283 -16
- package/dist/react.d.ts +283 -16
- package/dist/react.js +60 -28
- package/dist/react.mjs +2 -2
- package/dist/{wallet-standard-shim--YcrQNRt.d.ts → standard-shim-CT49DM5l.d.mts} +72 -252
- package/dist/{wallet-standard-shim-Dx7H8Ctf.d.mts → standard-shim-D9guL5fz.d.ts} +72 -252
- package/dist/{transaction-signer-D9d8nxwb.d.mts → transaction-signer-T-KVQFi8.d.mts} +2 -2
- package/dist/{transaction-signer-D9d8nxwb.d.ts → transaction-signer-T-KVQFi8.d.ts} +2 -2
- package/package.json +3 -3
- package/dist/chunk-3STZXVXD.mjs.map +0 -1
- package/dist/chunk-I64FD2EH.js +0 -312
- package/dist/chunk-I64FD2EH.js.map +0 -1
- package/dist/chunk-JUZVCBAI.js.map +0 -1
- package/dist/chunk-NQXK7PGX.js.map +0 -1
- package/dist/chunk-QKVL45F6.mjs.map +0 -1
- package/dist/chunk-QL3IT3TS.mjs +0 -299
- package/dist/chunk-QL3IT3TS.mjs.map +0 -1
- package/dist/chunk-ULUYX23Q.js.map +0 -1
- package/dist/chunk-VMSZJPR5.mjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkFTXIXM43_js = require('./chunk-FTXIXM43.js');
|
|
4
|
+
var chunkDSUCH44G_js = require('./chunk-DSUCH44G.js');
|
|
5
5
|
var React = require('react');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
var addresses = require('@solana/addresses');
|
|
@@ -11,8 +11,8 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
11
11
|
|
|
12
12
|
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
13
13
|
|
|
14
|
-
var logger =
|
|
15
|
-
|
|
14
|
+
var logger = chunkDSUCH44G_js.createLogger("ConnectorProvider");
|
|
15
|
+
chunkFTXIXM43_js.installPolyfills();
|
|
16
16
|
var ConnectorContext = React.createContext(null);
|
|
17
17
|
ConnectorContext.displayName = "ConnectorContext";
|
|
18
18
|
function ConnectorProviderInternal({
|
|
@@ -23,7 +23,7 @@ function ConnectorProviderInternal({
|
|
|
23
23
|
let clientRef = React.useRef(null), client = React__default.default.useCallback(() => {
|
|
24
24
|
if (!clientRef.current)
|
|
25
25
|
try {
|
|
26
|
-
clientRef.current = new
|
|
26
|
+
clientRef.current = new chunkFTXIXM43_js.ConnectorClient(config), typeof window < "u" && (window.__connectorClient = clientRef.current), config?.debug && logger.info("Client initialized successfully");
|
|
27
27
|
} catch (error) {
|
|
28
28
|
let err = error;
|
|
29
29
|
logger.error("Failed to initialize client", { error: err });
|
|
@@ -60,15 +60,15 @@ function ConnectorProviderInternal({
|
|
|
60
60
|
"solana:mainnet",
|
|
61
61
|
"solana:devnet",
|
|
62
62
|
"solana:testnet"
|
|
63
|
-
]
|
|
64
|
-
registerMwa({
|
|
63
|
+
], mwaConfig = {
|
|
65
64
|
appIdentity: mobile.appIdentity,
|
|
66
65
|
authorizationCache: mobile.authorizationCache ?? createDefaultAuthorizationCache(),
|
|
67
66
|
chains: mobile.chains ?? defaultChains,
|
|
68
67
|
chainSelector: mobile.chainSelector ?? createDefaultChainSelector(),
|
|
69
68
|
remoteHostAuthority: mobile.remoteHostAuthority,
|
|
70
69
|
onWalletNotFound: mobile.onWalletNotFound ?? createDefaultWalletNotFoundHandler()
|
|
71
|
-
}
|
|
70
|
+
};
|
|
71
|
+
registerMwa(mwaConfig);
|
|
72
72
|
} catch {
|
|
73
73
|
}
|
|
74
74
|
})(), () => {
|
|
@@ -83,7 +83,7 @@ function ConnectorProvider({
|
|
|
83
83
|
}) {
|
|
84
84
|
let errorBoundaryConfig = config?.errorBoundary;
|
|
85
85
|
return errorBoundaryConfig?.enabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
86
|
-
|
|
86
|
+
chunkFTXIXM43_js.ConnectorErrorBoundary,
|
|
87
87
|
{
|
|
88
88
|
maxRetries: errorBoundaryConfig.maxRetries ?? 3,
|
|
89
89
|
onError: errorBoundaryConfig.onError,
|
|
@@ -121,14 +121,15 @@ function useConnector() {
|
|
|
121
121
|
function useConnectorClient() {
|
|
122
122
|
return React.useContext(ConnectorContext);
|
|
123
123
|
}
|
|
124
|
-
function
|
|
125
|
-
let
|
|
124
|
+
function AppProvider({ children, connectorConfig, mobile, providers = [] }) {
|
|
125
|
+
let content = /* @__PURE__ */ jsxRuntime.jsx(ConnectorProvider, { config: connectorConfig, mobile, children });
|
|
126
126
|
for (let i = providers.length - 1; i >= 0; i--) {
|
|
127
127
|
let { component: Provider, props = {} } = providers[i];
|
|
128
128
|
content = /* @__PURE__ */ jsxRuntime.jsx(Provider, { ...props, children: content });
|
|
129
129
|
}
|
|
130
130
|
return content;
|
|
131
131
|
}
|
|
132
|
+
var UnifiedProvider = AppProvider;
|
|
132
133
|
function useCluster() {
|
|
133
134
|
let { cluster, clusters } = useConnector(), client = useConnectorClient();
|
|
134
135
|
if (!client)
|
|
@@ -140,7 +141,7 @@ function useCluster() {
|
|
|
140
141
|
[client]
|
|
141
142
|
);
|
|
142
143
|
return React.useMemo(() => {
|
|
143
|
-
let isMainnet = cluster ?
|
|
144
|
+
let isMainnet = cluster ? chunkFTXIXM43_js.isMainnetCluster(cluster) : false, isDevnet = cluster ? chunkFTXIXM43_js.isDevnetCluster(cluster) : false, isTestnet = cluster ? chunkFTXIXM43_js.isTestnetCluster(cluster) : false, isLocal = cluster ? chunkFTXIXM43_js.isLocalCluster(cluster) : false, explorerUrl = cluster ? chunkFTXIXM43_js.getClusterExplorerUrl(cluster) : "", type = cluster ? chunkFTXIXM43_js.getClusterType(cluster) : null;
|
|
144
145
|
return {
|
|
145
146
|
cluster,
|
|
146
147
|
clusters,
|
|
@@ -158,7 +159,7 @@ function useAccount() {
|
|
|
158
159
|
let { selectedAccount, accounts, connected, selectAccount } = useConnector(), [copied, setCopied] = React.useState(false), copyTimeoutRef = React__default.default.useRef(void 0), account = React.useMemo(
|
|
159
160
|
() => accounts.find((a) => a.address === selectedAccount) ?? null,
|
|
160
161
|
[accounts, selectedAccount]
|
|
161
|
-
), formatted = React.useMemo(() => selectedAccount ?
|
|
162
|
+
), formatted = React.useMemo(() => selectedAccount ? chunkFTXIXM43_js.formatAddress(selectedAccount) : "", [selectedAccount]), copy = React.useCallback(async () => selectedAccount ? (copyTimeoutRef.current && clearTimeout(copyTimeoutRef.current), await chunkFTXIXM43_js.copyAddressToClipboard(selectedAccount, {
|
|
162
163
|
onSuccess: () => {
|
|
163
164
|
setCopied(true), copyTimeoutRef.current = setTimeout(() => setCopied(false), 2e3);
|
|
164
165
|
}
|
|
@@ -224,7 +225,7 @@ function useTransactionSigner() {
|
|
|
224
225
|
let { selectedWallet, selectedAccount, accounts, cluster, connected } = useConnector(), client = useConnectorClient(), account = React.useMemo(
|
|
225
226
|
() => accounts.find((a) => a.address === selectedAccount)?.raw ?? null,
|
|
226
227
|
[accounts, selectedAccount]
|
|
227
|
-
), signer = React.useMemo(() => !connected || !selectedWallet || !account ? null :
|
|
228
|
+
), signer = React.useMemo(() => !connected || !selectedWallet || !account ? null : chunkFTXIXM43_js.createTransactionSigner({
|
|
228
229
|
wallet: selectedWallet,
|
|
229
230
|
account,
|
|
230
231
|
cluster: cluster ?? void 0,
|
|
@@ -252,20 +253,20 @@ function useTransactionSigner() {
|
|
|
252
253
|
function useKitTransactionSigner() {
|
|
253
254
|
let { signer: connectorSigner, ready } = useTransactionSigner();
|
|
254
255
|
return {
|
|
255
|
-
signer: React.useMemo(() => connectorSigner ?
|
|
256
|
+
signer: React.useMemo(() => connectorSigner ? chunkFTXIXM43_js.createKitTransactionSigner(connectorSigner) : null, [connectorSigner]),
|
|
256
257
|
ready
|
|
257
258
|
};
|
|
258
259
|
}
|
|
259
260
|
var useGillTransactionSigner = useKitTransactionSigner;
|
|
260
|
-
var logger2 =
|
|
261
|
+
var logger2 = chunkDSUCH44G_js.createLogger("useSolanaClient");
|
|
261
262
|
function useSolanaClient() {
|
|
262
263
|
let { type } = useCluster(), connectorClient = useConnectorClient(), client = React.useMemo(() => {
|
|
263
264
|
if (!type || !connectorClient) return null;
|
|
264
265
|
try {
|
|
265
266
|
let rpcUrl = connectorClient.getRpcUrl();
|
|
266
|
-
return rpcUrl ?
|
|
267
|
+
return rpcUrl ? chunkDSUCH44G_js.createSolanaClient({
|
|
267
268
|
urlOrMoniker: rpcUrl
|
|
268
|
-
}) : type !== "custom" ?
|
|
269
|
+
}) : type !== "custom" ? chunkDSUCH44G_js.createSolanaClient({
|
|
269
270
|
urlOrMoniker: type
|
|
270
271
|
}) : null;
|
|
271
272
|
} catch (error) {
|
|
@@ -286,8 +287,8 @@ function useTransactionPreparer() {
|
|
|
286
287
|
let { client, ready } = useSolanaClient(), prepare = React.useCallback(
|
|
287
288
|
async (transaction, options = {}) => {
|
|
288
289
|
if (!client)
|
|
289
|
-
throw new
|
|
290
|
-
return
|
|
290
|
+
throw new chunkDSUCH44G_js.NetworkError("RPC_ERROR", "Solana client not available. Cannot prepare transaction.");
|
|
291
|
+
return chunkDSUCH44G_js.prepareTransaction({
|
|
291
292
|
transaction,
|
|
292
293
|
rpc: client.rpc,
|
|
293
294
|
computeUnitLimitMultiplier: options.computeUnitLimitMultiplier,
|
|
@@ -305,73 +306,503 @@ function useTransactionPreparer() {
|
|
|
305
306
|
[prepare, ready]
|
|
306
307
|
);
|
|
307
308
|
}
|
|
308
|
-
var
|
|
309
|
-
function
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
309
|
+
var DEFAULT_CACHE_TIME_MS = 300 * 1e3, MAX_STORE_SIZE = 100, store = /* @__PURE__ */ new Map();
|
|
310
|
+
function evictStaleEntries() {
|
|
311
|
+
if (store.size <= MAX_STORE_SIZE) return;
|
|
312
|
+
let evictable = [];
|
|
313
|
+
for (let [key, entry] of store)
|
|
314
|
+
entry.subscribers.size === 0 && evictable.push([key, entry]);
|
|
315
|
+
evictable.sort((a, b) => a[1].lastAccessedAt - b[1].lastAccessedAt);
|
|
316
|
+
for (let [key, entry] of evictable) {
|
|
317
|
+
if (store.size <= MAX_STORE_SIZE) break;
|
|
318
|
+
entry.gcTimeoutId && clearTimeout(entry.gcTimeoutId), entry.intervalId && clearInterval(entry.intervalId), entry.abortController && entry.abortController.abort(), store.delete(key);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function getOrCreateEntry(key) {
|
|
322
|
+
let existing = store.get(key);
|
|
323
|
+
if (existing)
|
|
324
|
+
return existing.lastAccessedAt = Date.now(), existing;
|
|
325
|
+
let entry = {
|
|
326
|
+
snapshot: {
|
|
327
|
+
data: void 0,
|
|
328
|
+
error: null,
|
|
329
|
+
status: "idle",
|
|
330
|
+
updatedAt: null,
|
|
331
|
+
isFetching: false
|
|
332
|
+
},
|
|
333
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
334
|
+
promise: null,
|
|
335
|
+
abortController: null,
|
|
336
|
+
cacheTimeMs: DEFAULT_CACHE_TIME_MS,
|
|
337
|
+
gcTimeoutId: null,
|
|
338
|
+
queryFn: null,
|
|
339
|
+
intervalCounts: /* @__PURE__ */ new Map(),
|
|
340
|
+
activeIntervalMs: null,
|
|
341
|
+
intervalId: null,
|
|
342
|
+
lastAccessedAt: Date.now()
|
|
343
|
+
};
|
|
344
|
+
return store.set(key, entry), evictStaleEntries(), entry;
|
|
345
|
+
}
|
|
346
|
+
function emit(entry) {
|
|
347
|
+
for (let cb of entry.subscribers)
|
|
348
|
+
cb();
|
|
349
|
+
}
|
|
350
|
+
function setSnapshot(entry, next) {
|
|
351
|
+
let prev = entry.snapshot;
|
|
352
|
+
prev.status === next.status && prev.isFetching === next.isFetching && prev.updatedAt === next.updatedAt && prev.error === next.error && prev.data === next.data || (entry.snapshot = next, emit(entry));
|
|
353
|
+
}
|
|
354
|
+
function getMinIntervalMs(entry) {
|
|
355
|
+
let min = null;
|
|
356
|
+
for (let [ms, count] of entry.intervalCounts)
|
|
357
|
+
count <= 0 || (min === null || ms < min) && (min = ms);
|
|
358
|
+
return min;
|
|
359
|
+
}
|
|
360
|
+
function startOrRestartInterval(key, entry) {
|
|
361
|
+
let nextMs = getMinIntervalMs(entry);
|
|
362
|
+
if (nextMs === null) {
|
|
363
|
+
entry.intervalId && clearInterval(entry.intervalId), entry.intervalId = null, entry.activeIntervalMs = null;
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
entry.activeIntervalMs === nextMs && entry.intervalId || (entry.intervalId && clearInterval(entry.intervalId), entry.activeIntervalMs = nextMs, entry.intervalId = setInterval(() => {
|
|
367
|
+
let fn = entry.queryFn;
|
|
368
|
+
fn && fetchSharedQuery(key, fn, { force: true });
|
|
369
|
+
}, nextMs));
|
|
370
|
+
}
|
|
371
|
+
function subscribeSharedQuery(key, onChange, cacheTimeMs) {
|
|
372
|
+
let entry = getOrCreateEntry(key);
|
|
373
|
+
return entry.subscribers.add(onChange), typeof cacheTimeMs == "number" && (entry.cacheTimeMs = Math.max(entry.cacheTimeMs, cacheTimeMs)), entry.gcTimeoutId && (clearTimeout(entry.gcTimeoutId), entry.gcTimeoutId = null), () => {
|
|
374
|
+
if (entry.subscribers.delete(onChange), entry.subscribers.size > 0) return;
|
|
375
|
+
entry.abortController && entry.abortController.abort(), entry.abortController = null, entry.promise = null, entry.intervalId && clearInterval(entry.intervalId), entry.intervalId = null, entry.activeIntervalMs = null, entry.intervalCounts.clear();
|
|
376
|
+
let gcDelayMs = entry.cacheTimeMs ?? DEFAULT_CACHE_TIME_MS;
|
|
377
|
+
entry.gcTimeoutId = setTimeout(() => {
|
|
378
|
+
entry.subscribers.size === 0 && store.delete(key);
|
|
379
|
+
}, gcDelayMs);
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
async function fetchSharedQuery(key, queryFn, options = {}) {
|
|
383
|
+
let entry = getOrCreateEntry(key);
|
|
384
|
+
entry.queryFn = queryFn;
|
|
385
|
+
let staleTimeMs = options.staleTimeMs ?? 0, now = Date.now();
|
|
386
|
+
if (options.force !== true && entry.snapshot.status === "success" && entry.snapshot.updatedAt !== null && now - entry.snapshot.updatedAt < staleTimeMs && entry.snapshot.data !== void 0)
|
|
387
|
+
return entry.snapshot.data;
|
|
388
|
+
if (entry.promise)
|
|
389
|
+
return entry.promise;
|
|
390
|
+
let controller = new AbortController();
|
|
391
|
+
entry.abortController = controller, options.signal && (options.signal.aborted ? controller.abort() : options.signal.addEventListener("abort", () => controller.abort(), { once: true }));
|
|
392
|
+
let isFirstLoad = entry.snapshot.status === "idle" && entry.snapshot.updatedAt === null;
|
|
393
|
+
setSnapshot(entry, {
|
|
394
|
+
...entry.snapshot,
|
|
395
|
+
status: isFirstLoad ? "loading" : entry.snapshot.status,
|
|
396
|
+
isFetching: true,
|
|
397
|
+
error: null
|
|
398
|
+
});
|
|
399
|
+
let promise = (async () => {
|
|
400
|
+
try {
|
|
401
|
+
let data = await queryFn(controller.signal);
|
|
402
|
+
return setSnapshot(entry, {
|
|
403
|
+
data,
|
|
404
|
+
error: null,
|
|
405
|
+
status: "success",
|
|
406
|
+
updatedAt: Date.now(),
|
|
407
|
+
isFetching: false
|
|
408
|
+
}), data;
|
|
409
|
+
} catch (cause) {
|
|
410
|
+
if (controller.signal.aborted)
|
|
411
|
+
return setSnapshot(entry, {
|
|
412
|
+
data: entry.snapshot.data,
|
|
413
|
+
error: null,
|
|
414
|
+
status: entry.snapshot.status === "idle" ? "idle" : entry.snapshot.status,
|
|
415
|
+
updatedAt: entry.snapshot.updatedAt,
|
|
416
|
+
isFetching: false
|
|
417
|
+
}), entry.snapshot.data;
|
|
418
|
+
let error = cause instanceof Error ? cause : new Error(String(cause));
|
|
419
|
+
throw setSnapshot(entry, {
|
|
420
|
+
data: entry.snapshot.data,
|
|
421
|
+
error,
|
|
422
|
+
status: "error",
|
|
423
|
+
updatedAt: entry.snapshot.updatedAt,
|
|
424
|
+
isFetching: false
|
|
425
|
+
}), error;
|
|
426
|
+
} finally {
|
|
427
|
+
entry.promise = null, entry.abortController = null;
|
|
428
|
+
}
|
|
429
|
+
})();
|
|
430
|
+
return entry.promise = promise, promise;
|
|
431
|
+
}
|
|
432
|
+
function useSharedQuery(key, queryFn, options = {}) {
|
|
433
|
+
let {
|
|
434
|
+
enabled = true,
|
|
435
|
+
staleTimeMs = 0,
|
|
436
|
+
cacheTimeMs,
|
|
437
|
+
refetchOnMount = "stale",
|
|
438
|
+
refetchIntervalMs = false,
|
|
439
|
+
select
|
|
440
|
+
} = options, queryFnRef = React.useRef(queryFn);
|
|
441
|
+
queryFnRef.current = queryFn;
|
|
442
|
+
let stableQueryFn = React.useCallback((signal) => queryFnRef.current(signal), []), subscribe = React.useCallback(
|
|
443
|
+
(onChange) => key ? subscribeSharedQuery(key, onChange, cacheTimeMs) : () => {
|
|
444
|
+
},
|
|
445
|
+
[key, cacheTimeMs]
|
|
446
|
+
), emptySnapshot = React.useMemo(
|
|
447
|
+
() => ({
|
|
448
|
+
data: void 0,
|
|
449
|
+
error: null,
|
|
450
|
+
status: "idle",
|
|
451
|
+
updatedAt: null,
|
|
452
|
+
isFetching: false
|
|
453
|
+
}),
|
|
454
|
+
[]
|
|
455
|
+
), getSnapshot = React.useCallback(() => key ? getOrCreateEntry(key).snapshot : emptySnapshot, [key, emptySnapshot]), snapshot = React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot), selectedData = React.useMemo(() => select ? select(snapshot.data) : snapshot.data, [snapshot.data, select]), prevSelectedRef = React.useRef(selectedData), stableSelectedData = React.useMemo(() => Object.is(prevSelectedRef.current, selectedData) ? prevSelectedRef.current : (prevSelectedRef.current = selectedData, selectedData), [selectedData]), fetchedKeyRef = React.useRef(null);
|
|
456
|
+
React.useEffect(() => {
|
|
457
|
+
if (!key || !enabled) {
|
|
458
|
+
fetchedKeyRef.current = null;
|
|
319
459
|
return;
|
|
320
460
|
}
|
|
321
|
-
|
|
461
|
+
let entry = getOrCreateEntry(key);
|
|
462
|
+
if (entry.queryFn = stableQueryFn, fetchedKeyRef.current === key && entry.snapshot.status === "success")
|
|
463
|
+
return;
|
|
464
|
+
let current = entry.snapshot, isStale = current.updatedAt === null || Date.now() - current.updatedAt >= staleTimeMs;
|
|
465
|
+
refetchOnMount === true || current.status === "idle" || refetchOnMount === "stale" && isStale ? (fetchedKeyRef.current = key, fetchSharedQuery(key, stableQueryFn, {
|
|
466
|
+
staleTimeMs,
|
|
467
|
+
force: refetchOnMount === true
|
|
468
|
+
}).catch(() => {
|
|
469
|
+
})) : fetchedKeyRef.current = key;
|
|
470
|
+
}, [key, enabled, staleTimeMs, refetchOnMount, stableQueryFn]), React.useEffect(() => {
|
|
471
|
+
if (!key || !enabled || refetchIntervalMs === false) return;
|
|
472
|
+
let entry = getOrCreateEntry(key);
|
|
473
|
+
entry.queryFn = stableQueryFn;
|
|
474
|
+
let prev = entry.intervalCounts.get(refetchIntervalMs) ?? 0;
|
|
475
|
+
return entry.intervalCounts.set(refetchIntervalMs, prev + 1), startOrRestartInterval(key, entry), () => {
|
|
476
|
+
let count = entry.intervalCounts.get(refetchIntervalMs) ?? 0;
|
|
477
|
+
count <= 1 ? entry.intervalCounts.delete(refetchIntervalMs) : entry.intervalCounts.set(refetchIntervalMs, count - 1), startOrRestartInterval(key, entry);
|
|
478
|
+
};
|
|
479
|
+
}, [key, enabled, refetchIntervalMs, stableQueryFn]);
|
|
480
|
+
let refetch = React.useCallback(
|
|
481
|
+
async (refetchOptions) => {
|
|
482
|
+
if (key)
|
|
483
|
+
return fetchSharedQuery(key, stableQueryFn, {
|
|
484
|
+
force: true,
|
|
485
|
+
signal: refetchOptions?.signal
|
|
486
|
+
});
|
|
487
|
+
},
|
|
488
|
+
[key, stableQueryFn]
|
|
489
|
+
), abort = React.useCallback(() => {
|
|
490
|
+
if (!key) return;
|
|
491
|
+
let entry = store.get(key);
|
|
492
|
+
entry?.abortController && entry.abortController.abort();
|
|
493
|
+
}, [key]);
|
|
494
|
+
return React.useMemo(
|
|
495
|
+
() => ({
|
|
496
|
+
data: stableSelectedData,
|
|
497
|
+
error: snapshot.error,
|
|
498
|
+
status: snapshot.status,
|
|
499
|
+
updatedAt: snapshot.updatedAt,
|
|
500
|
+
isFetching: snapshot.isFetching,
|
|
501
|
+
refetch,
|
|
502
|
+
abort
|
|
503
|
+
}),
|
|
504
|
+
[stableSelectedData, snapshot.error, snapshot.status, snapshot.updatedAt, snapshot.isFetching, refetch, abort]
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
function invalidateSharedQuery(key) {
|
|
508
|
+
let entry = store.get(key);
|
|
509
|
+
entry && setSnapshot(entry, {
|
|
510
|
+
...entry.snapshot,
|
|
511
|
+
updatedAt: null
|
|
512
|
+
// Mark as stale
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function clearSharedQueryCache() {
|
|
516
|
+
for (let [, entry] of store)
|
|
517
|
+
entry.intervalId && clearInterval(entry.intervalId), entry.gcTimeoutId && clearTimeout(entry.gcTimeoutId), entry.abortController && entry.abortController.abort();
|
|
518
|
+
store.clear();
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/hooks/_internal/use-wallet-assets.ts
|
|
522
|
+
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb", NATIVE_SOL_MINT = "So11111111111111111111111111111111111111112";
|
|
523
|
+
function isRecord(value) {
|
|
524
|
+
return typeof value == "object" && value !== null;
|
|
525
|
+
}
|
|
526
|
+
function parseBigInt(value) {
|
|
527
|
+
if (typeof value == "bigint") return value;
|
|
528
|
+
if (typeof value == "number" && Number.isSafeInteger(value)) return BigInt(value);
|
|
529
|
+
if (typeof value == "string")
|
|
322
530
|
try {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
531
|
+
return BigInt(value);
|
|
532
|
+
} catch {
|
|
533
|
+
return 0n;
|
|
534
|
+
}
|
|
535
|
+
return 0n;
|
|
536
|
+
}
|
|
537
|
+
function getParsedTokenAccountInfo(data) {
|
|
538
|
+
if (!isRecord(data)) return null;
|
|
539
|
+
let parsed = data.parsed;
|
|
540
|
+
if (!isRecord(parsed)) return null;
|
|
541
|
+
let info = parsed.info;
|
|
542
|
+
return isRecord(info) ? info : null;
|
|
543
|
+
}
|
|
544
|
+
function parseTokenAccount(account, programId) {
|
|
545
|
+
let info = getParsedTokenAccountInfo(account.account.data);
|
|
546
|
+
if (!info) return null;
|
|
547
|
+
let mint = typeof info.mint == "string" ? info.mint : null, owner = typeof info.owner == "string" ? info.owner : null;
|
|
548
|
+
if (!mint || !owner) return null;
|
|
549
|
+
let tokenAmount = isRecord(info.tokenAmount) ? info.tokenAmount : null, amount = parseBigInt(tokenAmount?.amount), decimals = typeof tokenAmount?.decimals == "number" ? tokenAmount.decimals : 0, state = typeof info.state == "string" ? info.state : void 0;
|
|
550
|
+
return {
|
|
551
|
+
pubkey: String(account.pubkey),
|
|
552
|
+
mint,
|
|
553
|
+
owner,
|
|
554
|
+
amount,
|
|
555
|
+
decimals,
|
|
556
|
+
isFrozen: state === "frozen",
|
|
557
|
+
programId
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function getWalletAssetsQueryKey(rpcUrl, address) {
|
|
561
|
+
return !rpcUrl || !address ? null : JSON.stringify(["wallet-assets", rpcUrl, address]);
|
|
562
|
+
}
|
|
563
|
+
function useWalletAssets(options = {}) {
|
|
564
|
+
let {
|
|
565
|
+
enabled = true,
|
|
566
|
+
staleTimeMs = 0,
|
|
567
|
+
cacheTimeMs = 300 * 1e3,
|
|
568
|
+
// 5 minutes
|
|
569
|
+
refetchOnMount = "stale",
|
|
570
|
+
refetchIntervalMs = false,
|
|
571
|
+
client: clientOverride,
|
|
572
|
+
select
|
|
573
|
+
} = options, { address, connected } = useAccount(), { client: providerClient } = useSolanaClient(), rpcClient = clientOverride ?? providerClient, key = React.useMemo(() => {
|
|
574
|
+
if (!enabled || !connected || !address || !rpcClient) return null;
|
|
575
|
+
let rpcUrl = rpcClient.urlOrMoniker instanceof URL ? rpcClient.urlOrMoniker.toString() : String(rpcClient.urlOrMoniker);
|
|
576
|
+
return getWalletAssetsQueryKey(rpcUrl, address);
|
|
577
|
+
}, [enabled, connected, address, rpcClient]), queryFn = React.useCallback(
|
|
578
|
+
async (signal) => {
|
|
579
|
+
if (!connected || !address || !rpcClient)
|
|
580
|
+
return { lamports: 0n, tokenAccounts: [] };
|
|
581
|
+
if (signal.aborted)
|
|
582
|
+
throw new DOMException("Query aborted", "AbortError");
|
|
583
|
+
let rpc = rpcClient.rpc, walletAddress = addresses.address(address), tokenProgramId = addresses.address(TOKEN_PROGRAM_ID), token2022ProgramId = addresses.address(TOKEN_2022_PROGRAM_ID), [balanceResult, tokenAccountsResult, token2022AccountsResult] = await Promise.all([
|
|
584
|
+
rpc.getBalance(walletAddress).send(),
|
|
585
|
+
rpc.getTokenAccountsByOwner(walletAddress, { programId: tokenProgramId }, { encoding: "jsonParsed" }).send(),
|
|
586
|
+
rpc.getTokenAccountsByOwner(
|
|
587
|
+
walletAddress,
|
|
588
|
+
{ programId: token2022ProgramId },
|
|
589
|
+
{ encoding: "jsonParsed" }
|
|
590
|
+
).send()
|
|
591
|
+
]);
|
|
592
|
+
if (signal.aborted)
|
|
593
|
+
throw new DOMException("Query aborted", "AbortError");
|
|
594
|
+
let tokenAccounts = [];
|
|
595
|
+
for (let account of tokenAccountsResult.value) {
|
|
596
|
+
let parsed = parseTokenAccount(account, "token");
|
|
597
|
+
parsed && tokenAccounts.push(parsed);
|
|
345
598
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
599
|
+
for (let account of token2022AccountsResult.value) {
|
|
600
|
+
let parsed = parseTokenAccount(account, "token-2022");
|
|
601
|
+
parsed && tokenAccounts.push(parsed);
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
lamports: balanceResult.value,
|
|
605
|
+
tokenAccounts
|
|
606
|
+
};
|
|
607
|
+
},
|
|
608
|
+
[connected, address, rpcClient]
|
|
609
|
+
), { data, error, status, updatedAt, isFetching, refetch, abort } = useSharedQuery(
|
|
610
|
+
key,
|
|
611
|
+
queryFn,
|
|
612
|
+
{
|
|
613
|
+
enabled,
|
|
614
|
+
staleTimeMs,
|
|
615
|
+
cacheTimeMs,
|
|
616
|
+
refetchOnMount,
|
|
617
|
+
refetchIntervalMs,
|
|
618
|
+
select
|
|
351
619
|
}
|
|
352
|
-
|
|
353
|
-
React.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
620
|
+
), isLoading = status === "loading" || status === "idle";
|
|
621
|
+
return React.useMemo(
|
|
622
|
+
() => ({
|
|
623
|
+
data,
|
|
624
|
+
isLoading,
|
|
625
|
+
isFetching,
|
|
626
|
+
error,
|
|
627
|
+
refetch,
|
|
628
|
+
abort,
|
|
629
|
+
updatedAt
|
|
630
|
+
}),
|
|
631
|
+
[data, isLoading, isFetching, error, refetch, abort, updatedAt]
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/hooks/use-balance.ts
|
|
636
|
+
function getBalanceQueryKey(rpcUrl, address) {
|
|
637
|
+
return getWalletAssetsQueryKey(rpcUrl, address);
|
|
638
|
+
}
|
|
639
|
+
var LAMPORTS_PER_SOL2 = 1000000000n;
|
|
640
|
+
function formatTokenAccount(account) {
|
|
641
|
+
let formatted = chunkFTXIXM43_js.formatBigIntBalance(account.amount, account.decimals, {
|
|
642
|
+
maxDecimals: Math.min(account.decimals, 6)
|
|
643
|
+
});
|
|
644
|
+
return {
|
|
645
|
+
mint: account.mint,
|
|
646
|
+
amount: account.amount,
|
|
647
|
+
decimals: account.decimals,
|
|
648
|
+
formatted
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function selectBalance(assets) {
|
|
652
|
+
if (!assets)
|
|
653
|
+
return { lamports: 0n, tokens: [] };
|
|
654
|
+
let tokens = assets.tokenAccounts.filter((account) => account.amount > 0n).map(formatTokenAccount);
|
|
655
|
+
return {
|
|
656
|
+
lamports: assets.lamports,
|
|
657
|
+
tokens
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function useBalance(options = {}) {
|
|
661
|
+
let {
|
|
662
|
+
enabled = true,
|
|
663
|
+
autoRefresh = true,
|
|
664
|
+
refreshInterval = 3e4,
|
|
665
|
+
staleTimeMs = 0,
|
|
666
|
+
cacheTimeMs = 300 * 1e3,
|
|
667
|
+
// 5 minutes
|
|
668
|
+
refetchOnMount = "stale",
|
|
669
|
+
client: clientOverride
|
|
670
|
+
} = options, {
|
|
671
|
+
data,
|
|
672
|
+
error,
|
|
673
|
+
isFetching,
|
|
674
|
+
updatedAt,
|
|
675
|
+
refetch: sharedRefetch,
|
|
676
|
+
abort
|
|
677
|
+
} = useWalletAssets({
|
|
678
|
+
enabled,
|
|
679
|
+
staleTimeMs,
|
|
680
|
+
cacheTimeMs,
|
|
681
|
+
refetchOnMount,
|
|
682
|
+
refetchIntervalMs: autoRefresh ? refreshInterval : false,
|
|
683
|
+
client: clientOverride,
|
|
684
|
+
select: selectBalance
|
|
685
|
+
}), lamports = data?.lamports ?? 0n, tokens = data?.tokens ?? [], solBalance = React.useMemo(() => Number(lamports) / Number(LAMPORTS_PER_SOL2), [lamports]), formattedSol = React.useMemo(() => chunkFTXIXM43_js.formatLamportsToSolSafe(lamports, { maxDecimals: 4, suffix: true }), [lamports]), visibleError = updatedAt ? null : error, refetch = React.useCallback(
|
|
686
|
+
async (opts) => {
|
|
687
|
+
await sharedRefetch(opts);
|
|
688
|
+
},
|
|
689
|
+
[sharedRefetch]
|
|
690
|
+
);
|
|
361
691
|
return React.useMemo(
|
|
362
692
|
() => ({
|
|
363
693
|
solBalance,
|
|
364
694
|
lamports,
|
|
365
695
|
formattedSol,
|
|
366
696
|
tokens,
|
|
367
|
-
isLoading,
|
|
368
|
-
error,
|
|
369
|
-
refetch
|
|
370
|
-
|
|
697
|
+
isLoading: isFetching,
|
|
698
|
+
error: visibleError,
|
|
699
|
+
refetch,
|
|
700
|
+
abort,
|
|
701
|
+
lastUpdated: updatedAt ? new Date(updatedAt) : null
|
|
371
702
|
}),
|
|
372
|
-
[solBalance, lamports, formattedSol, tokens,
|
|
703
|
+
[solBalance, lamports, formattedSol, tokens, isFetching, visibleError, refetch, abort, updatedAt]
|
|
373
704
|
);
|
|
374
705
|
}
|
|
706
|
+
|
|
707
|
+
// src/utils/abort.ts
|
|
708
|
+
function createTimeoutSignal(ms) {
|
|
709
|
+
if (typeof AbortSignal.timeout == "function")
|
|
710
|
+
return { signal: AbortSignal.timeout(ms), cleanup: () => {
|
|
711
|
+
} };
|
|
712
|
+
let controller = new AbortController(), timeoutId = setTimeout(() => controller.abort(), ms);
|
|
713
|
+
return {
|
|
714
|
+
signal: controller.signal,
|
|
715
|
+
cleanup: () => clearTimeout(timeoutId)
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// src/hooks/_internal/solana-token-list.ts
|
|
720
|
+
var CLUSTER_CHAIN_IDS = {
|
|
721
|
+
mainnet: 101,
|
|
722
|
+
testnet: 102,
|
|
723
|
+
devnet: 103,
|
|
724
|
+
localnet: 103,
|
|
725
|
+
// Use devnet tokens for localnet
|
|
726
|
+
custom: 101
|
|
727
|
+
// Default to mainnet for custom clusters
|
|
728
|
+
}, TOKEN_LIST_API_BASE_URL = "https://token-list-api.solana.cloud/v1/mints";
|
|
729
|
+
function getTokenListApiUrl(cluster = "mainnet") {
|
|
730
|
+
let chainId = CLUSTER_CHAIN_IDS[cluster];
|
|
731
|
+
return `${TOKEN_LIST_API_BASE_URL}?chainId=${chainId}`;
|
|
732
|
+
}
|
|
733
|
+
var DEFAULT_TIMEOUT_MS = 1e4, TOKEN_LIST_CACHE_MAX_SIZE = 1500, MAX_ADDRESSES_PER_REQUEST = 100, tokenListCache = /* @__PURE__ */ new Map();
|
|
734
|
+
function getCachedTokenListMetadata(mint) {
|
|
735
|
+
let value = tokenListCache.get(mint);
|
|
736
|
+
if (value)
|
|
737
|
+
return tokenListCache.delete(mint), tokenListCache.set(mint, value), value;
|
|
738
|
+
}
|
|
739
|
+
function setCachedTokenListMetadata(mint, value) {
|
|
740
|
+
if (tokenListCache.has(mint) && tokenListCache.delete(mint), tokenListCache.set(mint, value), tokenListCache.size > TOKEN_LIST_CACHE_MAX_SIZE) {
|
|
741
|
+
let oldestKey = tokenListCache.keys().next().value;
|
|
742
|
+
oldestKey && tokenListCache.delete(oldestKey);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function createLinkedSignal(externalSignal, timeoutMs) {
|
|
746
|
+
let controller = new AbortController(), onAbort = () => controller.abort();
|
|
747
|
+
externalSignal && (externalSignal.aborted ? controller.abort() : externalSignal.addEventListener("abort", onAbort, { once: true }));
|
|
748
|
+
let { signal: timeoutSignal, cleanup: cleanupTimeout } = createTimeoutSignal(timeoutMs), onTimeoutAbort = () => controller.abort();
|
|
749
|
+
return timeoutSignal.aborted ? controller.abort() : timeoutSignal.addEventListener("abort", onTimeoutAbort, { once: true }), {
|
|
750
|
+
signal: controller.signal,
|
|
751
|
+
cleanup: () => {
|
|
752
|
+
cleanupTimeout(), externalSignal && externalSignal.removeEventListener("abort", onAbort), timeoutSignal.removeEventListener("abort", onTimeoutAbort);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
async function fetchSolanaTokenListMetadata(mints, options = {}) {
|
|
757
|
+
let results = /* @__PURE__ */ new Map();
|
|
758
|
+
if (!mints.length) return results;
|
|
759
|
+
let seen = /* @__PURE__ */ new Set(), uncached = [];
|
|
760
|
+
for (let mint of mints) {
|
|
761
|
+
let normalized = mint?.trim();
|
|
762
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
763
|
+
seen.add(normalized);
|
|
764
|
+
let cached = getCachedTokenListMetadata(normalized);
|
|
765
|
+
cached ? results.set(normalized, cached) : uncached.push(normalized);
|
|
766
|
+
}
|
|
767
|
+
if (!uncached.length) return results;
|
|
768
|
+
let timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS, apiUrl = getTokenListApiUrl(options.cluster);
|
|
769
|
+
for (let i = 0; i < uncached.length && !options.signal?.aborted; i += MAX_ADDRESSES_PER_REQUEST) {
|
|
770
|
+
let batch = uncached.slice(i, i + MAX_ADDRESSES_PER_REQUEST), { signal, cleanup } = createLinkedSignal(options.signal, timeoutMs);
|
|
771
|
+
try {
|
|
772
|
+
let response = await fetch(apiUrl, {
|
|
773
|
+
method: "POST",
|
|
774
|
+
headers: { "Content-Type": "application/json" },
|
|
775
|
+
body: JSON.stringify({ addresses: batch }),
|
|
776
|
+
signal
|
|
777
|
+
});
|
|
778
|
+
if (!response.ok) {
|
|
779
|
+
console.warn("[token-list] Solana Token List API error:", response.status, response.statusText);
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
let data = await response.json();
|
|
783
|
+
if (!data?.content?.length) continue;
|
|
784
|
+
for (let item of data.content)
|
|
785
|
+
item?.address && (results.set(item.address, item), setCachedTokenListMetadata(item.address, item));
|
|
786
|
+
} catch (error) {
|
|
787
|
+
console.warn("[token-list] Solana Token List API failed:", error);
|
|
788
|
+
} finally {
|
|
789
|
+
cleanup();
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
return results;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/utils/image.ts
|
|
796
|
+
function transformImageUrl(url, imageProxy) {
|
|
797
|
+
if (url)
|
|
798
|
+
return imageProxy ? `${imageProxy}${encodeURIComponent(url)}` : url;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// src/hooks/use-transactions.ts
|
|
802
|
+
function getTransactionsQueryKey(options) {
|
|
803
|
+
let { rpcUrl, address, clusterId, limit = 20, fetchDetails = false } = options;
|
|
804
|
+
return !rpcUrl || !address || !clusterId ? null : JSON.stringify(["wallet-transactions", rpcUrl, address, clusterId, limit, fetchDetails]);
|
|
805
|
+
}
|
|
375
806
|
function formatDate(timestamp) {
|
|
376
807
|
if (!timestamp)
|
|
377
808
|
return { date: "Unknown", time: "" };
|
|
@@ -383,6 +814,45 @@ function formatDate(timestamp) {
|
|
|
383
814
|
});
|
|
384
815
|
return { date: formattedDate, time: formattedTime };
|
|
385
816
|
}
|
|
817
|
+
var KNOWN_PROGRAMS = {
|
|
818
|
+
"11111111111111111111111111111111": "System Program",
|
|
819
|
+
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: "Token Program",
|
|
820
|
+
ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL: "Associated Token",
|
|
821
|
+
JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4: "Jupiter",
|
|
822
|
+
whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc: "Orca Whirlpool",
|
|
823
|
+
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8": "Raydium AMM",
|
|
824
|
+
Stake11111111111111111111111111111111111111: "Stake Program",
|
|
825
|
+
metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s: "Metaplex"
|
|
826
|
+
}, DEFAULT_IGNORED_PROGRAM_IDS = /* @__PURE__ */ new Set([
|
|
827
|
+
"11111111111111111111111111111111",
|
|
828
|
+
// System Program
|
|
829
|
+
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
830
|
+
// Token Program
|
|
831
|
+
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
|
|
832
|
+
// Associated Token
|
|
833
|
+
]);
|
|
834
|
+
function resolveProgramName(programId, programLabels) {
|
|
835
|
+
return programLabels?.[programId] ?? KNOWN_PROGRAMS[programId];
|
|
836
|
+
}
|
|
837
|
+
function pickPrimaryProgramId(programIds) {
|
|
838
|
+
for (let id of programIds)
|
|
839
|
+
if (!DEFAULT_IGNORED_PROGRAM_IDS.has(id)) return id;
|
|
840
|
+
return programIds.values().next().value;
|
|
841
|
+
}
|
|
842
|
+
function getParsedInstructionTypes(message) {
|
|
843
|
+
if (!Array.isArray(message.instructions)) return;
|
|
844
|
+
let types = [];
|
|
845
|
+
for (let ix of message.instructions) {
|
|
846
|
+
if (!ix || typeof ix != "object") continue;
|
|
847
|
+
let parsed = ix.parsed;
|
|
848
|
+
if (!parsed || typeof parsed != "object" || !("type" in parsed)) continue;
|
|
849
|
+
let t = parsed.type;
|
|
850
|
+
if (typeof t == "string" && (types.push(t), types.length >= 10))
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
let unique = [...new Set(types)];
|
|
854
|
+
return unique.length ? unique : void 0;
|
|
855
|
+
}
|
|
386
856
|
function isAccountKey(value) {
|
|
387
857
|
return typeof value == "object" && value !== null && "pubkey" in value && typeof value.pubkey == "string";
|
|
388
858
|
}
|
|
@@ -407,6 +877,13 @@ function isTransactionWithMeta(value) {
|
|
|
407
877
|
function isTransactionMessage(value) {
|
|
408
878
|
return typeof value == "object" && value !== null && "accountKeys" in value && Array.isArray(value.accountKeys);
|
|
409
879
|
}
|
|
880
|
+
function coerceMaybeAddressString(value) {
|
|
881
|
+
if (typeof value == "string") return value;
|
|
882
|
+
if (value && typeof value == "object") {
|
|
883
|
+
let str = String(value);
|
|
884
|
+
if (str && str !== "[object Object]") return str;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
410
887
|
function getAccountKeys(message) {
|
|
411
888
|
return Array.isArray(message.accountKeys) ? message.accountKeys.map((key) => typeof key == "string" ? key : isAccountKey(key) ? key.pubkey : "").filter(Boolean) : [];
|
|
412
889
|
}
|
|
@@ -438,12 +915,12 @@ function parseTokenTransfers(meta, accountKeys, walletAddress) {
|
|
|
438
915
|
return null;
|
|
439
916
|
let preTokenBalances = Array.isArray(meta.preTokenBalances) ? meta.preTokenBalances : [], postTokenBalances = Array.isArray(meta.postTokenBalances) ? meta.postTokenBalances : [], ourPreTokens = preTokenBalances.filter((balance) => {
|
|
440
917
|
if (!isTokenBalance(balance)) return false;
|
|
441
|
-
let accountKey = accountKeys[balance.accountIndex];
|
|
442
|
-
return accountKey && accountKey.trim() === walletAddress.trim() ||
|
|
918
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
919
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
443
920
|
}), ourPostTokens = postTokenBalances.filter((balance) => {
|
|
444
921
|
if (!isTokenBalance(balance)) return false;
|
|
445
|
-
let accountKey = accountKeys[balance.accountIndex];
|
|
446
|
-
return accountKey && accountKey.trim() === walletAddress.trim() ||
|
|
922
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
923
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
447
924
|
}), allMints = /* @__PURE__ */ new Set();
|
|
448
925
|
for (let token of ourPreTokens)
|
|
449
926
|
isTokenBalance(token) && allMints.add(token.mint);
|
|
@@ -487,6 +964,52 @@ function parseTokenTransfers(meta, accountKeys, walletAddress) {
|
|
|
487
964
|
}
|
|
488
965
|
return null;
|
|
489
966
|
}
|
|
967
|
+
function parseTokenAccountClosure(meta, accountKeys, walletAddress) {
|
|
968
|
+
if (!isTransactionMeta(meta))
|
|
969
|
+
return null;
|
|
970
|
+
let preTokenBalances = Array.isArray(meta.preTokenBalances) ? meta.preTokenBalances : [], postTokenBalances = Array.isArray(meta.postTokenBalances) ? meta.postTokenBalances : [], ourPreTokens = preTokenBalances.filter((balance) => {
|
|
971
|
+
if (!isTokenBalance(balance)) return false;
|
|
972
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
973
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
974
|
+
}), ourPostTokens = postTokenBalances.filter((balance) => {
|
|
975
|
+
if (!isTokenBalance(balance)) return false;
|
|
976
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
977
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
978
|
+
}), postKeys = /* @__PURE__ */ new Set();
|
|
979
|
+
for (let token of ourPostTokens)
|
|
980
|
+
isTokenBalance(token) && postKeys.add(`${token.accountIndex}:${token.mint}`);
|
|
981
|
+
for (let token of ourPreTokens) {
|
|
982
|
+
if (!isTokenBalance(token)) continue;
|
|
983
|
+
let key = `${token.accountIndex}:${token.mint}`;
|
|
984
|
+
if (!postKeys.has(key))
|
|
985
|
+
return { tokenMint: token.mint };
|
|
986
|
+
}
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
function parseSwapTokens(meta, accountKeys, walletAddress, solChange) {
|
|
990
|
+
if (!isTransactionMeta(meta))
|
|
991
|
+
return {};
|
|
992
|
+
let preTokenBalances = Array.isArray(meta.preTokenBalances) ? meta.preTokenBalances : [], postTokenBalances = Array.isArray(meta.postTokenBalances) ? meta.postTokenBalances : [], ourPreTokens = preTokenBalances.filter((balance) => {
|
|
993
|
+
if (!isTokenBalance(balance)) return false;
|
|
994
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
995
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
996
|
+
}), ourPostTokens = postTokenBalances.filter((balance) => {
|
|
997
|
+
if (!isTokenBalance(balance)) return false;
|
|
998
|
+
let accountKey = accountKeys[balance.accountIndex], owner = coerceMaybeAddressString(balance.owner);
|
|
999
|
+
return accountKey && accountKey.trim() === walletAddress.trim() || owner && owner.trim() === walletAddress.trim();
|
|
1000
|
+
}), allMints = /* @__PURE__ */ new Set();
|
|
1001
|
+
for (let token of ourPreTokens)
|
|
1002
|
+
isTokenBalance(token) && allMints.add(token.mint);
|
|
1003
|
+
for (let token of ourPostTokens)
|
|
1004
|
+
isTokenBalance(token) && allMints.add(token.mint);
|
|
1005
|
+
let fromToken, toToken;
|
|
1006
|
+
for (let mint of allMints) {
|
|
1007
|
+
let preBal = ourPreTokens.find((b) => isTokenBalance(b) && b.mint === mint), postBal = ourPostTokens.find((b) => isTokenBalance(b) && b.mint === mint), preAmount = isTokenBalance(preBal) && isUiTokenAmount(preBal.uiTokenAmount) ? Number(preBal.uiTokenAmount.amount) : 0, change = (isTokenBalance(postBal) && isUiTokenAmount(postBal.uiTokenAmount) ? Number(postBal.uiTokenAmount.amount) : 0) - preAmount;
|
|
1008
|
+
change < 0 && !fromToken ? fromToken = { mint } : change > 0 && !toToken && (toToken = { mint });
|
|
1009
|
+
}
|
|
1010
|
+
let WRAPPED_SOL_MINT = "So11111111111111111111111111111111111111112";
|
|
1011
|
+
return solChange < -1e-3 && !fromToken ? fromToken = { mint: WRAPPED_SOL_MINT } : solChange > 1e-3 && !toToken && (toToken = { mint: WRAPPED_SOL_MINT }), { fromToken, toToken };
|
|
1012
|
+
}
|
|
490
1013
|
function formatAmount(tokenAmount, tokenDecimals, direction, solChange) {
|
|
491
1014
|
if (tokenAmount !== void 0 && tokenDecimals !== void 0 && direction !== void 0) {
|
|
492
1015
|
let sign = direction === "in" ? "+" : "-", maxDecimals = Math.min(tokenDecimals, 6);
|
|
@@ -495,52 +1018,59 @@ function formatAmount(tokenAmount, tokenDecimals, direction, solChange) {
|
|
|
495
1018
|
if (solChange !== 0)
|
|
496
1019
|
return `${solChange > 0 ? "+" : ""}${solChange.toFixed(4)} SOL`;
|
|
497
1020
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
return imageProxy ? `${imageProxy}${encodeURIComponent(url)}` : url;
|
|
1021
|
+
function throwIfAborted(signal) {
|
|
1022
|
+
if (signal?.aborted)
|
|
1023
|
+
throw new DOMException("Query aborted", "AbortError");
|
|
502
1024
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
method: "POST",
|
|
515
|
-
headers: { "Content-Type": "application/json" },
|
|
516
|
-
body: JSON.stringify({ addresses: uncachedMints }),
|
|
517
|
-
signal: AbortSignal.timeout(5e3)
|
|
518
|
-
});
|
|
519
|
-
if (!response.ok) return results;
|
|
520
|
-
let data = await response.json();
|
|
521
|
-
for (let item of data.content) {
|
|
522
|
-
let metadata = { symbol: item.symbol, icon: item.logoURI };
|
|
523
|
-
results.set(item.address, metadata), tokenMetadataCache.set(item.address, metadata);
|
|
1025
|
+
function clampInt(value, min, max) {
|
|
1026
|
+
return Number.isFinite(value) ? Math.min(max, Math.max(min, Math.floor(value))) : min;
|
|
1027
|
+
}
|
|
1028
|
+
async function mapWithConcurrency(inputs, worker, options) {
|
|
1029
|
+
let concurrency = clampInt(options.concurrency, 1, 32), results = new Array(inputs.length), nextIndex = 0;
|
|
1030
|
+
async function run() {
|
|
1031
|
+
for (; ; ) {
|
|
1032
|
+
throwIfAborted(options.signal);
|
|
1033
|
+
let index = nextIndex;
|
|
1034
|
+
if (nextIndex += 1, index >= inputs.length) return;
|
|
1035
|
+
results[index] = await worker(inputs[index], index);
|
|
524
1036
|
}
|
|
525
|
-
} catch (error) {
|
|
526
|
-
console.warn("[useTransactions] Failed to fetch token metadata:", error);
|
|
527
1037
|
}
|
|
1038
|
+
let runners = Array.from({ length: Math.min(concurrency, inputs.length) }, () => run());
|
|
1039
|
+
return await Promise.all(runners), results;
|
|
1040
|
+
}
|
|
1041
|
+
async function fetchTransactionTokenMetadata(mints, options = {}) {
|
|
1042
|
+
let results = /* @__PURE__ */ new Map();
|
|
1043
|
+
if (!mints.length) return results;
|
|
1044
|
+
let tokenList = await fetchSolanaTokenListMetadata(mints, {
|
|
1045
|
+
timeoutMs: 5e3,
|
|
1046
|
+
signal: options.signal,
|
|
1047
|
+
cluster: options.cluster
|
|
1048
|
+
});
|
|
1049
|
+
for (let [mint, meta] of tokenList)
|
|
1050
|
+
results.set(mint, { symbol: meta.symbol, icon: meta.logoURI });
|
|
528
1051
|
return results;
|
|
529
1052
|
}
|
|
530
1053
|
function useTransactions(options = {}) {
|
|
531
|
-
let {
|
|
532
|
-
|
|
533
|
-
|
|
1054
|
+
let {
|
|
1055
|
+
enabled = true,
|
|
1056
|
+
limit = 10,
|
|
1057
|
+
autoRefresh = false,
|
|
1058
|
+
refreshInterval = 6e4,
|
|
1059
|
+
fetchDetails = true,
|
|
1060
|
+
detailsConcurrency = 6,
|
|
1061
|
+
staleTimeMs = 0,
|
|
1062
|
+
cacheTimeMs = 300 * 1e3,
|
|
1063
|
+
// 5 minutes
|
|
1064
|
+
refetchOnMount = "stale",
|
|
1065
|
+
client: clientOverride
|
|
1066
|
+
} = options, { address, connected } = useAccount(), { cluster } = useCluster(), { client: providerClient } = useSolanaClient(), connectorClient = useConnectorClient(), [paginatedTransactions, setPaginatedTransactions] = React.useState([]), [isPaginationLoading, setIsPaginationLoading] = React.useState(false), [hasMore, setHasMore] = React.useState(true), beforeSignatureRef = React.useRef(void 0), rpcClient = clientOverride ?? providerClient, connectorConfig = connectorClient?.getConfig(), imageProxy = connectorConfig?.imageProxy, programLabels = connectorConfig?.programLabels, parseTransaction = React.useCallback(
|
|
534
1067
|
(tx, walletAddress, sig, blockTime, slot, err, explorerUrl) => {
|
|
535
1068
|
let { date, time } = formatDate(blockTime), baseInfo = {
|
|
536
1069
|
signature: sig,
|
|
537
1070
|
blockTime,
|
|
538
1071
|
slot,
|
|
539
1072
|
status: err ? "failed" : "success",
|
|
540
|
-
error: err ? JSON.stringify(
|
|
541
|
-
err,
|
|
542
|
-
(_key, value) => typeof value == "bigint" ? value.toString() : value
|
|
543
|
-
) : void 0,
|
|
1073
|
+
error: err ? JSON.stringify(err, (_key, value) => typeof value == "bigint" ? value.toString() : value) : void 0,
|
|
544
1074
|
type: "unknown",
|
|
545
1075
|
formattedDate: date,
|
|
546
1076
|
formattedTime: time,
|
|
@@ -555,24 +1085,13 @@ function useTransactions(options = {}) {
|
|
|
555
1085
|
let { message } = transaction;
|
|
556
1086
|
if (!isTransactionMessage(message))
|
|
557
1087
|
return baseInfo;
|
|
558
|
-
let accountKeys = getAccountKeys(message), walletIndex = accountKeys.findIndex((
|
|
1088
|
+
let accountKeys = getAccountKeys(message), walletIndex = accountKeys.findIndex((key2) => key2.trim() === walletAddress.trim());
|
|
559
1089
|
if (walletIndex === -1)
|
|
560
1090
|
return baseInfo;
|
|
561
|
-
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;
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
type = "stake";
|
|
566
|
-
else if (hasMetaplex)
|
|
567
|
-
type = "nft";
|
|
568
|
-
else if (hasSystemProgram && Math.abs(balanceChange) > 0)
|
|
569
|
-
type = balanceChange > 0 ? "received" : "sent", direction = balanceChange > 0 ? "in" : "out", tokenMint = "So11111111111111111111111111111111111111112", accountKeys.length >= 2 && (counterparty = accountKeys.find(
|
|
570
|
-
(key, idx) => idx !== walletIndex && key !== "11111111111111111111111111111111"
|
|
571
|
-
));
|
|
572
|
-
else if (hasTokenProgram) {
|
|
573
|
-
let tokenTransfer = parseTokenTransfers(meta, accountKeys, walletAddress);
|
|
574
|
-
tokenTransfer && (type = tokenTransfer.type, direction = tokenTransfer.direction, tokenMint = tokenTransfer.tokenMint, tokenAmount = tokenTransfer.tokenAmount, tokenDecimals = tokenTransfer.tokenDecimals);
|
|
575
|
-
} else programIds.size > 0 && (type = "program");
|
|
1091
|
+
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"), tokenTransfer = hasTokenProgram ? parseTokenTransfers(meta, accountKeys, walletAddress) : null, tokenAccountClosure = hasTokenProgram ? parseTokenAccountClosure(meta, accountKeys, walletAddress) : null, inferredSwapTokens = parseSwapTokens(meta, accountKeys, walletAddress, solChange), inferredSwapFromMint = inferredSwapTokens.fromToken?.mint, inferredSwapToMint = inferredSwapTokens.toToken?.mint, hasNonTrivialProgram = [...programIds].some((id) => !DEFAULT_IGNORED_PROGRAM_IDS.has(id)), hasInferredSwap = !!(inferredSwapFromMint && inferredSwapToMint) && inferredSwapFromMint !== inferredSwapToMint && hasNonTrivialProgram && !tokenAccountClosure, programId = pickPrimaryProgramId(programIds), programName = programId ? resolveProgramName(programId, programLabels) : void 0, programIdsArray = [...programIds], instructionTypes = getParsedInstructionTypes(message), instructionCount = Array.isArray(message.instructions) ? message.instructions.length : void 0, type = "unknown", direction, counterparty, tokenMint, tokenAmount, tokenDecimals, swapFromToken, swapToToken;
|
|
1092
|
+
hasJupiter || hasOrca || hasRaydium ? (type = "swap", inferredSwapTokens.fromToken && (swapFromToken = { mint: inferredSwapTokens.fromToken.mint }), inferredSwapTokens.toToken && (swapToToken = { mint: inferredSwapTokens.toToken.mint })) : hasStake ? type = "stake" : hasMetaplex ? type = "nft" : hasInferredSwap ? (type = "swap", swapFromToken = { mint: inferredSwapFromMint }, swapToToken = { mint: inferredSwapToMint }) : tokenTransfer ? (type = tokenTransfer.type, direction = tokenTransfer.direction, tokenMint = tokenTransfer.tokenMint, tokenAmount = tokenTransfer.tokenAmount, tokenDecimals = tokenTransfer.tokenDecimals) : tokenAccountClosure ? (type = "tokenAccountClosed", tokenMint = tokenAccountClosure.tokenMint, direction = solChange > 0 ? "in" : void 0) : hasSystemProgram && Math.abs(balanceChange) > 0 ? (type = balanceChange > 0 ? "received" : "sent", direction = balanceChange > 0 ? "in" : "out", tokenMint = "So11111111111111111111111111111111111111112", accountKeys.length >= 2 && (counterparty = accountKeys.find(
|
|
1093
|
+
(key2, idx) => idx !== walletIndex && key2 !== "11111111111111111111111111111111"
|
|
1094
|
+
))) : programIds.size > 0 && (type = "program");
|
|
576
1095
|
let formattedAmount = formatAmount(tokenAmount, tokenDecimals, direction, solChange);
|
|
577
1096
|
return {
|
|
578
1097
|
...baseInfo,
|
|
@@ -581,136 +1100,197 @@ function useTransactions(options = {}) {
|
|
|
581
1100
|
amount: tokenAmount ?? Math.abs(solChange),
|
|
582
1101
|
formattedAmount,
|
|
583
1102
|
tokenMint,
|
|
584
|
-
counterparty: counterparty ? `${counterparty.slice(0, 4)}...${counterparty.slice(-4)}` : void 0
|
|
1103
|
+
counterparty: counterparty ? `${counterparty.slice(0, 4)}...${counterparty.slice(-4)}` : void 0,
|
|
1104
|
+
swapFromToken,
|
|
1105
|
+
swapToToken,
|
|
1106
|
+
programId,
|
|
1107
|
+
programName,
|
|
1108
|
+
programIds: programIdsArray.length ? programIdsArray : void 0,
|
|
1109
|
+
instructionTypes,
|
|
1110
|
+
instructionCount
|
|
585
1111
|
};
|
|
586
1112
|
} catch (parseError) {
|
|
587
1113
|
return console.warn("Failed to parse transaction:", parseError), baseInfo;
|
|
588
1114
|
}
|
|
589
1115
|
},
|
|
590
|
-
[]
|
|
591
|
-
),
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
1116
|
+
[programLabels]
|
|
1117
|
+
), key = React.useMemo(() => {
|
|
1118
|
+
if (!enabled || !connected || !address || !rpcClient || !cluster) return null;
|
|
1119
|
+
let rpcUrl = rpcClient.urlOrMoniker instanceof URL ? rpcClient.urlOrMoniker.toString() : String(rpcClient.urlOrMoniker);
|
|
1120
|
+
return getTransactionsQueryKey({ rpcUrl, address, clusterId: cluster.id, limit, fetchDetails });
|
|
1121
|
+
}, [enabled, connected, address, rpcClient, cluster, limit, fetchDetails]);
|
|
1122
|
+
React.useEffect(() => {
|
|
1123
|
+
beforeSignatureRef.current = void 0, setPaginatedTransactions([]), setIsPaginationLoading(false), setHasMore(true);
|
|
1124
|
+
}, [key]);
|
|
1125
|
+
let fetchAndEnrichTransactions = React.useCallback(
|
|
1126
|
+
async (beforeSignature, currentCluster, signal) => {
|
|
1127
|
+
if (!rpcClient || !address)
|
|
1128
|
+
return { transactions: [], hasMore: false };
|
|
1129
|
+
throwIfAborted(signal);
|
|
1130
|
+
let rpc = rpcClient.rpc, walletAddress = addresses.address(address), signaturesResult = await rpc.getSignaturesForAddress(walletAddress, {
|
|
1131
|
+
limit,
|
|
1132
|
+
...beforeSignature ? { before: keys.signature(beforeSignature) } : {}
|
|
1133
|
+
}).send();
|
|
1134
|
+
throwIfAborted(signal);
|
|
1135
|
+
let newTransactions;
|
|
1136
|
+
if (fetchDetails && signaturesResult.length > 0) {
|
|
1137
|
+
let txDetails = await mapWithConcurrency(
|
|
1138
|
+
signaturesResult,
|
|
1139
|
+
async (sig) => rpc.getTransaction(keys.signature(String(sig.signature)), {
|
|
1140
|
+
encoding: "jsonParsed",
|
|
1141
|
+
maxSupportedTransactionVersion: 0
|
|
1142
|
+
}).send().catch(() => null),
|
|
1143
|
+
{ concurrency: detailsConcurrency, signal }
|
|
1144
|
+
);
|
|
1145
|
+
throwIfAborted(signal), newTransactions = signaturesResult.map((sig, idx) => {
|
|
1146
|
+
let blockTimeNum = sig.blockTime ? Number(sig.blockTime) : null, tx = txDetails[idx];
|
|
1147
|
+
return parseTransaction(
|
|
1148
|
+
tx,
|
|
1149
|
+
address,
|
|
1150
|
+
String(sig.signature),
|
|
1151
|
+
blockTimeNum,
|
|
1152
|
+
Number(sig.slot),
|
|
1153
|
+
sig.err,
|
|
1154
|
+
chunkFTXIXM43_js.getTransactionUrl(String(sig.signature), currentCluster)
|
|
1155
|
+
);
|
|
1156
|
+
});
|
|
1157
|
+
} else
|
|
1158
|
+
newTransactions = signaturesResult.map((sig) => {
|
|
1159
|
+
let blockTimeNum = sig.blockTime ? Number(sig.blockTime) : null, { date, time } = formatDate(blockTimeNum);
|
|
1160
|
+
return {
|
|
1161
|
+
signature: String(sig.signature),
|
|
1162
|
+
blockTime: blockTimeNum,
|
|
1163
|
+
slot: Number(sig.slot),
|
|
1164
|
+
status: sig.err ? "failed" : "success",
|
|
1165
|
+
error: sig.err ? JSON.stringify(sig.err) : void 0,
|
|
1166
|
+
type: "unknown",
|
|
1167
|
+
formattedDate: date,
|
|
1168
|
+
formattedTime: time,
|
|
1169
|
+
explorerUrl: chunkFTXIXM43_js.getTransactionUrl(String(sig.signature), currentCluster)
|
|
1170
|
+
};
|
|
1171
|
+
});
|
|
1172
|
+
let mintsToFetch = [
|
|
1173
|
+
.../* @__PURE__ */ new Set([
|
|
1174
|
+
...newTransactions.filter((tx) => tx.tokenMint).map((tx) => tx.tokenMint),
|
|
1175
|
+
...newTransactions.filter((tx) => tx.swapFromToken?.mint).map((tx) => tx.swapFromToken.mint),
|
|
1176
|
+
...newTransactions.filter((tx) => tx.swapToToken?.mint).map((tx) => tx.swapToToken.mint)
|
|
1177
|
+
])
|
|
1178
|
+
];
|
|
1179
|
+
if (mintsToFetch.length > 0) {
|
|
1180
|
+
throwIfAborted(signal);
|
|
1181
|
+
let tokenMetadata = await fetchTransactionTokenMetadata(mintsToFetch, {
|
|
1182
|
+
signal,
|
|
1183
|
+
cluster: chunkFTXIXM43_js.getClusterType(currentCluster)
|
|
1184
|
+
});
|
|
1185
|
+
tokenMetadata.size > 0 && (newTransactions = newTransactions.map((tx) => {
|
|
1186
|
+
let enrichedTx = { ...tx };
|
|
1187
|
+
if (tx.tokenMint && tokenMetadata.has(tx.tokenMint)) {
|
|
1188
|
+
let meta = tokenMetadata.get(tx.tokenMint);
|
|
1189
|
+
enrichedTx = {
|
|
1190
|
+
...enrichedTx,
|
|
1191
|
+
tokenSymbol: meta.symbol,
|
|
1192
|
+
tokenIcon: transformImageUrl(meta.icon, imageProxy),
|
|
1193
|
+
formattedAmount: tx.formattedAmount ? `${tx.formattedAmount} ${meta.symbol}` : tx.formattedAmount
|
|
635
1194
|
};
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
return {
|
|
646
|
-
...tx,
|
|
647
|
-
tokenSymbol: meta.symbol,
|
|
648
|
-
tokenIcon: transformImageUrl(meta.icon, imageProxy),
|
|
649
|
-
// Update formatted amount with symbol
|
|
650
|
-
formattedAmount: tx.formattedAmount ? `${tx.formattedAmount} ${meta.symbol}` : tx.formattedAmount
|
|
651
|
-
};
|
|
1195
|
+
}
|
|
1196
|
+
if (tx.swapFromToken?.mint && tokenMetadata.has(tx.swapFromToken.mint)) {
|
|
1197
|
+
let meta = tokenMetadata.get(tx.swapFromToken.mint);
|
|
1198
|
+
enrichedTx = {
|
|
1199
|
+
...enrichedTx,
|
|
1200
|
+
swapFromToken: {
|
|
1201
|
+
...tx.swapFromToken,
|
|
1202
|
+
symbol: meta.symbol,
|
|
1203
|
+
icon: transformImageUrl(meta.icon, imageProxy)
|
|
652
1204
|
}
|
|
653
|
-
|
|
654
|
-
});
|
|
655
|
-
setTransactions(loadMore ? (prev) => [...prev.slice(0, -newTransactions.length), ...enrichedTransactions] : enrichedTransactions);
|
|
1205
|
+
};
|
|
656
1206
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1207
|
+
if (tx.swapToToken?.mint && tokenMetadata.has(tx.swapToToken.mint)) {
|
|
1208
|
+
let meta = tokenMetadata.get(tx.swapToToken.mint);
|
|
1209
|
+
enrichedTx = {
|
|
1210
|
+
...enrichedTx,
|
|
1211
|
+
swapToToken: {
|
|
1212
|
+
...tx.swapToToken,
|
|
1213
|
+
symbol: meta.symbol,
|
|
1214
|
+
icon: transformImageUrl(meta.icon, imageProxy)
|
|
1215
|
+
}
|
|
1216
|
+
};
|
|
662
1217
|
}
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
|
|
1218
|
+
return enrichedTx;
|
|
1219
|
+
}));
|
|
1220
|
+
}
|
|
1221
|
+
return {
|
|
1222
|
+
transactions: newTransactions,
|
|
1223
|
+
hasMore: newTransactions.length === limit
|
|
1224
|
+
};
|
|
1225
|
+
},
|
|
1226
|
+
[rpcClient, address, limit, fetchDetails, detailsConcurrency, parseTransaction, imageProxy]
|
|
1227
|
+
), queryFn = React.useCallback(
|
|
1228
|
+
async (signal) => {
|
|
1229
|
+
if (!connected || !address || !rpcClient || !cluster)
|
|
1230
|
+
return [];
|
|
1231
|
+
throwIfAborted(signal);
|
|
1232
|
+
let result = await fetchAndEnrichTransactions(void 0, cluster, signal);
|
|
1233
|
+
return throwIfAborted(signal), result.transactions;
|
|
1234
|
+
},
|
|
1235
|
+
[connected, address, rpcClient, cluster, fetchAndEnrichTransactions]
|
|
1236
|
+
), {
|
|
1237
|
+
data: initialTransactions,
|
|
1238
|
+
error,
|
|
1239
|
+
isFetching: isInitialLoading,
|
|
1240
|
+
updatedAt,
|
|
1241
|
+
refetch: sharedRefetch,
|
|
1242
|
+
abort
|
|
1243
|
+
} = useSharedQuery(key, queryFn, {
|
|
1244
|
+
enabled,
|
|
1245
|
+
staleTimeMs,
|
|
1246
|
+
cacheTimeMs,
|
|
1247
|
+
refetchOnMount,
|
|
1248
|
+
refetchIntervalMs: autoRefresh ? refreshInterval : false
|
|
1249
|
+
});
|
|
1250
|
+
React.useEffect(() => {
|
|
1251
|
+
initialTransactions && (beforeSignatureRef.current = initialTransactions.length ? initialTransactions[initialTransactions.length - 1].signature : void 0, setHasMore(initialTransactions.length === limit), setPaginatedTransactions((prev) => prev.length ? [] : prev));
|
|
1252
|
+
}, [initialTransactions, limit]);
|
|
1253
|
+
let loadMoreFn = React.useCallback(async () => {
|
|
1254
|
+
if (!(!hasMore || isPaginationLoading || !cluster)) {
|
|
1255
|
+
setIsPaginationLoading(true);
|
|
1256
|
+
try {
|
|
1257
|
+
let result = await fetchAndEnrichTransactions(beforeSignatureRef.current, cluster);
|
|
1258
|
+
result.transactions.length > 0 && (beforeSignatureRef.current = result.transactions[result.transactions.length - 1].signature, setPaginatedTransactions((prev) => [...prev, ...result.transactions])), setHasMore(result.hasMore);
|
|
666
1259
|
} catch (err) {
|
|
667
|
-
|
|
1260
|
+
console.error("Failed to load more transactions:", err);
|
|
668
1261
|
} finally {
|
|
669
|
-
|
|
1262
|
+
setIsPaginationLoading(false);
|
|
670
1263
|
}
|
|
1264
|
+
}
|
|
1265
|
+
}, [hasMore, isPaginationLoading, cluster, fetchAndEnrichTransactions]), refetch = React.useCallback(
|
|
1266
|
+
async (opts) => {
|
|
1267
|
+
beforeSignatureRef.current = void 0, setPaginatedTransactions([]), setHasMore(true), await sharedRefetch(opts);
|
|
671
1268
|
},
|
|
672
|
-
[
|
|
673
|
-
),
|
|
674
|
-
|
|
675
|
-
}, [fetchTransactions]), loadMoreFn = React.useCallback(async () => {
|
|
676
|
-
hasMore && !isLoading && await fetchTransactions(true);
|
|
677
|
-
}, [hasMore, isLoading, fetchTransactions]);
|
|
678
|
-
return React.useEffect(() => {
|
|
679
|
-
let prevDeps = prevDepsRef.current, currentDeps = { connected, address, cluster };
|
|
680
|
-
(!prevDeps || prevDeps.connected !== connected || prevDeps.address !== address || prevDeps.cluster !== cluster) && (prevDepsRef.current = currentDeps, beforeSignatureRef.current = void 0, fetchTransactions(false));
|
|
681
|
-
}, [connected, address, cluster, fetchTransactions]), React.useEffect(() => {
|
|
682
|
-
if (!connected || !autoRefresh) return;
|
|
683
|
-
let interval = setInterval(refetch, refreshInterval);
|
|
684
|
-
return () => clearInterval(interval);
|
|
685
|
-
}, [connected, autoRefresh, refreshInterval, refetch]), React.useMemo(
|
|
1269
|
+
[sharedRefetch]
|
|
1270
|
+
), transactions = React.useMemo(() => [...initialTransactions ?? [], ...paginatedTransactions], [initialTransactions, paginatedTransactions]), isLoading = isInitialLoading || isPaginationLoading, visibleError = updatedAt ? null : error;
|
|
1271
|
+
return React.useMemo(
|
|
686
1272
|
() => ({
|
|
687
1273
|
transactions,
|
|
688
1274
|
isLoading,
|
|
689
|
-
error,
|
|
1275
|
+
error: visibleError,
|
|
690
1276
|
hasMore,
|
|
691
1277
|
loadMore: loadMoreFn,
|
|
692
1278
|
refetch,
|
|
693
|
-
|
|
1279
|
+
abort,
|
|
1280
|
+
lastUpdated: updatedAt ? new Date(updatedAt) : null
|
|
694
1281
|
}),
|
|
695
|
-
[transactions, isLoading,
|
|
1282
|
+
[transactions, isLoading, visibleError, hasMore, loadMoreFn, refetch, abort, updatedAt]
|
|
696
1283
|
);
|
|
697
1284
|
}
|
|
698
|
-
function
|
|
699
|
-
|
|
700
|
-
return { signal: AbortSignal.timeout(ms), cleanup: () => {
|
|
701
|
-
} };
|
|
702
|
-
let controller = new AbortController(), timeoutId = setTimeout(() => controller.abort(), ms);
|
|
703
|
-
return {
|
|
704
|
-
signal: controller.signal,
|
|
705
|
-
cleanup: () => clearTimeout(timeoutId)
|
|
706
|
-
};
|
|
1285
|
+
function getTokensQueryKey(rpcUrl, address) {
|
|
1286
|
+
return getWalletAssetsQueryKey(rpcUrl, address);
|
|
707
1287
|
}
|
|
708
|
-
var
|
|
1288
|
+
var 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 {
|
|
709
1289
|
constructor(maxSize, options) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
1290
|
+
chunkDSUCH44G_js.__publicField(this, "cache", /* @__PURE__ */ new Map());
|
|
1291
|
+
chunkDSUCH44G_js.__publicField(this, "maxSize");
|
|
1292
|
+
chunkDSUCH44G_js.__publicField(this, "getTtl");
|
|
1293
|
+
chunkDSUCH44G_js.__publicField(this, "getTimestamp");
|
|
714
1294
|
this.maxSize = maxSize, this.getTtl = options?.getTtl, this.getTimestamp = options?.getTimestamp;
|
|
715
1295
|
}
|
|
716
1296
|
get(key) {
|
|
@@ -745,10 +1325,6 @@ var NATIVE_MINT = "So11111111111111111111111111111111111111112", CACHE_MAX_SIZE
|
|
|
745
1325
|
get size() {
|
|
746
1326
|
return this.cache.size;
|
|
747
1327
|
}
|
|
748
|
-
/**
|
|
749
|
-
* Prune stale entries based on TTL.
|
|
750
|
-
* Only works if getTtl and getTimestamp are provided.
|
|
751
|
-
*/
|
|
752
1328
|
pruneStale() {
|
|
753
1329
|
if (!this.getTtl || !this.getTimestamp) return 0;
|
|
754
1330
|
let now = Date.now(), pruned = 0;
|
|
@@ -773,27 +1349,6 @@ function stopCacheCleanup() {
|
|
|
773
1349
|
function clearTokenCaches() {
|
|
774
1350
|
metadataCache.clear(), priceCache.clear();
|
|
775
1351
|
}
|
|
776
|
-
async function fetchSolanaTokenMetadata(mints) {
|
|
777
|
-
let results = /* @__PURE__ */ new Map();
|
|
778
|
-
if (mints.length === 0) return results;
|
|
779
|
-
let { signal, cleanup } = createTimeoutSignal(1e4);
|
|
780
|
-
try {
|
|
781
|
-
let response = await fetch("https://token-list-api.solana.cloud/v1/mints?chainId=101", {
|
|
782
|
-
method: "POST",
|
|
783
|
-
headers: { "Content-Type": "application/json" },
|
|
784
|
-
body: JSON.stringify({ addresses: mints }),
|
|
785
|
-
signal
|
|
786
|
-
});
|
|
787
|
-
if (cleanup(), !response.ok)
|
|
788
|
-
throw new Error(`Solana Token List API error: ${response.status}`);
|
|
789
|
-
let data = await response.json();
|
|
790
|
-
for (let item of data.content)
|
|
791
|
-
results.set(item.address, item);
|
|
792
|
-
} catch (error) {
|
|
793
|
-
cleanup(), console.warn("[useTokens] Solana Token List API failed:", error);
|
|
794
|
-
}
|
|
795
|
-
return results;
|
|
796
|
-
}
|
|
797
1352
|
function calculateBackoffDelay(attempt, baseDelay, retryAfter) {
|
|
798
1353
|
if (retryAfter !== void 0 && retryAfter > 0) {
|
|
799
1354
|
let jitter2 = Math.random() * 500;
|
|
@@ -829,26 +1384,17 @@ async function fetchCoinGeckoPrices(coingeckoIds, config) {
|
|
|
829
1384
|
let elapsedTime = Date.now() - startTime;
|
|
830
1385
|
if (elapsedTime >= maxTimeout) {
|
|
831
1386
|
console.warn(
|
|
832
|
-
`[useTokens] CoinGecko API: Total timeout (${maxTimeout}ms) exceeded after ${attempt} attempts
|
|
1387
|
+
`[useTokens] CoinGecko API: Total timeout (${maxTimeout}ms) exceeded after ${attempt} attempts.`
|
|
833
1388
|
);
|
|
834
1389
|
break;
|
|
835
1390
|
}
|
|
836
1391
|
let remainingTimeout = maxTimeout - elapsedTime, requestTimeout = Math.min(1e4, remainingTimeout), { signal, cleanup } = createTimeoutSignal(requestTimeout);
|
|
837
1392
|
try {
|
|
838
|
-
let response = await fetch(url, {
|
|
839
|
-
headers,
|
|
840
|
-
signal
|
|
841
|
-
});
|
|
1393
|
+
let response = await fetch(url, { headers, signal });
|
|
842
1394
|
if (cleanup(), response.status === 429) {
|
|
843
1395
|
let retryAfter = parseRetryAfter(response.headers.get("Retry-After")), delay = calculateBackoffDelay(attempt, baseDelay, retryAfter);
|
|
844
|
-
if (console.warn(
|
|
845
|
-
`[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`
|
|
846
|
-
), Date.now() - startTime + delay >= maxTimeout) {
|
|
847
|
-
console.warn(
|
|
848
|
-
`[useTokens] CoinGecko API: Skipping retry - would exceed total timeout (${maxTimeout}ms). Returning cached/partial results.`
|
|
849
|
-
);
|
|
1396
|
+
if (console.warn(`[useTokens] CoinGecko API rate limited (429). Waiting ${Math.round(delay)}ms.`), Date.now() - startTime + delay >= maxTimeout)
|
|
850
1397
|
break;
|
|
851
|
-
}
|
|
852
1398
|
await new Promise((resolve) => setTimeout(resolve, delay)), attempt++;
|
|
853
1399
|
continue;
|
|
854
1400
|
}
|
|
@@ -859,174 +1405,195 @@ async function fetchCoinGeckoPrices(coingeckoIds, config) {
|
|
|
859
1405
|
priceData?.usd !== void 0 && (results.set(id, priceData.usd), priceCache.set(id, { price: priceData.usd, timestamp: fetchTime }));
|
|
860
1406
|
return results;
|
|
861
1407
|
} catch (error) {
|
|
862
|
-
if (cleanup(), lastError = error,
|
|
863
|
-
`[useTokens] CoinGecko API request timed out. Attempt ${attempt + 1}/${maxRetries + 1}.`
|
|
864
|
-
) : console.warn(
|
|
865
|
-
`[useTokens] CoinGecko API request failed. Attempt ${attempt + 1}/${maxRetries + 1}:`,
|
|
866
|
-
error
|
|
867
|
-
), attempt < maxRetries) {
|
|
1408
|
+
if (cleanup(), lastError = error, attempt < maxRetries) {
|
|
868
1409
|
let delay = calculateBackoffDelay(attempt, baseDelay);
|
|
869
1410
|
Date.now() - startTime + delay < maxTimeout && await new Promise((resolve) => setTimeout(resolve, delay));
|
|
870
1411
|
}
|
|
871
1412
|
attempt++;
|
|
872
1413
|
}
|
|
873
1414
|
}
|
|
874
|
-
return attempt > maxRetries && console.warn(
|
|
875
|
-
`[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`
|
|
876
|
-
), results;
|
|
1415
|
+
return attempt > maxRetries && lastError && console.warn(`[useTokens] CoinGecko API: All attempts failed. Last error: ${lastError.message}`), results;
|
|
877
1416
|
}
|
|
878
|
-
async function fetchTokenMetadataHybrid(mints, coingeckoConfig) {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
let uncachedMints = [], now = Date.now();
|
|
882
|
-
for (let mint of mints) {
|
|
883
|
-
let cached = metadataCache.get(mint);
|
|
884
|
-
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);
|
|
885
|
-
}
|
|
886
|
-
if (uncachedMints.length === 0) return results;
|
|
887
|
-
let solanaMetadata = await fetchSolanaTokenMetadata(uncachedMints), coingeckoIdToMint = /* @__PURE__ */ new Map();
|
|
888
|
-
for (let [mint, meta] of solanaMetadata)
|
|
889
|
-
meta.extensions?.coingeckoId && coingeckoIdToMint.set(meta.extensions.coingeckoId, mint);
|
|
1417
|
+
async function fetchTokenMetadataHybrid(mints, coingeckoConfig, options) {
|
|
1418
|
+
if (mints.length === 0) return false;
|
|
1419
|
+
let now = Date.now(), mintsNeedingTokenList = [], staleCoingeckoIdToMint = /* @__PURE__ */ new Map();
|
|
890
1420
|
for (let mint of mints) {
|
|
891
1421
|
let cached = metadataCache.get(mint);
|
|
892
|
-
|
|
1422
|
+
if (!cached) {
|
|
1423
|
+
mintsNeedingTokenList.push(mint);
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
if (!cached.coingeckoId) continue;
|
|
1427
|
+
let priceEntry = priceCache.get(cached.coingeckoId);
|
|
1428
|
+
!!(priceEntry && now - priceEntry.timestamp < PRICE_CACHE_TTL) || staleCoingeckoIdToMint.set(cached.coingeckoId, mint);
|
|
893
1429
|
}
|
|
894
|
-
let
|
|
895
|
-
|
|
896
|
-
|
|
1430
|
+
let didUpdate = false, tokenListMetadata = await fetchSolanaTokenListMetadata(mintsNeedingTokenList, {
|
|
1431
|
+
timeoutMs: 1e4,
|
|
1432
|
+
cluster: options?.cluster
|
|
1433
|
+
});
|
|
1434
|
+
for (let [mint, meta] of tokenListMetadata) {
|
|
1435
|
+
let coingeckoId = meta.extensions?.coingeckoId, usdPrice = (coingeckoId ? priceCache.get(coingeckoId) : void 0)?.price, combined = {
|
|
897
1436
|
address: meta.address,
|
|
898
|
-
name: meta.address ===
|
|
1437
|
+
name: meta.address === NATIVE_SOL_MINT ? "Solana" : meta.name,
|
|
899
1438
|
symbol: meta.symbol,
|
|
900
1439
|
decimals: meta.decimals,
|
|
901
1440
|
logoURI: meta.logoURI,
|
|
902
1441
|
coingeckoId,
|
|
903
1442
|
usdPrice
|
|
904
|
-
};
|
|
905
|
-
|
|
1443
|
+
}, existing = metadataCache.get(mint);
|
|
1444
|
+
(!existing || existing.name !== combined.name || existing.symbol !== combined.symbol || existing.decimals !== combined.decimals || existing.logoURI !== combined.logoURI || existing.coingeckoId !== combined.coingeckoId || existing.usdPrice !== combined.usdPrice) && (didUpdate = true, metadataCache.set(mint, combined));
|
|
906
1445
|
}
|
|
1446
|
+
didUpdate && options?.onUpdate?.();
|
|
1447
|
+
let coingeckoIdToMint = new Map(staleCoingeckoIdToMint);
|
|
1448
|
+
for (let [mint, meta] of tokenListMetadata)
|
|
1449
|
+
meta.extensions?.coingeckoId && coingeckoIdToMint.set(meta.extensions.coingeckoId, mint);
|
|
1450
|
+
if (coingeckoIdToMint.size === 0)
|
|
1451
|
+
return didUpdate;
|
|
1452
|
+
let prices = await fetchCoinGeckoPrices([...coingeckoIdToMint.keys()], coingeckoConfig), didUpdatePrices = false;
|
|
907
1453
|
for (let [coingeckoId, mint] of coingeckoIdToMint) {
|
|
908
|
-
let cached =
|
|
1454
|
+
let cached = metadataCache.get(mint);
|
|
909
1455
|
if (cached) {
|
|
910
1456
|
let usdPrice = prices.get(coingeckoId);
|
|
911
|
-
usdPrice !== void 0 &&
|
|
1457
|
+
usdPrice !== void 0 && cached.usdPrice !== usdPrice && (didUpdate = true, didUpdatePrices = true, cached.usdPrice = usdPrice, metadataCache.set(mint, cached));
|
|
912
1458
|
}
|
|
913
1459
|
}
|
|
914
|
-
return
|
|
1460
|
+
return didUpdatePrices && options?.onUpdate?.(), didUpdate;
|
|
915
1461
|
}
|
|
916
1462
|
function formatBalance(amount, decimals) {
|
|
917
|
-
return (
|
|
918
|
-
|
|
919
|
-
maximumFractionDigits: Math.min(decimals, 6)
|
|
1463
|
+
return chunkFTXIXM43_js.formatBigIntBalance(amount, decimals, {
|
|
1464
|
+
maxDecimals: Math.min(decimals, 6)
|
|
920
1465
|
});
|
|
921
1466
|
}
|
|
922
1467
|
function formatUsd(amount, decimals, usdPrice) {
|
|
923
|
-
return (
|
|
924
|
-
style: "currency",
|
|
925
|
-
currency: "USD",
|
|
926
|
-
minimumFractionDigits: 2,
|
|
927
|
-
maximumFractionDigits: 2
|
|
928
|
-
});
|
|
1468
|
+
return chunkFTXIXM43_js.formatBigIntUsd(amount, decimals, usdPrice);
|
|
929
1469
|
}
|
|
930
|
-
function
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1470
|
+
function selectTokens(assets, address) {
|
|
1471
|
+
return {
|
|
1472
|
+
lamports: assets?.lamports ?? 0n,
|
|
1473
|
+
tokenAccounts: assets?.tokenAccounts ?? [],
|
|
1474
|
+
address
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
function sortByValueDesc(a, b) {
|
|
1478
|
+
let metadataSort = (b.logo ? 1 : 0) - (a.logo ? 1 : 0);
|
|
1479
|
+
if (metadataSort !== 0) return metadataSort;
|
|
1480
|
+
let aValue = Number(a.amount) / Math.pow(10, a.decimals) * (a.usdPrice ?? 0);
|
|
1481
|
+
return Number(b.amount) / Math.pow(10, b.decimals) * (b.usdPrice ?? 0) - aValue;
|
|
935
1482
|
}
|
|
936
1483
|
function useTokens(options = {}) {
|
|
937
1484
|
let {
|
|
1485
|
+
enabled = true,
|
|
938
1486
|
includeZeroBalance = false,
|
|
939
1487
|
autoRefresh = false,
|
|
940
1488
|
refreshInterval = 6e4,
|
|
941
1489
|
fetchMetadata = true,
|
|
942
|
-
includeNativeSol = true
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
tokenList.sort((a, b) => {
|
|
998
|
-
let metadataSort = (b.logo ? 1 : 0) - (a.logo ? 1 : 0);
|
|
999
|
-
if (metadataSort !== 0) return metadataSort;
|
|
1000
|
-
let aValue = Number(a.amount) / Math.pow(10, a.decimals) * (a.usdPrice ?? 0);
|
|
1001
|
-
return Number(b.amount) / Math.pow(10, b.decimals) * (b.usdPrice ?? 0) - aValue;
|
|
1002
|
-
}), setTokens([...tokenList]);
|
|
1003
|
-
}
|
|
1004
|
-
} catch (err) {
|
|
1005
|
-
setError(err), console.error("[useTokens] Failed to fetch tokens:", err);
|
|
1006
|
-
} finally {
|
|
1007
|
-
setIsLoading(false);
|
|
1008
|
-
}
|
|
1009
|
-
}, [connected, address, rpcClient, includeZeroBalance, fetchMetadata, includeNativeSol, imageProxy, coingeckoConfig]);
|
|
1490
|
+
includeNativeSol = true,
|
|
1491
|
+
staleTimeMs = 0,
|
|
1492
|
+
cacheTimeMs = 300 * 1e3,
|
|
1493
|
+
// 5 minutes
|
|
1494
|
+
refetchOnMount = "stale",
|
|
1495
|
+
client: clientOverride
|
|
1496
|
+
} = options, { address, connected } = useAccount(), { type: clusterType } = useCluster(), connectorConfig = useConnectorClient()?.getConfig(), imageProxy = connectorConfig?.imageProxy, coingeckoConfig = connectorConfig?.coingecko, selectFn = React.useCallback(
|
|
1497
|
+
(assets) => selectTokens(assets, address ?? ""),
|
|
1498
|
+
[address]
|
|
1499
|
+
), {
|
|
1500
|
+
data: selection,
|
|
1501
|
+
error,
|
|
1502
|
+
isFetching,
|
|
1503
|
+
updatedAt,
|
|
1504
|
+
refetch: sharedRefetch,
|
|
1505
|
+
abort
|
|
1506
|
+
} = useWalletAssets({
|
|
1507
|
+
enabled,
|
|
1508
|
+
staleTimeMs,
|
|
1509
|
+
cacheTimeMs,
|
|
1510
|
+
refetchOnMount,
|
|
1511
|
+
refetchIntervalMs: autoRefresh ? refreshInterval : false,
|
|
1512
|
+
client: clientOverride,
|
|
1513
|
+
select: selectFn
|
|
1514
|
+
}), lamports = selection?.lamports ?? 0n, tokenAccounts = selection?.tokenAccounts ?? [], walletAddress = selection?.address ?? "", baseTokens = React.useMemo(() => {
|
|
1515
|
+
let result = [];
|
|
1516
|
+
includeNativeSol && walletAddress && (includeZeroBalance || lamports > 0n) && result.push({
|
|
1517
|
+
mint: NATIVE_SOL_MINT,
|
|
1518
|
+
tokenAccount: walletAddress,
|
|
1519
|
+
amount: lamports,
|
|
1520
|
+
decimals: 9,
|
|
1521
|
+
formatted: formatBalance(lamports, 9),
|
|
1522
|
+
isFrozen: false,
|
|
1523
|
+
owner: walletAddress
|
|
1524
|
+
});
|
|
1525
|
+
for (let account of tokenAccounts)
|
|
1526
|
+
!includeZeroBalance && account.amount === 0n || result.push({
|
|
1527
|
+
mint: account.mint,
|
|
1528
|
+
tokenAccount: account.pubkey,
|
|
1529
|
+
amount: account.amount,
|
|
1530
|
+
decimals: account.decimals,
|
|
1531
|
+
formatted: formatBalance(account.amount, account.decimals),
|
|
1532
|
+
isFrozen: account.isFrozen,
|
|
1533
|
+
owner: account.owner,
|
|
1534
|
+
programId: account.programId
|
|
1535
|
+
});
|
|
1536
|
+
return result;
|
|
1537
|
+
}, [lamports, tokenAccounts, walletAddress, includeNativeSol, includeZeroBalance]), mints = React.useMemo(() => {
|
|
1538
|
+
let unique = /* @__PURE__ */ new Set();
|
|
1539
|
+
for (let token of baseTokens)
|
|
1540
|
+
unique.add(token.mint);
|
|
1541
|
+
return [...unique].sort();
|
|
1542
|
+
}, [baseTokens]), mintsKey = React.useMemo(() => mints.join(","), [mints]), [metadataVersion, setMetadataVersion] = React.useState(0);
|
|
1010
1543
|
React.useEffect(() => {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1544
|
+
if (!fetchMetadata || !mintsKey) return;
|
|
1545
|
+
let isMounted = true;
|
|
1546
|
+
return (async () => {
|
|
1547
|
+
try {
|
|
1548
|
+
let mintList = mintsKey.split(",");
|
|
1549
|
+
await fetchTokenMetadataHybrid(mintList, coingeckoConfig, {
|
|
1550
|
+
onUpdate: () => {
|
|
1551
|
+
isMounted && setMetadataVersion((v) => v + 1);
|
|
1552
|
+
},
|
|
1553
|
+
cluster: clusterType ?? void 0
|
|
1554
|
+
}), isMounted && setMetadataVersion((v) => v + 1);
|
|
1555
|
+
} catch (err) {
|
|
1556
|
+
console.error("[useTokens] Failed to fetch metadata:", err);
|
|
1557
|
+
}
|
|
1558
|
+
})(), () => {
|
|
1559
|
+
isMounted = false;
|
|
1560
|
+
};
|
|
1561
|
+
}, [mintsKey, fetchMetadata, coingeckoConfig, clusterType]);
|
|
1562
|
+
let tokens = React.useMemo(() => fetchMetadata ? baseTokens.map((token) => {
|
|
1563
|
+
let meta = metadataCache.get(token.mint);
|
|
1564
|
+
if (!meta) return token;
|
|
1565
|
+
let usdPrice = (meta.coingeckoId ? priceCache.get(meta.coingeckoId) : void 0)?.price ?? meta.usdPrice;
|
|
1566
|
+
return {
|
|
1567
|
+
...token,
|
|
1568
|
+
name: meta.name,
|
|
1569
|
+
symbol: meta.symbol,
|
|
1570
|
+
logo: transformImageUrl(meta.logoURI, imageProxy),
|
|
1571
|
+
usdPrice,
|
|
1572
|
+
formattedUsd: usdPrice ? formatUsd(token.amount, token.decimals, usdPrice) : void 0
|
|
1573
|
+
};
|
|
1574
|
+
}).sort(sortByValueDesc) : baseTokens.slice().sort(sortByValueDesc), [baseTokens, fetchMetadata, imageProxy, metadataVersion]), totalAccounts = tokenAccounts.length + (includeNativeSol ? 1 : 0);
|
|
1575
|
+
React.useEffect(() => (startCacheCleanup(), () => stopCacheCleanup()), []);
|
|
1017
1576
|
let wasConnectedRef = React.useRef(connected);
|
|
1018
|
-
|
|
1577
|
+
React.useEffect(() => {
|
|
1019
1578
|
wasConnectedRef.current && !connected && clearTokenCaches(), wasConnectedRef.current = connected;
|
|
1020
|
-
}, [connected])
|
|
1579
|
+
}, [connected]);
|
|
1580
|
+
let visibleError = updatedAt ? null : error, refetch = React.useCallback(
|
|
1581
|
+
async (opts) => {
|
|
1582
|
+
await sharedRefetch(opts);
|
|
1583
|
+
},
|
|
1584
|
+
[sharedRefetch]
|
|
1585
|
+
);
|
|
1586
|
+
return React.useMemo(
|
|
1021
1587
|
() => ({
|
|
1022
1588
|
tokens,
|
|
1023
|
-
isLoading,
|
|
1024
|
-
error,
|
|
1025
|
-
refetch
|
|
1026
|
-
|
|
1589
|
+
isLoading: isFetching,
|
|
1590
|
+
error: visibleError,
|
|
1591
|
+
refetch,
|
|
1592
|
+
abort,
|
|
1593
|
+
lastUpdated: updatedAt ? new Date(updatedAt) : null,
|
|
1027
1594
|
totalAccounts
|
|
1028
1595
|
}),
|
|
1029
|
-
[tokens,
|
|
1596
|
+
[tokens, isFetching, visibleError, refetch, abort, updatedAt, totalAccounts]
|
|
1030
1597
|
);
|
|
1031
1598
|
}
|
|
1032
1599
|
function DisconnectElement({
|
|
@@ -1663,6 +2230,43 @@ function WalletListElement({
|
|
|
1663
2230
|
);
|
|
1664
2231
|
}
|
|
1665
2232
|
WalletListElement.displayName = "WalletListElement";
|
|
2233
|
+
var shineStyles = `
|
|
2234
|
+
.ck-skeleton {
|
|
2235
|
+
position: relative;
|
|
2236
|
+
overflow: hidden;
|
|
2237
|
+
}
|
|
2238
|
+
.ck-skeleton-shine {
|
|
2239
|
+
position: absolute;
|
|
2240
|
+
top: 0;
|
|
2241
|
+
left: 0;
|
|
2242
|
+
width: 500%;
|
|
2243
|
+
height: 500%;
|
|
2244
|
+
background: linear-gradient(135deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.1) 50%, rgba(255,255,255,0) 100%);
|
|
2245
|
+
animation: ck-skeleton-slide 0.5s infinite;
|
|
2246
|
+
z-index: 1;
|
|
2247
|
+
pointer-events: none;
|
|
2248
|
+
}
|
|
2249
|
+
@keyframes ck-skeleton-slide {
|
|
2250
|
+
0% { transform: translate(-100%, -100%); }
|
|
2251
|
+
100% { transform: translate(100%, 100%); }
|
|
2252
|
+
}
|
|
2253
|
+
`, stylesInjected = false;
|
|
2254
|
+
function injectStyles() {
|
|
2255
|
+
if (!stylesInjected && typeof document < "u") {
|
|
2256
|
+
let styleId = "ck-skeleton-shine-styles";
|
|
2257
|
+
if (!document.getElementById(styleId)) {
|
|
2258
|
+
let style = document.createElement("style");
|
|
2259
|
+
style.id = styleId, style.textContent = shineStyles, document.head.appendChild(style);
|
|
2260
|
+
}
|
|
2261
|
+
stylesInjected = true;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
function SkeletonShine() {
|
|
2265
|
+
return React__default.default.useEffect(() => {
|
|
2266
|
+
injectStyles();
|
|
2267
|
+
}, []), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton-shine", "data-slot": "skeleton-shine" });
|
|
2268
|
+
}
|
|
2269
|
+
SkeletonShine.displayName = "SkeletonShine";
|
|
1666
2270
|
function BalanceElement({
|
|
1667
2271
|
showSol = true,
|
|
1668
2272
|
showTokens = false,
|
|
@@ -1705,10 +2309,10 @@ function BalanceElement({
|
|
|
1705
2309
|
"data-variant": variant,
|
|
1706
2310
|
"data-loading": "true",
|
|
1707
2311
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ck-balance-block-skeleton", "data-slot": "balance-element-skeleton", children: [
|
|
1708
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text" }),
|
|
2312
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonShine, {}) }),
|
|
1709
2313
|
showTokens && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1710
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short" }),
|
|
1711
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short" })
|
|
2314
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonShine, {}) }),
|
|
2315
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--text ck-skeleton--short", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonShine, {}) })
|
|
1712
2316
|
] })
|
|
1713
2317
|
] })
|
|
1714
2318
|
}
|
|
@@ -1870,6 +2474,8 @@ function BalanceElement({
|
|
|
1870
2474
|
BalanceElement.displayName = "BalanceElement";
|
|
1871
2475
|
function TransactionHistoryElement({
|
|
1872
2476
|
limit = 5,
|
|
2477
|
+
fetchDetails = true,
|
|
2478
|
+
detailsConcurrency,
|
|
1873
2479
|
showStatus = true,
|
|
1874
2480
|
showTime = true,
|
|
1875
2481
|
className,
|
|
@@ -1879,7 +2485,11 @@ function TransactionHistoryElement({
|
|
|
1879
2485
|
render,
|
|
1880
2486
|
renderItem
|
|
1881
2487
|
}) {
|
|
1882
|
-
let { transactions, isLoading, error, hasMore, loadMore, refetch } = useTransactions({
|
|
2488
|
+
let { transactions, isLoading, error, hasMore, loadMore, refetch } = useTransactions({
|
|
2489
|
+
limit,
|
|
2490
|
+
fetchDetails,
|
|
2491
|
+
detailsConcurrency
|
|
2492
|
+
});
|
|
1883
2493
|
if (render)
|
|
1884
2494
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: render({ transactions, isLoading, error, hasMore, loadMore, refetch }) });
|
|
1885
2495
|
let statusIcon = (status) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1929,7 +2539,7 @@ function TransactionHistoryElement({
|
|
|
1929
2539
|
"data-slot": "tx-history-element",
|
|
1930
2540
|
"data-variant": variant,
|
|
1931
2541
|
"data-loading": "true",
|
|
1932
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-tx-history-skeleton", "data-slot": "tx-history-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--tx" }, i)) })
|
|
2542
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-tx-history-skeleton", "data-slot": "tx-history-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--tx", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonShine, {}) }, i)) })
|
|
1933
2543
|
}
|
|
1934
2544
|
);
|
|
1935
2545
|
if (error)
|
|
@@ -2093,7 +2703,7 @@ function TokenListElement({
|
|
|
2093
2703
|
"data-slot": "token-list-element",
|
|
2094
2704
|
"data-variant": variant,
|
|
2095
2705
|
"data-loading": "true",
|
|
2096
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-token-list-skeleton", "data-slot": "token-list-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--token" }, i)) })
|
|
2706
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-token-list-skeleton", "data-slot": "token-list-skeleton", children: Array.from({ length: Math.min(limit, 3) }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ck-skeleton ck-skeleton--token", children: /* @__PURE__ */ jsxRuntime.jsx(SkeletonShine, {}) }, i)) })
|
|
2097
2707
|
}
|
|
2098
2708
|
);
|
|
2099
2709
|
if (error)
|
|
@@ -2187,14 +2797,23 @@ function TokenListElement({
|
|
|
2187
2797
|
TokenListElement.displayName = "TokenListElement";
|
|
2188
2798
|
|
|
2189
2799
|
exports.AccountElement = AccountElement;
|
|
2800
|
+
exports.AppProvider = AppProvider;
|
|
2190
2801
|
exports.BalanceElement = BalanceElement;
|
|
2191
2802
|
exports.ClusterElement = ClusterElement;
|
|
2192
2803
|
exports.ConnectorProvider = ConnectorProvider;
|
|
2193
2804
|
exports.DisconnectElement = DisconnectElement;
|
|
2805
|
+
exports.SkeletonShine = SkeletonShine;
|
|
2194
2806
|
exports.TokenListElement = TokenListElement;
|
|
2195
2807
|
exports.TransactionHistoryElement = TransactionHistoryElement;
|
|
2196
2808
|
exports.UnifiedProvider = UnifiedProvider;
|
|
2197
2809
|
exports.WalletListElement = WalletListElement;
|
|
2810
|
+
exports.clearSharedQueryCache = clearSharedQueryCache;
|
|
2811
|
+
exports.clearTokenCaches = clearTokenCaches;
|
|
2812
|
+
exports.getBalanceQueryKey = getBalanceQueryKey;
|
|
2813
|
+
exports.getTokensQueryKey = getTokensQueryKey;
|
|
2814
|
+
exports.getTransactionsQueryKey = getTransactionsQueryKey;
|
|
2815
|
+
exports.getWalletAssetsQueryKey = getWalletAssetsQueryKey;
|
|
2816
|
+
exports.invalidateSharedQuery = invalidateSharedQuery;
|
|
2198
2817
|
exports.useAccount = useAccount;
|
|
2199
2818
|
exports.useBalance = useBalance;
|
|
2200
2819
|
exports.useCluster = useCluster;
|
|
@@ -2209,5 +2828,5 @@ exports.useTransactionPreparer = useTransactionPreparer;
|
|
|
2209
2828
|
exports.useTransactionSigner = useTransactionSigner;
|
|
2210
2829
|
exports.useTransactions = useTransactions;
|
|
2211
2830
|
exports.useWalletInfo = useWalletInfo;
|
|
2212
|
-
//# sourceMappingURL=chunk-
|
|
2213
|
-
//# sourceMappingURL=chunk-
|
|
2831
|
+
//# sourceMappingURL=chunk-K3BNIGPX.js.map
|
|
2832
|
+
//# sourceMappingURL=chunk-K3BNIGPX.js.map
|