@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,267 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useState } from 'react';
3
+ import { useQuote } from '../hooks/useQuote.js';
4
+ import { useAccount } from 'wagmi';
5
+ // Demo component to demonstrate the bridge quote hook
6
+ function BridgeQuoteDemo() {
7
+ const { address } = useAccount();
8
+ const { getQuote, estimateLive, interpolateSamples, ingressEstimates, egressEstimates, isLoading, error } = useQuote({
9
+ address: address || undefined,
10
+ maxImpactPercent: 5,
11
+ });
12
+ const solveOptimalUsdcAmount = useCallback(async (srcChainId, srcToken, srcAmount) => {
13
+ throw new Error('TODO: implement example');
14
+ return {};
15
+ }, [address]);
16
+ // Results state
17
+ const [quoteResult, setQuoteResult] = useState(null);
18
+ const [solveResult, setSolveResult] = useState(null);
19
+ const [estimateResult, setEstimateResult] = useState(null);
20
+ const [interpolateResult, setInterpolateResult] = useState(null);
21
+ const [isActionLoading, setIsActionLoading] = useState(false);
22
+ // getQuote parameters
23
+ const [quoteSrcChain, setQuoteSrcChain] = useState('1');
24
+ const [quoteSrcToken, setQuoteSrcToken] = useState('0x0000000000000000000000000000000000000000');
25
+ const [quoteSrcAmount, setQuoteSrcAmount] = useState('100000000000000000');
26
+ const [quoteDstChain, setQuoteDstChain] = useState('43114');
27
+ const [quoteDstToken, setQuoteDstToken] = useState('0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E');
28
+ // solveUsdcAmount parameters
29
+ const [solveSrcChain, setSolveSrcChain] = useState('1');
30
+ const [solveSrcToken, setSolveSrcToken] = useState('0x0000000000000000000000000000000000000000');
31
+ const [solveSrcAmount, setSolveSrcAmount] = useState('100000000000000000');
32
+ // estimateLive parameters
33
+ const [estimateDirection, setEstimateDirection] = useState('ingress');
34
+ const [estimateCaip19, setEstimateCaip19] = useState('eip155:1/slip44:60');
35
+ const [estimateChainId, setEstimateChainId] = useState('1');
36
+ const [estimateToken, setEstimateToken] = useState('0x0000000000000000000000000000000000000000');
37
+ const [estimateAmount, setEstimateAmount] = useState('0.1');
38
+ const [estimateUsdPrice, setEstimateUsdPrice] = useState('3000');
39
+ /**
40
+ * Test getting a quote for cross-chain swap
41
+ */
42
+ const handleGetQuote = async () => {
43
+ if (!address) {
44
+ alert('Please connect your wallet first');
45
+ return;
46
+ }
47
+ setIsActionLoading(true);
48
+ try {
49
+ const result = await getQuote(parseInt(quoteSrcChain), quoteSrcToken, quoteSrcAmount, parseInt(quoteDstChain), quoteDstToken);
50
+ setQuoteResult(JSON.stringify({
51
+ provider: result.provider,
52
+ outputAmount: result.outputAmount,
53
+ outputAmountFormatted: (Number(result.outputAmount) / 1e6).toFixed(6) + ' tokens',
54
+ inputAmount: result.inputAmount,
55
+ inputAmountFormatted: (Number(result.inputAmount) / 1e18).toFixed(6) + ' tokens',
56
+ feeUsd: result.feeUsd.toFixed(2),
57
+ slippage: result.slippage.toFixed(2) + '%',
58
+ estimatedTime: result.estimatedTime + 's',
59
+ retentionRate: (result.retentionRate * 100).toFixed(2) + '%',
60
+ txCount: result.txCount,
61
+ explanation: `Best quote from ${result.provider} with ${result.retentionRate.toFixed(4)} retention rate`,
62
+ }, null, 2));
63
+ }
64
+ catch (error) {
65
+ console.error('Get quote failed:', error);
66
+ setQuoteResult(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
67
+ }
68
+ finally {
69
+ setIsActionLoading(false);
70
+ }
71
+ };
72
+ /**
73
+ * Test solving optimal USDC amount
74
+ */
75
+ const handleSolveUsdcAmount = async () => {
76
+ if (!address) {
77
+ alert('Please connect your wallet first');
78
+ return;
79
+ }
80
+ setIsActionLoading(true);
81
+ try {
82
+ const result = await solveOptimalUsdcAmount(parseInt(solveSrcChain), solveSrcToken, solveSrcAmount);
83
+ setSolveResult(JSON.stringify({
84
+ provider: result.provider,
85
+ usdcAmountOut: result.usdcAmountOut.toString(),
86
+ usdcAmountOutFormatted: (Number(result.usdcAmountOut) / 1e6).toFixed(6) + ' USDC',
87
+ actualAmountIn: result.actualAmountIn.toString(),
88
+ actualAmountInFormatted: (Number(result.actualAmountIn) / 1e18).toFixed(6) + ' tokens',
89
+ allowanceTarget: result.allowanceTarget || 'N/A',
90
+ explanation: `Found optimal quote from ${result.provider}`,
91
+ }, null, 2));
92
+ }
93
+ catch (error) {
94
+ console.error('Solve USDC amount failed:', error);
95
+ setSolveResult(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
96
+ }
97
+ finally {
98
+ setIsActionLoading(false);
99
+ }
100
+ };
101
+ /**
102
+ * Test getting live estimate
103
+ */
104
+ const handleEstimateLive = async () => {
105
+ if (!address) {
106
+ alert('Please connect your wallet first');
107
+ return;
108
+ }
109
+ setIsActionLoading(true);
110
+ try {
111
+ const result = await estimateLive(estimateDirection, estimateCaip19, parseInt(estimateChainId), estimateToken, parseFloat(estimateAmount), parseFloat(estimateUsdPrice));
112
+ setEstimateResult(JSON.stringify({
113
+ provider: result.provider,
114
+ gasFee: result.estimate.gasFee,
115
+ gasAmount: result.gasAmount.toString(),
116
+ samplesCount: result.estimate.samples.length,
117
+ samples: result.estimate.samples.map((s) => ({
118
+ baseline: s.baseline,
119
+ retention: s.retention,
120
+ source: s.source,
121
+ })),
122
+ explanation: `${result.provider} quote with ${(result.estimate.samples[result.estimate.samples.length - 1]?.retention * 100 || 0).toFixed(2)}% retention rate`,
123
+ }, null, 2));
124
+ }
125
+ catch (error) {
126
+ console.error('Estimate live failed:', error);
127
+ setEstimateResult(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
128
+ }
129
+ finally {
130
+ setIsActionLoading(false);
131
+ }
132
+ };
133
+ /**
134
+ * Test sample interpolation
135
+ */
136
+ const handleInterpolateSamples = async () => {
137
+ setIsActionLoading(true);
138
+ try {
139
+ // Create sample data
140
+ const samples = [
141
+ { baseline: 100, retention: 0.95, source: 'relay' },
142
+ { baseline: 500, retention: 0.93, source: 'relay' },
143
+ { baseline: 1000, retention: 0.91, source: 'debridge' },
144
+ { baseline: 5000, retention: 0.89, source: 'relay' },
145
+ ];
146
+ // Test interpolation at various points
147
+ const results = [
148
+ { value: 50, retention: interpolateSamples(samples, 50) },
149
+ { value: 300, retention: interpolateSamples(samples, 300) },
150
+ { value: 750, retention: interpolateSamples(samples, 750) },
151
+ { value: 3000, retention: interpolateSamples(samples, 3000) },
152
+ { value: 5500, retention: interpolateSamples(samples, 5500) },
153
+ ];
154
+ setInterpolateResult(JSON.stringify({
155
+ samples,
156
+ interpolations: results.map((r) => ({
157
+ usdValue: r.value,
158
+ retention: r.retention,
159
+ retentionPercent: `${(r.retention * 100).toFixed(2)}%`,
160
+ })),
161
+ explanation: 'Interpolation smoothly estimates retention rates between known sample points',
162
+ }, null, 2));
163
+ }
164
+ catch (error) {
165
+ console.error('Interpolate samples failed:', error);
166
+ setInterpolateResult(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
167
+ }
168
+ finally {
169
+ setIsActionLoading(false);
170
+ }
171
+ };
172
+ const isDisabled = isLoading || isActionLoading;
173
+ const inputStyle = {
174
+ width: '100%',
175
+ padding: '8px 12px',
176
+ background: '#f8f9fa',
177
+ border: '1px solid #dee2e6',
178
+ borderRadius: '4px',
179
+ fontSize: '14px',
180
+ fontFamily: 'monospace',
181
+ };
182
+ const labelStyle = {
183
+ display: 'block',
184
+ marginBottom: '5px',
185
+ fontWeight: 'bold',
186
+ fontSize: '14px',
187
+ };
188
+ const buttonStyle = (disabled) => ({
189
+ width: '100%',
190
+ padding: '12px 20px',
191
+ background: disabled ? '#6c757d' : '#007bff',
192
+ color: 'white',
193
+ border: 'none',
194
+ borderRadius: '4px',
195
+ cursor: disabled ? 'not-allowed' : 'pointer',
196
+ fontSize: '16px',
197
+ fontWeight: 'bold',
198
+ opacity: disabled ? 0.6 : 1,
199
+ });
200
+ const sectionStyle = {
201
+ marginBottom: '20px',
202
+ padding: '15px',
203
+ border: '2px solid #e0e0e0',
204
+ borderRadius: '8px',
205
+ background: '#fafafa',
206
+ };
207
+ return (_jsxs("div", { style: { maxWidth: '800px', fontFamily: 'Arial, sans-serif' }, children: [_jsx("h2", { children: "\uD83D\uDCB1 SilentSwap Bridge Quote - Advanced Estimation" }), _jsx("p", { style: { color: '#666', marginBottom: '20px' }, children: "Comprehensive bridge quote system with optimal solving, retention rate tracking, and sample-based interpolation" }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "Connection Status" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px' }, children: [_jsxs("p", { children: [_jsx("strong", { children: "Loading:" }), " ", isLoading || isActionLoading ? '⏳ Processing...' : '✅ Ready'] }), _jsxs("p", { children: [_jsx("strong", { children: "Error:" }), " ", error ? `❌ ${error.message}` : '✅ None'] }), !address && (_jsx("div", { style: {
208
+ padding: '10px',
209
+ background: '#fff3cd',
210
+ border: '1px solid #ffc107',
211
+ borderRadius: '4px',
212
+ color: '#856404',
213
+ }, children: "\u26A0\uFE0F Please connect your wallet to test bridge functions" })), address && (_jsxs("p", { children: [_jsx("strong", { children: "Address:" }), " ", address.slice(0, 6), "...", address.slice(-4)] }))] })] }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "Estimate Cache" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px' }, children: [_jsxs("p", { children: [_jsx("strong", { children: "Ingress Estimates:" }), " ", Object.keys(ingressEstimates).length, " assets cached"] }), _jsxs("p", { children: [_jsx("strong", { children: "Egress Estimates:" }), " ", Object.keys(egressEstimates).length, " assets cached"] }), Object.keys(ingressEstimates).length > 0 && (_jsxs("details", { children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff' }, children: "View Ingress Cache" }), _jsx("pre", { style: {
214
+ fontSize: '12px',
215
+ marginTop: '8px',
216
+ overflow: 'auto',
217
+ background: '#f8f9fa',
218
+ padding: '10px',
219
+ borderRadius: '4px',
220
+ }, children: JSON.stringify(ingressEstimates, null, 2) })] }))] })] }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "\uD83D\uDCB1 Get Cross-Chain Quote" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px' }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Chain ID" }), _jsx("input", { style: inputStyle, value: quoteSrcChain, onChange: (e) => setQuoteSrcChain(e.target.value), placeholder: "1" })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Token Address" }), _jsx("input", { style: inputStyle, value: quoteSrcToken, onChange: (e) => setQuoteSrcToken(e.target.value), placeholder: "0x..." })] })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Amount (wei)" }), _jsx("input", { style: inputStyle, value: quoteSrcAmount, onChange: (e) => setQuoteSrcAmount(e.target.value), placeholder: "100000000000000000" })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Destination Chain ID" }), _jsx("input", { style: inputStyle, value: quoteDstChain, onChange: (e) => setQuoteDstChain(e.target.value), placeholder: "43114" })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Destination Token Address" }), _jsx("input", { style: inputStyle, value: quoteDstToken, onChange: (e) => setQuoteDstToken(e.target.value), placeholder: "0x..." })] })] }), _jsx("button", { onClick: handleGetQuote, disabled: isDisabled || !address, style: buttonStyle(isDisabled || !address), children: isActionLoading ? '⏳ Getting Quote...' : 'Get Quote' }), quoteResult && (_jsx("div", { style: { marginTop: '12px' }, children: _jsxs("details", { open: true, children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff', fontWeight: 'bold', marginBottom: '10px' }, children: "\uD83D\uDCB1 Cross-Chain Quote Result" }), _jsx("pre", { style: {
221
+ overflow: 'auto',
222
+ maxHeight: '400px',
223
+ fontSize: '12px',
224
+ background: '#000',
225
+ color: '#fff',
226
+ padding: '15px',
227
+ borderRadius: '4px',
228
+ }, children: quoteResult })] }) }))] })] }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "\uD83C\uDFAF Solve Optimal USDC Amount" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px' }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Chain ID" }), _jsx("input", { style: inputStyle, value: solveSrcChain, onChange: (e) => setSolveSrcChain(e.target.value), placeholder: "1" })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Token Address" }), _jsx("input", { style: inputStyle, value: solveSrcToken, onChange: (e) => setSolveSrcToken(e.target.value), placeholder: "0x..." })] })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Source Amount (wei)" }), _jsx("input", { style: inputStyle, value: solveSrcAmount, onChange: (e) => setSolveSrcAmount(e.target.value), placeholder: "100000000000000000" })] }), _jsx("button", { onClick: handleSolveUsdcAmount, disabled: isDisabled || !address, style: buttonStyle(isDisabled || !address), children: isActionLoading ? '⏳ Solving...' : 'Solve USDC Amount' }), solveResult && (_jsx("div", { style: { marginTop: '12px' }, children: _jsxs("details", { open: true, children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff', fontWeight: 'bold', marginBottom: '10px' }, children: "\uD83C\uDFAF Solve USDC Amount Result" }), _jsx("pre", { style: {
229
+ overflow: 'auto',
230
+ maxHeight: '400px',
231
+ fontSize: '12px',
232
+ background: '#000',
233
+ color: '#fff',
234
+ padding: '15px',
235
+ borderRadius: '4px',
236
+ }, children: solveResult })] }) }))] })] }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "\uD83D\uDCCA Get Live Estimate" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px' }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Direction" }), _jsxs("select", { value: estimateDirection, onChange: (e) => setEstimateDirection(e.target.value), style: inputStyle, children: [_jsx("option", { value: "ingress", children: "Ingress" }), _jsx("option", { value: "egress", children: "Egress" })] })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "CAIP-19 Asset ID" }), _jsx("input", { style: inputStyle, value: estimateCaip19, onChange: (e) => setEstimateCaip19(e.target.value), placeholder: "eip155:1/slip44:60" })] })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Chain ID" }), _jsx("input", { style: inputStyle, value: estimateChainId, onChange: (e) => setEstimateChainId(e.target.value), placeholder: "1" })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Token Address" }), _jsx("input", { style: inputStyle, value: estimateToken, onChange: (e) => setEstimateToken(e.target.value), placeholder: "0x..." })] })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }, children: [_jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "Amount (decimal)" }), _jsx("input", { style: inputStyle, value: estimateAmount, onChange: (e) => setEstimateAmount(e.target.value), placeholder: "0.1" })] }), _jsxs("div", { children: [_jsx("label", { style: labelStyle, children: "USD Price" }), _jsx("input", { style: inputStyle, value: estimateUsdPrice, onChange: (e) => setEstimateUsdPrice(e.target.value), placeholder: "3000" })] })] }), _jsx("button", { onClick: handleEstimateLive, disabled: isDisabled || !address, style: buttonStyle(isDisabled || !address), children: isActionLoading ? '⏳ Estimating...' : 'Get Live Estimate' }), estimateResult && (_jsx("div", { style: { marginTop: '12px' }, children: _jsxs("details", { open: true, children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff', fontWeight: 'bold', marginBottom: '10px' }, children: "\uD83D\uDCCA Live Estimate Result" }), _jsx("pre", { style: {
237
+ overflow: 'auto',
238
+ maxHeight: '400px',
239
+ fontSize: '12px',
240
+ background: '#000',
241
+ color: '#fff',
242
+ padding: '15px',
243
+ borderRadius: '4px',
244
+ }, children: estimateResult })] }) }))] })] }), _jsxs("div", { style: sectionStyle, children: [_jsx("h3", { children: "\uD83D\uDCC8 Interpolate Samples" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '12px' }, children: [_jsx("p", { style: { fontSize: '14px', color: '#666' }, children: "Test retention rate interpolation using sample data points" }), _jsx("button", { onClick: handleInterpolateSamples, disabled: isDisabled, style: buttonStyle(isDisabled), children: isActionLoading ? '⏳ Interpolating...' : 'Run Interpolation Test' }), interpolateResult && (_jsx("div", { style: { marginTop: '12px' }, children: _jsxs("details", { open: true, children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff', fontWeight: 'bold', marginBottom: '10px' }, children: "\uD83D\uDCC8 Sample Interpolation Result" }), _jsx("pre", { style: {
245
+ overflow: 'auto',
246
+ maxHeight: '400px',
247
+ fontSize: '12px',
248
+ background: '#000',
249
+ color: '#fff',
250
+ padding: '15px',
251
+ borderRadius: '4px',
252
+ }, children: interpolateResult })] }) }))] })] }), _jsx("div", { style: { marginTop: '20px' }, children: _jsxs("details", { children: [_jsx("summary", { style: { cursor: 'pointer', color: '#007bff', fontWeight: 'bold', fontSize: '18px', marginBottom: '15px' }, children: "\uD83D\uDCDA Available Methods Documentation" }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '20px', marginTop: '15px' }, children: [_jsxs("div", { style: { borderLeft: '4px solid #28a745', paddingLeft: '15px' }, children: [_jsx("h4", { style: { color: '#28a745', marginBottom: '8px' }, children: "getQuote()" }), _jsx("p", { style: { fontSize: '14px', marginBottom: '8px' }, children: "Gets the best cross-chain quote by comparing multiple providers" }), _jsxs("ul", { style: { listStyle: 'disc', marginLeft: '20px', fontSize: '14px', color: '#666' }, children: [_jsx("li", { children: "Queries relay.link and deBridge in parallel" }), _jsx("li", { children: "Compares retention rates to select the best provider" }), _jsx("li", { children: "Returns unified quote with output amount, fees, and estimated time" }), _jsx("li", { children: "Handles provider-specific errors gracefully" })] })] }), _jsxs("div", { style: { borderLeft: '4px solid #007bff', paddingLeft: '15px' }, children: [_jsx("h4", { style: { color: '#007bff', marginBottom: '8px' }, children: "solveUsdcAmount()" }), _jsx("p", { style: { fontSize: '14px', marginBottom: '8px' }, children: "Finds the optimal USDC output amount by querying both relay and debridge, then comparing rates" }), _jsxs("ul", { style: { listStyle: 'disc', marginLeft: '20px', fontSize: '14px', color: '#666' }, children: [_jsx("li", { children: "Iteratively solves for best bridge price (up to 4 attempts)" }), _jsx("li", { children: "Validates price impact is below threshold" }), _jsx("li", { children: "Returns provider with best rate (USDC out / amount in)" }), _jsx("li", { children: "Handles allowance targets for deBridge" })] })] }), _jsxs("div", { style: { borderLeft: '4px solid #ffc107', paddingLeft: '15px' }, children: [_jsx("h4", { style: { color: '#ffc107', marginBottom: '8px' }, children: "estimateLive()" }), _jsx("p", { style: { fontSize: '14px', marginBottom: '8px' }, children: "Gets live quotes from providers and calculates retention rates with sample caching" }), _jsxs("ul", { style: { listStyle: 'disc', marginLeft: '20px', fontSize: '14px', color: '#666' }, children: [_jsx("li", { children: "Queries relay.link and deBridge in parallel" }), _jsx("li", { children: "Calculates retention rate (value preserved after fees)" }), _jsx("li", { children: "Stores samples for interpolation" }), _jsx("li", { children: "Returns gas estimates and provider details" })] })] }), _jsxs("div", { style: { borderLeft: '4px solid #6f42c1', paddingLeft: '15px' }, children: [_jsx("h4", { style: { color: '#6f42c1', marginBottom: '8px' }, children: "interpolateSamples()" }), _jsx("p", { style: { fontSize: '14px', marginBottom: '8px' }, children: "Uses linear interpolation to estimate retention rates between sample points" }), _jsxs("ul", { style: { listStyle: 'disc', marginLeft: '20px', fontSize: '14px', color: '#666' }, children: [_jsx("li", { children: "Returns exact match if sample exists at USD value" }), _jsx("li", { children: "Uses lowest sample for values below range" }), _jsx("li", { children: "Uses highest sample for values above range (with optional margin check)" }), _jsx("li", { children: "Linearly interpolates for values within sample range" })] })] }), _jsxs("div", { style: { borderLeft: '4px solid #e83e8c', paddingLeft: '15px' }, children: [_jsx("h4", { style: { color: '#e83e8c', marginBottom: '8px' }, children: "ingressEstimates / egressEstimates" }), _jsx("p", { style: { fontSize: '14px', marginBottom: '8px' }, children: "Cached estimate data indexed by CAIP-19 asset identifier" }), _jsxs("ul", { style: { listStyle: 'disc', marginLeft: '20px', fontSize: '14px', color: '#666' }, children: [_jsx("li", { children: "Stores retention rate samples for each asset" }), _jsx("li", { children: "Automatically updated on each estimateLive call" }), _jsx("li", { children: "Samples within $5 of each other are deduplicated" }), _jsx("li", { children: "Enables fast estimation via interpolation" })] })] })] })] }) })] }));
253
+ }
254
+ const meta = {
255
+ title: 'Hooks/useQuote',
256
+ component: BridgeQuoteDemo,
257
+ tags: ['autodocs'],
258
+ parameters: {
259
+ docs: {
260
+ description: {
261
+ component: 'Advanced bridge quote hook with optimal solving, retention rate tracking, and sample-based interpolation. Replicates functionality from the original estimate.ts implementation.',
262
+ },
263
+ },
264
+ },
265
+ };
266
+ export default meta;
267
+ export const Default = {};
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ declare function BridgeDemo(): import("react/jsx-runtime").JSX.Element;
3
+ declare const meta: Meta<typeof BridgeDemo>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
@@ -0,0 +1,121 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { useTransaction, useQuote } from '../index.js';
4
+ import { useAccount, useWalletClient } from 'wagmi';
5
+ import { getBridgeQuote } from '@silentswap/sdk';
6
+ import { Button, Card } from '@silentswap/ui-kit';
7
+ // Demo component to demonstrate the bridge execution hook
8
+ function BridgeDemo() {
9
+ const { address, connector } = useAccount();
10
+ const { data: walletClient } = useWalletClient();
11
+ // Get the best quote using optimal USDC solving
12
+ const { isLoading: quoteLoading, error: quoteError } = useQuote({
13
+ address: address || undefined,
14
+ });
15
+ // Execute the transaction
16
+ const { executeTransaction, getStatus, isLoading: bridgeLoading, currentStep, error: bridgeError, } = useTransaction({
17
+ address: address,
18
+ walletClient: walletClient,
19
+ connector: connector || undefined,
20
+ });
21
+ const [quote, setQuote] = useState(null);
22
+ const [statusResult, setStatusResult] = useState(null);
23
+ const [isActionLoading, setIsActionLoading] = useState(false);
24
+ const [loadingAction, setLoadingAction] = useState(null);
25
+ const handleGetQuote = async () => {
26
+ if (!address) {
27
+ alert('Please connect your wallet first');
28
+ return;
29
+ }
30
+ setIsActionLoading(true);
31
+ setLoadingAction('quote');
32
+ try {
33
+ const quoteResult = await getBridgeQuote(1, // Ethereum
34
+ '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum
35
+ '1000000', // 1 USDC (6 decimals)
36
+ 43114, // Avalanche
37
+ '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', // USDC.e on Avalanche
38
+ address, new AbortController().signal);
39
+ if (quoteResult) {
40
+ setQuote(quoteResult);
41
+ console.log('Quote:', quoteResult);
42
+ }
43
+ }
44
+ catch (error) {
45
+ console.error('Get quote failed:', error);
46
+ }
47
+ finally {
48
+ setIsActionLoading(false);
49
+ setLoadingAction(null);
50
+ }
51
+ };
52
+ const handleExecuteTransaction = async () => {
53
+ if (!quote) {
54
+ alert('Please get a quote first');
55
+ return;
56
+ }
57
+ if (!walletClient || !connector) {
58
+ alert('Wallet client and connector required');
59
+ return;
60
+ }
61
+ setIsActionLoading(true);
62
+ setLoadingAction('execute');
63
+ try {
64
+ const result = await executeTransaction(quote);
65
+ if (result) {
66
+ console.log('Bridge transaction executed:', result);
67
+ setStatusResult(JSON.stringify(result, null, 2));
68
+ }
69
+ }
70
+ catch (error) {
71
+ console.error('Execute transaction failed:', error);
72
+ }
73
+ finally {
74
+ setIsActionLoading(false);
75
+ setLoadingAction(null);
76
+ }
77
+ };
78
+ const handleGetStatus = async () => {
79
+ if (!quote?.route) {
80
+ alert('No quote available');
81
+ return;
82
+ }
83
+ setIsActionLoading(true);
84
+ setLoadingAction('status');
85
+ try {
86
+ // Extract request ID from quote
87
+ const requestId = quote.provider === 'relay' ? quote.route.steps?.find((s) => s.requestId)?.requestId : quote.route.orderId;
88
+ if (!requestId) {
89
+ throw new Error('No request ID found in quote');
90
+ }
91
+ const status = await getStatus(requestId, quote.provider);
92
+ if (status) {
93
+ setStatusResult(JSON.stringify(status, null, 2));
94
+ }
95
+ }
96
+ catch (error) {
97
+ console.error('Get status failed:', error);
98
+ setStatusResult(`Error: ${error instanceof Error ? error.message : 'Unknown error'}`);
99
+ }
100
+ finally {
101
+ setIsActionLoading(false);
102
+ setLoadingAction(null);
103
+ }
104
+ };
105
+ const isDisabled = quoteLoading || bridgeLoading || isActionLoading;
106
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-xl font-bold", children: "SilentSwap Bridge Execution Demo" }), _jsx("p", { className: "text-gray-400", children: "Execute bridge transactions from quotes obtained via useQuote" }), _jsx(Card, { children: _jsxs("div", { className: "space-y-2", children: [_jsxs("p", { children: [_jsx("strong", { children: "Loading:" }), " ", isDisabled ? '⏳' : '✅'] }), _jsxs("p", { children: [_jsx("strong", { children: "Quote Error:" }), " ", quoteError ? `❌ ${quoteError.message}` : '✅ None'] }), _jsxs("p", { children: [_jsx("strong", { children: "Bridge Error:" }), " ", bridgeError ? `❌ ${bridgeError.message}` : '✅ None'] }), currentStep && (_jsxs("p", { children: [_jsx("strong", { children: "Current Step:" }), " ", currentStep] })), !address && (_jsx("p", { className: "text-red-500", children: _jsx("strong", { children: "\u26A0\uFE0F Please connect your wallet" }) }))] }) }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx(Button, { onClick: handleGetQuote, disabled: isDisabled || !address, variant: "primary", children: loadingAction === 'quote' ? '⏳ Getting Quote...' : '1. Get Best Quote' }), _jsx(Button, { onClick: handleExecuteTransaction, disabled: isDisabled || !quote || !walletClient || !connector, variant: "primary", children: loadingAction === 'execute' ? '⏳ Executing...' : '2. Execute Transaction' }), _jsx(Button, { onClick: handleGetStatus, disabled: isDisabled || !quote, variant: "secondary", children: loadingAction === 'status' ? '⏳ Checking...' : '3. Get Status' })] }), quote && (_jsxs("details", { children: [_jsxs("summary", { className: "cursor-pointer text-blue-400 hover:text-blue-300", children: ["Current Quote (", quote.provider, ")"] }), _jsx(Card, { className: "mt-2", children: _jsxs("div", { className: "space-y-1", children: [_jsxs("p", { children: [_jsx("strong", { children: "Provider:" }), " ", quote.provider] }), _jsxs("p", { children: [_jsx("strong", { children: "Fee:" }), " ", quote.fee.amount, " ", quote.fee.token] }), quote.fee.usdValue && (_jsxs("p", { children: [_jsx("strong", { children: "Fee (USD):" }), " $", quote.fee.usdValue] })), _jsxs("p", { children: [_jsx("strong", { children: "Slippage:" }), " ", quote.slippage, "%"] }), _jsxs("p", { children: [_jsx("strong", { children: "Estimated Time:" }), " ", quote.estimatedTime, "s"] }), _jsxs("p", { children: [_jsx("strong", { children: "Transactions:" }), " ", quote.txs.length] })] }) })] })), statusResult && (_jsxs("details", { children: [_jsx("summary", { className: "cursor-pointer text-blue-400 hover:text-blue-300", children: "Status Result" }), _jsx(Card, { className: "mt-2", children: _jsx("pre", { className: "overflow-auto max-h-96 text-sm", children: statusResult }) })] })), _jsxs("details", { className: "mt-5", children: [_jsx("summary", { className: "cursor-pointer text-blue-400 hover:text-blue-300", children: "Available Methods:" }), _jsx(Card, { className: "mt-2", children: _jsxs("ul", { className: "list-disc list-inside space-y-2", children: [_jsxs("li", { children: [_jsx("code", { className: "text-blue-300", children: "executeTransaction(quote: BridgeQuote)" }), " - Execute a bridge transaction", _jsxs("ul", { className: "list-disc list-inside ml-4 mt-1 space-y-1", children: [_jsx("li", { children: "Automatically switches chains as needed" }), _jsx("li", { children: "Handles multiple transactions for relay provider" }), _jsx("li", { children: "Returns bridge status with transaction hashes and request ID" })] })] }), _jsxs("li", { children: [_jsx("code", { className: "text-blue-300", children: "getStatus(requestId: string, provider: BridgeProvider)" }), " - Get bridge status", _jsxs("ul", { className: "list-disc list-inside ml-4 mt-1 space-y-1", children: [_jsx("li", { children: "Monitors the status of a bridge transaction" }), _jsx("li", { children: "Returns current status (pending, success, failed, etc.)" })] })] })] }) })] })] }));
107
+ }
108
+ const meta = {
109
+ title: 'Hooks/useTransaction',
110
+ component: BridgeDemo,
111
+ tags: ['autodocs'],
112
+ parameters: {
113
+ docs: {
114
+ description: {
115
+ component: 'React hook for executing bridge transactions. Works with quotes from useQuote to execute cross-chain bridge operations.',
116
+ },
117
+ },
118
+ },
119
+ };
120
+ export default meta;
121
+ export const Default = {};
@@ -0,0 +1,33 @@
1
+ import type { AssetInfo } from '@silentswap/sdk';
2
+ /**
3
+ * Format USD value with comma as decimal separator (German format: $19.966,98)
4
+ * Used for displaying USD values in InputPlate and OutputPlate
5
+ */
6
+ export declare function formatUsdValue(value: number | string | null): string | null;
7
+ export declare function formatUSD(amount: string | number): string;
8
+ /**
9
+ * Format price for display (e.g., "1 ETH = $2,500.00")
10
+ * Uses comma as decimal separator
11
+ */
12
+ export declare function formatPrice(price: number): string;
13
+ /**
14
+ * Format balance for display using asset decimals and precision
15
+ */
16
+ export declare function formatBalance(balance: bigint | undefined, assetInfo: AssetInfo | null): string;
17
+ /**
18
+ * Calculate USD value from amount and price
19
+ */
20
+ export declare function calculateUsdValue(amount: string, price: number | undefined): number | null;
21
+ /**
22
+ * Calculate dynamic font size for large numbers
23
+ * Used in OutputPlate for amount display
24
+ */
25
+ export declare function calculateAmountFontSize(amount: string): number;
26
+ /**
27
+ * Format secondary value for swap transaction card (matches Figma: "WBTC $30,253,08")
28
+ * Combines asset symbol with formatted USD value
29
+ * @param assetInfo - Asset information with symbol (can be null or undefined)
30
+ * @param usdValue - USD value (can be number or already formatted string)
31
+ * @returns Formatted string like "WBTC $30,253,08" or null if inputs are invalid
32
+ */
33
+ export declare function formatSecondaryValue(assetInfo: AssetInfo | null | undefined, usdValue: number | string | null): string | null;
@@ -0,0 +1,82 @@
1
+ import { BigNumber } from 'bignumber.js';
2
+ /**
3
+ * Format USD value with comma as decimal separator (German format: $19.966,98)
4
+ * Used for displaying USD values in InputPlate and OutputPlate
5
+ */
6
+ export function formatUsdValue(value) {
7
+ if (value === null || value === undefined)
8
+ return null;
9
+ const num = typeof value === 'string' ? parseFloat(value) : value;
10
+ if (isNaN(num))
11
+ return null;
12
+ // Format with thousands separator (dot) and decimal separator (comma)
13
+ return num.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
14
+ }
15
+ export function formatUSD(amount) {
16
+ // Convert to number and handle potential parsing errors
17
+ const numAmount = typeof amount === 'string' ? parseFloat(amount.replace(/[^0-9.-]/g, '')) : amount;
18
+ // Check for invalid input
19
+ if (isNaN(numAmount)) {
20
+ return '0';
21
+ }
22
+ return new Intl.NumberFormat('en-US', {
23
+ style: 'currency',
24
+ currency: 'USD',
25
+ maximumFractionDigits: 2,
26
+ minimumFractionDigits: 0,
27
+ }).format(numAmount);
28
+ }
29
+ /**
30
+ * Format price for display (e.g., "1 ETH = $2,500.00")
31
+ * Uses comma as decimal separator
32
+ */
33
+ export function formatPrice(price) {
34
+ return price.toFixed(2).replace('.', ',');
35
+ }
36
+ /**
37
+ * Format balance for display using asset decimals and precision
38
+ */
39
+ export function formatBalance(balance, assetInfo) {
40
+ if (!balance || !assetInfo)
41
+ return '0';
42
+ const balanceBN = BigNumber(balance.toString()).shiftedBy(-assetInfo.decimals);
43
+ return balanceBN.toFixed(assetInfo.precision ?? 6);
44
+ }
45
+ /**
46
+ * Calculate USD value from amount and price
47
+ */
48
+ export function calculateUsdValue(amount, price) {
49
+ if (!amount || !price)
50
+ return null;
51
+ const numAmount = parseFloat(amount) || 0;
52
+ return numAmount * price;
53
+ }
54
+ /**
55
+ * Calculate dynamic font size for large numbers
56
+ * Used in OutputPlate for amount display
57
+ */
58
+ export function calculateAmountFontSize(amount) {
59
+ const len = amount.length;
60
+ if (len > 12)
61
+ return 20;
62
+ if (len > 8)
63
+ return 24;
64
+ return 28;
65
+ }
66
+ /**
67
+ * Format secondary value for swap transaction card (matches Figma: "WBTC $30,253,08")
68
+ * Combines asset symbol with formatted USD value
69
+ * @param assetInfo - Asset information with symbol (can be null or undefined)
70
+ * @param usdValue - USD value (can be number or already formatted string)
71
+ * @returns Formatted string like "WBTC $30,253,08" or null if inputs are invalid
72
+ */
73
+ export function formatSecondaryValue(assetInfo, usdValue) {
74
+ if (!assetInfo || !usdValue)
75
+ return null;
76
+ // Format USD value if it's a number, otherwise use the string as-is
77
+ const formatted = typeof usdValue === 'number' ? formatUsdValue(usdValue) : usdValue;
78
+ if (!formatted)
79
+ return null;
80
+ const symbol = assetInfo.symbol?.toUpperCase() || '';
81
+ return `${symbol} $${formatted}`;
82
+ }
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@silentswap/react",
3
+ "type": "module",
4
+ "version": "0.0.41",
5
+ "license": "MIT",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "clean": "rm -rf dist",
14
+ "dev": "tsc --watch",
15
+ "lint": "eslint src --ext .ts",
16
+ "lint:fix": "eslint src --ext .ts --fix",
17
+ "format": "prettier --write \"src/**/*.{ts,tsx}\"",
18
+ "storybook": "storybook dev -p 6006",
19
+ "build-storybook": "storybook build"
20
+ },
21
+ "peerDependencies": {
22
+ "react": ">=16.8.0"
23
+ },
24
+ "dependencies": {
25
+ "@ensdomains/ensjs": "^4.2.0",
26
+ "@silentswap/sdk": "workspace:*",
27
+ "@silentswap/ui-kit": "workspace:*",
28
+ "@solana/codecs-strings": "^5.1.0",
29
+ "@solana/kit": "^5.1.0",
30
+ "@solana/rpc": "^5.1.0",
31
+ "@solana/rpc-subscriptions": "^5.1.0",
32
+ "@solana/spl-token": "^0.4.14",
33
+ "@solana/wallet-adapter-base": "^0.9.27",
34
+ "@solana/wallet-adapter-react": "^0.15.39",
35
+ "@storybook/react": "10.0.7",
36
+ "@tanstack/react-query": "5.90.14",
37
+ "bignumber.js": "9.3.1",
38
+ "usehooks-ts": "^3.1.1",
39
+ "viem": "2.43.3",
40
+ "wagmi": "3.1.3",
41
+ "zustand": "^5.0.9"
42
+ },
43
+ "devDependencies": {
44
+ "@eslint/js": "9.38.0",
45
+ "@storybook/addon-docs": "10.0.7",
46
+ "@storybook/addon-onboarding": "10.0.7",
47
+ "@storybook/react-vite": "10.0.7",
48
+ "@stylistic/eslint-plugin": "5.5.0",
49
+ "@tsconfig/node24": "24.0.1",
50
+ "@types/node": "24.9.1",
51
+ "@types/react": "19.2.2",
52
+ "@types/web": "0.0.283",
53
+ "@typescript-eslint/parser": "8.46.2",
54
+ "buffer": "^6.0.3",
55
+ "eslint": "9.38.0",
56
+ "eslint-import-resolver-typescript": "4.4.4",
57
+ "eslint-plugin-import-x": "4.16.1",
58
+ "eslint-plugin-prettier": "5.2.3",
59
+ "eslint-plugin-storybook": "10.0.7",
60
+ "prettier": "3.5.3",
61
+ "react": "19.2.0",
62
+ "storybook": "10.0.7",
63
+ "typescript": "5.9.3",
64
+ "typescript-eslint": "8.46.2",
65
+ "vite-plugin-node-polyfills": "^0.24.0"
66
+ }
67
+ }