@silentswap/react 0.0.41

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.
Files changed (86) hide show
  1. package/README.md +48 -0
  2. package/dist/contexts/AssetsContext.d.ts +24 -0
  3. package/dist/contexts/AssetsContext.js +83 -0
  4. package/dist/contexts/BalancesContext.d.ts +28 -0
  5. package/dist/contexts/BalancesContext.js +533 -0
  6. package/dist/contexts/OrdersContext.d.ts +53 -0
  7. package/dist/contexts/OrdersContext.js +240 -0
  8. package/dist/contexts/PricesContext.d.ts +12 -0
  9. package/dist/contexts/PricesContext.js +109 -0
  10. package/dist/contexts/SilentSwapContext.d.ts +58 -0
  11. package/dist/contexts/SilentSwapContext.js +205 -0
  12. package/dist/hooks/silent/orderTrackingWebSocketManager.d.ts +48 -0
  13. package/dist/hooks/silent/orderTrackingWebSocketManager.js +284 -0
  14. package/dist/hooks/silent/solana-transaction.d.ts +60 -0
  15. package/dist/hooks/silent/solana-transaction.js +236 -0
  16. package/dist/hooks/silent/useAuth.d.ts +90 -0
  17. package/dist/hooks/silent/useAuth.js +269 -0
  18. package/dist/hooks/silent/useBridgeExecution.d.ts +39 -0
  19. package/dist/hooks/silent/useBridgeExecution.js +877 -0
  20. package/dist/hooks/silent/useOrderSigning.d.ts +34 -0
  21. package/dist/hooks/silent/useOrderSigning.js +133 -0
  22. package/dist/hooks/silent/useOrderTracking.d.ts +174 -0
  23. package/dist/hooks/silent/useOrderTracking.js +524 -0
  24. package/dist/hooks/silent/useQuoteCalculation.d.ts +50 -0
  25. package/dist/hooks/silent/useQuoteCalculation.js +331 -0
  26. package/dist/hooks/silent/useQuoteFetching.d.ts +18 -0
  27. package/dist/hooks/silent/useQuoteFetching.js +54 -0
  28. package/dist/hooks/silent/useRefund.d.ts +26 -0
  29. package/dist/hooks/silent/useRefund.js +134 -0
  30. package/dist/hooks/silent/useSilentClient.d.ts +16 -0
  31. package/dist/hooks/silent/useSilentClient.js +32 -0
  32. package/dist/hooks/silent/useSilentOrders.d.ts +174 -0
  33. package/dist/hooks/silent/useSilentOrders.js +73 -0
  34. package/dist/hooks/silent/useSilentQuote.d.ts +88 -0
  35. package/dist/hooks/silent/useSilentQuote.js +381 -0
  36. package/dist/hooks/silent/useWallet.d.ts +76 -0
  37. package/dist/hooks/silent/useWallet.js +203 -0
  38. package/dist/hooks/useAssetPrice.d.ts +8 -0
  39. package/dist/hooks/useAssetPrice.js +47 -0
  40. package/dist/hooks/useContacts.d.ts +52 -0
  41. package/dist/hooks/useContacts.js +259 -0
  42. package/dist/hooks/useEgressEstimates.d.ts +32 -0
  43. package/dist/hooks/useEgressEstimates.js +230 -0
  44. package/dist/hooks/useHiddenSwapFees.d.ts +22 -0
  45. package/dist/hooks/useHiddenSwapFees.js +81 -0
  46. package/dist/hooks/useOrderEstimates.d.ts +37 -0
  47. package/dist/hooks/useOrderEstimates.js +393 -0
  48. package/dist/hooks/useOutputAssetInfo.d.ts +12 -0
  49. package/dist/hooks/useOutputAssetInfo.js +38 -0
  50. package/dist/hooks/usePrices.d.ts +60 -0
  51. package/dist/hooks/usePrices.js +188 -0
  52. package/dist/hooks/useQuote.d.ts +73 -0
  53. package/dist/hooks/useQuote.js +507 -0
  54. package/dist/hooks/useResetSwapForm.d.ts +16 -0
  55. package/dist/hooks/useResetSwapForm.js +68 -0
  56. package/dist/hooks/useSlippageUsd.d.ts +11 -0
  57. package/dist/hooks/useSlippageUsd.js +19 -0
  58. package/dist/hooks/useSolanaAdapter.d.ts +15 -0
  59. package/dist/hooks/useSolanaAdapter.js +55 -0
  60. package/dist/hooks/useStatus.d.ts +25 -0
  61. package/dist/hooks/useStatus.js +60 -0
  62. package/dist/hooks/useSwap.d.ts +67 -0
  63. package/dist/hooks/useSwap.js +285 -0
  64. package/dist/hooks/useTransaction.d.ts +119 -0
  65. package/dist/hooks/useTransaction.js +353 -0
  66. package/dist/hooks/useTransactionAddress.d.ts +11 -0
  67. package/dist/hooks/useTransactionAddress.js +26 -0
  68. package/dist/hooks/useUsdValue.d.ts +7 -0
  69. package/dist/hooks/useUsdValue.js +19 -0
  70. package/dist/index.d.ts +54 -0
  71. package/dist/index.js +41 -0
  72. package/dist/stories/SilentSwapOverview.stories.d.ts +10 -0
  73. package/dist/stories/SilentSwapOverview.stories.js +364 -0
  74. package/dist/stories/useAuth.stories.d.ts +6 -0
  75. package/dist/stories/useAuth.stories.js +55 -0
  76. package/dist/stories/useSilentClient.stories.d.ts +9 -0
  77. package/dist/stories/useSilentClient.stories.js +39 -0
  78. package/dist/stories/useSilentOrders.stories.d.ts +1 -0
  79. package/dist/stories/useSilentOrders.stories.js +1 -0
  80. package/dist/stories/useSilentQuote.stories.d.ts +6 -0
  81. package/dist/stories/useSilentQuote.stories.js +267 -0
  82. package/dist/stories/useTransaction.stories.d.ts +6 -0
  83. package/dist/stories/useTransaction.stories.js +121 -0
  84. package/dist/utils/formatters.d.ts +33 -0
  85. package/dist/utils/formatters.js +82 -0
  86. package/package.json +67 -0
@@ -0,0 +1,240 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useState, useEffect, useCallback, useMemo, useRef } from 'react';
4
+ import { bytes_to_base58, DepositStatus, hex_to_bytes } from '@silentswap/sdk';
5
+ import { useLocalStorage } from 'usehooks-ts';
6
+ import { useSilentSwap } from './SilentSwapContext.js';
7
+ export const useWalletFacilitatorGroups = (wallet, setFacilitatorGroups) => {
8
+ // Automatically set facilitator groups from wallet (matches Svelte behavior)
9
+ // In Svelte: UserState.facilitatorGroups = a_accounts.map(g => g.group) when wallet loads
10
+ // This ensures orders can be fetched even after page refresh, since wallet data is in sessionStorage
11
+ // The wallet entropy is persisted in sessionStorage, and groups are recreated from it
12
+ useEffect(() => {
13
+ if (wallet?.accounts && wallet.accounts.length > 0) {
14
+ // Replace facilitator groups with wallet accounts (matches Svelte assignment behavior)
15
+ // This prevents duplication and ensures groups match the current wallet state
16
+ setFacilitatorGroups(wallet.accounts.map((account) => account.group));
17
+ }
18
+ else if (!wallet) {
19
+ // Clear groups when wallet is null (matches Svelte reset behavior)
20
+ setFacilitatorGroups([]);
21
+ }
22
+ }, [wallet, setFacilitatorGroups]);
23
+ };
24
+ const OrdersContext = createContext(undefined);
25
+ export const OrdersProvider = ({ children }) => {
26
+ const [orders, setOrders] = useState([]);
27
+ const [loading, setLoading] = useState(false);
28
+ const [facilitatorGroups, setFacilitatorGroupsState] = useState([]);
29
+ const [orderIdToViewingAuth, setOrderIdToViewingAuth] = useLocalStorage('orderIdToViewingAuth', {}, { initializeWithValue: true });
30
+ const [orderIdToDefaultPublicKey, setOrderIdToDefaultPublicKey] = useLocalStorage('orderIdToDefaultPublicKey', {}, { initializeWithValue: true });
31
+ // Generate viewing auth token from facilitator group
32
+ const facilitator_group_authorize_order_view = useCallback(async (groupGetter) => {
33
+ try {
34
+ const k_group = await groupGetter();
35
+ const k_viewer = await k_group.viewer();
36
+ const y_signer_viewer = await k_viewer.evmSigner();
37
+ // Reformat its 20-byte address to base58 for compactness
38
+ return bytes_to_base58(hex_to_bytes(y_signer_viewer.address.replace(/^0x/, '')));
39
+ }
40
+ catch (error) {
41
+ console.warn('Failed to authorize order view:', error);
42
+ return '';
43
+ }
44
+ }, []);
45
+ // Get baseUrl from environment
46
+ const { config } = useSilentSwap();
47
+ const baseUrl = config.baseUrl;
48
+ // Fetch recent orders from API (matches Svelte implementation)
49
+ const request_recent_orders = useCallback(async (sb58_auth_view) => {
50
+ try {
51
+ // Request current orders from backend using facilitator auth
52
+ const d_res = await fetch(`${baseUrl}/recent?${new URLSearchParams({
53
+ auth: sb58_auth_view,
54
+ })}`);
55
+ // Parse response body
56
+ const sx_res = await d_res.text();
57
+ // Attempt to parse JSON (with safe parsing like Svelte)
58
+ let a_orders;
59
+ try {
60
+ const parsed = JSON.parse(sx_res);
61
+ if (Array.isArray(parsed)) {
62
+ a_orders = parsed.filter((order) => order !== null && typeof order === 'object' && 'orderId' in order);
63
+ }
64
+ else {
65
+ throw new Error('Response is not an array');
66
+ }
67
+ }
68
+ catch (parseError) {
69
+ throw new Error('Unable to retrieve recent orders');
70
+ }
71
+ // Add order ID to viewing auth map (same as Svelte)
72
+ // Use functional update to avoid dependency on orderIdToViewingAuth
73
+ setOrderIdToViewingAuth((prevMapping) => {
74
+ const newMapping = { ...prevMapping };
75
+ for (const g_order of a_orders) {
76
+ newMapping[g_order.orderId] = sb58_auth_view;
77
+ }
78
+ return newMapping;
79
+ });
80
+ return a_orders;
81
+ }
82
+ catch (error) {
83
+ console.warn('Failed to fetch recent orders:', error);
84
+ throw error;
85
+ }
86
+ }, [baseUrl, setOrderIdToViewingAuth]);
87
+ // Store facilitatorGroups in a ref for use in loadOrders
88
+ const facilitatorGroupsRef = useRef(facilitatorGroups);
89
+ useEffect(() => {
90
+ facilitatorGroupsRef.current = facilitatorGroups;
91
+ }, [facilitatorGroups]);
92
+ const loadOrders = useCallback(async () => {
93
+ // Get fresh facilitatorGroups from ref to avoid stale closures
94
+ const currentGroups = facilitatorGroupsRef.current;
95
+ if (currentGroups.length === 0)
96
+ return;
97
+ setLoading(true);
98
+ try {
99
+ const a_all_orders = [];
100
+ // Fetch orders for each facilitator group
101
+ await Promise.all(currentGroups.map(async (f_group) => {
102
+ try {
103
+ const sb58_auth_view = await facilitator_group_authorize_order_view(f_group);
104
+ const a_recents = await request_recent_orders(sb58_auth_view);
105
+ // At least one is complete - convert all others in INIT state to REPLACED
106
+ const b_complete = !!a_recents?.find((g) => 'COMPLETE' === g.status);
107
+ if (b_complete) {
108
+ for (const g of a_recents) {
109
+ if ('INIT' === g.status)
110
+ g.status = 'REPLACED';
111
+ }
112
+ }
113
+ // Update orders; augmenting with auth
114
+ a_all_orders.push(...a_recents.map((g) => ({ ...g, auth: sb58_auth_view })));
115
+ }
116
+ catch (error) {
117
+ console.warn('Failed to load orders for facilitator group:', error);
118
+ }
119
+ }));
120
+ // Sort by modification time (newest first)
121
+ a_all_orders.sort((g_a, g_b) => (g_b.modified ?? 0) - (g_a.modified ?? 0));
122
+ setOrders(a_all_orders);
123
+ }
124
+ catch (error) {
125
+ console.error('Failed to load orders:', error);
126
+ }
127
+ finally {
128
+ setLoading(false);
129
+ }
130
+ }, [facilitator_group_authorize_order_view, request_recent_orders]);
131
+ // Store loadOrders in a ref to avoid dependency issues
132
+ const loadOrdersRef = useRef(loadOrders);
133
+ useEffect(() => {
134
+ loadOrdersRef.current = loadOrders;
135
+ }, [loadOrders]);
136
+ // Poll for recent orders when facilitator groups change (matching Svelte $effect behavior)
137
+ // In Svelte: $effect(() => { ... }) watches UserState.facilitatorGroups array reference
138
+ useEffect(() => {
139
+ if (facilitatorGroups.length === 0)
140
+ return;
141
+ // Initial load when groups change (matches Svelte $effect behavior)
142
+ loadOrdersRef.current();
143
+ }, [facilitatorGroups]); // Depend on array reference to trigger when groups are replaced
144
+ const addFacilitatorGroup = useCallback((group) => {
145
+ // Add a single facilitator group (for manual additions, e.g., after swap)
146
+ setFacilitatorGroupsState((prev) => {
147
+ // Check if group already exists to prevent duplicates
148
+ // Since groups are functions, we can't easily compare them, so we'll just append
149
+ // The main use case is setFacilitatorGroups which replaces the array
150
+ return [...prev, group];
151
+ });
152
+ }, []);
153
+ const setFacilitatorGroups = useCallback((groups) => {
154
+ // Replace facilitator groups (matches Svelte UserState.facilitatorGroups = ... behavior)
155
+ setFacilitatorGroupsState(groups);
156
+ }, []);
157
+ const setOrderDefaultPublicKey = useCallback((orderId, publicKey) => {
158
+ setOrderIdToDefaultPublicKey((prev) => ({
159
+ ...prev,
160
+ [orderId]: publicKey,
161
+ }));
162
+ }, [setOrderIdToDefaultPublicKey]);
163
+ const clearFacilitatorGroups = useCallback(() => {
164
+ setFacilitatorGroupsState([]);
165
+ setOrders([]);
166
+ setOrderIdToViewingAuth({});
167
+ setOrderIdToDefaultPublicKey({});
168
+ }, [setOrderIdToViewingAuth, setOrderIdToDefaultPublicKey]);
169
+ const refreshOrders = useCallback(() => {
170
+ loadOrders();
171
+ }, [loadOrders]);
172
+ // Helper function to get order age text
173
+ const getOrderAgeText = useCallback((modified) => {
174
+ if (!modified)
175
+ return 'Unknown';
176
+ const xt_age = Date.now() - modified;
177
+ const xt_minutes = Math.round(xt_age / 60000);
178
+ const xt_hours = Math.min(999, Math.round(xt_age / 3600000));
179
+ if (xt_age < 90 * 60 * 1000) {
180
+ // Less than 90 minutes
181
+ return xt_minutes <= 1 ? '1 min ago' : `${xt_minutes} min ago`;
182
+ }
183
+ else {
184
+ return xt_hours <= 1 ? '1 hr ago' : `${xt_hours} hr ago`;
185
+ }
186
+ }, []);
187
+ // Helper function to get status display info
188
+ const getStatusInfo = useCallback((status, refundEligibility) => {
189
+ if (!refundEligibility?.refundable && refundEligibility?.code === DepositStatus.ABORTED) {
190
+ return { text: 'Aborted', pulsing: false, color: 'text-gray-400' };
191
+ }
192
+ switch (status) {
193
+ case 'INIT':
194
+ return { text: 'Waiting for deposit', pulsing: true, color: 'text-white' };
195
+ case 'REPLACED':
196
+ return { text: 'Replaced', pulsing: false, color: 'text-gray-400' };
197
+ case 'IN_PROGRESS':
198
+ return { text: 'In progress', pulsing: true, color: 'text-white' };
199
+ case 'COMPLETE':
200
+ return { text: 'Completed', pulsing: false, color: 'text-green-400' };
201
+ default:
202
+ return { text: status, pulsing: false, color: 'text-white' };
203
+ }
204
+ }, []);
205
+ const value = useMemo(() => ({
206
+ orders,
207
+ loading,
208
+ facilitatorGroups,
209
+ orderIdToViewingAuth,
210
+ orderIdToDefaultPublicKey,
211
+ addFacilitatorGroup,
212
+ setFacilitatorGroups,
213
+ clearFacilitatorGroups,
214
+ setOrderDefaultPublicKey,
215
+ refreshOrders,
216
+ getOrderAgeText,
217
+ getStatusInfo,
218
+ }), [
219
+ orders,
220
+ loading,
221
+ facilitatorGroups,
222
+ orderIdToViewingAuth,
223
+ orderIdToDefaultPublicKey,
224
+ addFacilitatorGroup,
225
+ setFacilitatorGroups,
226
+ clearFacilitatorGroups,
227
+ setOrderDefaultPublicKey,
228
+ refreshOrders,
229
+ getOrderAgeText,
230
+ getStatusInfo,
231
+ ]);
232
+ return _jsx(OrdersContext.Provider, { value: value, children: children });
233
+ };
234
+ export const useOrdersContext = () => {
235
+ const context = useContext(OrdersContext);
236
+ if (context === undefined) {
237
+ throw new Error('useOrdersContext must be used within an OrdersProvider');
238
+ }
239
+ return context;
240
+ };
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import type { AssetInfo } from '@silentswap/sdk';
3
+ export type PricesContextType = {
4
+ prices: Record<string, number | undefined>;
5
+ getPrice: (asset: AssetInfo | null) => number | undefined;
6
+ isLoading: (caip19: string) => boolean;
7
+ refetchPrice: (asset: AssetInfo) => Promise<void>;
8
+ };
9
+ export declare const PricesProvider: React.FC<{
10
+ children: React.ReactNode;
11
+ }>;
12
+ export declare const usePricesContext: () => PricesContextType;
@@ -0,0 +1,109 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useState, useCallback, useMemo } from 'react';
4
+ import { usePrices } from '../hooks/usePrices.js';
5
+ const PRICE_STALE_AGE = 10 * 1000; // 10 seconds in milliseconds
6
+ const PricesContext = createContext(undefined);
7
+ export const PricesProvider = ({ children }) => {
8
+ const { getPrice: fetchPrice } = usePrices();
9
+ const [priceData, setPriceData] = useState({});
10
+ const [loadingAssets, setLoadingAssets] = useState(new Set());
11
+ // Fetch price for an asset and cache it with timestamp
12
+ const fetchAndCachePrice = useCallback(async (asset) => {
13
+ const caip19 = asset.caip19;
14
+ // Skip if already loading
15
+ if (loadingAssets.has(caip19)) {
16
+ return;
17
+ }
18
+ setLoadingAssets((prev) => new Set(prev).add(caip19));
19
+ try {
20
+ const price = await fetchPrice(asset);
21
+ const now = Date.now();
22
+ setPriceData((prev) => ({
23
+ ...prev,
24
+ [caip19]: {
25
+ price,
26
+ timestamp: now,
27
+ },
28
+ }));
29
+ }
30
+ catch (error) {
31
+ console.warn(`Failed to fetch price for ${caip19}:`, error);
32
+ const now = Date.now();
33
+ setPriceData((prev) => ({
34
+ ...prev,
35
+ [caip19]: {
36
+ price: undefined,
37
+ timestamp: now,
38
+ },
39
+ }));
40
+ }
41
+ finally {
42
+ setLoadingAssets((prev) => {
43
+ const next = new Set(prev);
44
+ next.delete(caip19);
45
+ return next;
46
+ });
47
+ }
48
+ }, [fetchPrice, loadingAssets]);
49
+ // Check if price is stale (older than 10 seconds)
50
+ const isPriceStale = useCallback((caip19) => {
51
+ const data = priceData[caip19];
52
+ if (!data)
53
+ return true;
54
+ const age = Date.now() - data.timestamp;
55
+ return age > PRICE_STALE_AGE;
56
+ }, [priceData]);
57
+ // Get price from cache or trigger fetch
58
+ const getPrice = useCallback((asset) => {
59
+ if (!asset)
60
+ return undefined;
61
+ const caip19 = asset.caip19;
62
+ const data = priceData[caip19];
63
+ // If no cached data, trigger fetch
64
+ if (!data) {
65
+ if (!loadingAssets.has(caip19)) {
66
+ fetchAndCachePrice(asset);
67
+ }
68
+ return undefined;
69
+ }
70
+ // If price is stale, trigger refetch in background
71
+ if (isPriceStale(caip19)) {
72
+ if (!loadingAssets.has(caip19)) {
73
+ fetchAndCachePrice(asset);
74
+ }
75
+ }
76
+ // Return cached price (even if stale, to avoid flickering)
77
+ return data.price;
78
+ }, [priceData, loadingAssets, fetchAndCachePrice, isPriceStale]);
79
+ // Check if price is loading
80
+ const isLoading = useCallback((caip19) => {
81
+ return loadingAssets.has(caip19);
82
+ }, [loadingAssets]);
83
+ // Refetch price for an asset
84
+ const refetchPrice = useCallback(async (asset) => {
85
+ await fetchAndCachePrice(asset);
86
+ }, [fetchAndCachePrice]);
87
+ // Convert priceData to prices record for backward compatibility
88
+ const prices = useMemo(() => {
89
+ const result = {};
90
+ Object.entries(priceData).forEach(([caip19, data]) => {
91
+ result[caip19] = data.price;
92
+ });
93
+ return result;
94
+ }, [priceData]);
95
+ const value = useMemo(() => ({
96
+ prices,
97
+ getPrice,
98
+ isLoading,
99
+ refetchPrice,
100
+ }), [prices, getPrice, isLoading, refetchPrice]);
101
+ return _jsx(PricesContext.Provider, { value: value, children: children });
102
+ };
103
+ export const usePricesContext = () => {
104
+ const context = useContext(PricesContext);
105
+ if (context === undefined) {
106
+ throw new Error('usePricesContext must be used within a PricesProvider');
107
+ }
108
+ return context;
109
+ };
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { type Connector } from 'wagmi';
3
+ import { type WalletClient } from 'viem';
4
+ import { ENVIRONMENT, type SilentSwapClient, type SilentSwapClientConfig, type AuthResponse, type QuoteResponse } from '@silentswap/sdk';
5
+ import { type ExecuteSwapParams, type SwapResult } from '../hooks/silent/useSilentQuote.js';
6
+ import { type OutputStatus } from '../hooks/silent/useOrderTracking.js';
7
+ import { type SolanaWalletConnector, type SolanaConnection } from '../hooks/silent/solana-transaction.js';
8
+ import { type SilentSwapWallet } from '../hooks/silent/useWallet.js';
9
+ export interface SilentSwapContextType {
10
+ client: SilentSwapClient;
11
+ environment: ENVIRONMENT;
12
+ config: SilentSwapClientConfig;
13
+ wallet: SilentSwapWallet | null;
14
+ walletLoading: boolean;
15
+ auth: AuthResponse | null;
16
+ authLoading: boolean;
17
+ executeSwap: (params: ExecuteSwapParams) => Promise<SwapResult | null>;
18
+ swapLoading: boolean;
19
+ isSwapping: boolean;
20
+ currentStep?: string;
21
+ swapError: Error | null;
22
+ quote: QuoteResponse | null;
23
+ orderId: string | null;
24
+ viewingAuth: string | null;
25
+ clearQuote: () => void;
26
+ depositAmountUsdc: number;
27
+ loadingAmounts: boolean;
28
+ orderProgresses: (number | undefined)[];
29
+ orderStatusTexts: string[];
30
+ orderComplete: boolean;
31
+ orderTrackingError: Error | null;
32
+ orderOutputs: OutputStatus[];
33
+ serviceFeeUsd: number;
34
+ bridgeFeeIngressUsd: number;
35
+ bridgeFeeEgressUsd: number;
36
+ slippageUsd: number;
37
+ serviceFeeRate: number;
38
+ overheadUsd: number;
39
+ egressEstimatesLoading: boolean;
40
+ fetchEstimates: (direction?: 'input-to-output' | 'output-to-input') => Promise<void>;
41
+ handleNewSwap: () => void;
42
+ solanaRpcUrl?: string;
43
+ }
44
+ export declare function useSilentSwap(): SilentSwapContextType;
45
+ export declare function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, environment, baseUrl, solanaRpcUrl, walletClient, }: {
46
+ children: React.ReactNode;
47
+ client: SilentSwapClient;
48
+ evmAddress?: string;
49
+ solAddress?: string;
50
+ connector?: Connector;
51
+ isConnected?: boolean;
52
+ walletClient?: WalletClient;
53
+ solanaConnector?: SolanaWalletConnector;
54
+ solanaConnection?: SolanaConnection;
55
+ environment?: ENVIRONMENT;
56
+ baseUrl?: string;
57
+ solanaRpcUrl?: string;
58
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,205 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect, useMemo } from 'react';
4
+ import { useAuth } from '../hooks/silent/useAuth.js';
5
+ import { useWallet } from '../hooks/silent/useWallet.js';
6
+ import { useSilentQuote } from '../hooks/silent/useSilentQuote.js';
7
+ import { useOrderTracking } from '../hooks/silent/useOrderTracking.js';
8
+ import { usePrices } from '../hooks/usePrices.js';
9
+ import { useSwap } from '../hooks/useSwap.js';
10
+ import { useEgressEstimates } from '../hooks/useEgressEstimates.js';
11
+ import { useStatus } from '../hooks/useStatus.js';
12
+ import { useHiddenSwapFees } from '../hooks/useHiddenSwapFees.js';
13
+ import { useSlippageUsd } from '../hooks/useSlippageUsd.js';
14
+ import { useResetSwapForm } from '../hooks/useResetSwapForm.js';
15
+ import { useTransactionAddress } from '../hooks/useTransactionAddress.js';
16
+ import { PricesProvider } from './PricesContext.js';
17
+ import { AssetsProvider } from './AssetsContext.js';
18
+ import { BalancesProvider } from './BalancesContext.js';
19
+ import { OrdersProvider, useOrdersContext, useWalletFacilitatorGroups } from './OrdersContext.js';
20
+ import { ENVIRONMENT, ENVIRONMENT_CONFIGS, } from '@silentswap/sdk';
21
+ const DEFAULT_CONTEXT = {
22
+ client: {}, // Placeholder
23
+ environment: ENVIRONMENT.STAGING,
24
+ config: {
25
+ environment: ENVIRONMENT.STAGING,
26
+ baseUrl: ENVIRONMENT_CONFIGS[ENVIRONMENT.STAGING].baseUrl,
27
+ },
28
+ wallet: null,
29
+ walletLoading: false,
30
+ auth: null,
31
+ authLoading: false,
32
+ executeSwap: async () => null,
33
+ swapLoading: false,
34
+ isSwapping: false,
35
+ currentStep: '',
36
+ swapError: null,
37
+ quote: null,
38
+ orderId: null,
39
+ viewingAuth: null,
40
+ clearQuote: () => { },
41
+ depositAmountUsdc: 0,
42
+ loadingAmounts: false,
43
+ orderProgresses: [],
44
+ orderStatusTexts: [],
45
+ orderComplete: false,
46
+ orderTrackingError: null,
47
+ orderOutputs: [],
48
+ serviceFeeUsd: 0,
49
+ bridgeFeeIngressUsd: 0,
50
+ bridgeFeeEgressUsd: 0,
51
+ slippageUsd: 0,
52
+ serviceFeeRate: 0,
53
+ overheadUsd: 0,
54
+ egressEstimatesLoading: false,
55
+ fetchEstimates: async (_direction) => { },
56
+ handleNewSwap: () => { },
57
+ };
58
+ const SilentSwapContext = createContext(DEFAULT_CONTEXT);
59
+ export function useSilentSwap() {
60
+ const context = useContext(SilentSwapContext);
61
+ if (!context) {
62
+ throw new Error('useSilentSwap must be used within a SilentSwapProvider');
63
+ }
64
+ return context;
65
+ }
66
+ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, solanaConnector, solanaConnection, environment, config, solanaRpcUrl, connector, isConnected = false, walletClient, }) {
67
+ // Authentication hook - only for EVM
68
+ const { auth, isLoading: authLoading } = useAuth({
69
+ client,
70
+ address: evmAddress,
71
+ walletClient: walletClient,
72
+ autoAuthenticate: true,
73
+ });
74
+ // Wallet management hook
75
+ const { wallet, generateWallet, refreshWallet, isLoading: walletLoading, } = useWallet({
76
+ client,
77
+ address: evmAddress,
78
+ auth: auth || undefined,
79
+ walletClient: walletClient,
80
+ connector: connector,
81
+ allDeposits: true,
82
+ });
83
+ const { setFacilitatorGroups } = useOrdersContext();
84
+ useWalletFacilitatorGroups(wallet, setFacilitatorGroups);
85
+ const tokenIn = useSwap((state) => state.tokenIn);
86
+ const inputAmount = useSwap((state) => state.inputAmount);
87
+ const setInputAmount = useSwap((state) => state.setInputAmount);
88
+ const destinations = useSwap((state) => state.destinations);
89
+ const slippage = useSwap((state) => state.slippage);
90
+ const setDestinations = useSwap((state) => state.setDestinations);
91
+ const updateDestinationAmount = useSwap((state) => state.updateDestinationAmount);
92
+ const splits = useSwap((state) => state.splits);
93
+ const transactionAddress = useTransactionAddress(tokenIn, evmAddress, solAddress);
94
+ const effectiveQuoteAddress = transactionAddress;
95
+ const { getPrice } = usePrices();
96
+ const { serviceFeeRate, overheadUsd } = useStatus();
97
+ const { fetchEstimates, isLoading: egressEstimatesLoading, egressQuotes: egressQuotesFromEstimates, ingressQuote: ingressQuoteFromEstimates, depositAmountUsd: depositAmountUsdFromEstimates, bridgeProviderFromQuote, usdcPrice: usdcPriceFromEstimates, } = useEgressEstimates({
98
+ evmAddress,
99
+ solAddress,
100
+ quoteAddress: effectiveQuoteAddress,
101
+ tokenIn,
102
+ inputAmount,
103
+ destinations,
104
+ splits,
105
+ updateDestinationAmount,
106
+ serviceFeeRate,
107
+ overheadUsd,
108
+ setInputAmount, // Pass setInputAmount for reverse calculation
109
+ });
110
+ useEffect(() => {
111
+ if (auth && walletClient && connector && !wallet && !walletLoading) {
112
+ generateWallet().catch((err) => {
113
+ console.error('Failed to generate wallet:', err);
114
+ });
115
+ }
116
+ }, [auth, walletClient, connector, wallet, walletLoading, generateWallet]);
117
+ const { executeSwap, isLoading: swapLoading, isSwapping, currentStep, error: swapError, quote, orderId, viewingAuth, clearQuote, depositAmountUsdc, loadingAmounts, } = useSilentQuote({
118
+ client,
119
+ address: effectiveQuoteAddress,
120
+ evmAddress: evmAddress,
121
+ solAddress: solAddress,
122
+ setDestinations,
123
+ wallet,
124
+ walletLoading,
125
+ walletClient,
126
+ connector,
127
+ solanaConnector,
128
+ solanaConnection,
129
+ getPrice,
130
+ });
131
+ const { handleNewSwap } = useResetSwapForm({
132
+ clearQuote,
133
+ isConnected,
134
+ wallet,
135
+ setFacilitatorGroups,
136
+ refreshWallet,
137
+ });
138
+ const effectiveDepositAmountUsd = useMemo(() => {
139
+ return depositAmountUsdFromEstimates > 0 ? depositAmountUsdFromEstimates : depositAmountUsdc;
140
+ }, [depositAmountUsdFromEstimates, depositAmountUsdc]);
141
+ const usdcPrice = usdcPriceFromEstimates || 1;
142
+ const { serviceFeeUsd, bridgeFeeIngressUsd, bridgeFeeEgressUsd } = useHiddenSwapFees({
143
+ depositAmountUsdc: effectiveDepositAmountUsd,
144
+ bridgeProvider: bridgeProviderFromQuote,
145
+ serviceFeeRate,
146
+ overheadUsd,
147
+ usdcPrice,
148
+ bridgeFeeRate: 0.001,
149
+ ingressQuote: ingressQuoteFromEstimates,
150
+ egressQuotes: egressQuotesFromEstimates,
151
+ });
152
+ const slippageUsd = useSlippageUsd({
153
+ inputUsdValue: effectiveDepositAmountUsd,
154
+ slippage,
155
+ inputAmount,
156
+ token: tokenIn,
157
+ });
158
+ const { progresses: orderProgresses, statusTexts: orderStatusTexts, isComplete: orderComplete, error: orderTrackingError, outputs: orderOutputs, } = useOrderTracking({
159
+ client,
160
+ orderId: orderId || undefined,
161
+ viewingAuth: viewingAuth || undefined,
162
+ });
163
+ return _jsx(SilentSwapContext.Provider, { value: {
164
+ client,
165
+ environment,
166
+ config,
167
+ wallet,
168
+ walletLoading,
169
+ auth,
170
+ authLoading,
171
+ executeSwap,
172
+ swapLoading,
173
+ isSwapping,
174
+ currentStep,
175
+ swapError,
176
+ quote,
177
+ orderId,
178
+ viewingAuth,
179
+ clearQuote,
180
+ depositAmountUsdc,
181
+ loadingAmounts,
182
+ orderProgresses,
183
+ orderStatusTexts,
184
+ orderComplete,
185
+ orderTrackingError,
186
+ orderOutputs,
187
+ serviceFeeUsd,
188
+ bridgeFeeIngressUsd,
189
+ bridgeFeeEgressUsd,
190
+ slippageUsd,
191
+ serviceFeeRate,
192
+ overheadUsd,
193
+ egressEstimatesLoading,
194
+ fetchEstimates,
195
+ handleNewSwap,
196
+ solanaRpcUrl,
197
+ }, children: children });
198
+ }
199
+ export function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, environment = ENVIRONMENT.STAGING, baseUrl, solanaRpcUrl, walletClient, }) {
200
+ const config = useMemo(() => ({
201
+ environment,
202
+ baseUrl: baseUrl ?? ENVIRONMENT_CONFIGS[environment].baseUrl,
203
+ }), [environment, baseUrl]);
204
+ return (_jsx(AssetsProvider, { children: _jsx(PricesProvider, { children: _jsx(BalancesProvider, { evmAddress: evmAddress, solAddress: solAddress, solanaRpcUrl: solanaRpcUrl, children: _jsx(OrdersProvider, { children: _jsx(SilentSwapInnerProvider, { client: client, connector: connector, isConnected: isConnected, evmAddress: evmAddress, solAddress: solAddress, solanaConnector: solanaConnector, solanaConnection: solanaConnection, environment: environment, config: config, solanaRpcUrl: solanaRpcUrl, walletClient: walletClient, children: children }) }) }) }) }));
205
+ }
@@ -0,0 +1,48 @@
1
+ import type { SilentSwapClient } from '@silentswap/sdk';
2
+ import type { OrderStatus, StatusUpdate } from './useOrderTracking.js';
3
+ /**
4
+ * Shared WebSocket connection manager for order tracking
5
+ * Maintains one connection per client/baseUrl and handles multiple order subscriptions
6
+ */
7
+ declare class OrderTrackingWebSocketManager {
8
+ private connections;
9
+ /**
10
+ * Get connection key from client
11
+ */
12
+ private getConnectionKey;
13
+ /**
14
+ * Get WebSocket URL from client
15
+ */
16
+ private getWebSocketUrl;
17
+ /**
18
+ * Get or create connection state
19
+ */
20
+ private getConnectionState;
21
+ /**
22
+ * Connect WebSocket if not already connected
23
+ */
24
+ private connectWebSocket;
25
+ /**
26
+ * Schedule reconnection with exponential backoff
27
+ */
28
+ private scheduleReconnect;
29
+ /**
30
+ * Subscribe to an order
31
+ */
32
+ private subscribeOrder;
33
+ /**
34
+ * Subscribe to order tracking
35
+ */
36
+ subscribe(client: SilentSwapClient | undefined, orderId: string, auth: string, handlers: {
37
+ onStatusUpdate: (status: OrderStatus) => void;
38
+ onStatusChange: (update: StatusUpdate) => void;
39
+ onError: (error: Error) => void;
40
+ onComplete: () => void;
41
+ }): () => void;
42
+ /**
43
+ * Get connection status
44
+ */
45
+ isConnected(client?: SilentSwapClient): boolean;
46
+ }
47
+ export declare const orderTrackingWebSocketManager: OrderTrackingWebSocketManager;
48
+ export {};