@whetstone-research/doppler-sdk 1.0.2 → 1.0.4

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.
@@ -0,0 +1,1465 @@
1
+ 'use strict';
2
+
3
+ var chunkBXATWUGJ_cjs = require('../../chunk-BXATWUGJ.cjs');
4
+ var chunkDPKVNI6Q_cjs = require('../../chunk-DPKVNI6Q.cjs');
5
+ require('../../chunk-Q7SFCCGT.cjs');
6
+ var react = require('react');
7
+ var jsxRuntime = require('react/jsx-runtime');
8
+ var kit = require('@solana/kit');
9
+
10
+ var AmmContext = react.createContext(null);
11
+ function AmmProvider({
12
+ rpc,
13
+ programId = chunkDPKVNI6Q_cjs.CPMM_PROGRAM_ID,
14
+ commitment = "confirmed",
15
+ refreshInterval = 3e4,
16
+ defaultSlippageBps = 50,
17
+ children
18
+ }) {
19
+ const value = react.useMemo(
20
+ () => ({
21
+ rpc,
22
+ programId,
23
+ commitment,
24
+ refreshInterval,
25
+ defaultSlippageBps
26
+ }),
27
+ [rpc, programId, commitment, refreshInterval, defaultSlippageBps]
28
+ );
29
+ return /* @__PURE__ */ jsxRuntime.jsx(AmmContext.Provider, { value, children });
30
+ }
31
+ function useAmm() {
32
+ const context = react.useContext(AmmContext);
33
+ if (!context) {
34
+ throw new Error("useAmm must be used within an AmmProvider");
35
+ }
36
+ return context;
37
+ }
38
+ function useAmmOptional() {
39
+ return react.useContext(AmmContext);
40
+ }
41
+ var WalletContext = react.createContext(null);
42
+ function WalletProvider({
43
+ wallet,
44
+ signAndSendTransaction,
45
+ children
46
+ }) {
47
+ const value = react.useMemo(
48
+ () => ({
49
+ ...wallet,
50
+ signAndSendTransaction
51
+ }),
52
+ [wallet, signAndSendTransaction]
53
+ );
54
+ return /* @__PURE__ */ jsxRuntime.jsx(WalletContext.Provider, { value, children });
55
+ }
56
+ function useWallet() {
57
+ const context = react.useContext(WalletContext);
58
+ if (!context) {
59
+ throw new Error("useWallet must be used within a WalletProvider");
60
+ }
61
+ return context;
62
+ }
63
+ function useWalletOptional() {
64
+ return react.useContext(WalletContext);
65
+ }
66
+ function useWalletAddress() {
67
+ const { connected, address } = useWallet();
68
+ if (!connected || !address) {
69
+ throw new Error("Wallet is not connected");
70
+ }
71
+ return address;
72
+ }
73
+ var AmmContext2 = react.createContext(null);
74
+ AmmContext2.displayName = "AmmContext";
75
+ function useAmm2() {
76
+ const ctx = react.useContext(AmmContext2);
77
+ if (!ctx) {
78
+ throw new Error("useAmm must be used within AmmProvider");
79
+ }
80
+ return ctx;
81
+ }
82
+ function createAmmContextValue(config) {
83
+ const {
84
+ endpoint,
85
+ programId,
86
+ commitment = "confirmed",
87
+ refreshInterval = 3e4,
88
+ defaultSlippageBps = 50
89
+ } = config;
90
+ const rpc = kit.createSolanaRpc(endpoint);
91
+ return {
92
+ rpc,
93
+ endpoint,
94
+ programId: programId ?? chunkDPKVNI6Q_cjs.CPMM_PROGRAM_ID,
95
+ commitment,
96
+ refreshInterval,
97
+ defaultSlippageBps
98
+ };
99
+ }
100
+ function AmmProvider2({
101
+ children,
102
+ endpoint,
103
+ programId,
104
+ commitment = "confirmed",
105
+ refreshInterval = 3e4,
106
+ defaultSlippageBps = 50
107
+ }) {
108
+ const value = react.useMemo(
109
+ () => createAmmContextValue({
110
+ endpoint,
111
+ programId,
112
+ commitment,
113
+ refreshInterval,
114
+ defaultSlippageBps
115
+ }),
116
+ [endpoint, programId, commitment, refreshInterval, defaultSlippageBps]
117
+ );
118
+ return /* @__PURE__ */ jsxRuntime.jsx(AmmContext2.Provider, { value, children });
119
+ }
120
+ function isConnectableWallet(wallet) {
121
+ return "standard:connect" in wallet.features;
122
+ }
123
+ function getWallets() {
124
+ if (typeof window === "undefined") {
125
+ return [];
126
+ }
127
+ const registry = window.navigator?.wallets;
128
+ if (!registry) {
129
+ return [];
130
+ }
131
+ const wallets = [];
132
+ try {
133
+ const registered = registry.get?.() ?? [];
134
+ for (const wallet of registered) {
135
+ const supportsSolana = wallet.chains?.some(
136
+ (chain) => chain.startsWith("solana:")
137
+ );
138
+ if (supportsSolana && isConnectableWallet(wallet)) {
139
+ wallets.push(wallet);
140
+ }
141
+ }
142
+ } catch {
143
+ }
144
+ return wallets;
145
+ }
146
+ var WalletContext2 = react.createContext(null);
147
+ WalletContext2.displayName = "WalletContext";
148
+ function useWallet2() {
149
+ const ctx = react.useContext(WalletContext2);
150
+ if (!ctx) {
151
+ throw new Error("useWallet must be used within WalletProvider");
152
+ }
153
+ return ctx;
154
+ }
155
+ function createWalletContextValue() {
156
+ return {
157
+ wallet: null,
158
+ account: null,
159
+ connected: false,
160
+ connecting: false,
161
+ wallets: [],
162
+ select: () => {
163
+ },
164
+ connect: async () => {
165
+ },
166
+ disconnect: async () => {
167
+ },
168
+ error: null
169
+ };
170
+ }
171
+ function WalletProvider2({
172
+ children,
173
+ autoConnect = false,
174
+ onConnect,
175
+ onDisconnect,
176
+ onError
177
+ }) {
178
+ const [wallets, setWallets] = react.useState([]);
179
+ const [wallet, setWallet] = react.useState(null);
180
+ const [account, setAccount] = react.useState(null);
181
+ const [connecting, setConnecting] = react.useState(false);
182
+ const [error, setError] = react.useState(null);
183
+ const connected = account !== null;
184
+ react.useEffect(() => {
185
+ const discovered = getWallets();
186
+ setWallets(discovered);
187
+ if (typeof window !== "undefined") {
188
+ const registry = window.navigator?.wallets;
189
+ if (registry?.on) {
190
+ const unsubscribe = registry.on("register", () => {
191
+ setWallets(getWallets());
192
+ });
193
+ return () => {
194
+ unsubscribe?.();
195
+ };
196
+ }
197
+ }
198
+ return void 0;
199
+ }, []);
200
+ const select = react.useCallback((newWallet) => {
201
+ setWallet(newWallet);
202
+ setError(null);
203
+ }, []);
204
+ const connect = react.useCallback(async () => {
205
+ if (!wallet) {
206
+ const err = new Error("No wallet selected");
207
+ setError(err);
208
+ onError?.(err);
209
+ return;
210
+ }
211
+ setConnecting(true);
212
+ setError(null);
213
+ try {
214
+ const connectFeature = wallet.features["standard:connect"];
215
+ const result = await connectFeature.connect();
216
+ if (result.accounts.length > 0) {
217
+ const connectedAccount = result.accounts[0];
218
+ setAccount(connectedAccount);
219
+ onConnect?.(connectedAccount);
220
+ } else {
221
+ throw new Error("No accounts returned from wallet");
222
+ }
223
+ } catch (err) {
224
+ const error2 = err instanceof Error ? err : new Error(String(err));
225
+ setError(error2);
226
+ onError?.(error2);
227
+ } finally {
228
+ setConnecting(false);
229
+ }
230
+ }, [wallet, onConnect, onError]);
231
+ const disconnect = react.useCallback(async () => {
232
+ if (!wallet) {
233
+ return;
234
+ }
235
+ try {
236
+ const disconnectFeature = wallet.features["standard:disconnect"];
237
+ if (disconnectFeature) {
238
+ await disconnectFeature.disconnect();
239
+ }
240
+ } catch (err) {
241
+ console.warn("Disconnect error:", err);
242
+ } finally {
243
+ setAccount(null);
244
+ onDisconnect?.();
245
+ }
246
+ }, [wallet, onDisconnect]);
247
+ react.useEffect(() => {
248
+ if (autoConnect && wallet && !connected && !connecting) {
249
+ const connectFeature = wallet.features["standard:connect"];
250
+ connectFeature.connect({ silent: true }).then(
251
+ (result) => {
252
+ if (result.accounts.length > 0) {
253
+ setAccount(result.accounts[0]);
254
+ onConnect?.(result.accounts[0]);
255
+ }
256
+ }
257
+ ).catch(() => {
258
+ });
259
+ }
260
+ }, [autoConnect, wallet, connected, connecting, onConnect]);
261
+ react.useEffect(() => {
262
+ if (!wallet) return void 0;
263
+ const eventsFeature = wallet.features["standard:events"];
264
+ if (eventsFeature?.on) {
265
+ const unsubscribe = eventsFeature.on("change", () => {
266
+ if (wallet.accounts.length > 0) {
267
+ setAccount(wallet.accounts[0]);
268
+ } else {
269
+ setAccount(null);
270
+ onDisconnect?.();
271
+ }
272
+ });
273
+ return () => {
274
+ unsubscribe?.();
275
+ };
276
+ }
277
+ return void 0;
278
+ }, [wallet, onDisconnect]);
279
+ const value = react.useMemo(
280
+ () => ({
281
+ wallet,
282
+ account,
283
+ connected,
284
+ connecting,
285
+ wallets,
286
+ select,
287
+ connect,
288
+ disconnect,
289
+ error
290
+ }),
291
+ [
292
+ wallet,
293
+ account,
294
+ connected,
295
+ connecting,
296
+ wallets,
297
+ select,
298
+ connect,
299
+ disconnect,
300
+ error
301
+ ]
302
+ );
303
+ return /* @__PURE__ */ jsxRuntime.jsx(WalletContext2.Provider, { value, children });
304
+ }
305
+ function usePool(poolAddress, options = {}) {
306
+ const {
307
+ rpc,
308
+ programId,
309
+ commitment: defaultCommitment,
310
+ refreshInterval: defaultRefreshInterval
311
+ } = useAmm();
312
+ const {
313
+ refreshInterval = defaultRefreshInterval,
314
+ fetchOnMount = true,
315
+ commitment = defaultCommitment
316
+ } = options;
317
+ const [pool, setPool] = react.useState(null);
318
+ const [loading, setLoading] = react.useState(true);
319
+ const [error, setError] = react.useState(null);
320
+ const [refetching, setRefetching] = react.useState(false);
321
+ const mountedRef = react.useRef(true);
322
+ const fetchPoolData = react.useCallback(
323
+ async (isRefetch = false) => {
324
+ if (!poolAddress) {
325
+ setPool(null);
326
+ setLoading(false);
327
+ return;
328
+ }
329
+ if (isRefetch) {
330
+ setRefetching(true);
331
+ } else {
332
+ setLoading(true);
333
+ }
334
+ setError(null);
335
+ try {
336
+ const poolData = await chunkBXATWUGJ_cjs.fetchPool(rpc, poolAddress, {
337
+ programId,
338
+ commitment
339
+ });
340
+ if (mountedRef.current) {
341
+ setPool(poolData);
342
+ }
343
+ } catch (err) {
344
+ if (mountedRef.current) {
345
+ setError(err instanceof Error ? err : new Error(String(err)));
346
+ }
347
+ } finally {
348
+ if (mountedRef.current) {
349
+ setLoading(false);
350
+ setRefetching(false);
351
+ }
352
+ }
353
+ },
354
+ [poolAddress, rpc, programId, commitment]
355
+ );
356
+ const refetch = react.useCallback(async () => {
357
+ await fetchPoolData(true);
358
+ }, [fetchPoolData]);
359
+ react.useEffect(() => {
360
+ mountedRef.current = true;
361
+ if (fetchOnMount) {
362
+ fetchPoolData(false);
363
+ }
364
+ return () => {
365
+ mountedRef.current = false;
366
+ };
367
+ }, [fetchPoolData, fetchOnMount]);
368
+ react.useEffect(() => {
369
+ if (refreshInterval <= 0 || !poolAddress) {
370
+ return;
371
+ }
372
+ const intervalId = setInterval(() => {
373
+ fetchPoolData(true);
374
+ }, refreshInterval);
375
+ return () => {
376
+ clearInterval(intervalId);
377
+ };
378
+ }, [fetchPoolData, refreshInterval, poolAddress]);
379
+ return {
380
+ pool,
381
+ loading,
382
+ error,
383
+ refetch,
384
+ refetching
385
+ };
386
+ }
387
+ function usePools(poolAddresses, options = {}) {
388
+ const {
389
+ rpc,
390
+ programId,
391
+ commitment: defaultCommitment,
392
+ refreshInterval: defaultRefreshInterval
393
+ } = useAmm();
394
+ const {
395
+ refreshInterval = defaultRefreshInterval,
396
+ fetchOnMount = true,
397
+ commitment = defaultCommitment
398
+ } = options;
399
+ const [pools, setPools] = react.useState(/* @__PURE__ */ new Map());
400
+ const [loading, setLoading] = react.useState(true);
401
+ const [error, setError] = react.useState(null);
402
+ const mountedRef = react.useRef(true);
403
+ const fetchPools = react.useCallback(async () => {
404
+ if (poolAddresses.length === 0) {
405
+ setPools(/* @__PURE__ */ new Map());
406
+ setLoading(false);
407
+ return;
408
+ }
409
+ setLoading(true);
410
+ setError(null);
411
+ try {
412
+ const results = await Promise.all(
413
+ poolAddresses.map(
414
+ (addr) => chunkBXATWUGJ_cjs.fetchPool(rpc, addr, { programId, commitment }).then((pool) => [addr, pool]).catch(() => [addr, null])
415
+ )
416
+ );
417
+ if (mountedRef.current) {
418
+ const poolMap = /* @__PURE__ */ new Map();
419
+ for (const [addr, pool] of results) {
420
+ if (pool) {
421
+ poolMap.set(addr, pool);
422
+ }
423
+ }
424
+ setPools(poolMap);
425
+ }
426
+ } catch (err) {
427
+ if (mountedRef.current) {
428
+ setError(err instanceof Error ? err : new Error(String(err)));
429
+ }
430
+ } finally {
431
+ if (mountedRef.current) {
432
+ setLoading(false);
433
+ }
434
+ }
435
+ }, [poolAddresses, rpc, programId, commitment]);
436
+ react.useEffect(() => {
437
+ mountedRef.current = true;
438
+ if (fetchOnMount) {
439
+ fetchPools();
440
+ }
441
+ return () => {
442
+ mountedRef.current = false;
443
+ };
444
+ }, [fetchPools, fetchOnMount]);
445
+ react.useEffect(() => {
446
+ if (refreshInterval <= 0 || poolAddresses.length === 0) {
447
+ return;
448
+ }
449
+ const intervalId = setInterval(fetchPools, refreshInterval);
450
+ return () => clearInterval(intervalId);
451
+ }, [fetchPools, refreshInterval, poolAddresses.length]);
452
+ return {
453
+ pools,
454
+ loading,
455
+ error,
456
+ refetch: fetchPools
457
+ };
458
+ }
459
+ function useSwap(options) {
460
+ const { defaultSlippageBps: contextSlippage } = useAmm();
461
+ const {
462
+ defaultSlippageBps = contextSlippage ?? 50,
463
+ pool,
464
+ token0Mint,
465
+ token1Mint
466
+ } = options;
467
+ const [state, setState] = react.useState({
468
+ inputToken: token0Mint,
469
+ outputToken: token1Mint,
470
+ inputAmount: 0n,
471
+ outputAmount: 0n,
472
+ exactInput: true,
473
+ slippageBps: defaultSlippageBps
474
+ });
475
+ const [quoting] = react.useState(false);
476
+ const direction = react.useMemo(() => {
477
+ if (!token0Mint || !token1Mint || !state.inputToken) return null;
478
+ if (state.inputToken === token0Mint) return 0;
479
+ if (state.inputToken === token1Mint) return 1;
480
+ return null;
481
+ }, [token0Mint, token1Mint, state.inputToken]);
482
+ const quote = react.useMemo(() => {
483
+ if (!pool || direction === null) {
484
+ return null;
485
+ }
486
+ if (state.exactInput) {
487
+ if (state.inputAmount === 0n) {
488
+ return {
489
+ amountOut: 0n,
490
+ feeTotal: 0n,
491
+ feeDist: 0n,
492
+ feeComp: 0n,
493
+ priceImpact: 0,
494
+ executionPrice: 0,
495
+ minAmountOut: 0n,
496
+ maxAmountIn: 0n,
497
+ direction,
498
+ isValid: false,
499
+ error: null
500
+ };
501
+ }
502
+ try {
503
+ const swapQuote = chunkBXATWUGJ_cjs.getSwapQuote(pool, state.inputAmount, direction);
504
+ const slippageFactor = chunkDPKVNI6Q_cjs.BPS_DENOM - BigInt(state.slippageBps);
505
+ const minAmountOut = swapQuote.amountOut * slippageFactor / chunkDPKVNI6Q_cjs.BPS_DENOM;
506
+ return {
507
+ ...swapQuote,
508
+ minAmountOut,
509
+ maxAmountIn: state.inputAmount,
510
+ direction,
511
+ isValid: swapQuote.amountOut > 0n,
512
+ error: null
513
+ };
514
+ } catch (err) {
515
+ return {
516
+ amountOut: 0n,
517
+ feeTotal: 0n,
518
+ feeDist: 0n,
519
+ feeComp: 0n,
520
+ priceImpact: 0,
521
+ executionPrice: 0,
522
+ minAmountOut: 0n,
523
+ maxAmountIn: 0n,
524
+ direction,
525
+ isValid: false,
526
+ error: err instanceof Error ? err.message : "Failed to calculate quote"
527
+ };
528
+ }
529
+ } else {
530
+ if (state.outputAmount === 0n) {
531
+ return {
532
+ amountOut: 0n,
533
+ feeTotal: 0n,
534
+ feeDist: 0n,
535
+ feeComp: 0n,
536
+ priceImpact: 0,
537
+ executionPrice: 0,
538
+ minAmountOut: 0n,
539
+ maxAmountIn: 0n,
540
+ direction,
541
+ isValid: false,
542
+ error: null
543
+ };
544
+ }
545
+ try {
546
+ const { amountIn, feeTotal } = chunkBXATWUGJ_cjs.getSwapQuoteExactOut(
547
+ pool,
548
+ state.outputAmount,
549
+ direction
550
+ );
551
+ const slippageFactor = chunkDPKVNI6Q_cjs.BPS_DENOM + BigInt(state.slippageBps);
552
+ const maxAmountIn = amountIn * slippageFactor / chunkDPKVNI6Q_cjs.BPS_DENOM;
553
+ const forwardQuote = chunkBXATWUGJ_cjs.getSwapQuote(pool, amountIn, direction);
554
+ return {
555
+ amountOut: state.outputAmount,
556
+ feeTotal,
557
+ feeDist: 0n,
558
+ // Not calculated for exact out
559
+ feeComp: 0n,
560
+ priceImpact: forwardQuote.priceImpact,
561
+ executionPrice: chunkBXATWUGJ_cjs.ratioToNumber(state.outputAmount, amountIn),
562
+ minAmountOut: state.outputAmount,
563
+ maxAmountIn,
564
+ direction,
565
+ isValid: amountIn > 0n,
566
+ error: null
567
+ };
568
+ } catch (err) {
569
+ return {
570
+ amountOut: 0n,
571
+ feeTotal: 0n,
572
+ feeDist: 0n,
573
+ feeComp: 0n,
574
+ priceImpact: 0,
575
+ executionPrice: 0,
576
+ minAmountOut: 0n,
577
+ maxAmountIn: 0n,
578
+ direction,
579
+ isValid: false,
580
+ error: err instanceof Error ? err.message : "Failed to calculate quote"
581
+ };
582
+ }
583
+ }
584
+ }, [
585
+ pool,
586
+ direction,
587
+ state.inputAmount,
588
+ state.outputAmount,
589
+ state.exactInput,
590
+ state.slippageBps
591
+ ]);
592
+ const setInputToken = react.useCallback((token) => {
593
+ setState((s) => ({ ...s, inputToken: token }));
594
+ }, []);
595
+ const setOutputToken = react.useCallback((token) => {
596
+ setState((s) => ({ ...s, outputToken: token }));
597
+ }, []);
598
+ const setInputAmount = react.useCallback((amount) => {
599
+ setState((s) => ({
600
+ ...s,
601
+ inputAmount: amount,
602
+ exactInput: true
603
+ }));
604
+ }, []);
605
+ const setOutputAmount = react.useCallback((amount) => {
606
+ setState((s) => ({
607
+ ...s,
608
+ outputAmount: amount,
609
+ exactInput: false
610
+ }));
611
+ }, []);
612
+ const setSlippage = react.useCallback((bps) => {
613
+ setState((s) => ({ ...s, slippageBps: bps }));
614
+ }, []);
615
+ const flipTokens = react.useCallback(() => {
616
+ setState((s) => ({
617
+ ...s,
618
+ inputToken: s.outputToken,
619
+ outputToken: s.inputToken,
620
+ inputAmount: s.outputAmount,
621
+ outputAmount: s.inputAmount
622
+ }));
623
+ }, []);
624
+ const reset = react.useCallback(() => {
625
+ setState({
626
+ inputToken: token0Mint,
627
+ outputToken: token1Mint,
628
+ inputAmount: 0n,
629
+ outputAmount: 0n,
630
+ exactInput: true,
631
+ slippageBps: defaultSlippageBps
632
+ });
633
+ }, [token0Mint, token1Mint, defaultSlippageBps]);
634
+ const canSwap = react.useMemo(() => {
635
+ return !!(quote?.isValid && state.inputToken && state.outputToken && (state.exactInput ? state.inputAmount > 0n : state.outputAmount > 0n));
636
+ }, [quote, state]);
637
+ return {
638
+ state,
639
+ quote,
640
+ quoting,
641
+ setInputToken,
642
+ setOutputToken,
643
+ setInputAmount,
644
+ setOutputAmount,
645
+ setSlippage,
646
+ flipTokens,
647
+ reset,
648
+ canSwap
649
+ };
650
+ }
651
+ function useLiquidity(options) {
652
+ const { defaultSlippageBps: contextSlippage } = useAmm();
653
+ const {
654
+ pool,
655
+ userShares = 0n,
656
+ defaultSlippageBps = contextSlippage ?? 50,
657
+ defaultMode = "add"
658
+ } = options;
659
+ const [mode, setMode] = react.useState(defaultMode);
660
+ const [addState, setAddState] = react.useState({
661
+ amount0: 0n,
662
+ amount1: 0n,
663
+ slippageBps: defaultSlippageBps
664
+ });
665
+ const [removeState, setRemoveState] = react.useState({
666
+ shares: 0n,
667
+ percentage: 0,
668
+ slippageBps: defaultSlippageBps
669
+ });
670
+ const addQuote = react.useMemo(() => {
671
+ if (!pool) {
672
+ return null;
673
+ }
674
+ if (addState.amount0 === 0n && addState.amount1 === 0n) {
675
+ return {
676
+ sharesOut: 0n,
677
+ amount0: 0n,
678
+ amount1: 0n,
679
+ poolShare: 0,
680
+ minSharesOut: 0n,
681
+ isValid: false,
682
+ error: null
683
+ };
684
+ }
685
+ try {
686
+ const quote = chunkBXATWUGJ_cjs.getAddLiquidityQuote(
687
+ pool,
688
+ addState.amount0,
689
+ addState.amount1
690
+ );
691
+ const slippageFactor = chunkDPKVNI6Q_cjs.BPS_DENOM - BigInt(addState.slippageBps);
692
+ const minSharesOut = quote.sharesOut * slippageFactor / chunkDPKVNI6Q_cjs.BPS_DENOM;
693
+ return {
694
+ ...quote,
695
+ minSharesOut,
696
+ isValid: quote.sharesOut > 0n,
697
+ error: null
698
+ };
699
+ } catch (err) {
700
+ return {
701
+ sharesOut: 0n,
702
+ amount0: 0n,
703
+ amount1: 0n,
704
+ poolShare: 0,
705
+ minSharesOut: 0n,
706
+ isValid: false,
707
+ error: err instanceof Error ? err.message : "Failed to calculate quote"
708
+ };
709
+ }
710
+ }, [pool, addState.amount0, addState.amount1, addState.slippageBps]);
711
+ const removeQuote = react.useMemo(() => {
712
+ if (!pool) {
713
+ return null;
714
+ }
715
+ if (removeState.shares === 0n) {
716
+ return {
717
+ amount0: 0n,
718
+ amount1: 0n,
719
+ minAmount0Out: 0n,
720
+ minAmount1Out: 0n,
721
+ isValid: false,
722
+ error: null
723
+ };
724
+ }
725
+ try {
726
+ const quote = chunkBXATWUGJ_cjs.getRemoveLiquidityQuote(pool, removeState.shares);
727
+ const slippageFactor = chunkDPKVNI6Q_cjs.BPS_DENOM - BigInt(removeState.slippageBps);
728
+ const minAmount0Out = quote.amount0 * slippageFactor / chunkDPKVNI6Q_cjs.BPS_DENOM;
729
+ const minAmount1Out = quote.amount1 * slippageFactor / chunkDPKVNI6Q_cjs.BPS_DENOM;
730
+ return {
731
+ ...quote,
732
+ minAmount0Out,
733
+ minAmount1Out,
734
+ isValid: quote.amount0 > 0n || quote.amount1 > 0n,
735
+ error: null
736
+ };
737
+ } catch (err) {
738
+ return {
739
+ amount0: 0n,
740
+ amount1: 0n,
741
+ minAmount0Out: 0n,
742
+ minAmount1Out: 0n,
743
+ isValid: false,
744
+ error: err instanceof Error ? err.message : "Failed to calculate quote"
745
+ };
746
+ }
747
+ }, [pool, removeState.shares, removeState.slippageBps]);
748
+ const setAmount0 = react.useCallback((amount) => {
749
+ setAddState((s) => ({ ...s, amount0: amount }));
750
+ }, []);
751
+ const setAmount1 = react.useCallback((amount) => {
752
+ setAddState((s) => ({ ...s, amount1: amount }));
753
+ }, []);
754
+ const setShares = react.useCallback(
755
+ (shares) => {
756
+ setRemoveState((s) => ({
757
+ ...s,
758
+ shares,
759
+ percentage: userShares > 0n ? Number(shares * 100n / userShares) : 0
760
+ }));
761
+ },
762
+ [userShares]
763
+ );
764
+ const setPercentage = react.useCallback(
765
+ (percentage) => {
766
+ const clampedPercentage = Math.min(100, Math.max(0, percentage));
767
+ const shares = userShares * BigInt(Math.round(clampedPercentage)) / 100n;
768
+ setRemoveState((s) => ({
769
+ ...s,
770
+ shares,
771
+ percentage: clampedPercentage
772
+ }));
773
+ },
774
+ [userShares]
775
+ );
776
+ const setSlippage = react.useCallback((bps) => {
777
+ setAddState((s) => ({ ...s, slippageBps: bps }));
778
+ setRemoveState((s) => ({ ...s, slippageBps: bps }));
779
+ }, []);
780
+ const reset = react.useCallback(() => {
781
+ setAddState({
782
+ amount0: 0n,
783
+ amount1: 0n,
784
+ slippageBps: defaultSlippageBps
785
+ });
786
+ setRemoveState({
787
+ shares: 0n,
788
+ percentage: 0,
789
+ slippageBps: defaultSlippageBps
790
+ });
791
+ }, [defaultSlippageBps]);
792
+ const canAdd = react.useMemo(() => {
793
+ return !!(addQuote?.isValid && (addState.amount0 > 0n || addState.amount1 > 0n));
794
+ }, [addQuote, addState]);
795
+ const canRemove = react.useMemo(() => {
796
+ return !!(removeQuote?.isValid && removeState.shares > 0n && removeState.shares <= userShares);
797
+ }, [removeQuote, removeState.shares, userShares]);
798
+ return {
799
+ mode,
800
+ setMode,
801
+ addState,
802
+ addQuote,
803
+ setAmount0,
804
+ setAmount1,
805
+ canAdd,
806
+ removeState,
807
+ removeQuote,
808
+ setShares,
809
+ setPercentage,
810
+ canRemove,
811
+ setSlippage,
812
+ reset
813
+ };
814
+ }
815
+ function usePosition(poolAddress, positionId = 0n, options = {}) {
816
+ const {
817
+ rpc,
818
+ programId,
819
+ commitment: defaultCommitment,
820
+ refreshInterval: defaultRefreshInterval
821
+ } = useAmm();
822
+ const wallet = useWalletOptional();
823
+ const {
824
+ refreshInterval = defaultRefreshInterval,
825
+ fetchOnMount = true,
826
+ commitment = defaultCommitment,
827
+ pool: providedPool
828
+ } = options;
829
+ const [position, setPosition] = react.useState(null);
830
+ const [positionAddress, setPositionAddress] = react.useState();
831
+ const [pool, setPool] = react.useState(providedPool ?? null);
832
+ const [loading, setLoading] = react.useState(true);
833
+ const [error, setError] = react.useState(null);
834
+ const mountedRef = react.useRef(true);
835
+ const ownerAddress = wallet?.address;
836
+ const fetchPositionData = react.useCallback(async () => {
837
+ if (!poolAddress || !ownerAddress) {
838
+ setPosition(null);
839
+ setPositionAddress(void 0);
840
+ setLoading(false);
841
+ return;
842
+ }
843
+ setLoading(true);
844
+ setError(null);
845
+ try {
846
+ const { getPositionAddress } = await import('../../pda-ZZMBZSFU.cjs');
847
+ const [posAddr] = await getPositionAddress(
848
+ poolAddress,
849
+ ownerAddress,
850
+ positionId,
851
+ programId
852
+ );
853
+ setPositionAddress(posAddr);
854
+ const [positionData, poolData] = await Promise.all([
855
+ chunkBXATWUGJ_cjs.fetchPosition(rpc, posAddr, { programId, commitment }),
856
+ providedPool ? Promise.resolve(providedPool) : chunkBXATWUGJ_cjs.fetchPool(rpc, poolAddress, { programId, commitment })
857
+ ]);
858
+ if (mountedRef.current) {
859
+ setPosition(positionData);
860
+ setPool(poolData);
861
+ }
862
+ } catch (err) {
863
+ if (mountedRef.current) {
864
+ setError(err instanceof Error ? err : new Error(String(err)));
865
+ }
866
+ } finally {
867
+ if (mountedRef.current) {
868
+ setLoading(false);
869
+ }
870
+ }
871
+ }, [
872
+ poolAddress,
873
+ ownerAddress,
874
+ positionId,
875
+ rpc,
876
+ programId,
877
+ commitment,
878
+ providedPool
879
+ ]);
880
+ const refetch = react.useCallback(async () => {
881
+ await fetchPositionData();
882
+ }, [fetchPositionData]);
883
+ const pendingFees = react.useMemo(() => {
884
+ if (!pool || !position) return null;
885
+ return chunkBXATWUGJ_cjs.getPendingFees(pool, position);
886
+ }, [pool, position]);
887
+ const value = react.useMemo(() => {
888
+ if (!pool || !position) return null;
889
+ return chunkBXATWUGJ_cjs.getPositionValue(pool, position);
890
+ }, [pool, position]);
891
+ react.useEffect(() => {
892
+ mountedRef.current = true;
893
+ if (fetchOnMount) {
894
+ fetchPositionData();
895
+ }
896
+ return () => {
897
+ mountedRef.current = false;
898
+ };
899
+ }, [fetchPositionData, fetchOnMount]);
900
+ react.useEffect(() => {
901
+ if (refreshInterval <= 0 || !poolAddress || !ownerAddress) {
902
+ return;
903
+ }
904
+ const intervalId = setInterval(fetchPositionData, refreshInterval);
905
+ return () => clearInterval(intervalId);
906
+ }, [fetchPositionData, refreshInterval, poolAddress, ownerAddress]);
907
+ return {
908
+ position,
909
+ positionAddress,
910
+ loading,
911
+ error,
912
+ refetch,
913
+ pendingFees,
914
+ value
915
+ };
916
+ }
917
+ function useUserPositions(poolFilter, options = {}) {
918
+ const {
919
+ rpc,
920
+ programId,
921
+ commitment: defaultCommitment,
922
+ refreshInterval: defaultRefreshInterval
923
+ } = useAmm();
924
+ const wallet = useWalletOptional();
925
+ const {
926
+ refreshInterval = defaultRefreshInterval,
927
+ fetchOnMount = true,
928
+ commitment = defaultCommitment
929
+ } = options;
930
+ const [positions, setPositions] = react.useState([]);
931
+ const [loading, setLoading] = react.useState(true);
932
+ const [error, setError] = react.useState(null);
933
+ const mountedRef = react.useRef(true);
934
+ const ownerAddress = wallet?.address;
935
+ const fetchPositions = react.useCallback(async () => {
936
+ if (!ownerAddress) {
937
+ setPositions([]);
938
+ setLoading(false);
939
+ return;
940
+ }
941
+ setLoading(true);
942
+ setError(null);
943
+ try {
944
+ const positionsData = await chunkBXATWUGJ_cjs.fetchUserPositions(
945
+ rpc,
946
+ ownerAddress,
947
+ poolFilter,
948
+ {
949
+ programId,
950
+ commitment
951
+ }
952
+ );
953
+ if (mountedRef.current) {
954
+ setPositions(positionsData.filter((p) => p.account.shares > 0n));
955
+ }
956
+ } catch (err) {
957
+ if (mountedRef.current) {
958
+ setError(err instanceof Error ? err : new Error(String(err)));
959
+ }
960
+ } finally {
961
+ if (mountedRef.current) {
962
+ setLoading(false);
963
+ }
964
+ }
965
+ }, [ownerAddress, poolFilter, rpc, programId, commitment]);
966
+ react.useEffect(() => {
967
+ mountedRef.current = true;
968
+ if (fetchOnMount) {
969
+ fetchPositions();
970
+ }
971
+ return () => {
972
+ mountedRef.current = false;
973
+ };
974
+ }, [fetchPositions, fetchOnMount]);
975
+ react.useEffect(() => {
976
+ if (refreshInterval <= 0 || !ownerAddress) {
977
+ return;
978
+ }
979
+ const intervalId = setInterval(fetchPositions, refreshInterval);
980
+ return () => clearInterval(intervalId);
981
+ }, [fetchPositions, refreshInterval, ownerAddress]);
982
+ return {
983
+ positions,
984
+ loading,
985
+ error,
986
+ refetch: fetchPositions
987
+ };
988
+ }
989
+ function useFees(positionAddress, poolAddress, options = {}) {
990
+ const {
991
+ rpc,
992
+ programId,
993
+ commitment: defaultCommitment,
994
+ refreshInterval: defaultRefreshInterval
995
+ } = useAmm();
996
+ const wallet = useWalletOptional();
997
+ const {
998
+ refreshInterval = defaultRefreshInterval,
999
+ fetchOnMount = true,
1000
+ commitment = defaultCommitment,
1001
+ pool: providedPool,
1002
+ position: providedPosition
1003
+ } = options;
1004
+ const [pool, setPool] = react.useState(providedPool ?? null);
1005
+ const [position, setPosition] = react.useState(
1006
+ providedPosition ?? null
1007
+ );
1008
+ const [loading, setLoading] = react.useState(true);
1009
+ const [refetching, setRefetching] = react.useState(false);
1010
+ const [error, setError] = react.useState(null);
1011
+ const [status, setStatus] = react.useState("idle");
1012
+ const [txError, setTxError] = react.useState(null);
1013
+ const [txSignature, setTxSignature] = react.useState(null);
1014
+ const mountedRef = react.useRef(true);
1015
+ react.useEffect(() => {
1016
+ if (providedPool) setPool(providedPool);
1017
+ if (providedPosition) setPosition(providedPosition);
1018
+ }, [providedPool, providedPosition]);
1019
+ const fees = react.useMemo(() => {
1020
+ if (!pool || !position) return null;
1021
+ const { pending0, pending1 } = chunkBXATWUGJ_cjs.getPendingFees(pool, position);
1022
+ return {
1023
+ pending0,
1024
+ pending1,
1025
+ hasFees: pending0 > 0n || pending1 > 0n
1026
+ };
1027
+ }, [pool, position]);
1028
+ const fetchFeesData = react.useCallback(
1029
+ async (isRefetch = false) => {
1030
+ if (providedPool && providedPosition) {
1031
+ setLoading(false);
1032
+ return;
1033
+ }
1034
+ if (!positionAddress && !providedPosition) {
1035
+ setLoading(false);
1036
+ return;
1037
+ }
1038
+ if (isRefetch) {
1039
+ setRefetching(true);
1040
+ } else {
1041
+ setLoading(true);
1042
+ }
1043
+ setError(null);
1044
+ try {
1045
+ const promises = [];
1046
+ if (!providedPosition && positionAddress) {
1047
+ promises.push(
1048
+ chunkBXATWUGJ_cjs.fetchPosition(rpc, positionAddress, { programId, commitment })
1049
+ );
1050
+ } else {
1051
+ promises.push(Promise.resolve(providedPosition));
1052
+ }
1053
+ if (!providedPool && poolAddress) {
1054
+ promises.push(chunkBXATWUGJ_cjs.fetchPool(rpc, poolAddress, { programId, commitment }));
1055
+ } else {
1056
+ promises.push(Promise.resolve(providedPool));
1057
+ }
1058
+ const [posData, poolData] = await Promise.all(promises);
1059
+ if (mountedRef.current) {
1060
+ if (posData && !providedPosition) setPosition(posData);
1061
+ if (poolData && !providedPool) setPool(poolData);
1062
+ }
1063
+ } catch (err) {
1064
+ if (mountedRef.current) {
1065
+ setError(err instanceof Error ? err : new Error(String(err)));
1066
+ }
1067
+ } finally {
1068
+ if (mountedRef.current) {
1069
+ setLoading(false);
1070
+ setRefetching(false);
1071
+ }
1072
+ }
1073
+ },
1074
+ [
1075
+ positionAddress,
1076
+ poolAddress,
1077
+ providedPool,
1078
+ providedPosition,
1079
+ rpc,
1080
+ programId,
1081
+ commitment
1082
+ ]
1083
+ );
1084
+ const refetch = react.useCallback(async () => {
1085
+ await fetchFeesData(true);
1086
+ }, [fetchFeesData]);
1087
+ const collect = react.useCallback(
1088
+ async (collectOptions) => {
1089
+ if (!pool || !poolAddress || !position || !positionAddress || !wallet?.address) {
1090
+ throw new Error("Pool, position, or wallet not available");
1091
+ }
1092
+ if (!wallet.signer) {
1093
+ throw new Error("Wallet signer is not available");
1094
+ }
1095
+ setStatus("signing");
1096
+ setTxError(null);
1097
+ setTxSignature(null);
1098
+ try {
1099
+ const {
1100
+ max0 = chunkBXATWUGJ_cjs.MAX_FEE_AMOUNT,
1101
+ max1 = chunkBXATWUGJ_cjs.MAX_FEE_AMOUNT,
1102
+ userToken0,
1103
+ userToken1
1104
+ } = collectOptions;
1105
+ const ix = chunkBXATWUGJ_cjs.createCollectFeesInstruction(
1106
+ {
1107
+ pool: poolAddress,
1108
+ position: positionAddress,
1109
+ owner: wallet.address,
1110
+ authority: pool.authority,
1111
+ vault0: pool.vault0,
1112
+ vault1: pool.vault1,
1113
+ token0Mint: pool.token0Mint,
1114
+ token1Mint: pool.token1Mint,
1115
+ user0: userToken0,
1116
+ user1: userToken1
1117
+ },
1118
+ { max0, max1 },
1119
+ programId
1120
+ );
1121
+ const { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment }).send();
1122
+ const baseMessage = kit.createTransactionMessage({ version: "legacy" });
1123
+ const messageWithPayer = kit.setTransactionMessageFeePayerSigner(
1124
+ wallet.signer,
1125
+ baseMessage
1126
+ );
1127
+ const messageWithLifetime = kit.setTransactionMessageLifetimeUsingBlockhash(
1128
+ latestBlockhash,
1129
+ messageWithPayer
1130
+ );
1131
+ const messageWithIx = kit.appendTransactionMessageInstruction(
1132
+ ix,
1133
+ messageWithLifetime
1134
+ );
1135
+ setStatus("sending");
1136
+ const signedTransaction = await kit.signTransactionMessageWithSigners(messageWithIx);
1137
+ const wireTransaction = kit.getBase64EncodedWireTransaction(signedTransaction);
1138
+ const signature = await rpc.sendTransaction(wireTransaction, { encoding: "base64" }).send();
1139
+ setStatus("success");
1140
+ setTxSignature(signature);
1141
+ await fetchFeesData(true);
1142
+ return signature;
1143
+ } catch (err) {
1144
+ setStatus("error");
1145
+ const error2 = err instanceof Error ? err : new Error(String(err));
1146
+ setTxError(error2);
1147
+ throw error2;
1148
+ }
1149
+ },
1150
+ [
1151
+ pool,
1152
+ poolAddress,
1153
+ position,
1154
+ positionAddress,
1155
+ wallet,
1156
+ programId,
1157
+ rpc,
1158
+ commitment,
1159
+ fetchFeesData
1160
+ ]
1161
+ );
1162
+ const reset = react.useCallback(() => {
1163
+ setStatus("idle");
1164
+ setTxError(null);
1165
+ setTxSignature(null);
1166
+ }, []);
1167
+ const canCollect = react.useMemo(() => {
1168
+ return !!(fees?.hasFees && wallet?.connected && wallet?.signer && pool && position);
1169
+ }, [fees, wallet, pool, position]);
1170
+ react.useEffect(() => {
1171
+ mountedRef.current = true;
1172
+ if (fetchOnMount) {
1173
+ fetchFeesData(false);
1174
+ }
1175
+ return () => {
1176
+ mountedRef.current = false;
1177
+ };
1178
+ }, [fetchFeesData, fetchOnMount]);
1179
+ react.useEffect(() => {
1180
+ if (refreshInterval <= 0) {
1181
+ return;
1182
+ }
1183
+ const intervalId = setInterval(() => {
1184
+ fetchFeesData(true);
1185
+ }, refreshInterval);
1186
+ return () => {
1187
+ clearInterval(intervalId);
1188
+ };
1189
+ }, [fetchFeesData, refreshInterval]);
1190
+ return {
1191
+ fees,
1192
+ loading,
1193
+ error,
1194
+ refetch,
1195
+ refetching,
1196
+ collect,
1197
+ status,
1198
+ txError,
1199
+ txSignature,
1200
+ reset,
1201
+ canCollect
1202
+ };
1203
+ }
1204
+ function useFeesFromData(pool, position) {
1205
+ return react.useMemo(() => {
1206
+ if (!pool || !position) return null;
1207
+ const { pending0, pending1 } = chunkBXATWUGJ_cjs.getPendingFees(pool, position);
1208
+ return {
1209
+ pending0,
1210
+ pending1,
1211
+ hasFees: pending0 > 0n || pending1 > 0n
1212
+ };
1213
+ }, [pool, position]);
1214
+ }
1215
+ function useOracle(poolAddress, options = {}) {
1216
+ const {
1217
+ rpc,
1218
+ programId,
1219
+ commitment: defaultCommitment,
1220
+ refreshInterval: defaultRefreshInterval
1221
+ } = useAmm();
1222
+ const {
1223
+ refreshInterval = defaultRefreshInterval,
1224
+ fetchOnMount = true,
1225
+ commitment = defaultCommitment
1226
+ } = options;
1227
+ const [oracle, setOracle] = react.useState(null);
1228
+ const [oracleAddress, setOracleAddress] = react.useState(null);
1229
+ const [loading, setLoading] = react.useState(true);
1230
+ const [error, setError] = react.useState(null);
1231
+ const mountedRef = react.useRef(true);
1232
+ const fetchOracleData = react.useCallback(async () => {
1233
+ if (!poolAddress) {
1234
+ setOracle(null);
1235
+ setOracleAddress(null);
1236
+ setLoading(false);
1237
+ return;
1238
+ }
1239
+ setLoading(true);
1240
+ setError(null);
1241
+ try {
1242
+ const [oracleAddr] = await chunkDPKVNI6Q_cjs.getOracleAddress(poolAddress, programId);
1243
+ setOracleAddress(oracleAddr);
1244
+ const oracleData = await chunkBXATWUGJ_cjs.fetchOracle(rpc, oracleAddr, {
1245
+ programId,
1246
+ commitment
1247
+ });
1248
+ if (mountedRef.current) {
1249
+ setOracle(oracleData);
1250
+ }
1251
+ } catch (err) {
1252
+ if (mountedRef.current) {
1253
+ setError(err instanceof Error ? err : new Error(String(err)));
1254
+ }
1255
+ } finally {
1256
+ if (mountedRef.current) {
1257
+ setLoading(false);
1258
+ }
1259
+ }
1260
+ }, [poolAddress, rpc, programId, commitment]);
1261
+ const refetch = react.useCallback(async () => {
1262
+ await fetchOracleData();
1263
+ }, [fetchOracleData]);
1264
+ const twap = react.useCallback(
1265
+ (windowSeconds) => {
1266
+ if (!oracle || !oracle.initialized) return null;
1267
+ return chunkBXATWUGJ_cjs.consultTwap(oracle, windowSeconds);
1268
+ },
1269
+ [oracle]
1270
+ );
1271
+ const spotPrice = react.useMemo(() => {
1272
+ if (!oracle || !oracle.initialized) return null;
1273
+ const prices = chunkBXATWUGJ_cjs.getOracleSpotPrices(oracle);
1274
+ return { price0: prices.price0, price1: prices.price1 };
1275
+ }, [oracle]);
1276
+ const deviation = react.useMemo(() => {
1277
+ if (!oracle || !oracle.initialized) return null;
1278
+ const dev = chunkBXATWUGJ_cjs.getOracleDeviation(oracle);
1279
+ return { deviation0: dev.deviation0, deviation1: dev.deviation1 };
1280
+ }, [oracle]);
1281
+ const age = react.useMemo(() => {
1282
+ if (!oracle || !oracle.initialized) return null;
1283
+ return chunkBXATWUGJ_cjs.getOracleAge(oracle);
1284
+ }, [oracle]);
1285
+ const isStaleCheck = react.useCallback(
1286
+ (maxAgeSeconds) => {
1287
+ if (!oracle || !oracle.initialized) return true;
1288
+ return chunkBXATWUGJ_cjs.isOracleStale(oracle, maxAgeSeconds);
1289
+ },
1290
+ [oracle]
1291
+ );
1292
+ const bufferStats = react.useMemo(() => {
1293
+ if (!oracle || !oracle.initialized) return null;
1294
+ const stats = chunkBXATWUGJ_cjs.getOracleBufferStats(oracle);
1295
+ return {
1296
+ capacity: stats.capacity,
1297
+ filledCount: stats.filledCount,
1298
+ currentIndex: stats.currentIndex,
1299
+ timeSpanSeconds: stats.timeSpanSeconds
1300
+ };
1301
+ }, [oracle]);
1302
+ const compareWithPool = react.useCallback(
1303
+ (pool) => {
1304
+ if (!oracle || !oracle.initialized) return null;
1305
+ return chunkBXATWUGJ_cjs.comparePoolAndOraclePrices(pool, oracle);
1306
+ },
1307
+ [oracle]
1308
+ );
1309
+ react.useEffect(() => {
1310
+ mountedRef.current = true;
1311
+ if (fetchOnMount) {
1312
+ fetchOracleData();
1313
+ }
1314
+ return () => {
1315
+ mountedRef.current = false;
1316
+ };
1317
+ }, [fetchOracleData, fetchOnMount]);
1318
+ react.useEffect(() => {
1319
+ if (refreshInterval <= 0 || !poolAddress) {
1320
+ return;
1321
+ }
1322
+ const intervalId = setInterval(fetchOracleData, refreshInterval);
1323
+ return () => clearInterval(intervalId);
1324
+ }, [fetchOracleData, refreshInterval, poolAddress]);
1325
+ return {
1326
+ oracle,
1327
+ oracleAddress,
1328
+ loading,
1329
+ error,
1330
+ refetch,
1331
+ twap,
1332
+ spotPrice,
1333
+ deviation,
1334
+ age,
1335
+ isStale: isStaleCheck,
1336
+ bufferStats,
1337
+ compareWithPool
1338
+ };
1339
+ }
1340
+ function useTwap(poolAddress, windowSeconds, options = {}) {
1341
+ const { oracle, loading, error, refetch } = useOracle(poolAddress, options);
1342
+ const twap = react.useMemo(() => {
1343
+ if (!oracle || !oracle.initialized) return null;
1344
+ return chunkBXATWUGJ_cjs.consultTwap(oracle, windowSeconds);
1345
+ }, [oracle, windowSeconds]);
1346
+ return {
1347
+ twap,
1348
+ loading,
1349
+ error,
1350
+ refetch
1351
+ };
1352
+ }
1353
+ function useOracles(poolAddresses, options = {}) {
1354
+ const {
1355
+ rpc,
1356
+ programId,
1357
+ commitment: defaultCommitment,
1358
+ refreshInterval: defaultRefreshInterval
1359
+ } = useAmm();
1360
+ const {
1361
+ refreshInterval = defaultRefreshInterval,
1362
+ fetchOnMount = true,
1363
+ commitment = defaultCommitment
1364
+ } = options;
1365
+ const [oracles, setOracles] = react.useState(
1366
+ /* @__PURE__ */ new Map()
1367
+ );
1368
+ const [loading, setLoading] = react.useState(true);
1369
+ const [error, setError] = react.useState(null);
1370
+ const mountedRef = react.useRef(true);
1371
+ const fetchOracles = react.useCallback(async () => {
1372
+ if (poolAddresses.length === 0) {
1373
+ setOracles(/* @__PURE__ */ new Map());
1374
+ setLoading(false);
1375
+ return;
1376
+ }
1377
+ setLoading(true);
1378
+ setError(null);
1379
+ try {
1380
+ const results = await Promise.all(
1381
+ poolAddresses.map(async (poolAddr) => {
1382
+ try {
1383
+ const result = await chunkBXATWUGJ_cjs.getOracleForPool(rpc, poolAddr, {
1384
+ programId,
1385
+ commitment
1386
+ });
1387
+ return [poolAddr, result];
1388
+ } catch {
1389
+ return [poolAddr, null];
1390
+ }
1391
+ })
1392
+ );
1393
+ if (mountedRef.current) {
1394
+ const oracleMap = /* @__PURE__ */ new Map();
1395
+ for (const [poolAddr, oracleData] of results) {
1396
+ if (oracleData) {
1397
+ oracleMap.set(poolAddr, oracleData);
1398
+ }
1399
+ }
1400
+ setOracles(oracleMap);
1401
+ }
1402
+ } catch (err) {
1403
+ if (mountedRef.current) {
1404
+ setError(err instanceof Error ? err : new Error(String(err)));
1405
+ }
1406
+ } finally {
1407
+ if (mountedRef.current) {
1408
+ setLoading(false);
1409
+ }
1410
+ }
1411
+ }, [poolAddresses, rpc, programId, commitment]);
1412
+ react.useEffect(() => {
1413
+ mountedRef.current = true;
1414
+ if (fetchOnMount) {
1415
+ fetchOracles();
1416
+ }
1417
+ return () => {
1418
+ mountedRef.current = false;
1419
+ };
1420
+ }, [fetchOracles, fetchOnMount]);
1421
+ react.useEffect(() => {
1422
+ if (refreshInterval <= 0 || poolAddresses.length === 0) {
1423
+ return;
1424
+ }
1425
+ const intervalId = setInterval(fetchOracles, refreshInterval);
1426
+ return () => clearInterval(intervalId);
1427
+ }, [fetchOracles, refreshInterval, poolAddresses.length]);
1428
+ return {
1429
+ oracles,
1430
+ loading,
1431
+ error,
1432
+ refetch: fetchOracles
1433
+ };
1434
+ }
1435
+
1436
+ exports.AmmContext = AmmContext;
1437
+ exports.AmmProvider = AmmProvider;
1438
+ exports.EndpointAmmContext = AmmContext2;
1439
+ exports.EndpointAmmProvider = AmmProvider2;
1440
+ exports.WalletContext = WalletContext;
1441
+ exports.WalletProvider = WalletProvider;
1442
+ exports.WalletStandardContext = WalletContext2;
1443
+ exports.WalletStandardProvider = WalletProvider2;
1444
+ exports.createAmmContextValue = createAmmContextValue;
1445
+ exports.createWalletContextValue = createWalletContextValue;
1446
+ exports.useAmm = useAmm;
1447
+ exports.useAmmOptional = useAmmOptional;
1448
+ exports.useEndpointAmm = useAmm2;
1449
+ exports.useFees = useFees;
1450
+ exports.useFeesFromData = useFeesFromData;
1451
+ exports.useLiquidity = useLiquidity;
1452
+ exports.useOracle = useOracle;
1453
+ exports.useOracles = useOracles;
1454
+ exports.usePool = usePool;
1455
+ exports.usePools = usePools;
1456
+ exports.usePosition = usePosition;
1457
+ exports.useStandardWallet = useWallet2;
1458
+ exports.useSwap = useSwap;
1459
+ exports.useTwap = useTwap;
1460
+ exports.useUserPositions = useUserPositions;
1461
+ exports.useWallet = useWallet;
1462
+ exports.useWalletAddress = useWalletAddress;
1463
+ exports.useWalletOptional = useWalletOptional;
1464
+ //# sourceMappingURL=index.cjs.map
1465
+ //# sourceMappingURL=index.cjs.map