@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.
- package/README.md +48 -0
- package/dist/contexts/AssetsContext.d.ts +24 -0
- package/dist/contexts/AssetsContext.js +83 -0
- package/dist/contexts/BalancesContext.d.ts +28 -0
- package/dist/contexts/BalancesContext.js +533 -0
- package/dist/contexts/OrdersContext.d.ts +53 -0
- package/dist/contexts/OrdersContext.js +240 -0
- package/dist/contexts/PricesContext.d.ts +12 -0
- package/dist/contexts/PricesContext.js +109 -0
- package/dist/contexts/SilentSwapContext.d.ts +58 -0
- package/dist/contexts/SilentSwapContext.js +205 -0
- package/dist/hooks/silent/orderTrackingWebSocketManager.d.ts +48 -0
- package/dist/hooks/silent/orderTrackingWebSocketManager.js +284 -0
- package/dist/hooks/silent/solana-transaction.d.ts +60 -0
- package/dist/hooks/silent/solana-transaction.js +236 -0
- package/dist/hooks/silent/useAuth.d.ts +90 -0
- package/dist/hooks/silent/useAuth.js +269 -0
- package/dist/hooks/silent/useBridgeExecution.d.ts +39 -0
- package/dist/hooks/silent/useBridgeExecution.js +877 -0
- package/dist/hooks/silent/useOrderSigning.d.ts +34 -0
- package/dist/hooks/silent/useOrderSigning.js +133 -0
- package/dist/hooks/silent/useOrderTracking.d.ts +174 -0
- package/dist/hooks/silent/useOrderTracking.js +524 -0
- package/dist/hooks/silent/useQuoteCalculation.d.ts +50 -0
- package/dist/hooks/silent/useQuoteCalculation.js +331 -0
- package/dist/hooks/silent/useQuoteFetching.d.ts +18 -0
- package/dist/hooks/silent/useQuoteFetching.js +54 -0
- package/dist/hooks/silent/useRefund.d.ts +26 -0
- package/dist/hooks/silent/useRefund.js +134 -0
- package/dist/hooks/silent/useSilentClient.d.ts +16 -0
- package/dist/hooks/silent/useSilentClient.js +32 -0
- package/dist/hooks/silent/useSilentOrders.d.ts +174 -0
- package/dist/hooks/silent/useSilentOrders.js +73 -0
- package/dist/hooks/silent/useSilentQuote.d.ts +88 -0
- package/dist/hooks/silent/useSilentQuote.js +381 -0
- package/dist/hooks/silent/useWallet.d.ts +76 -0
- package/dist/hooks/silent/useWallet.js +203 -0
- package/dist/hooks/useAssetPrice.d.ts +8 -0
- package/dist/hooks/useAssetPrice.js +47 -0
- package/dist/hooks/useContacts.d.ts +52 -0
- package/dist/hooks/useContacts.js +259 -0
- package/dist/hooks/useEgressEstimates.d.ts +32 -0
- package/dist/hooks/useEgressEstimates.js +230 -0
- package/dist/hooks/useHiddenSwapFees.d.ts +22 -0
- package/dist/hooks/useHiddenSwapFees.js +81 -0
- package/dist/hooks/useOrderEstimates.d.ts +37 -0
- package/dist/hooks/useOrderEstimates.js +393 -0
- package/dist/hooks/useOutputAssetInfo.d.ts +12 -0
- package/dist/hooks/useOutputAssetInfo.js +38 -0
- package/dist/hooks/usePrices.d.ts +60 -0
- package/dist/hooks/usePrices.js +188 -0
- package/dist/hooks/useQuote.d.ts +73 -0
- package/dist/hooks/useQuote.js +507 -0
- package/dist/hooks/useResetSwapForm.d.ts +16 -0
- package/dist/hooks/useResetSwapForm.js +68 -0
- package/dist/hooks/useSlippageUsd.d.ts +11 -0
- package/dist/hooks/useSlippageUsd.js +19 -0
- package/dist/hooks/useSolanaAdapter.d.ts +15 -0
- package/dist/hooks/useSolanaAdapter.js +55 -0
- package/dist/hooks/useStatus.d.ts +25 -0
- package/dist/hooks/useStatus.js +60 -0
- package/dist/hooks/useSwap.d.ts +67 -0
- package/dist/hooks/useSwap.js +285 -0
- package/dist/hooks/useTransaction.d.ts +119 -0
- package/dist/hooks/useTransaction.js +353 -0
- package/dist/hooks/useTransactionAddress.d.ts +11 -0
- package/dist/hooks/useTransactionAddress.js +26 -0
- package/dist/hooks/useUsdValue.d.ts +7 -0
- package/dist/hooks/useUsdValue.js +19 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +41 -0
- package/dist/stories/SilentSwapOverview.stories.d.ts +10 -0
- package/dist/stories/SilentSwapOverview.stories.js +364 -0
- package/dist/stories/useAuth.stories.d.ts +6 -0
- package/dist/stories/useAuth.stories.js +55 -0
- package/dist/stories/useSilentClient.stories.d.ts +9 -0
- package/dist/stories/useSilentClient.stories.js +39 -0
- package/dist/stories/useSilentOrders.stories.d.ts +1 -0
- package/dist/stories/useSilentOrders.stories.js +1 -0
- package/dist/stories/useSilentQuote.stories.d.ts +6 -0
- package/dist/stories/useSilentQuote.stories.js +267 -0
- package/dist/stories/useTransaction.stories.d.ts +6 -0
- package/dist/stories/useTransaction.stories.js +121 -0
- package/dist/utils/formatters.d.ts +33 -0
- package/dist/utils/formatters.js +82 -0
- package/package.json +67 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import BigNumber from 'bignumber.js';
|
|
3
|
+
// Global price cache (similar to Svelte's H_PRICES)
|
|
4
|
+
const priceCache = {};
|
|
5
|
+
const PRICE_CACHE_DURATION = 60 * 1000; // 60 seconds
|
|
6
|
+
const MAX_PRICE_AGE = 15 * 1000; // 15 seconds for fresh prices
|
|
7
|
+
// Mutex pool for preventing duplicate requests
|
|
8
|
+
const loadingMutexes = {};
|
|
9
|
+
/**
|
|
10
|
+
* React hook for fetching and caching asset prices from CoinGecko
|
|
11
|
+
*
|
|
12
|
+
* Provides price fetching functionality similar to the Svelte Asset.priceUsd() method
|
|
13
|
+
* with caching and batch fetching support.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Configuration options
|
|
16
|
+
* @returns Object with price fetching methods and state
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { usePrices } from '@silentswap/react';
|
|
21
|
+
* import { getAssetByCaip19 } from '@silentswap/sdk';
|
|
22
|
+
*
|
|
23
|
+
* function MyComponent() {
|
|
24
|
+
* const { getPrice, getPrices } = usePrices();
|
|
25
|
+
*
|
|
26
|
+
* const handleGetPrice = async () => {
|
|
27
|
+
* const asset = getAssetByCaip19('eip155:1/erc20:0xA0b8...');
|
|
28
|
+
* if (asset) {
|
|
29
|
+
* const price = await getPrice(asset);
|
|
30
|
+
* console.log('Price:', price);
|
|
31
|
+
* }
|
|
32
|
+
* };
|
|
33
|
+
*
|
|
34
|
+
* return <button onClick={handleGetPrice}>Get Price</button>;
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function usePrices(options = {}) {
|
|
39
|
+
const { maxPriceAge = MAX_PRICE_AGE, coingeckoApiKey = 'CG-QftACwuv13UVKqCnDdf4fkfn' } = options;
|
|
40
|
+
const [loadingPrices, setLoadingPrices] = useState(new Set());
|
|
41
|
+
// Get USD price for a single asset (similar to Asset.priceUsd())
|
|
42
|
+
const getPrice = useCallback(async (asset, maxAge = maxPriceAge) => {
|
|
43
|
+
const caip19 = asset.caip19;
|
|
44
|
+
// Check cache first
|
|
45
|
+
const cached = priceCache[caip19];
|
|
46
|
+
if (cached && cached.published + maxAge > Date.now()) {
|
|
47
|
+
return cached.priceUsd;
|
|
48
|
+
}
|
|
49
|
+
// Check if already loading - prevent double requests
|
|
50
|
+
if (!!loadingMutexes[caip19]) {
|
|
51
|
+
return loadingMutexes[caip19];
|
|
52
|
+
}
|
|
53
|
+
// Start loading - set mutex immediately to prevent race condition
|
|
54
|
+
setLoadingPrices((prev) => new Set(prev).add(caip19));
|
|
55
|
+
// Create and assign promise immediately to prevent concurrent requests
|
|
56
|
+
const pricePromise = (async () => {
|
|
57
|
+
try {
|
|
58
|
+
if (asset.coingeckoId) {
|
|
59
|
+
// Fetch from CoinGecko Pro API (same as Svelte)
|
|
60
|
+
const response = await fetch(`https://pro-api.coingecko.com/api/v3/simple/price?ids=${asset.coingeckoId}&vs_currencies=usd`, {
|
|
61
|
+
headers: {
|
|
62
|
+
'X-CG-Pro-Api-Key': coingeckoApiKey,
|
|
63
|
+
},
|
|
64
|
+
signal: AbortSignal.timeout(30 * 1000),
|
|
65
|
+
});
|
|
66
|
+
if (response.ok) {
|
|
67
|
+
const data = await response.json();
|
|
68
|
+
const price = data[asset.coingeckoId]?.usd || 0;
|
|
69
|
+
// Cache the price
|
|
70
|
+
priceCache[caip19] = {
|
|
71
|
+
priceUsd: price,
|
|
72
|
+
published: Date.now(),
|
|
73
|
+
expiration: Date.now() + PRICE_CACHE_DURATION,
|
|
74
|
+
source: 'coingecko',
|
|
75
|
+
};
|
|
76
|
+
// Also cache for other assets with same CoinGecko ID
|
|
77
|
+
// (Note: This would require access to all assets, which we don't have here)
|
|
78
|
+
// The Svelte version does this, but for simplicity we'll just cache this asset
|
|
79
|
+
return price;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Fallback: retry after delay
|
|
83
|
+
await new Promise((resolve) => setTimeout(resolve, 10 * 1000));
|
|
84
|
+
return getPrice(asset, maxAge);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
console.warn(`Failed to fetch price for ${caip19}:`, error);
|
|
88
|
+
// Fallback: retry after delay
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, 10 * 1000));
|
|
90
|
+
return getPrice(asset, maxAge);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
delete loadingMutexes[caip19];
|
|
94
|
+
setLoadingPrices((prev) => {
|
|
95
|
+
const next = new Set(prev);
|
|
96
|
+
next.delete(caip19);
|
|
97
|
+
return next;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
// Assign mutex BEFORE returning to prevent race condition
|
|
102
|
+
loadingMutexes[caip19] = pricePromise;
|
|
103
|
+
return pricePromise;
|
|
104
|
+
}, [maxPriceAge, coingeckoApiKey]);
|
|
105
|
+
// Get prices for multiple assets (batch fetch, similar to asset_prices())
|
|
106
|
+
const getPrices = useCallback(async (assets, maxAge = maxPriceAge) => {
|
|
107
|
+
const prices = [];
|
|
108
|
+
// Group by CoinGecko ID for batch requests
|
|
109
|
+
const coingeckoGroups = {};
|
|
110
|
+
for (const asset of assets) {
|
|
111
|
+
if (asset.coingeckoId) {
|
|
112
|
+
if (!coingeckoGroups[asset.coingeckoId]) {
|
|
113
|
+
coingeckoGroups[asset.coingeckoId] = [];
|
|
114
|
+
}
|
|
115
|
+
coingeckoGroups[asset.coingeckoId].push(asset);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Process each CoinGecko ID group
|
|
119
|
+
const coingeckoIds = Object.keys(coingeckoGroups);
|
|
120
|
+
if (coingeckoIds.length > 0) {
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch(`https://pro-api.coingecko.com/api/v3/simple/price?ids=${coingeckoIds.join(',')}&vs_currencies=usd`, {
|
|
123
|
+
headers: {
|
|
124
|
+
'X-CG-Pro-Api-Key': coingeckoApiKey,
|
|
125
|
+
},
|
|
126
|
+
signal: AbortSignal.timeout(30 * 1000),
|
|
127
|
+
});
|
|
128
|
+
if (response.ok) {
|
|
129
|
+
const data = await response.json();
|
|
130
|
+
// Update cache for all returned prices
|
|
131
|
+
for (const [coingeckoId, priceData] of Object.entries(data)) {
|
|
132
|
+
const price = priceData.usd || 0;
|
|
133
|
+
const groupAssets = coingeckoGroups[coingeckoId];
|
|
134
|
+
groupAssets.forEach((asset) => {
|
|
135
|
+
priceCache[asset.caip19] = {
|
|
136
|
+
priceUsd: price,
|
|
137
|
+
published: Date.now(),
|
|
138
|
+
expiration: Date.now() + PRICE_CACHE_DURATION,
|
|
139
|
+
source: 'coingecko',
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.warn('Failed to batch fetch prices:', error);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Return prices from cache (or 0 if not available)
|
|
150
|
+
return assets.map((asset) => {
|
|
151
|
+
const cached = priceCache[asset.caip19];
|
|
152
|
+
return cached && cached.published + maxAge > Date.now() ? cached.priceUsd : 0;
|
|
153
|
+
});
|
|
154
|
+
}, [maxPriceAge, coingeckoApiKey]);
|
|
155
|
+
// Get USD value for atomic units (similar to Asset.unitValueUsd)
|
|
156
|
+
const getUnitValueUsd = useCallback(async (asset, amount) => {
|
|
157
|
+
const price = await getPrice(asset);
|
|
158
|
+
const humanAmount = Number(BigNumber(amount.toString()).shiftedBy(-asset.decimals));
|
|
159
|
+
return humanAmount * price;
|
|
160
|
+
}, [getPrice]);
|
|
161
|
+
// Get USD value for human-readable amounts (similar to Asset.wholeValueUsd)
|
|
162
|
+
const getWholeValueUsd = useCallback(async (asset, amount) => {
|
|
163
|
+
const price = await getPrice(asset);
|
|
164
|
+
return BigNumber(amount.toString()).times(price).toNumber();
|
|
165
|
+
}, [getPrice]);
|
|
166
|
+
// Check if price is loading
|
|
167
|
+
const isPriceLoading = useCallback((caip19) => {
|
|
168
|
+
return loadingPrices.has(caip19);
|
|
169
|
+
}, [loadingPrices]);
|
|
170
|
+
// Get cached price (without fetching)
|
|
171
|
+
const getCachedPrice = useCallback((caip19, maxAge = maxPriceAge) => {
|
|
172
|
+
const cached = priceCache[caip19];
|
|
173
|
+
if (cached && cached.published + maxAge > Date.now()) {
|
|
174
|
+
return cached.priceUsd;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}, [maxPriceAge]);
|
|
178
|
+
const loadingPricesValue = useMemo(() => loadingPrices.size > 0, [loadingPrices]);
|
|
179
|
+
return {
|
|
180
|
+
getPrice,
|
|
181
|
+
getPrices,
|
|
182
|
+
getUnitValueUsd,
|
|
183
|
+
getWholeValueUsd,
|
|
184
|
+
isPriceLoading,
|
|
185
|
+
getCachedPrice,
|
|
186
|
+
loadingPrices: loadingPricesValue,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { BridgeProvider, RelayQuoteResponse, DeBridgeOrderResponse, SolveUsdcResult } from '@silentswap/sdk';
|
|
2
|
+
import { type EstimateSample, type Estimate, type BridgeQuoteResult } from '@silentswap/sdk';
|
|
3
|
+
export interface useQuoteOptions {
|
|
4
|
+
/** User's address (EVM hex address or Solana base58 address) */
|
|
5
|
+
address?: `0x${string}` | string;
|
|
6
|
+
/** Maximum price impact percentage allowed (default from SDK constants) */
|
|
7
|
+
maxImpactPercent?: number;
|
|
8
|
+
/** Timeout for quote requests in milliseconds (default: 30000) */
|
|
9
|
+
quoteTimeout?: number;
|
|
10
|
+
}
|
|
11
|
+
export type { RelayQuoteResponse, DeBridgeOrderResponse, SolveUsdcResult, EstimateSample, Estimate, BridgeQuoteResult, } from '@silentswap/sdk';
|
|
12
|
+
export type SolveResult = SolveUsdcResult;
|
|
13
|
+
/**
|
|
14
|
+
* Estimate result with quote details
|
|
15
|
+
*/
|
|
16
|
+
export interface EstimateResult {
|
|
17
|
+
/** Estimate data with samples */
|
|
18
|
+
estimate: Estimate;
|
|
19
|
+
/** Amount of gas needed on source chain */
|
|
20
|
+
gasAmount: bigint;
|
|
21
|
+
/** Raw response from provider */
|
|
22
|
+
response: RelayQuoteResponse | DeBridgeOrderResponse;
|
|
23
|
+
/** Bridge provider used */
|
|
24
|
+
provider: BridgeProvider;
|
|
25
|
+
/** Calculated input amount for reverse calculation (output-to-input) */
|
|
26
|
+
calculatedInputAmount?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface useQuoteReturn {
|
|
29
|
+
isLoading: boolean;
|
|
30
|
+
error: Error | null;
|
|
31
|
+
ingressEstimates: Record<string, Estimate>;
|
|
32
|
+
egressEstimates: Record<string, Estimate>;
|
|
33
|
+
/**
|
|
34
|
+
* Get quote for cross-chain swap
|
|
35
|
+
* @param srcChainId - Source chain ID
|
|
36
|
+
* @param srcToken - Source token address (0x0 for native)
|
|
37
|
+
* @param srcAmount - Source amount in token units (as string)
|
|
38
|
+
* @param dstChainId - Destination chain ID
|
|
39
|
+
* @param dstToken - Destination token address (0x0 for native)
|
|
40
|
+
* @param recipientAddress - Optional recipient address (required for Solana destinations)
|
|
41
|
+
* @param sourceAddress - Optional source chain address (for relay.link, must match source chain format)
|
|
42
|
+
* @returns Promise resolving to best quote with all details
|
|
43
|
+
*/
|
|
44
|
+
getQuote: (srcChainId: number, srcToken: string, srcAmount: string, dstChainId: number, dstToken: string, recipientAddress?: string, sourceAddress?: string) => Promise<BridgeQuoteResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Get live estimate for a given direction
|
|
47
|
+
* @param direction - 'ingress' (into Silent) or 'egress' (out of Silent)
|
|
48
|
+
* @param assetCaip19 - CAIP-19 asset identifier
|
|
49
|
+
* @param chainId - Chain ID
|
|
50
|
+
* @param tokenAddress - Token address (0x0 for native)
|
|
51
|
+
* @param amount - Amount in human-readable format
|
|
52
|
+
* @param usdPrice - USD price per token
|
|
53
|
+
* @param externalSignal - Optional abort signal
|
|
54
|
+
* @param recipientAddress - Optional recipient address (required for Solana destinations in egress)
|
|
55
|
+
* @param isReverseCalculation - For reverse calculation (output-to-input)
|
|
56
|
+
* @param targetAmount - Target amount for reverse calculation (output USD for ingress, output amount for egress)
|
|
57
|
+
* @returns Promise resolving to estimate result
|
|
58
|
+
*/
|
|
59
|
+
estimateLive: (direction: 'ingress' | 'egress', assetCaip19: string, chainId: number | string, tokenAddress: string, amount: number, usdPrice: number, externalSignal?: AbortSignal, recipientAddress?: string, isReverseCalculation?: boolean, targetAmount?: number) => Promise<EstimateResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Interpolate retention rate from samples
|
|
62
|
+
* @param samples - Array of estimate samples
|
|
63
|
+
* @param usdValue - USD value to interpolate for
|
|
64
|
+
* @param marginHi - Maximum margin above highest sample (default: Infinity)
|
|
65
|
+
* @returns Interpolated retention rate
|
|
66
|
+
*/
|
|
67
|
+
interpolateSamples: (samples: EstimateSample[], usdValue: number, marginHi?: number) => number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Hook for getting optimized bridge quotes with retention rate tracking
|
|
71
|
+
* Implements the same functionality as estimate.ts from the original app
|
|
72
|
+
*/
|
|
73
|
+
export declare function useQuote({ address, maxImpactPercent }?: useQuoteOptions): useQuoteReturn;
|