@silentswap/react 0.0.88 → 0.0.89

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.
@@ -110,7 +110,7 @@ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bit
110
110
  const transactionAddress = useTransactionAddress(tokenIn, evmAddress, solAddress, bitcoinAddress);
111
111
  const effectiveQuoteAddress = transactionAddress;
112
112
  const { getPrice } = usePrices();
113
- const { serviceFeeRate, overheadUsd, platformHealth: statusPlatformHealth, minimumDepositUusdc, maximumDepositUusdc, outputLimit, identity, volume, liquidity, storage, isLoading: statusLoading, } = useStatus(proId ? { proId } : undefined);
113
+ const { serviceFeeRate, overheadUsd, platformHealth: statusPlatformHealth, minimumDepositUusdc, maximumDepositUusdc, outputLimit, identity, volume, liquidity, storage, isLoading: statusLoading, } = useStatus({ baseUrl: config.baseUrl ?? '', environment: config.environment, proId });
114
114
  const { fetchEstimates, isLoading: egressEstimatesLoading, egressQuotes: egressQuotesFromEstimates, ingressQuote: ingressQuoteFromEstimates, depositAmountUsd: depositAmountUsdFromEstimates, bridgeProviderFromQuote, usdcPrice: usdcPriceFromEstimates, } = useEgressEstimates({
115
115
  evmAddress,
116
116
  solAddress,
@@ -12,14 +12,20 @@ export interface StatusResponse {
12
12
  storage?: Record<string, string>;
13
13
  }
14
14
  export interface UseStatusOptions {
15
+ /** Base URL for the status endpoint (e.g. https://api.silentswap.io) */
16
+ baseUrl: string;
17
+ /** Environment name, used to re-fetch when environment changes */
18
+ environment: string;
15
19
  /** Pro user ID for volume tracking (from ?pro= URL or localStorage) */
16
20
  proId?: string;
17
21
  }
18
22
  /**
19
- * Hook to fetch the current platform status, fee rates, and limits
20
- * When proId is provided, fetches with ?pro= for pro user volume tracking and returns identity/volume/liquidity.
23
+ * Hook to fetch the current platform status, fee rates, and limits.
24
+ * Requires baseUrl and environment to be passed directly (since this hook
25
+ * is called inside SilentSwapInnerProvider before the context is available).
26
+ * When proId is provided, fetches with ?pro= for pro user volume tracking.
21
27
  */
22
- export declare function useStatus(options?: UseStatusOptions): {
28
+ export declare function useStatus(options: UseStatusOptions): {
23
29
  status: StatusResponse;
24
30
  isLoading: boolean;
25
31
  error: Error | null;
@@ -1,72 +1,62 @@
1
1
  import { useState, useEffect } from 'react';
2
- import { useSilentSwap } from '../contexts/SilentSwapContext.js';
2
+ // Module-level cache: survives component unmount/remount and Strict Mode cycles.
3
+ // Keyed by fetch params so a new fetch only happens when params actually change.
4
+ let statusCache = null;
3
5
  /**
4
- * Hook to fetch the current platform status, fee rates, and limits
5
- * When proId is provided, fetches with ?pro= for pro user volume tracking and returns identity/volume/liquidity.
6
+ * Hook to fetch the current platform status, fee rates, and limits.
7
+ * Requires baseUrl and environment to be passed directly (since this hook
8
+ * is called inside SilentSwapInnerProvider before the context is available).
9
+ * When proId is provided, fetches with ?pro= for pro user volume tracking.
6
10
  */
7
11
  export function useStatus(options) {
8
- const { config, client } = useSilentSwap();
9
- const baseUrl = config.baseUrl;
10
- const proId = options?.proId;
11
- const [status, setStatus] = useState({});
12
- const [isLoading, setIsLoading] = useState(true);
12
+ const { baseUrl, environment, proId } = options;
13
+ const fetchKey = `${baseUrl}|${environment}|${proId ?? ''}`;
14
+ const [status, setStatus] = useState(() => statusCache?.key === fetchKey && statusCache.data ? statusCache.data : {});
15
+ const [isLoading, setIsLoading] = useState(() => !(statusCache?.key === fetchKey && statusCache.data && Object.keys(statusCache.data).length > 0));
13
16
  const [error, setError] = useState(null);
14
17
  useEffect(() => {
15
- // Skip if baseUrl is not yet available (shouldn't happen, but safety check)
16
- if (!baseUrl) {
17
- console.warn('[useStatus] baseUrl is not available yet');
18
+ if (!baseUrl)
18
19
  return;
19
- }
20
- // Skip if we're using the default/placeholder context
21
- // The DEFAULT_CONTEXT has client: {} as SilentSwapClient (empty object placeholder)
22
- // Real SilentSwapClient instances are class instances, not plain objects
23
- // Check if client is the placeholder by verifying it's a plain empty object
24
- const isPlaceholderClient = client &&
25
- typeof client === 'object' &&
26
- Object.getPrototypeOf(client) === Object.prototype &&
27
- Object.keys(client).length === 0;
28
- if (isPlaceholderClient) {
29
- console.warn('[useStatus] Context not yet initialized (placeholder client detected), skipping fetch until real context is available');
30
- setIsLoading(false);
31
- return;
32
- }
33
- let isMounted = true;
34
- const fetchStatus = async () => {
35
- try {
36
- setIsLoading(true);
37
- const search = proId ? `?${new URLSearchParams({ pro: proId }).toString()}` : '';
38
- const statusUrl = `${baseUrl}/status${search}`;
39
- console.log('[useStatus] Fetching status from:', statusUrl, 'environment:', config.environment);
40
- const response = await fetch(statusUrl);
41
- if (!response.ok) {
42
- throw new Error(`Failed to fetch status: ${response.statusText}`);
43
- }
44
- const data = await response.json();
45
- if (isMounted) {
46
- console.log('[useStatus] Status fetched successfully from:', statusUrl);
20
+ // Already fetched or in-flight for this exact param set — skip
21
+ if (statusCache?.key === fetchKey) {
22
+ if (statusCache.promise) {
23
+ // In-flight from another mount wait for it and apply
24
+ statusCache.promise.then((data) => {
47
25
  setStatus(data);
48
- setError(null);
49
- }
50
- }
51
- catch (err) {
52
- if (isMounted) {
53
- console.error('[useStatus] Failed to fetch status from:', baseUrl, err);
54
- setError(err instanceof Error ? err : new Error('Failed to fetch status'));
55
- // Use defaults on error
56
- setStatus({});
57
- }
58
- }
59
- finally {
60
- if (isMounted) {
61
26
  setIsLoading(false);
62
- }
27
+ });
63
28
  }
64
- };
65
- fetchStatus();
66
- return () => {
67
- isMounted = false;
68
- };
69
- }, [baseUrl, config.environment, proId]);
29
+ return;
30
+ }
31
+ const search = proId ? `?${new URLSearchParams({ pro: proId }).toString()}` : '';
32
+ const statusUrl = `${baseUrl}/status${search}`;
33
+ console.log('[useStatus] Fetching status from:', statusUrl, 'environment:', environment);
34
+ const promise = fetch(statusUrl)
35
+ .then((response) => {
36
+ if (!response.ok)
37
+ throw new Error(`Failed to fetch status: ${response.statusText}`);
38
+ return response.json();
39
+ })
40
+ .then((data) => {
41
+ console.log('[useStatus] Status fetched successfully from:', statusUrl);
42
+ statusCache = { key: fetchKey, data };
43
+ setStatus(data);
44
+ setError(null);
45
+ return data;
46
+ })
47
+ .catch((err) => {
48
+ console.error('[useStatus] Failed to fetch status from:', baseUrl, err);
49
+ setError(err instanceof Error ? err : new Error('Failed to fetch status'));
50
+ setStatus({});
51
+ statusCache = null; // Allow retry
52
+ return {};
53
+ })
54
+ .finally(() => {
55
+ setIsLoading(false);
56
+ });
57
+ // Claim the slot immediately so no other mount starts a duplicate
58
+ statusCache = { key: fetchKey, data: {}, promise };
59
+ }, [baseUrl, environment, proId, fetchKey]);
70
60
  // Convert overheadUsd from string to number
71
61
  const overheadUsd = status.overheadUsd ? parseFloat(status.overheadUsd) : 0;
72
62
  // serviceFeeRate is a Decimal (0.01 = 1%), convert to number
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@silentswap/react",
3
3
  "type": "module",
4
- "version": "0.0.88",
4
+ "version": "0.0.89",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -24,8 +24,8 @@
24
24
  "dependencies": {
25
25
  "@bigmi/core": "^0.6.5",
26
26
  "@ensdomains/ensjs": "^4.2.0",
27
- "@silentswap/sdk": "0.0.88",
28
- "@silentswap/ui-kit": "0.0.88",
27
+ "@silentswap/sdk": "0.0.89",
28
+ "@silentswap/ui-kit": "0.0.89",
29
29
  "@solana/codecs-strings": "^5.1.0",
30
30
  "@solana/kit": "^5.1.0",
31
31
  "@solana/rpc": "^5.1.0",