@silentswap/react 0.0.86 → 0.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contexts/SilentSwapContext.d.ts +35 -13
- package/dist/contexts/SilentSwapContext.js +61 -27
- package/dist/contexts/SwapFormEstimatesContext.js +69 -1
- package/dist/hooks/silent/useSilentQuote.js +7 -4
- package/dist/hooks/usePlatformHealth.d.ts +6 -5
- package/dist/hooks/usePlatformHealth.js +12 -11
- package/dist/index.d.ts +1 -1
- package/package.json +3 -3
|
@@ -1,12 +1,43 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type Connector } from 'wagmi';
|
|
3
3
|
import { type WalletClient } from 'viem';
|
|
4
|
+
import type { PlatformHealthStatus } from '../hooks/usePlatformHealth.js';
|
|
4
5
|
import { ENVIRONMENT, type SilentSwapClient, type SilentSwapClientConfig, type AuthResponse, type QuoteResponse, type CalculationDirection } from '@silentswap/sdk';
|
|
5
6
|
import { type ExecuteSwapParams, type SwapResult } from '../hooks/silent/useSilentQuote.js';
|
|
6
7
|
import { type OutputStatus } from '../hooks/silent/useOrderTracking.js';
|
|
7
8
|
import { type SolanaWalletConnector, type SolanaConnection } from '../hooks/silent/solana-transaction.js';
|
|
8
9
|
import { type BitcoinWalletConnector, type BitcoinConnection } from '../hooks/silent/bitcoin-transaction.js';
|
|
9
10
|
import { type SilentSwapWallet } from '../hooks/silent/useWallet.js';
|
|
11
|
+
export interface SilentSwapStatusData {
|
|
12
|
+
platformHealth: PlatformHealthStatus | undefined;
|
|
13
|
+
serviceFeeRate: number;
|
|
14
|
+
overheadUsd: number;
|
|
15
|
+
minimumDepositUusdc: string | undefined;
|
|
16
|
+
maximumDepositUusdc: string | undefined;
|
|
17
|
+
outputLimit: number | undefined;
|
|
18
|
+
identity: string | undefined;
|
|
19
|
+
volume: number | undefined;
|
|
20
|
+
liquidity: number | undefined;
|
|
21
|
+
storage: Record<string, string> | undefined;
|
|
22
|
+
isLoading: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface SilentSwapFees {
|
|
25
|
+
serviceFeeUsd: number;
|
|
26
|
+
bridgeFeeIngressUsd: number;
|
|
27
|
+
bridgeFeeEgressUsd: number;
|
|
28
|
+
slippageUsd: number;
|
|
29
|
+
}
|
|
30
|
+
export interface SilentSwapOrderTracking {
|
|
31
|
+
progresses: (number | undefined)[];
|
|
32
|
+
statusTexts: string[];
|
|
33
|
+
isComplete: boolean;
|
|
34
|
+
error: Error | null;
|
|
35
|
+
outputs: OutputStatus[];
|
|
36
|
+
}
|
|
37
|
+
export interface SilentSwapEstimates {
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
fetchEstimates: (direction?: CalculationDirection) => Promise<void>;
|
|
40
|
+
}
|
|
10
41
|
export interface SilentSwapContextType {
|
|
11
42
|
client: SilentSwapClient;
|
|
12
43
|
environment: ENVIRONMENT;
|
|
@@ -26,19 +57,10 @@ export interface SilentSwapContextType {
|
|
|
26
57
|
clearQuote: () => void;
|
|
27
58
|
depositAmountUsdc: number;
|
|
28
59
|
loadingAmounts: boolean;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
orderOutputs: OutputStatus[];
|
|
34
|
-
serviceFeeUsd: number;
|
|
35
|
-
bridgeFeeIngressUsd: number;
|
|
36
|
-
bridgeFeeEgressUsd: number;
|
|
37
|
-
slippageUsd: number;
|
|
38
|
-
serviceFeeRate: number;
|
|
39
|
-
overheadUsd: number;
|
|
40
|
-
egressEstimatesLoading: boolean;
|
|
41
|
-
fetchEstimates: (direction?: CalculationDirection) => Promise<void>;
|
|
60
|
+
status: SilentSwapStatusData;
|
|
61
|
+
fees: SilentSwapFees;
|
|
62
|
+
order: SilentSwapOrderTracking;
|
|
63
|
+
estimates: SilentSwapEstimates;
|
|
42
64
|
handleNewSwap: () => void;
|
|
43
65
|
solanaRpcUrl?: string;
|
|
44
66
|
}
|
|
@@ -40,19 +40,36 @@ const DEFAULT_CONTEXT = {
|
|
|
40
40
|
clearQuote: () => { },
|
|
41
41
|
depositAmountUsdc: 0,
|
|
42
42
|
loadingAmounts: false,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
status: {
|
|
44
|
+
platformHealth: undefined,
|
|
45
|
+
serviceFeeRate: 0,
|
|
46
|
+
overheadUsd: 0,
|
|
47
|
+
minimumDepositUusdc: undefined,
|
|
48
|
+
maximumDepositUusdc: undefined,
|
|
49
|
+
outputLimit: undefined,
|
|
50
|
+
identity: undefined,
|
|
51
|
+
volume: undefined,
|
|
52
|
+
liquidity: undefined,
|
|
53
|
+
storage: undefined,
|
|
54
|
+
isLoading: true,
|
|
55
|
+
},
|
|
56
|
+
fees: {
|
|
57
|
+
serviceFeeUsd: 0,
|
|
58
|
+
bridgeFeeIngressUsd: 0,
|
|
59
|
+
bridgeFeeEgressUsd: 0,
|
|
60
|
+
slippageUsd: 0,
|
|
61
|
+
},
|
|
62
|
+
order: {
|
|
63
|
+
progresses: [],
|
|
64
|
+
statusTexts: [],
|
|
65
|
+
isComplete: false,
|
|
66
|
+
error: null,
|
|
67
|
+
outputs: [],
|
|
68
|
+
},
|
|
69
|
+
estimates: {
|
|
70
|
+
isLoading: false,
|
|
71
|
+
fetchEstimates: async (_direction) => { },
|
|
72
|
+
},
|
|
56
73
|
handleNewSwap: () => { },
|
|
57
74
|
};
|
|
58
75
|
const SilentSwapContext = createContext(DEFAULT_CONTEXT);
|
|
@@ -93,7 +110,7 @@ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bit
|
|
|
93
110
|
const transactionAddress = useTransactionAddress(tokenIn, evmAddress, solAddress, bitcoinAddress);
|
|
94
111
|
const effectiveQuoteAddress = transactionAddress;
|
|
95
112
|
const { getPrice } = usePrices();
|
|
96
|
-
const { serviceFeeRate, overheadUsd } = useStatus();
|
|
113
|
+
const { serviceFeeRate, overheadUsd, platformHealth: statusPlatformHealth, minimumDepositUusdc, maximumDepositUusdc, outputLimit, identity, volume, liquidity, storage, isLoading: statusLoading, } = useStatus(proId ? { proId } : undefined);
|
|
97
114
|
const { fetchEstimates, isLoading: egressEstimatesLoading, egressQuotes: egressQuotesFromEstimates, ingressQuote: ingressQuoteFromEstimates, depositAmountUsd: depositAmountUsdFromEstimates, bridgeProviderFromQuote, usdcPrice: usdcPriceFromEstimates, } = useEgressEstimates({
|
|
98
115
|
evmAddress,
|
|
99
116
|
solAddress,
|
|
@@ -206,19 +223,36 @@ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bit
|
|
|
206
223
|
clearQuote,
|
|
207
224
|
depositAmountUsdc,
|
|
208
225
|
loadingAmounts,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
226
|
+
status: {
|
|
227
|
+
platformHealth: statusPlatformHealth,
|
|
228
|
+
serviceFeeRate,
|
|
229
|
+
overheadUsd,
|
|
230
|
+
minimumDepositUusdc,
|
|
231
|
+
maximumDepositUusdc,
|
|
232
|
+
outputLimit,
|
|
233
|
+
identity,
|
|
234
|
+
volume,
|
|
235
|
+
liquidity,
|
|
236
|
+
storage,
|
|
237
|
+
isLoading: statusLoading,
|
|
238
|
+
},
|
|
239
|
+
fees: {
|
|
240
|
+
serviceFeeUsd: effectiveServiceFeeUsd,
|
|
241
|
+
bridgeFeeIngressUsd: effectiveBridgeFeeIngressUsd,
|
|
242
|
+
bridgeFeeEgressUsd: effectiveBridgeFeeEgressUsd,
|
|
243
|
+
slippageUsd,
|
|
244
|
+
},
|
|
245
|
+
order: {
|
|
246
|
+
progresses: orderProgresses,
|
|
247
|
+
statusTexts: orderStatusTexts,
|
|
248
|
+
isComplete: orderComplete,
|
|
249
|
+
error: orderTrackingError,
|
|
250
|
+
outputs: orderOutputs,
|
|
251
|
+
},
|
|
252
|
+
estimates: {
|
|
253
|
+
isLoading: egressEstimatesLoading,
|
|
254
|
+
fetchEstimates,
|
|
255
|
+
},
|
|
222
256
|
handleNewSwap,
|
|
223
257
|
solanaRpcUrl,
|
|
224
258
|
}, children: children });
|
|
@@ -6,6 +6,10 @@ import { usePlatformHealthContext } from '../hooks/usePlatformHealth.js';
|
|
|
6
6
|
import { usePricesContext } from './PricesContext.js';
|
|
7
7
|
import { getAssetByCaip19, CALCULATION_DIRECTION_INPUT_TO_OUTPUT, CALCULATION_DIRECTION_OUTPUT_TO_INPUT, } from '@silentswap/sdk';
|
|
8
8
|
const XT_DELAY_DEBOUNCE_QUOTE = 550;
|
|
9
|
+
// After a reverse (output-to-input) calculation completes, ignore re-trigger attempts
|
|
10
|
+
// for this duration. Bridge quotes aren't perfectly deterministic, so the calculated
|
|
11
|
+
// input oscillates slightly each cycle — the cooldown prevents infinite loops.
|
|
12
|
+
const REVERSE_CALC_SETTLE_MS = 2000;
|
|
9
13
|
const SwapFormEstimatesContext = createContext(undefined);
|
|
10
14
|
export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, serviceFeeRate: serviceFeeRateOverride, }) {
|
|
11
15
|
const setSplits = useSwap((state) => state.setSplits);
|
|
@@ -24,6 +28,7 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
24
28
|
const programmaticInputChangeRef = useRef(false);
|
|
25
29
|
const shouldFetchAfterInputRecalcRef = useRef(false);
|
|
26
30
|
const isFetchingEstimatesRef = useRef(false);
|
|
31
|
+
const reverseCalcTimestampRef = useRef(0);
|
|
27
32
|
const [calculationDirection, setCalculationDirection] = React.useState(CALCULATION_DIRECTION_INPUT_TO_OUTPUT);
|
|
28
33
|
const calculationDirectionRef = useRef(CALCULATION_DIRECTION_INPUT_TO_OUTPUT);
|
|
29
34
|
// Refs for destination amount calculation (from useDestinationAmountCalculation)
|
|
@@ -37,6 +42,14 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
37
42
|
if (isDraggingSlider) {
|
|
38
43
|
return;
|
|
39
44
|
}
|
|
45
|
+
console.log('[SwapFormEstimates] scheduleFetchEstimates called', {
|
|
46
|
+
immediate,
|
|
47
|
+
direction,
|
|
48
|
+
effectiveDirection: direction || calculationDirectionRef.current || CALCULATION_DIRECTION_INPUT_TO_OUTPUT,
|
|
49
|
+
isFetching: isFetchingEstimatesRef.current,
|
|
50
|
+
cooldownMs: Date.now() - reverseCalcTimestampRef.current,
|
|
51
|
+
caller: new Error().stack?.split('\n')[2]?.trim(),
|
|
52
|
+
});
|
|
40
53
|
if (debounceTimerRef.current) {
|
|
41
54
|
clearTimeout(debounceTimerRef.current);
|
|
42
55
|
debounceTimerRef.current = null;
|
|
@@ -47,6 +60,12 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
47
60
|
calculationDirectionRef.current = effectiveDirection;
|
|
48
61
|
setCalculationDirection(effectiveDirection);
|
|
49
62
|
}
|
|
63
|
+
// Set the cooldown timestamp at the START of a reverse calc (not just in .finally())
|
|
64
|
+
// so that effects firing DURING the fetch (e.g. ref-change effect triggered by
|
|
65
|
+
// SilentSwapAppProvider re-renders) are already within the cooldown window.
|
|
66
|
+
if (effectiveDirection === CALCULATION_DIRECTION_OUTPUT_TO_INPUT) {
|
|
67
|
+
reverseCalcTimestampRef.current = Date.now();
|
|
68
|
+
}
|
|
50
69
|
isFetchingEstimatesRef.current = true;
|
|
51
70
|
const fetchPromise = immediate
|
|
52
71
|
? fetchEstimatesRef.current(effectiveDirection)
|
|
@@ -67,6 +86,13 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
67
86
|
console.error('Failed to fetch estimates:', err);
|
|
68
87
|
})
|
|
69
88
|
.finally(() => {
|
|
89
|
+
// When a reverse (output-to-input) calculation completes, it updates inputAmount
|
|
90
|
+
// programmatically. Record the timestamp so ALL re-trigger paths (initial-fetch
|
|
91
|
+
// effect AND ref-change effect) will skip during the cooldown window. This prevents
|
|
92
|
+
// infinite loops caused by non-deterministic bridge quotes oscillating slightly.
|
|
93
|
+
if (effectiveDirection === CALCULATION_DIRECTION_OUTPUT_TO_INPUT) {
|
|
94
|
+
reverseCalcTimestampRef.current = Date.now();
|
|
95
|
+
}
|
|
70
96
|
isFetchingEstimatesRef.current = false;
|
|
71
97
|
});
|
|
72
98
|
}, [isDraggingSlider]);
|
|
@@ -77,8 +103,25 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
77
103
|
React.useEffect(() => {
|
|
78
104
|
const prev = fetchEstimatesRef.current;
|
|
79
105
|
fetchEstimatesRef.current = fetchEstimates;
|
|
80
|
-
// When fetchEstimates changes and we had already fetched, re-trigger
|
|
106
|
+
// When fetchEstimates changes and we had already fetched, re-trigger —
|
|
107
|
+
// but NOT if we're currently fetching (avoids scheduling a duplicate) or
|
|
108
|
+
// if a reverse calc is in progress / recently completed (SilentSwapAppProvider
|
|
109
|
+
// re-renders frequently during fetches, giving fetchEstimates a new identity).
|
|
81
110
|
if (prev !== fetchEstimates && lastFetchedKeyRef.current) {
|
|
111
|
+
const cooldownMs = Date.now() - reverseCalcTimestampRef.current;
|
|
112
|
+
if (isFetchingEstimatesRef.current ||
|
|
113
|
+
cooldownMs < REVERSE_CALC_SETTLE_MS) {
|
|
114
|
+
console.log('[SwapFormEstimates] ref-change effect SKIPPED (loop guard)', {
|
|
115
|
+
isFetching: isFetchingEstimatesRef.current,
|
|
116
|
+
cooldownMs,
|
|
117
|
+
direction: calculationDirectionRef.current,
|
|
118
|
+
});
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
console.log('[SwapFormEstimates] ref-change effect TRIGGERING fetch', {
|
|
122
|
+
cooldownMs,
|
|
123
|
+
direction: calculationDirectionRef.current,
|
|
124
|
+
});
|
|
82
125
|
lastFetchedKeyRef.current = null;
|
|
83
126
|
scheduleFetchEstimates(true);
|
|
84
127
|
}
|
|
@@ -220,10 +263,12 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
220
263
|
}, [tokenIn, setSplits, setInputAmount, getPrice, getServiceFeeRate]);
|
|
221
264
|
// Handle slider change (splits changed)
|
|
222
265
|
const handleSliderChange = useCallback(() => {
|
|
266
|
+
reverseCalcTimestampRef.current = 0;
|
|
223
267
|
scheduleFetchEstimates();
|
|
224
268
|
}, [scheduleFetchEstimates]);
|
|
225
269
|
// Handle destination amount change (user manually edited)
|
|
226
270
|
const handleDestinationAmountChange = useCallback(() => {
|
|
271
|
+
reverseCalcTimestampRef.current = 0;
|
|
227
272
|
// Mark that this is a manual destination change
|
|
228
273
|
// This prevents performDestinationAmountCalculation from overwriting user's changes
|
|
229
274
|
isManualDestinationChangeRef.current = true;
|
|
@@ -240,6 +285,7 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
240
285
|
}, [recalculateSplitsFromAmounts, scheduleFetchEstimates]);
|
|
241
286
|
// Handle input amount change (user manually edited)
|
|
242
287
|
const handleInputAmountChange = useCallback(() => {
|
|
288
|
+
reverseCalcTimestampRef.current = 0;
|
|
243
289
|
// Mark as user-initiated change (not programmatic)
|
|
244
290
|
programmaticInputChangeRef.current = false;
|
|
245
291
|
shouldFetchAfterInputRecalcRef.current = false;
|
|
@@ -345,6 +391,14 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
345
391
|
if (programmaticInputChangeRef.current) {
|
|
346
392
|
return;
|
|
347
393
|
}
|
|
394
|
+
// Skip recalculation during the reverse-calc cooldown window.
|
|
395
|
+
// A reverse calc just set inputAmount programmatically — recalculating
|
|
396
|
+
// destination amounts from this input would overwrite the user's desired
|
|
397
|
+
// output values and could feed back into another reverse cycle.
|
|
398
|
+
if (Date.now() - reverseCalcTimestampRef.current < REVERSE_CALC_SETTLE_MS) {
|
|
399
|
+
console.log('[SwapFormEstimates] dest-calc effect SKIPPED (reverse calc cooldown)');
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
348
402
|
const splitsKey = splits.join(',');
|
|
349
403
|
const hasSplitsChanged = prevSplitsRef.current !== splitsKey;
|
|
350
404
|
const hasInputAmountChanged = prevInputAmountForCalcRef.current !== inputAmount;
|
|
@@ -414,14 +468,28 @@ export function SwapFormEstimatesProvider({ children, tokenIn, fetchEstimates, s
|
|
|
414
468
|
useEffect(() => {
|
|
415
469
|
// Skip if we're already fetching to prevent loops
|
|
416
470
|
if (isFetchingEstimatesRef.current) {
|
|
471
|
+
console.log('[SwapFormEstimates] initial-fetch effect SKIPPED (already fetching)', { estimateKey });
|
|
417
472
|
// Update lastFetchedKeyRef to the new key to prevent re-triggering when fetch completes
|
|
418
473
|
if (estimateKey) {
|
|
419
474
|
lastFetchedKeyRef.current = estimateKey;
|
|
420
475
|
}
|
|
421
476
|
return;
|
|
422
477
|
}
|
|
478
|
+
// After a reverse calculation (output-to-input) completes, it programmatically
|
|
479
|
+
// updates inputAmount which changes estimateKey. Skip re-fetching during the
|
|
480
|
+
// cooldown window to avoid an infinite loop (bridge quotes aren't perfectly
|
|
481
|
+
// deterministic, so the calculated input oscillates slightly each cycle).
|
|
482
|
+
const cooldownMs = Date.now() - reverseCalcTimestampRef.current;
|
|
483
|
+
if (cooldownMs < REVERSE_CALC_SETTLE_MS) {
|
|
484
|
+
console.log('[SwapFormEstimates] initial-fetch effect SKIPPED (reverse calc cooldown)', { cooldownMs, estimateKey });
|
|
485
|
+
if (estimateKey) {
|
|
486
|
+
lastFetchedKeyRef.current = estimateKey;
|
|
487
|
+
}
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
423
490
|
// Only fetch if we have a valid estimate key and it's different from the last one we fetched
|
|
424
491
|
if (estimateKey && estimateKey !== lastFetchedKeyRef.current) {
|
|
492
|
+
console.log('[SwapFormEstimates] initial-fetch effect TRIGGERING fetch', { estimateKey, lastKey: lastFetchedKeyRef.current });
|
|
425
493
|
// Mark this key as fetched to prevent duplicate calls
|
|
426
494
|
lastFetchedKeyRef.current = estimateKey;
|
|
427
495
|
// Use the debounced fetch function to avoid rapid duplicate calls
|
|
@@ -280,10 +280,13 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
280
280
|
if (sourceAssetMatch) {
|
|
281
281
|
const sourceChainId = parseInt(sourceAssetMatch[1]);
|
|
282
282
|
const tokenAddress = sourceAssetMatch[2];
|
|
283
|
-
await approveTokenSpending(sourceChainId, tokenAddress, effectiveAllowanceTarget, sourceAmountInUnits, evmSignerAddress);
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
|
|
283
|
+
const approvalHash = await approveTokenSpending(sourceChainId, tokenAddress, effectiveAllowanceTarget, sourceAmountInUnits, evmSignerAddress);
|
|
284
|
+
// Only delay if an approval tx was actually sent (null means allowance was already sufficient)
|
|
285
|
+
if (approvalHash) {
|
|
286
|
+
// Delay after approve so RPC/nodes confirm approval before next tx (avoids MetaMask RPC errors)
|
|
287
|
+
setCurrentStep('Waiting for network...');
|
|
288
|
+
await new Promise((resolve) => setTimeout(resolve, APPROVE_POST_DELAY_MS));
|
|
289
|
+
}
|
|
287
290
|
}
|
|
288
291
|
}
|
|
289
292
|
// Handle EVM bridge swaps
|
|
@@ -28,8 +28,8 @@ export type PlatformHealthContextType = {
|
|
|
28
28
|
export type PlatformHealthProviderProps = {
|
|
29
29
|
children: React.ReactNode;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
31
|
+
* @deprecated proId is now read from the parent SilentSwapContext (passed via SilentSwapProvider).
|
|
32
|
+
* This prop is ignored.
|
|
33
33
|
*/
|
|
34
34
|
proId?: string;
|
|
35
35
|
/**
|
|
@@ -44,10 +44,11 @@ export type PlatformHealthProviderProps = {
|
|
|
44
44
|
onTrackingDisabledChange?: (disabled: boolean) => void;
|
|
45
45
|
};
|
|
46
46
|
/**
|
|
47
|
-
* Provider that monitors platform health from
|
|
48
|
-
* for deposit amounts, output limits,
|
|
47
|
+
* Provider that monitors platform health from SilentSwapContext (which calls useStatus
|
|
48
|
+
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
49
|
+
* and service fee rates.
|
|
49
50
|
*/
|
|
50
|
-
export declare function PlatformHealthProvider({ children,
|
|
51
|
+
export declare function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, }: PlatformHealthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
51
52
|
/**
|
|
52
53
|
* Hook to access platform health context
|
|
53
54
|
*/
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import React, { createContext, useContext, useEffect, useMemo, useCallback } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { useSilentSwap } from '../contexts/SilentSwapContext.js';
|
|
5
5
|
import { BigNumber } from 'bignumber.js';
|
|
6
6
|
const MAX_DEPOSIT_USD = 25000;
|
|
7
7
|
const PlatformHealthContext = createContext(undefined);
|
|
8
8
|
/**
|
|
9
|
-
* Provider that monitors platform health from
|
|
10
|
-
* for deposit amounts, output limits,
|
|
9
|
+
* Provider that monitors platform health from SilentSwapContext (which calls useStatus
|
|
10
|
+
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
11
|
+
* and service fee rates.
|
|
11
12
|
*/
|
|
12
|
-
export function PlatformHealthProvider({ children,
|
|
13
|
-
|
|
13
|
+
export function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, }) {
|
|
14
|
+
// Consume status data from parent SilentSwapContext instead of calling useStatus again
|
|
15
|
+
const { status } = useSilentSwap();
|
|
16
|
+
const { platformHealth: statusPlatformHealth, maximumDepositUusdc, minimumDepositUusdc, outputLimit, serviceFeeRate, overheadUsd, identity, volume, liquidity, storage, } = status;
|
|
14
17
|
// Normalize platform health status
|
|
15
18
|
const platformHealth = useMemo(() => {
|
|
16
19
|
if (!statusPlatformHealth)
|
|
@@ -88,14 +91,12 @@ export function PlatformHealthProvider({ children, proId, onFormDisabledChange,
|
|
|
88
91
|
}
|
|
89
92
|
}, [maximumDepositUusdc]);
|
|
90
93
|
const getServiceFeeRate = useCallback(() => {
|
|
91
|
-
if (
|
|
94
|
+
if (serviceFeeRate == null)
|
|
92
95
|
return 0.01;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
catch {
|
|
96
|
+
const rate = +serviceFeeRate;
|
|
97
|
+
if (isNaN(rate))
|
|
97
98
|
return 0.01;
|
|
98
|
-
|
|
99
|
+
return rate;
|
|
99
100
|
}, [serviceFeeRate]);
|
|
100
101
|
// Validate deposit amount against min/max limits
|
|
101
102
|
const validateDepositAmount = useCallback((usdAmount) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type { BalancesContextType, UserBalance } from './contexts/BalancesContex
|
|
|
10
10
|
export { OrdersProvider, useOrdersContext, useWalletFacilitatorGroups } from './contexts/OrdersContext.js';
|
|
11
11
|
export type { OrdersContextOrderMetadata, OrdersContextOrder, OrderDestination, FacilitatorGroup, OrdersContextType } from './contexts/OrdersContext.js';
|
|
12
12
|
export { SilentSwapProvider, useSilentSwap } from './contexts/SilentSwapContext.js';
|
|
13
|
-
export type { SilentSwapContextType } from './contexts/SilentSwapContext.js';
|
|
13
|
+
export type { SilentSwapContextType, SilentSwapStatusData, SilentSwapFees, SilentSwapOrderTracking, SilentSwapEstimates, } from './contexts/SilentSwapContext.js';
|
|
14
14
|
export { useSilentOrders } from './hooks/silent/useSilentOrders.js';
|
|
15
15
|
export { useAuth } from './hooks/silent/useAuth.js';
|
|
16
16
|
export { useWallet } from './hooks/silent/useWallet.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silentswap/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.88",
|
|
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.
|
|
28
|
-
"@silentswap/ui-kit": "0.0.
|
|
27
|
+
"@silentswap/sdk": "0.0.88",
|
|
28
|
+
"@silentswap/ui-kit": "0.0.88",
|
|
29
29
|
"@solana/codecs-strings": "^5.1.0",
|
|
30
30
|
"@solana/kit": "^5.1.0",
|
|
31
31
|
"@solana/rpc": "^5.1.0",
|