@silentswap/react 0.0.78 → 0.0.80

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.
@@ -1,523 +1,47 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
1
  /**
3
- * Output stage enum matching Svelte's OutputStage (string values)
2
+ * Order tracking via WebSocket state and connections live in OrdersContext.
3
+ * This hook subscribes to tracking for (orderId, auth) and returns the state from context.
4
4
  */
5
- export var OutputStage;
6
- (function (OutputStage) {
7
- OutputStage["NONE"] = "NONE";
8
- OutputStage["INIT"] = "INIT";
9
- OutputStage["FUNDED"] = "FUNDED";
10
- OutputStage["REDEEMED"] = "REDEEMED";
11
- OutputStage["IBC_SENT"] = "IBC_SENT";
12
- OutputStage["IBC_RCVD"] = "IBC_RCVD";
13
- OutputStage["BRIDGE_SENT"] = "BRIDGE_SENT";
14
- OutputStage["BRIDGE_CFRM"] = "BRIDGE_CFRM";
15
- OutputStage["BRIDGE_RCVD"] = "BRIDGE_RCVD";
16
- OutputStage["SWAP_USDC_GAS"] = "SWAP_USDC_GAS";
17
- OutputStage["SWAP_USDC_TRG"] = "SWAP_USDC_TRG";
18
- OutputStage["LTRL_TRG_SENT"] = "LTRL_TRG_SENT";
19
- OutputStage["LTRL_TRG_RCVD"] = "LTRL_TRG_RCVD";
20
- OutputStage["SWAP_TRG_DST"] = "SWAP_TRG_DST";
21
- OutputStage["XFER_TRG_DST"] = "XFER_TRG_DST";
22
- OutputStage["REFUND_NATIVE"] = "REFUND_NATIVE";
23
- OutputStage["FINALIZED"] = "FINALIZED";
24
- })(OutputStage || (OutputStage = {}));
25
- /**
26
- * Get human-readable status text from output stage
27
- */
28
- export function getStatusTextFromStage(stage) {
29
- switch (stage) {
30
- case OutputStage.NONE:
31
- return 'Uncertain state';
32
- case OutputStage.INIT:
33
- return 'Verifying deposit';
34
- case OutputStage.FUNDED:
35
- return 'Initializing';
36
- case OutputStage.REDEEMED:
37
- return 'Anonymizing';
38
- case OutputStage.IBC_SENT:
39
- return 'Moving';
40
- case OutputStage.IBC_RCVD:
41
- return 'Staging';
42
- case OutputStage.BRIDGE_SENT:
43
- case OutputStage.BRIDGE_CFRM:
44
- case OutputStage.BRIDGE_RCVD:
45
- return 'Bridging';
46
- case OutputStage.SWAP_USDC_GAS:
47
- return 'Fueling';
48
- case OutputStage.SWAP_USDC_TRG:
49
- return 'Swapping';
50
- case OutputStage.LTRL_TRG_SENT:
51
- case OutputStage.LTRL_TRG_RCVD:
52
- case OutputStage.SWAP_TRG_DST:
53
- return 'Finalizing';
54
- case OutputStage.XFER_TRG_DST:
55
- case OutputStage.REFUND_NATIVE:
56
- case OutputStage.FINALIZED:
57
- return 'Complete';
58
- default:
59
- return 'Processing';
60
- }
61
- }
62
- /**
63
- * Get progress value (0-1) from output stage
64
- */
65
- export function getProgressFromStage(stage) {
66
- switch (stage) {
67
- case OutputStage.NONE:
68
- return 0;
69
- case OutputStage.INIT:
70
- return 0;
71
- case OutputStage.FUNDED:
72
- return 0.1;
73
- case OutputStage.REDEEMED:
74
- return 0.15;
75
- case OutputStage.IBC_SENT:
76
- return 0.25;
77
- case OutputStage.IBC_RCVD:
78
- return 0.35;
79
- case OutputStage.BRIDGE_SENT:
80
- return 0.5;
81
- case OutputStage.BRIDGE_CFRM:
82
- return 0.6;
83
- case OutputStage.BRIDGE_RCVD:
84
- return 0.7;
85
- case OutputStage.SWAP_USDC_GAS:
86
- return 0.8;
87
- case OutputStage.SWAP_USDC_TRG:
88
- return 0.9;
89
- case OutputStage.LTRL_TRG_SENT:
90
- case OutputStage.LTRL_TRG_RCVD:
91
- case OutputStage.SWAP_TRG_DST:
92
- return 0.95;
93
- case OutputStage.XFER_TRG_DST:
94
- case OutputStage.REFUND_NATIVE:
95
- case OutputStage.FINALIZED:
96
- return 1;
97
- default:
98
- return 0;
99
- }
100
- }
101
- /**
102
- * React hook for tracking SilentSwap orders via WebSocket
103
- */
104
- export function useOrderTracking({ client, orderId: initialOrderId, viewingAuth: initialAuth, onStatusUpdate, onError, onComplete, } = {}) {
105
- const [isConnected, setIsConnected] = useState(false);
106
- const [isLoading, setIsLoading] = useState(false);
107
- const [error, setError] = useState(null);
108
- const [orderStatus, setOrderStatus] = useState(null);
109
- const [deposit, setDeposit] = useState(null);
110
- const [outputs, setOutputs] = useState([]);
111
- const [progresses, setProgresses] = useState([undefined]);
112
- const [statusTexts, setStatusTexts] = useState(['Connecting']);
113
- const [completedTimestamp, setCompletedTimestamp] = useState(null);
114
- const [isComplete, setIsComplete] = useState(false);
115
- const wsRef = useRef(null);
116
- const orderIdRef = useRef(initialOrderId);
117
- const authRef = useRef(initialAuth);
118
- const requestCounterRef = useRef(0);
119
- const responseHandlersRef = useRef(new Map());
120
- const reconnectTimeoutRef = useRef(null);
121
- const lastReceivedRef = useRef(0);
122
- const isReconnectingRef = useRef(false);
123
- const reconnectAttemptsRef = useRef(0);
124
- const maxReconnectAttempts = 5; // Maximum number of reconnection attempts
125
- const reconnectDelayRef = useRef(1000); // Initial delay in ms, will increase exponentially
126
- // Track the last connected orderId/auth to prevent unnecessary reconnections
127
- // These are used in both the auto-connect useEffect and the onclose handler
128
- const lastConnectedOrderIdRef = useRef(undefined);
129
- const lastConnectedAuthRef = useRef(undefined);
130
- // Update output state when status changes
131
- const updateOutput = useCallback((index, stage, timestamp = Date.now(), asset) => {
132
- const progress = getProgressFromStage(stage);
133
- const status = getStatusTextFromStage(stage);
134
- setProgresses((prev) => {
135
- const newProgresses = [...prev];
136
- newProgresses[index] = progress;
137
- return newProgresses;
138
- });
139
- setStatusTexts((prev) => {
140
- const newTexts = [...prev];
141
- newTexts[index] = status;
142
- return newTexts;
143
- });
144
- setOutputs((prev) => {
145
- const newOutputs = [...prev];
146
- newOutputs[index] = {
147
- ...newOutputs[index],
148
- index,
149
- stage,
150
- timestamp,
151
- ...(asset ? { asset } : {}),
152
- // Preserve recipient if it exists
153
- ...(prev[index]?.recipient ? { recipient: prev[index].recipient } : {}),
154
- };
155
- return newOutputs;
156
- });
157
- // Check if all outputs are complete
158
- setProgresses((currentProgresses) => {
159
- if (currentProgresses.every((p) => (p ?? 0) >= 1)) {
160
- setIsComplete(true);
161
- setCompletedTimestamp(timestamp);
162
- onComplete?.();
163
- }
164
- return currentProgresses;
165
- });
166
- }, [onComplete]);
167
- // Submit JSON-RPC request
168
- const submitRequest = useCallback((method, params, handler) => {
169
- const ws = wsRef.current;
170
- if (!ws || ws.readyState !== WebSocket.OPEN) {
171
- console.warn('WebSocket not connected, cannot send request');
172
- return -1;
173
- }
174
- const requestId = requestCounterRef.current++;
175
- const request = {
176
- jsonrpc: '2.0',
177
- id: requestId,
178
- method,
179
- params,
180
- };
181
- if (handler) {
182
- responseHandlersRef.current.set(requestId, handler);
183
- }
184
- ws.send(JSON.stringify(request));
185
- return requestId;
186
- }, []);
187
- // Connect to WebSocket using JSON-RPC protocol (matching Svelte implementation)
188
- const connect = useCallback((orderId, auth) => {
189
- orderIdRef.current = orderId;
190
- authRef.current = auth;
191
- setIsLoading(true);
192
- setError(null);
193
- isReconnectingRef.current = false;
194
- // Clear any existing reconnection timeout
195
- if (reconnectTimeoutRef.current) {
196
- clearTimeout(reconnectTimeoutRef.current);
197
- reconnectTimeoutRef.current = null;
198
- }
199
- // Close existing connection
200
- if (wsRef.current) {
201
- wsRef.current.close();
202
- wsRef.current = null;
203
- }
204
- // Clear response handlers
205
- responseHandlersRef.current.clear();
206
- requestCounterRef.current = 0;
207
- // Reset reconnection attempts and delay for new connection
208
- reconnectAttemptsRef.current = 0;
209
- reconnectDelayRef.current = 1000;
210
- // Get WebSocket URL (matching Svelte implementation)
211
- // Use env var if available, otherwise use client baseUrl, otherwise construct from location
212
- // IMPORTANT: URL should be just /websocket with NO path or query params
213
- // Auth is sent via JSON-RPC connect method, not in URL
214
- let wsUrl;
215
- if (typeof window !== 'undefined' && window.__WEBSOCKET_URL__) {
216
- // WebSocket URL from window (for runtime override)
217
- wsUrl = window.__WEBSOCKET_URL__;
218
- }
219
- else if (client) {
220
- // Use client baseUrl (convert http/https to ws/wss)
221
- const baseUrl = client.baseUrl;
222
- try {
223
- const url = new URL(baseUrl);
224
- const protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';
225
- wsUrl = `${protocol}//${url.host}/websocket`;
226
- }
227
- catch {
228
- // If URL parsing fails, try simple string replacement
229
- wsUrl = baseUrl.replace(/^https?:\/\//, 'wss://').replace(/^http:\/\//, 'ws://') + '/websocket';
230
- }
231
- }
232
- else if (typeof window !== 'undefined') {
233
- // Construct from current location
234
- wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${window.location.host}/websocket`;
235
- }
236
- else {
237
- wsUrl = 'ws://localhost/websocket';
238
- }
239
- // Ensure URL doesn't have any path or query params (just /websocket)
240
- // This is critical: the WebSocket URL must be exactly: wss://domain/websocket (no params)
241
- try {
242
- const url = new URL(wsUrl);
243
- // Force protocol to ws/wss (remove any existing path/query)
244
- const protocol = url.protocol === 'https:' || url.protocol === 'wss:' ? 'wss:' : 'ws:';
245
- // Reconstruct URL with only host and /websocket path
246
- wsUrl = `${protocol}//${url.host}/websocket`;
247
- }
248
- catch {
249
- // If URL parsing fails, try to clean it manually
250
- // Remove any query params, hash, or extra paths
251
- wsUrl = wsUrl.split('?')[0].split('#')[0].replace(/\/+$/, '') + '/websocket';
252
- }
253
- try {
254
- const ws = new WebSocket(wsUrl);
255
- wsRef.current = ws;
256
- ws.onopen = () => {
257
- lastReceivedRef.current = Date.now();
258
- setIsConnected(true);
259
- setIsLoading(false);
260
- isReconnectingRef.current = false;
261
- // Reset reconnection attempts on successful connection
262
- reconnectAttemptsRef.current = 0;
263
- reconnectDelayRef.current = 1000;
264
- // Send connect JSON-RPC request (matching Svelte)
265
- const connectRequestId = submitRequest('connect', {
266
- auth: {
267
- orderId,
268
- viewingAuth: auth,
269
- },
270
- }, (error, result) => {
271
- if (error) {
272
- const err = new Error(error.message || 'Connection error');
273
- setError(err);
274
- setIsLoading(false);
275
- onError?.(err);
276
- return;
277
- }
278
- // Handle connected response
279
- const status = result;
280
- setOrderStatus(status);
281
- if (status.deposit) {
282
- setDeposit({
283
- amount: status.deposit.amount,
284
- timestamp: status.deposit.timestamp,
285
- duration: status.deposit.duration,
286
- orderId: status.deposit.orderId,
287
- tx: status.deposit.tx,
288
- });
289
- }
290
- // Initialize outputs
291
- const numOutputs = status.outputs?.length ?? 1;
292
- setProgresses(new Array(numOutputs).fill(undefined));
293
- setStatusTexts(new Array(numOutputs).fill('Connecting'));
294
- // Process initial output statuses
295
- status.outputs?.forEach((output, index) => {
296
- // Set output with recipient information (matching Svelte)
297
- setOutputs((prev) => {
298
- const newOutputs = [...prev];
299
- newOutputs[index] = {
300
- index,
301
- stage: output.stage,
302
- timestamp: output.timestamp,
303
- recipient: output.recipient,
304
- asset: output.output,
305
- txs: output.txs,
306
- };
307
- return newOutputs;
308
- });
309
- // Update progress and status
310
- updateOutput(index, output.stage, output.timestamp, output.output);
311
- });
312
- // Register status handler for subsequent updates (matching Svelte pattern)
313
- // Status updates come as responses to the same request ID
314
- if (connectRequestId >= 0) {
315
- responseHandlersRef.current.set(connectRequestId, (statusError, statusResult) => {
316
- if (statusError) {
317
- const err = new Error(statusError.message || 'Status error');
318
- setError(err);
319
- onError?.(err);
320
- return;
321
- }
322
- // Handle status update
323
- const update = statusResult;
324
- handleStatusUpdate(update);
325
- });
326
- }
327
- onStatusUpdate?.(status);
328
- });
329
- };
330
- ws.onmessage = (event) => {
331
- lastReceivedRef.current = Date.now();
332
- try {
333
- const response = JSON.parse(event.data);
334
- // Validate JSON-RPC response
335
- if (response.jsonrpc !== '2.0' || typeof response.id !== 'number') {
336
- return;
337
- }
338
- // Get handler(s) for this request ID (matching Svelte pattern)
339
- // Status updates come as multiple responses to the same request ID
340
- // So we DON'T delete the handler - it stays registered for subsequent updates
341
- const handler = responseHandlersRef.current.get(response.id);
342
- if (handler) {
343
- // Call handler but DON'T delete it - status updates reuse the same request ID
344
- handler(response.error, response.result);
345
- }
346
- }
347
- catch (parseError) {
348
- console.warn('Failed to parse WebSocket message:', parseError);
349
- }
350
- };
351
- ws.onerror = (event) => {
352
- const err = new Error('WebSocket connection error');
353
- setError(err);
354
- setIsLoading(false);
355
- // Don't call onError here to prevent infinite error logging
356
- // The error will be handled by onclose reconnection logic
357
- };
358
- ws.onclose = async () => {
359
- setIsConnected(false);
360
- responseHandlersRef.current.clear();
361
- // Automatic reconnection with retry limit and exponential backoff
362
- // Only reconnect if we still have valid orderId/auth and we're not already reconnecting
363
- // Also check that the orderId/auth matches what we're supposed to be tracking
364
- if (orderIdRef.current &&
365
- authRef.current &&
366
- !isReconnectingRef.current &&
367
- orderIdRef.current === lastConnectedOrderIdRef.current &&
368
- authRef.current === lastConnectedAuthRef.current) {
369
- // Check if we've exceeded max reconnection attempts
370
- if (reconnectAttemptsRef.current >= maxReconnectAttempts) {
371
- const err = new Error(`WebSocket connection failed after ${maxReconnectAttempts} attempts`);
372
- setError(err);
373
- setIsLoading(false);
374
- onError?.(err);
375
- // Reset attempts after a longer delay (30 seconds) to allow retry later
376
- reconnectTimeoutRef.current = setTimeout(() => {
377
- reconnectAttemptsRef.current = 0;
378
- reconnectDelayRef.current = 1000;
379
- }, 30000);
380
- return;
381
- }
382
- isReconnectingRef.current = true;
383
- reconnectAttemptsRef.current += 1;
384
- // Exponential backoff: delay increases with each attempt (1s, 2s, 4s, 8s, 16s)
385
- const currentDelay = reconnectDelayRef.current;
386
- reconnectDelayRef.current = Math.min(currentDelay * 2, 30000); // Cap at 30 seconds
387
- // If last received was a while ago, add extra delay
388
- const timeSinceLastReceived = Date.now() - lastReceivedRef.current;
389
- const extraDelay = timeSinceLastReceived > 90000 ? 5000 : 0;
390
- const totalDelay = currentDelay + extraDelay;
391
- reconnectTimeoutRef.current = setTimeout(() => {
392
- // Double-check that orderId/auth still match before reconnecting
393
- if (orderIdRef.current &&
394
- authRef.current &&
395
- orderIdRef.current === lastConnectedOrderIdRef.current &&
396
- authRef.current === lastConnectedAuthRef.current) {
397
- isReconnectingRef.current = false; // Reset before connecting
398
- connect(orderIdRef.current, authRef.current);
399
- }
400
- else {
401
- // Order changed, don't reconnect
402
- isReconnectingRef.current = false;
403
- reconnectAttemptsRef.current = 0;
404
- reconnectDelayRef.current = 1000;
405
- }
406
- }, totalDelay);
407
- }
408
- };
409
- }
410
- catch (err) {
411
- const error = err instanceof Error ? err : new Error('Failed to connect to order tracking');
412
- setError(error);
413
- setIsLoading(false);
414
- onError?.(error);
415
- }
416
- }, [submitRequest, updateOutput, onStatusUpdate, onError]);
417
- // Handle status updates
418
- const handleStatusUpdate = useCallback((update) => {
419
- switch (update.type) {
420
- case 'deposit': {
421
- setDeposit({
422
- amount: update.data.amount,
423
- timestamp: update.data.timestamp,
424
- duration: update.data.duration,
425
- orderId: update.data.orderId,
426
- tx: update.data.tx,
427
- });
428
- break;
429
- }
430
- case 'stage': {
431
- updateOutput(update.data.index, update.data.stage, update.data.timestamp, update.data.asset);
432
- break;
433
- }
434
- case 'transaction': {
435
- setOutputs((prev) => {
436
- const newOutputs = [...prev];
437
- if (newOutputs[update.data.index]) {
438
- const existingTxs = newOutputs[update.data.index].txs || {};
439
- newOutputs[update.data.index] = {
440
- ...newOutputs[update.data.index],
441
- txs: {
442
- ...existingTxs,
443
- [update.data.kind]: {
444
- txId: update.data.txId,
445
- chain: update.data.chain,
446
- },
447
- },
448
- };
449
- }
450
- return newOutputs;
451
- });
452
- break;
453
- }
454
- case 'error': {
455
- const err = new Error(update.data.message || 'Order tracking error');
456
- setError(err);
457
- onError?.(err);
458
- break;
459
- }
460
- }
461
- }, [updateOutput, onError]);
462
- // Disconnect from WebSocket
463
- const disconnect = useCallback(() => {
464
- // Clear reconnection timeout
465
- if (reconnectTimeoutRef.current) {
466
- clearTimeout(reconnectTimeoutRef.current);
467
- reconnectTimeoutRef.current = null;
468
- }
469
- isReconnectingRef.current = true; // Prevent reconnection
470
- orderIdRef.current = undefined;
471
- authRef.current = undefined;
472
- if (wsRef.current) {
473
- wsRef.current.close();
474
- wsRef.current = null;
475
- }
476
- responseHandlersRef.current.clear();
477
- setIsConnected(false);
478
- }, []);
479
- // Auto-connect if orderId and auth are provided
5
+ import { useEffect, useMemo } from 'react';
6
+ import { useOrdersContext } from '../../contexts/OrdersContext.js';
7
+ import { getOrderTrackingCacheKey, getStatusTextFromStage, getProgressFromStage, DEFAULT_ORDER_TRACKING_STATE, } from '../../contexts/orderTrackingTypes.js';
8
+ // Re-export types and helpers for consumers
9
+ export { OutputStage, getStatusTextFromStage, getProgressFromStage, getOrderTrackingCacheKey, } from '../../contexts/orderTrackingTypes.js';
10
+ export function useOrderTracking({ client, orderId: initialOrderId, viewingAuth: initialAuth, onStatusUpdate, onError, onComplete, fetchAssetPrice, } = {}) {
11
+ const ctx = useOrdersContext();
12
+ const stableState = useMemo(() => {
13
+ const key = initialOrderId && initialAuth
14
+ ? getOrderTrackingCacheKey(initialOrderId, initialAuth)
15
+ : '';
16
+ const state = key ? ctx.getOrderTrackingState(initialOrderId, initialAuth) : null;
17
+ return state ?? DEFAULT_ORDER_TRACKING_STATE;
18
+ }, [initialOrderId, initialAuth, ctx]);
19
+ const options = useMemo(() => ({
20
+ client,
21
+ onStatusUpdate,
22
+ onError,
23
+ onComplete,
24
+ fetchAssetPrice,
25
+ }), [client, onStatusUpdate, onError, onComplete, fetchAssetPrice]);
26
+ const { connectOrderTracking, disconnectOrderTracking } = ctx;
480
27
  useEffect(() => {
481
- // Only connect if orderId/auth changed or if not yet connected
482
- // Also check if we're already connected to the same orderId/auth to prevent reconnection
483
- const shouldConnect = initialOrderId &&
484
- initialAuth &&
485
- client &&
486
- (lastConnectedOrderIdRef.current !== initialOrderId || lastConnectedAuthRef.current !== initialAuth) &&
487
- !isReconnectingRef.current &&
488
- (!wsRef.current || wsRef.current.readyState === WebSocket.CLOSED);
489
- if (shouldConnect) {
490
- lastConnectedOrderIdRef.current = initialOrderId;
491
- lastConnectedAuthRef.current = initialAuth;
492
- connect(initialOrderId, initialAuth);
493
- }
28
+ if (!initialOrderId || !initialAuth || !client)
29
+ return;
30
+ connectOrderTracking(initialOrderId, initialAuth, options);
494
31
  return () => {
495
- // Only disconnect if we're actually disconnecting (orderId/auth cleared)
496
- if (!initialOrderId || !initialAuth) {
497
- lastConnectedOrderIdRef.current = undefined;
498
- lastConnectedAuthRef.current = undefined;
499
- disconnect();
500
- }
32
+ disconnectOrderTracking(initialOrderId, initialAuth);
501
33
  };
502
- // Only depend on initialOrderId, initialAuth, and client
503
- // Don't include connect/disconnect to prevent infinite loops
504
- // eslint-disable-next-line react-hooks/exhaustive-deps
505
- }, [initialOrderId, initialAuth, client]);
34
+ }, [initialOrderId, initialAuth, client, options, connectOrderTracking, disconnectOrderTracking]);
506
35
  return {
507
- // State
508
- isConnected,
509
- isLoading,
510
- error,
511
- orderStatus,
512
- deposit,
513
- outputs,
514
- progresses,
515
- statusTexts,
516
- completedTimestamp,
517
- isComplete,
518
- // Methods
519
- connect,
520
- disconnect,
36
+ ...stableState,
37
+ connect: (orderId, auth) => {
38
+ ctx.connectOrderTracking(orderId, auth, options);
39
+ },
40
+ disconnect: () => {
41
+ if (initialOrderId && initialAuth) {
42
+ ctx.disconnectOrderTracking(initialOrderId, initialAuth);
43
+ }
44
+ },
521
45
  getStatusText: getStatusTextFromStage,
522
46
  getProgress: getProgressFromStage,
523
47
  };
@@ -290,7 +290,8 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
290
290
  const result = await executeEvmSwap(sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, // Use amount from solveOptimalUsdcAmount (matches Svelte)
291
291
  providerForSwap, orderResponse, evmSignerAddress, // Use EVM signer address, not normalizedAddress
292
292
  viewingAuth, executeEvmBridge, senderContactId, // Pass sender contact ID to extract sender address
293
- integratorId);
293
+ integratorId, // Pass integratorId
294
+ effectiveAllowanceTarget);
294
295
  setOrderId(result.orderId);
295
296
  setViewingAuth(result.viewingAuth);
296
297
  return result;
@@ -504,7 +505,8 @@ viewingAuth, createOrder, executeBitcoinBridge, facilitatorGroup, integratorId)
504
505
  */
505
506
  async function executeEvmSwap(sourceAsset, sourceAmount, usdcAmount, provider, orderResponse, evmSignerAddress, // EVM signer address (matches Svelte's s0x_signer)
506
507
  viewingAuth, executeEvmBridge, senderContactId, // Sender contact ID to extract sender address
507
- integratorId) {
508
+ integratorId, // Optional integrator ID
509
+ allowanceTarget) {
508
510
  // Parse source asset to get chain ID and token address
509
511
  const sourceEvmParsed = parseEvmCaip19(sourceAsset);
510
512
  if (!sourceEvmParsed) {
@@ -531,7 +533,7 @@ integratorId) {
531
533
  const bridgeResult = await executeEvmBridge(sourceChainId, sourceTokenAddress, sourceAmount, usdcAmount, // Use amount from solveOptimalUsdcAmount (matches Svelte)
532
534
  depositParams, evmSignerAddress, // Use EVM signer address for deposit calldata
533
535
  evmSenderAddress, // Use EVM sender address for bridge quotes
534
- provider);
536
+ provider, allowanceTarget);
535
537
  const resultOrderId = orderResponse.response.orderId;
536
538
  // Note: setOrderId is not available in this function scope,
537
539
  // but the orderId will be set by the calling executeSwap function
@@ -3,6 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React, { createContext, useContext, useEffect, useMemo, useCallback } from 'react';
4
4
  import { useStatus } from '../hooks/useStatus.js';
5
5
  import { BigNumber } from 'bignumber.js';
6
+ const MAX_DEPOSIT_USD = 25000;
6
7
  const PlatformHealthContext = createContext(undefined);
7
8
  /**
8
9
  * Provider that monitors platform health from status API and provides validation functions
@@ -103,12 +104,12 @@ export function PlatformHealthProvider({ children, proId, onFormDisabledChange,
103
104
  return { valid: false, error: 'Amount must be greater than zero' };
104
105
  }
105
106
  const minUsd = getMinimumDepositUsd();
106
- const maxUsd = getMaximumDepositUsd();
107
+ const maxUsd = Math.min(MAX_DEPOSIT_USD, getMaximumDepositUsd() ?? MAX_DEPOSIT_USD);
107
108
  if (minUsd !== null && amount < minUsd) {
108
- return { valid: false, error: `Minimum deposit is $${minUsd.toFixed(2)}` };
109
+ return { valid: false, error: `Minimum value is $${minUsd.toFixed(2)}` };
109
110
  }
110
111
  if (maxUsd !== null && amount > maxUsd) {
111
- return { valid: false, error: `Maximum deposit is $${maxUsd.toFixed(2)}` };
112
+ return { valid: false, error: `Maximum value is $${maxUsd.toFixed(2)}` };
112
113
  }
113
114
  return { valid: true };
114
115
  }, [getMinimumDepositUsd, getMaximumDepositUsd]);
package/dist/index.d.ts CHANGED
@@ -1,19 +1,21 @@
1
1
  export { useSilentClient } from './hooks/silent/useSilentClient.js';
2
2
  export { PricesProvider, usePricesContext } from './contexts/PricesContext.js';
3
3
  export type { PricesContextType } from './contexts/PricesContext.js';
4
+ export { SwapFormEstimatesProvider, useSwapFormEstimatesContext, } from './contexts/SwapFormEstimatesContext.js';
5
+ export type { SwapFormEstimatesContextType, SwapFormEstimatesProviderProps, } from './contexts/SwapFormEstimatesContext.js';
4
6
  export { AssetsProvider, useAssetsContext } from './contexts/AssetsContext.js';
5
7
  export type { AssetsContextType, Chain, ChainInfo } from './contexts/AssetsContext.js';
6
8
  export { BalancesProvider, useBalancesContext } from './contexts/BalancesContext.js';
7
9
  export type { BalancesContextType, UserBalance } from './contexts/BalancesContext.js';
8
10
  export { OrdersProvider, useOrdersContext, useWalletFacilitatorGroups } from './contexts/OrdersContext.js';
9
- export type { OrdersContextOrderMetadata, OrdersContextOrder, FacilitatorGroup, OrdersContextType } from './contexts/OrdersContext.js';
11
+ export type { OrdersContextOrderMetadata, OrdersContextOrder, OrderDestination, FacilitatorGroup, OrdersContextType } from './contexts/OrdersContext.js';
10
12
  export { SilentSwapProvider, useSilentSwap } from './contexts/SilentSwapContext.js';
11
13
  export type { SilentSwapContextType } from './contexts/SilentSwapContext.js';
12
14
  export { useSilentOrders } from './hooks/silent/useSilentOrders.js';
13
15
  export { useAuth } from './hooks/silent/useAuth.js';
14
16
  export { useWallet } from './hooks/silent/useWallet.js';
15
17
  export { useSilentQuote } from './hooks/silent/useSilentQuote.js';
16
- export { useOrderTracking, OutputStage, getStatusTextFromStage, getProgressFromStage, } from './hooks/silent/useOrderTracking.js';
18
+ export { useOrderTracking, OutputStage, getStatusTextFromStage, getProgressFromStage, getOrderTrackingCacheKey, } from './hooks/silent/useOrderTracking.js';
17
19
  export { useRefund } from './hooks/silent/useRefund.js';
18
20
  export { useTransaction } from './hooks/useTransaction.js';
19
21
  export { useQuote } from './hooks/useQuote.js';
@@ -52,9 +54,10 @@ export type { useTransactionOptions, useTransactionReturn } from './hooks/useTra
52
54
  export type { useQuoteOptions, useQuoteReturn } from './hooks/useQuote.js';
53
55
  export type { OrderEstimateResult, UseOrderEstimatesOptions } from './hooks/useOrderEstimates.js';
54
56
  export type { usePricesOptions, usePricesReturn, CachedPrice } from './hooks/usePrices.js';
55
- export type { UseOrderTrackingOptions, UseOrderTrackingReturn, OrderDeposit, OutputStatus, OrderStatus, StatusUpdate, } from './hooks/silent/useOrderTracking.js';
57
+ export type { UseOrderTrackingOptions, UseOrderTrackingReturn, OrderDeposit, OutputStatus, OrderStatus, StatusUpdate, OrderTrackingState, OrderTrackingOptions, } from './hooks/silent/useOrderTracking.js';
56
58
  export type { UseRefundOptions, UseRefundReturn } from './hooks/silent/useRefund.js';
57
59
  export { createSolanaTransactionExecutor, convertRelaySolanaStepToTransaction, } from './hooks/silent/solana-transaction.js';
58
60
  export type { SolanaWalletConnector, SolanaConnection } from './hooks/silent/solana-transaction.js';
59
61
  export { createBitcoinTransactionExecutor, convertRelayBitcoinStepToTransaction, } from './hooks/silent/bitcoin-transaction.js';
60
62
  export type { BitcoinWalletConnector, BitcoinConnection } from './hooks/silent/bitcoin-transaction.js';
63
+ export type { Outputs, IOutput } from './contexts/orderTrackingTypes.js';