@bitzy-app/bitzy-sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +932 -0
- package/dist/BitzySwapSDK.d.ts +32 -0
- package/dist/BitzySwapSDK.d.ts.map +1 -0
- package/dist/__tests__/setup.d.ts +9 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/api/Client.d.ts +43 -0
- package/dist/api/Client.d.ts.map +1 -0
- package/dist/common/FetchSwapRoute.d.ts +55 -0
- package/dist/common/FetchSwapRoute.d.ts.map +1 -0
- package/dist/constants/Abis.d.ts +46 -0
- package/dist/constants/Abis.d.ts.map +1 -0
- package/dist/constants/index.d.ts +71 -0
- package/dist/constants/index.d.ts.map +1 -0
- package/dist/hooks/useSwapV3Routes.d.ts +107 -0
- package/dist/hooks/useSwapV3Routes.d.ts.map +1 -0
- package/dist/index.d.ts +800 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/services/SwapV3Service.d.ts +64 -0
- package/dist/services/SwapV3Service.d.ts.map +1 -0
- package/dist/types/index.d.ts +259 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/PartCount.d.ts +101 -0
- package/dist/utils/PartCount.d.ts.map +1 -0
- package/dist/utils/index.d.ts +68 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +77 -0
package/README.md
ADDED
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
# Bitzy Swap V3 - Common Function & Hot Hook
|
|
2
|
+
|
|
3
|
+
A comprehensive SDK for fetching swap routes and executing swaps on Bitzy's decentralized exchange. Provides both **common functions** for any environment and **React hooks** for frontend applications.
|
|
4
|
+
|
|
5
|
+
## **What This Package Provides**
|
|
6
|
+
|
|
7
|
+
- **Common Functions** - Work in Node.js, browser, or any JavaScript environment
|
|
8
|
+
- **React Hooks** - Hot reloading with automatic updates and error handling
|
|
9
|
+
- **TypeScript Support** - Full type safety throughout
|
|
10
|
+
- **Intelligent Routing** - Automatic optimization based on token characteristics
|
|
11
|
+
- **Multiple Networks** - Support for Botanix Mainnet and Testnet
|
|
12
|
+
|
|
13
|
+
## **Quick Start**
|
|
14
|
+
|
|
15
|
+
### **Installation**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @bitzy/swap-sdk
|
|
19
|
+
# or
|
|
20
|
+
yarn add @bitzy/swap-sdk
|
|
21
|
+
# or
|
|
22
|
+
pnpm add @bitzy/swap-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## **1. Using Functions**
|
|
26
|
+
|
|
27
|
+
### **1.1 `fetchSwapRoute()` - Main Route Finding Function**
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { fetchSwapRoute } from '@bitzy/swap-sdk';
|
|
31
|
+
|
|
32
|
+
// Basic usage with defaults
|
|
33
|
+
const result = await fetchSwapRoute({
|
|
34
|
+
amountIn: '1.5',
|
|
35
|
+
srcToken: {
|
|
36
|
+
address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
|
|
37
|
+
symbol: 'BTC',
|
|
38
|
+
name: 'Bitcoin',
|
|
39
|
+
decimals: 18,
|
|
40
|
+
chainId: 3637
|
|
41
|
+
},
|
|
42
|
+
dstToken: {
|
|
43
|
+
address: '0x29eE6138DD4C9815f46D34a4A1ed48F46758A402',
|
|
44
|
+
symbol: 'USDC.e',
|
|
45
|
+
name: 'Bridged USDC (Stargate)',
|
|
46
|
+
decimals: 6,
|
|
47
|
+
chainId: 3637
|
|
48
|
+
},
|
|
49
|
+
chainId: 3637
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
console.log('Routes found:', result.routes.length);
|
|
53
|
+
console.log('Amount out:', result.amountOutBN.toFixed());
|
|
54
|
+
console.log('Distributions:', result.distributions);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### **1.2 `fetchBatchSwapRoutes()` - Multiple Routes at Once**
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { fetchBatchSwapRoutes } from '@bitzy/swap-sdk';
|
|
61
|
+
|
|
62
|
+
// Fetch multiple routes simultaneously
|
|
63
|
+
const results = await fetchBatchSwapRoutes([
|
|
64
|
+
{
|
|
65
|
+
options: {
|
|
66
|
+
amountIn: '1.0',
|
|
67
|
+
srcToken: btcToken,
|
|
68
|
+
dstToken: usdcToken,
|
|
69
|
+
chainId: 3637
|
|
70
|
+
},
|
|
71
|
+
config: { apiBaseUrl: 'https://api-public.bitzy.app' }
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
options: {
|
|
75
|
+
amountIn: '2.0',
|
|
76
|
+
srcToken: ethToken,
|
|
77
|
+
dstToken: usdtToken,
|
|
78
|
+
chainId: 3637
|
|
79
|
+
},
|
|
80
|
+
config: { apiBaseUrl: 'https://api-public.bitzy.app' }
|
|
81
|
+
}
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
// Results array with success/error status for each
|
|
85
|
+
results.forEach((result, index) => {
|
|
86
|
+
if (result.success) {
|
|
87
|
+
console.log(`Route ${index + 1}:`, result.data.routes.length, 'routes');
|
|
88
|
+
} else {
|
|
89
|
+
console.error(`Route ${index + 1} failed:`, result.error);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### **1.3 `getSwapQuote()` - Simple Price Quote**
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { getSwapQuote } from '@bitzy/swap-sdk';
|
|
98
|
+
|
|
99
|
+
// Get a simple quote without full routing details
|
|
100
|
+
const quote = await getSwapQuote(
|
|
101
|
+
srcToken,
|
|
102
|
+
dstToken,
|
|
103
|
+
'1.5',
|
|
104
|
+
3637,
|
|
105
|
+
{ apiBaseUrl: 'https://api-public.bitzy.app' }
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
console.log('Amount out:', quote.amountOut);
|
|
109
|
+
console.log('Route count:', quote.routes);
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### **1.4 `fetchSwapRouteSimple()` - Minimal Configuration**
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import { fetchSwapRouteSimple } from '@bitzy/swap-sdk';
|
|
116
|
+
|
|
117
|
+
// Simplified function with minimal parameters
|
|
118
|
+
const result = await fetchSwapRouteSimple(
|
|
119
|
+
srcToken,
|
|
120
|
+
dstToken,
|
|
121
|
+
'1.0',
|
|
122
|
+
3637
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// Returns the same SwapResult as fetchSwapRoute
|
|
126
|
+
console.log('Best route:', result.routes[0]);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## **2. Using React Hooks**
|
|
130
|
+
|
|
131
|
+
### **2.1 `useSwapV3Routes()` - Main React Hook**
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { useSwapV3Routes } from '@bitzy/swap-sdk';
|
|
135
|
+
|
|
136
|
+
function SwapComponent() {
|
|
137
|
+
const [srcToken, setSrcToken] = useState(btcToken);
|
|
138
|
+
const [dstToken, setDstToken] = useState(usdcToken);
|
|
139
|
+
const [amountIn, setAmountIn] = useState('1.0');
|
|
140
|
+
|
|
141
|
+
// Basic usage with defaults
|
|
142
|
+
const {
|
|
143
|
+
routes,
|
|
144
|
+
distributions,
|
|
145
|
+
amountOutRoutes,
|
|
146
|
+
amountOutBN,
|
|
147
|
+
amountInParts,
|
|
148
|
+
isLoading,
|
|
149
|
+
isAmountOutError,
|
|
150
|
+
isFirstFetch,
|
|
151
|
+
isWrap,
|
|
152
|
+
error,
|
|
153
|
+
fetchRoute,
|
|
154
|
+
clearError
|
|
155
|
+
} = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);
|
|
156
|
+
|
|
157
|
+
// Advanced usage with custom configuration
|
|
158
|
+
const swapConfig = {
|
|
159
|
+
apiBaseUrl: 'https://api-public.bitzy.app',
|
|
160
|
+
config: {
|
|
161
|
+
routerAddress: '0xA5E0AE4e5103dc71cA290AA3654830442357A489',
|
|
162
|
+
bitzyQueryAddress: '0x...',
|
|
163
|
+
wrappedAddress: '0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56',
|
|
164
|
+
nativeAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
|
|
165
|
+
},
|
|
166
|
+
defaultPartCount: 5,
|
|
167
|
+
timeout: 30000,
|
|
168
|
+
publicClient: publicClient,
|
|
169
|
+
types: [1, 2], // V2 and V3 liquidity sources
|
|
170
|
+
enabledSources: [1], // Bitzy source
|
|
171
|
+
useOnlinePartCount: true, // Enable intelligent routing
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const advancedResult = useSwapV3Routes(
|
|
175
|
+
srcToken,
|
|
176
|
+
dstToken,
|
|
177
|
+
amountIn,
|
|
178
|
+
3637,
|
|
179
|
+
swapConfig
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div>
|
|
184
|
+
{isLoading ? (
|
|
185
|
+
<div>Finding best routes...</div>
|
|
186
|
+
) : (
|
|
187
|
+
<div>
|
|
188
|
+
{routes.length > 0 ? (
|
|
189
|
+
<div>
|
|
190
|
+
<p>Amount out: {amountOutBN.toString()} {dstToken.symbol}</p>
|
|
191
|
+
<p>Routes found: {routes.length}</p>
|
|
192
|
+
<p>Is wrap: {isWrap || 'No'}</p>
|
|
193
|
+
</div>
|
|
194
|
+
) : (
|
|
195
|
+
<div>No routes found</div>
|
|
196
|
+
)}
|
|
197
|
+
</div>
|
|
198
|
+
)}
|
|
199
|
+
|
|
200
|
+
{error && (
|
|
201
|
+
<div className="error">
|
|
202
|
+
{error}
|
|
203
|
+
<button onClick={clearError}>Dismiss</button>
|
|
204
|
+
</div>
|
|
205
|
+
)}
|
|
206
|
+
|
|
207
|
+
<button onClick={fetchRoute}>Refresh Routes</button>
|
|
208
|
+
</div>
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## **3. Prepare to Swap Using Response**
|
|
214
|
+
|
|
215
|
+
Based on the main repository implementation, here's how to use the SDK response to prepare and execute swaps:
|
|
216
|
+
|
|
217
|
+
### **3.1 Complete Swap Implementation**
|
|
218
|
+
|
|
219
|
+
Here are generic examples showing how to execute swaps using direct contract calls with the SDK response data:
|
|
220
|
+
|
|
221
|
+
#### **Example 1: Using Viem with BitzyAggregator Contract**
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
import { useSwapV3Routes } from '@bitzy/swap-sdk';
|
|
225
|
+
import { useWriteContract, useAccount } from 'wagmi';
|
|
226
|
+
import { parseUnits, formatUnits } from 'viem';
|
|
227
|
+
|
|
228
|
+
function SwapComponent() {
|
|
229
|
+
const [srcToken, setSrcToken] = useState(btcToken);
|
|
230
|
+
const [dstToken, setDstToken] = useState(usdcToken);
|
|
231
|
+
const [amountIn, setAmountIn] = useState('1.0'); // 1 BTC
|
|
232
|
+
const [slippage, setSlippage] = useState(0.005); // 0.05%
|
|
233
|
+
|
|
234
|
+
const { address, publicClient } = useAccount();
|
|
235
|
+
const { writeContract } = useWriteContract();
|
|
236
|
+
|
|
237
|
+
// Get swap routes using SDK
|
|
238
|
+
const {
|
|
239
|
+
routes,
|
|
240
|
+
distributions,
|
|
241
|
+
amountOutRoutes,
|
|
242
|
+
amountOutBN,
|
|
243
|
+
amountInParts,
|
|
244
|
+
isLoading,
|
|
245
|
+
isAmountOutError,
|
|
246
|
+
isFirstFetch,
|
|
247
|
+
isWrap,
|
|
248
|
+
error,
|
|
249
|
+
fetchRoute
|
|
250
|
+
} = useSwapV3Routes(srcToken, dstToken, amountIn, 3637, {
|
|
251
|
+
apiBaseUrl: 'https://api-public.bitzy.app',
|
|
252
|
+
config: {
|
|
253
|
+
routerAddress: '0xA5E0AE4e5103dc71cA290AA3654830442357A489',
|
|
254
|
+
bitzyQueryAddress: '0x...',
|
|
255
|
+
wrappedAddress: '0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56',
|
|
256
|
+
nativeAddress: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
|
|
257
|
+
},
|
|
258
|
+
defaultPartCount: 5,
|
|
259
|
+
timeout: 30000,
|
|
260
|
+
publicClient: publicClient,
|
|
261
|
+
types: [1, 2],
|
|
262
|
+
enabledSources: [1],
|
|
263
|
+
useOnlinePartCount: true,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Execute swap using direct contract call
|
|
267
|
+
const handleSwap = useCallback(async () => {
|
|
268
|
+
if (!srcToken || !dstToken || !routes.length || !address) return;
|
|
269
|
+
|
|
270
|
+
const amountInBN = parseUnits(amountIn, srcToken.decimals);
|
|
271
|
+
const amountOutBN = BigNumber(amountOutBN.toFixed());
|
|
272
|
+
const slippageBN = BigNumber(slippage);
|
|
273
|
+
const amountOutMin = amountOutBN.times(1 - slippageBN);
|
|
274
|
+
|
|
275
|
+
// Handle wrap/unwrap cases
|
|
276
|
+
if (isWrap === 'wrap') {
|
|
277
|
+
// Native to Wrapped (e.g., ETH to WETH)
|
|
278
|
+
await writeContract({
|
|
279
|
+
address: wrappedAddress, // WETH contract
|
|
280
|
+
abi: [
|
|
281
|
+
{
|
|
282
|
+
name: 'deposit',
|
|
283
|
+
type: 'function',
|
|
284
|
+
stateMutability: 'payable',
|
|
285
|
+
inputs: [],
|
|
286
|
+
outputs: []
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
functionName: 'deposit',
|
|
290
|
+
value: amountInBN,
|
|
291
|
+
});
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (isWrap === 'unwrap') {
|
|
296
|
+
// Wrapped to Native (e.g., WETH to ETH)
|
|
297
|
+
await writeContract({
|
|
298
|
+
address: wrappedAddress, // WETH contract
|
|
299
|
+
abi: [
|
|
300
|
+
{
|
|
301
|
+
name: 'withdraw',
|
|
302
|
+
type: 'function',
|
|
303
|
+
stateMutability: 'nonpayable',
|
|
304
|
+
inputs: [{ name: 'amount', type: 'uint256' }],
|
|
305
|
+
outputs: []
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
functionName: 'withdraw',
|
|
309
|
+
args: [amountInBN],
|
|
310
|
+
});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Regular swap using splitTrade
|
|
315
|
+
const tradeRoutes = routes.map((route, i) => {
|
|
316
|
+
const amountInPart = amountInParts[i];
|
|
317
|
+
const amountOutMinPart = amountOutRoutes[i].times(1 - slippageBN);
|
|
318
|
+
const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
srcToken: srcToken.address,
|
|
322
|
+
dstToken: dstToken.address,
|
|
323
|
+
amountIn: amountInPart.toFixed(0),
|
|
324
|
+
amountOutMin: amountOutMinPart.toFixed(0),
|
|
325
|
+
to: address,
|
|
326
|
+
routes: route,
|
|
327
|
+
isRouterSource: isRouterSource,
|
|
328
|
+
isSourceFee: true,
|
|
329
|
+
};
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
await writeContract({
|
|
333
|
+
address: '0xA5E0AE4e5103dc71cA290AA3654830442357A489', // BitzyAggregator
|
|
334
|
+
abi: [
|
|
335
|
+
{
|
|
336
|
+
name: 'splitTrade',
|
|
337
|
+
type: 'function',
|
|
338
|
+
stateMutability: 'payable',
|
|
339
|
+
inputs: [
|
|
340
|
+
{ name: 'srcToken', type: 'address' },
|
|
341
|
+
{ name: 'dstToken', type: 'address' },
|
|
342
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
343
|
+
{ name: 'amountOutMin', type: 'uint256' },
|
|
344
|
+
{ name: 'isSrcNative', type: 'bool' },
|
|
345
|
+
{ name: 'tradeRoutes', type: 'tuple[]' },
|
|
346
|
+
{ name: 'to', type: 'address' }
|
|
347
|
+
],
|
|
348
|
+
outputs: []
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
functionName: 'splitTrade',
|
|
352
|
+
args: [
|
|
353
|
+
srcToken.address,
|
|
354
|
+
dstToken.address,
|
|
355
|
+
amountInBN.toFixed(0),
|
|
356
|
+
amountOutMin.toFixed(0),
|
|
357
|
+
srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', // isSrcNative
|
|
358
|
+
tradeRoutes,
|
|
359
|
+
address
|
|
360
|
+
],
|
|
361
|
+
value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN : 0n,
|
|
362
|
+
});
|
|
363
|
+
}, [srcToken, dstToken, amountIn, routes, distributions, amountOutRoutes, amountInParts, slippage, address, writeContract, isWrap]);
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
<div>
|
|
367
|
+
<input
|
|
368
|
+
value={amountIn}
|
|
369
|
+
onChange={(e) => setAmountIn(e.target.value)}
|
|
370
|
+
placeholder="Amount to swap"
|
|
371
|
+
/>
|
|
372
|
+
|
|
373
|
+
{isLoading ? (
|
|
374
|
+
<div>Finding best routes...</div>
|
|
375
|
+
) : (
|
|
376
|
+
<div>
|
|
377
|
+
{routes.length > 0 ? (
|
|
378
|
+
<div>
|
|
379
|
+
<p>Amount out: {formatUnits(amountOutBN.toFixed(), dstToken.decimals)} {dstToken.symbol}</p>
|
|
380
|
+
<p>Routes found: {routes.length}</p>
|
|
381
|
+
<p>Is wrap: {isWrap || 'No'}</p>
|
|
382
|
+
</div>
|
|
383
|
+
) : (
|
|
384
|
+
<div>No routes found</div>
|
|
385
|
+
)}
|
|
386
|
+
</div>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{error && <div className="error">{error}</div>}
|
|
390
|
+
|
|
391
|
+
<button onClick={handleSwap} disabled={!routes.length}>
|
|
392
|
+
{isWrap ? capitalize(isWrap) : 'Swap'}
|
|
393
|
+
</button>
|
|
394
|
+
|
|
395
|
+
<button onClick={fetchRoute}>Refresh Routes</button>
|
|
396
|
+
</div>
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### **Example 2: Using Ethers.js**
|
|
402
|
+
|
|
403
|
+
```typescript
|
|
404
|
+
import { useSwapV3Routes } from '@bitzy/swap-sdk';
|
|
405
|
+
import { ethers } from 'ethers';
|
|
406
|
+
|
|
407
|
+
function SwapWithEthers() {
|
|
408
|
+
const [provider, setProvider] = useState<ethers.BrowserProvider | null>(null);
|
|
409
|
+
const [signer, setSigner] = useState<ethers.JsonRpcSigner | null>(null);
|
|
410
|
+
|
|
411
|
+
// Get swap routes using SDK
|
|
412
|
+
const {
|
|
413
|
+
routes,
|
|
414
|
+
distributions,
|
|
415
|
+
amountOutRoutes,
|
|
416
|
+
amountOutBN,
|
|
417
|
+
amountInParts,
|
|
418
|
+
isLoading,
|
|
419
|
+
isWrap,
|
|
420
|
+
error,
|
|
421
|
+
fetchRoute
|
|
422
|
+
} = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);
|
|
423
|
+
|
|
424
|
+
// Execute swap using ethers.js
|
|
425
|
+
const executeSwap = async () => {
|
|
426
|
+
if (!signer || !routes.length) return;
|
|
427
|
+
|
|
428
|
+
const aggregatorContract = new ethers.Contract(
|
|
429
|
+
'0xA5E0AE4e5103dc71cA290AA3654830442357A489', // BitzyAggregator
|
|
430
|
+
[
|
|
431
|
+
'function splitTrade(address srcToken, address dstToken, uint256 amountIn, uint256 amountOutMin, bool isSrcNative, tuple[] tradeRoutes, address to) payable'
|
|
432
|
+
],
|
|
433
|
+
signer
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
const amountInBN = ethers.parseUnits(amountIn, srcToken.decimals);
|
|
437
|
+
const amountOutMin = amountOutBN.times(1 - slippage)
|
|
438
|
+
|
|
439
|
+
const tradeRoutes = routes.map((route, i) => {
|
|
440
|
+
const amountInPart = amountInParts[i];
|
|
441
|
+
const amountOutMinPart = amountOutRoutes[i].times(1 - slippage);
|
|
442
|
+
const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';
|
|
443
|
+
|
|
444
|
+
return [
|
|
445
|
+
srcToken.address,
|
|
446
|
+
dstToken.address,
|
|
447
|
+
amountInPart.toFixed(0),
|
|
448
|
+
amountOutMinPart.toFixed(0),
|
|
449
|
+
userAddress,
|
|
450
|
+
route,
|
|
451
|
+
isRouterSource,
|
|
452
|
+
true
|
|
453
|
+
];
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const tx = await aggregatorContract.splitTrade(
|
|
457
|
+
srcToken.address,
|
|
458
|
+
dstToken.address,
|
|
459
|
+
amountInBN.toFixed(0),
|
|
460
|
+
amountOutMin.toFixed(0),
|
|
461
|
+
srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
|
|
462
|
+
tradeRoutes,
|
|
463
|
+
userAddress,
|
|
464
|
+
{
|
|
465
|
+
value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN.toFixed() : 0
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const receipt = await tx.wait();
|
|
470
|
+
console.log('Swap completed:', receipt.transactionHash);
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
return (
|
|
474
|
+
<div>
|
|
475
|
+
{/* UI components */}
|
|
476
|
+
<button onClick={executeSwap} disabled={!routes.length}>
|
|
477
|
+
Execute Swap
|
|
478
|
+
</button>
|
|
479
|
+
</div>
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
#### **Example 3: Using Web3.js**
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
import { useSwapV3Routes } from '@bitzy/swap-sdk';
|
|
488
|
+
import Web3 from 'web3';
|
|
489
|
+
|
|
490
|
+
function SwapWithWeb3() {
|
|
491
|
+
const [web3, setWeb3] = useState<Web3 | null>(null);
|
|
492
|
+
const [account, setAccount] = useState<string | null>(null);
|
|
493
|
+
|
|
494
|
+
// Get swap routes using SDK
|
|
495
|
+
const {
|
|
496
|
+
routes,
|
|
497
|
+
distributions,
|
|
498
|
+
amountOutRoutes,
|
|
499
|
+
amountInParts,
|
|
500
|
+
isLoading,
|
|
501
|
+
isWrap,
|
|
502
|
+
error,
|
|
503
|
+
fetchRoute
|
|
504
|
+
} = useSwapV3Routes(srcToken, dstToken, amountIn, 3637);
|
|
505
|
+
|
|
506
|
+
// Execute swap using web3.js
|
|
507
|
+
const executeSwap = async () => {
|
|
508
|
+
if (!web3 || !account || !routes.length) return;
|
|
509
|
+
|
|
510
|
+
const aggregatorContract = new web3.eth.Contract([
|
|
511
|
+
{
|
|
512
|
+
name: 'splitTrade',
|
|
513
|
+
type: 'function',
|
|
514
|
+
stateMutability: 'payable',
|
|
515
|
+
inputs: [
|
|
516
|
+
{ name: 'srcToken', type: 'address' },
|
|
517
|
+
{ name: 'dstToken', type: 'address' },
|
|
518
|
+
{ name: 'amountIn', type: 'uint256' },
|
|
519
|
+
{ name: 'amountOutMin', type: 'uint256' },
|
|
520
|
+
{ name: 'isSrcNative', type: 'bool' },
|
|
521
|
+
{ name: 'tradeRoutes', type: 'tuple[]' },
|
|
522
|
+
{ name: 'to', type: 'address' }
|
|
523
|
+
],
|
|
524
|
+
outputs: []
|
|
525
|
+
}
|
|
526
|
+
], '0xA5E0AE4e5103dc71cA290AA3654830442357A489');
|
|
527
|
+
|
|
528
|
+
const amountInBN = web3.utils.toWei(amountIn, 'ether');
|
|
529
|
+
const amountOutMin = amountOutBN.times(1 - slippage)
|
|
530
|
+
|
|
531
|
+
const tradeRoutes = routes.map((route, i) => {
|
|
532
|
+
const amountInPart = amountInParts[i];
|
|
533
|
+
const amountOutMinPart = amountOutRoutes[i].times(1 - slippage);
|
|
534
|
+
const isRouterSource = route[0].from === '0x0000000000000000000000000000000000000000';
|
|
535
|
+
|
|
536
|
+
return [
|
|
537
|
+
srcToken.address,
|
|
538
|
+
dstToken.address,
|
|
539
|
+
amountInPart.toString(),
|
|
540
|
+
amountOutMinPart.toString(),
|
|
541
|
+
account,
|
|
542
|
+
route,
|
|
543
|
+
isRouterSource,
|
|
544
|
+
true
|
|
545
|
+
];
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
const tx = await aggregatorContract.methods.splitTrade(
|
|
549
|
+
srcToken.address,
|
|
550
|
+
dstToken.address,
|
|
551
|
+
amountInBN,
|
|
552
|
+
amountOutMin.toFixed(0),
|
|
553
|
+
srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
|
|
554
|
+
tradeRoutes,
|
|
555
|
+
account
|
|
556
|
+
).send({
|
|
557
|
+
from: account,
|
|
558
|
+
value: srcToken.address === '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' ? amountInBN : '0'
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
console.log('Swap completed:', tx.transactionHash);
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
return (
|
|
565
|
+
<div>
|
|
566
|
+
{/* UI components */}
|
|
567
|
+
<button onClick={executeSwap} disabled={!routes.length}>
|
|
568
|
+
Execute Swap
|
|
569
|
+
</button>
|
|
570
|
+
</div>
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### **3.2 Key Data from SDK Response**
|
|
576
|
+
|
|
577
|
+
The SDK provides all the necessary data for swap execution:
|
|
578
|
+
|
|
579
|
+
```typescript
|
|
580
|
+
interface SwapResult {
|
|
581
|
+
routes: SwapRoute[][]; // Array of route arrays
|
|
582
|
+
distributions: number[]; // Liquidity distribution percentages
|
|
583
|
+
amountOutRoutes: string[]; // Output amounts per route
|
|
584
|
+
amountOutBN: BigNumber; // Total output amount
|
|
585
|
+
amountInParts: string[]; // Input amounts per part
|
|
586
|
+
isWrap?: "wrap" | "unwrap"; // Wrap/unwrap indicator
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// Example usage in your swap function:
|
|
590
|
+
swap(
|
|
591
|
+
srcToken,
|
|
592
|
+
dstToken,
|
|
593
|
+
amountIn, // User input
|
|
594
|
+
amountOut, // Calculated from amountOutBN
|
|
595
|
+
routes, // From SDK - route details
|
|
596
|
+
distributions, // From SDK - how to split liquidity
|
|
597
|
+
amountOutRoutes, // From SDK - amounts per route
|
|
598
|
+
amountInParts, // From SDK - input amounts per part
|
|
599
|
+
slippageNumber // User setting
|
|
600
|
+
);
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
### **3.3 Environment Variables**
|
|
604
|
+
|
|
605
|
+
```bash
|
|
606
|
+
# .env file
|
|
607
|
+
NEXT_PUBLIC_BITZY_API_KEY=your-api-key-here
|
|
608
|
+
NEXT_PUBLIC_BITZY_API_URL=https://api-public.bitzy.app
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
```typescript
|
|
612
|
+
// The SDK will automatically use these environment variables
|
|
613
|
+
const result = useSwapV3Routes(srcToken, dstToken, amountIn, chainId);
|
|
614
|
+
// Uses process.env.NEXT_PUBLIC_BITZY_API_KEY if available
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
## **Advanced Features**
|
|
618
|
+
|
|
619
|
+
### **Hot Hook Features**
|
|
620
|
+
|
|
621
|
+
The `useSwapV3Routes` hook is designed for **hot reloading** and **real-time updates**:
|
|
622
|
+
|
|
623
|
+
- **Auto-updates** - Fetches fresh routes every 10 seconds
|
|
624
|
+
- **Debounced** - Prevents excessive API calls
|
|
625
|
+
- **Error handling** - Built-in error state and recovery
|
|
626
|
+
- **Hot reload** - Automatically reinitializes when config changes
|
|
627
|
+
- **📱 React Native ready** - Works in any React environment
|
|
628
|
+
|
|
629
|
+
### **Intelligent Routing**
|
|
630
|
+
|
|
631
|
+
The SDK automatically optimizes swap execution based on token characteristics:
|
|
632
|
+
|
|
633
|
+
- **High-value pairs** (BTC-USDC, ETH-USDT): Uses `partCount = 5` for optimal execution
|
|
634
|
+
- **Mixed pairs** (BTC-MEME, ETH-SHIB): Uses `partCount = 1` for simplicity
|
|
635
|
+
- **Low-value pairs** (MEME-SHIB): Uses `partCount = 1` for simplicity
|
|
636
|
+
- **Online mode**: Checks minimum amount thresholds from API to determine if multi-route is beneficial
|
|
637
|
+
|
|
638
|
+
### **High-Value Tokens (Network-Specific)**
|
|
639
|
+
|
|
640
|
+
```typescript
|
|
641
|
+
// Botanix Mainnet (3637)
|
|
642
|
+
const highValueTokens = [
|
|
643
|
+
"0x0D2437F93Fed6EA64Ef01cCde385FB1263910C56", // pBTC (Botanix)
|
|
644
|
+
"0x29eE6138DD4C9815f46D34a4A1ed48F46758A402", // USDC.e (Bridged USDC Stargate)
|
|
645
|
+
"0x9BC574a6f1170e90D80826D86a6126d59198A3Ef", // rovBTC (Rover BTC)
|
|
646
|
+
"0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C", // USDC
|
|
647
|
+
"0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
|
|
648
|
+
];
|
|
649
|
+
|
|
650
|
+
// Botanix Testnet (3636)
|
|
651
|
+
const highValueTokens = [
|
|
652
|
+
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // ETH/BTC native
|
|
653
|
+
"0x233631132FD56c8f86D1FC97F0b82420a8d20af3", // WBTC
|
|
654
|
+
"0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C", // USDC
|
|
655
|
+
"0xdAC17F958D2ee523a2206206994597C13D831ec7", // USDT
|
|
656
|
+
];
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
## 📚 **API Reference**
|
|
660
|
+
|
|
661
|
+
### **Functions**
|
|
662
|
+
|
|
663
|
+
#### **`fetchSwapRoute(options, config?)`**
|
|
664
|
+
Main function for fetching swap routes in any environment.
|
|
665
|
+
|
|
666
|
+
**Parameters:**
|
|
667
|
+
- `options: SwapOptions` - Swap parameters
|
|
668
|
+
- `config?: FetchSwapRouteConfig` - Optional configuration
|
|
669
|
+
|
|
670
|
+
**Returns:** `Promise<SwapResult>`
|
|
671
|
+
|
|
672
|
+
#### **`fetchBatchSwapRoutes(requests)`**
|
|
673
|
+
Fetch multiple routes simultaneously.
|
|
674
|
+
|
|
675
|
+
**Parameters:**
|
|
676
|
+
- `requests: Array<{options: SwapOptions, config?: FetchSwapRouteConfig}>`
|
|
677
|
+
|
|
678
|
+
**Returns:** `Promise<Array<{success: boolean, data?: SwapResult, error?: string}>>`
|
|
679
|
+
|
|
680
|
+
#### **`getSwapQuote(srcToken, dstToken, amountIn, chainId, config?)`**
|
|
681
|
+
Get a simple price quote without full routing details.
|
|
682
|
+
|
|
683
|
+
**Returns:** `Promise<{amountOut: string, routes: number}>`
|
|
684
|
+
|
|
685
|
+
#### **`fetchSwapRouteSimple(srcToken, dstToken, amountIn, chainId)`**
|
|
686
|
+
Simplified function with minimal parameters.
|
|
687
|
+
|
|
688
|
+
**Returns:** `Promise<SwapResult>`
|
|
689
|
+
|
|
690
|
+
### **React Hooks**
|
|
691
|
+
|
|
692
|
+
#### **`useSwapV3Routes(srcToken, dstToken, amountIn, chainId, config?)`**
|
|
693
|
+
|
|
694
|
+
**Parameters:**
|
|
695
|
+
- `srcToken: Token | null` - Source token
|
|
696
|
+
- `dstToken: Token | null` - Destination token
|
|
697
|
+
- `amountIn: string` - Input amount
|
|
698
|
+
- `chainId: number` - Network chain ID
|
|
699
|
+
- `config?: UseSwapV3RoutesConfig` - Optional configuration
|
|
700
|
+
|
|
701
|
+
**Returns:**
|
|
702
|
+
```typescript
|
|
703
|
+
{
|
|
704
|
+
routes: SwapRoute[][]; // Array of route arrays
|
|
705
|
+
distributions: number[]; // Liquidity distribution percentages
|
|
706
|
+
amountOutRoutes: string[]; // Output amounts per route
|
|
707
|
+
amountOutBN: BigNumber; // Total output amount
|
|
708
|
+
amountInParts: string[]; // Input amounts per part
|
|
709
|
+
fetchRoute: () => void; // Manual fetch function
|
|
710
|
+
isLoading: boolean; // Loading state
|
|
711
|
+
isAmountOutError: boolean; // Error flag
|
|
712
|
+
isFirstFetch: boolean; // First fetch completed
|
|
713
|
+
isWrap?: "wrap" | "unwrap"; // Wrap/unwrap indicator
|
|
714
|
+
error: string | null; // Error message
|
|
715
|
+
clearError: () => void // Clear error function
|
|
716
|
+
}
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
### **Types**
|
|
720
|
+
|
|
721
|
+
#### **`SwapOptions`**
|
|
722
|
+
```typescript
|
|
723
|
+
interface SwapOptions {
|
|
724
|
+
amountIn: string; // Input amount (e.g., "1.5")
|
|
725
|
+
srcToken: Token; // Source token
|
|
726
|
+
dstToken: Token; // Destination token
|
|
727
|
+
chainId: number; // Network chain ID
|
|
728
|
+
partCount?: number; // Optional: Liquidity parts
|
|
729
|
+
}
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
#### **`FetchSwapRouteConfig`**
|
|
733
|
+
```typescript
|
|
734
|
+
interface FetchSwapRouteConfig {
|
|
735
|
+
apiBaseUrl?: string; // Optional: API base URL (defaults to https://api-public.bitzy.app)
|
|
736
|
+
networks?: Record<number, any>; // Optional: Custom network configs
|
|
737
|
+
defaultPartCount?: number; // Optional: Default parts (defaults to 5)
|
|
738
|
+
timeout?: number; // Optional: Request timeout (defaults to 30000)
|
|
739
|
+
headers?: Record<string, string>; // Optional: Custom HTTP headers (defaults to {})
|
|
740
|
+
forcePartCount?: number; // Optional: Force specific partCount, overriding intelligent calculation
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
#### **`UseSwapV3RoutesConfig`**
|
|
745
|
+
```typescript
|
|
746
|
+
interface UseSwapV3RoutesConfig {
|
|
747
|
+
apiBaseUrl?: string; // Base URL for the Bitzy API
|
|
748
|
+
apiKey?: string; // API key for authentication (optional)
|
|
749
|
+
config?: UseSwapV3RoutesAddressConfig; // Contract addresses configuration
|
|
750
|
+
defaultPartCount?: number; // Default number of routes to split large swaps into
|
|
751
|
+
timeout?: number; // Request timeout in milliseconds
|
|
752
|
+
headers?: Record<string, string>; // Additional HTTP headers
|
|
753
|
+
refreshInterval?: number; // Interval for automatic route refresh
|
|
754
|
+
publicClient?: PublicClient; // Viem PublicClient instance
|
|
755
|
+
types?: number[]; // Array of liquidity source types to include
|
|
756
|
+
enabledSources?: number[]; // Array of enabled liquidity sources
|
|
757
|
+
forcePartCount?: number; // Override partCount calculation logic
|
|
758
|
+
useOnlinePartCount?: boolean; // Use online API to determine optimal partCount
|
|
759
|
+
}
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
#### **`Token`**
|
|
763
|
+
```typescript
|
|
764
|
+
interface Token {
|
|
765
|
+
address: Address; // Token contract address
|
|
766
|
+
symbol: string; // Token symbol (e.g., "BTC", "USDC")
|
|
767
|
+
name: string; // Token name (e.g., "Bitcoin", "USD Coin")
|
|
768
|
+
decimals: number; // Token decimals
|
|
769
|
+
chainId: number; // Network chain ID
|
|
770
|
+
logoURI?: string; // Optional: Token logo URL
|
|
771
|
+
}
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
## 🎨 **Additional Examples**
|
|
775
|
+
|
|
776
|
+
### **Backend Usage (Node.js)**
|
|
777
|
+
|
|
778
|
+
```typescript
|
|
779
|
+
import { fetchSwapRoute, fetchBatchSwapRoutes } from '@bitzy/swap-sdk';
|
|
780
|
+
|
|
781
|
+
// Express.js endpoint
|
|
782
|
+
app.post('/api/swap/routes', async (req, res) => {
|
|
783
|
+
try {
|
|
784
|
+
const { amountIn, srcToken, dstToken, chainId } = req.body;
|
|
785
|
+
|
|
786
|
+
const result = await fetchSwapRoute(
|
|
787
|
+
{ amountIn, srcToken, dstToken, chainId }
|
|
788
|
+
// No config needed - uses defaults
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
res.json({ success: true, data: result });
|
|
792
|
+
} catch (error) {
|
|
793
|
+
res.status(500).json({
|
|
794
|
+
success: false,
|
|
795
|
+
error: error.message
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// Batch processing
|
|
801
|
+
app.post('/api/swap/batch', async (req, res) => {
|
|
802
|
+
const { swaps } = req.body;
|
|
803
|
+
|
|
804
|
+
const results = await fetchBatchSwapRoutes(
|
|
805
|
+
swaps.map(swap => ({
|
|
806
|
+
options: swap,
|
|
807
|
+
config: { apiBaseUrl: process.env.NEXT_PUBLIC_BITZY_API_URL }
|
|
808
|
+
}))
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
res.json({ success: true, data: results });
|
|
812
|
+
});
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### **Utility Functions**
|
|
816
|
+
|
|
817
|
+
```typescript
|
|
818
|
+
import {
|
|
819
|
+
isHighValueToken,
|
|
820
|
+
getPartCountOffline,
|
|
821
|
+
getPartCountOnline,
|
|
822
|
+
getPartCountWithFallback,
|
|
823
|
+
clearMinimumAmountsCache,
|
|
824
|
+
APIClient
|
|
825
|
+
} from '@bitzy/swap-sdk';
|
|
826
|
+
|
|
827
|
+
// Check if token is high-value (requires chainId)
|
|
828
|
+
const isHighValue = isHighValueToken(token, 3637);
|
|
829
|
+
|
|
830
|
+
// Get offline partCount (requires chainId)
|
|
831
|
+
const partCount = getPartCountOffline(srcToken, dstToken, 3637, 5);
|
|
832
|
+
|
|
833
|
+
// Get online partCount with real-time data
|
|
834
|
+
const onlinePartCount = await getPartCountOnline(
|
|
835
|
+
srcToken, dstToken, amountIn, 3637, apiBaseUrl
|
|
836
|
+
);
|
|
837
|
+
|
|
838
|
+
// Get partCount with fallback
|
|
839
|
+
const partCount = await getPartCountWithFallback(
|
|
840
|
+
srcToken, dstToken, amountIn, 3637, apiBaseUrl, 5
|
|
841
|
+
);
|
|
842
|
+
|
|
843
|
+
// Cache management functions
|
|
844
|
+
clearMinimumAmountsCache(); // Clear cached minimum amounts data
|
|
845
|
+
APIClient.resetInstance(); // Reset singleton APIClient and cache
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
## **Configuration**
|
|
849
|
+
|
|
850
|
+
### **Network Configuration**
|
|
851
|
+
|
|
852
|
+
```typescript
|
|
853
|
+
interface NetworkConfig {
|
|
854
|
+
routerAddress: string; // Router contract address
|
|
855
|
+
bitzyQueryAddress: string; // Query contract address
|
|
856
|
+
wrappedAddress: string; // Wrapped token address (WETH, WBNB, etc.)
|
|
857
|
+
nativeAddress: string; // Native token address
|
|
858
|
+
}
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### **Default Networks**
|
|
862
|
+
|
|
863
|
+
The package includes default configurations for:
|
|
864
|
+
- **Botanix Mainnet** (Chain ID: 3637)
|
|
865
|
+
- **Botanix Testnet** (Chain ID: 3636)
|
|
866
|
+
|
|
867
|
+
### **Default Values**
|
|
868
|
+
|
|
869
|
+
When no config is provided, the SDK uses these sensible defaults:
|
|
870
|
+
|
|
871
|
+
- **API URL**: `https://api-public.bitzy.app` (from `DEFAULT_API_BASE_URL`)
|
|
872
|
+
- **API Key**: From `NEXT_PUBLIC_BITZY_API_KEY` environment variable or fallback
|
|
873
|
+
- **Addresses**: Network-specific defaults from `CONTRACT_ADDRESSES`
|
|
874
|
+
- **PartCount**: `5` for high-value pairs, `1` for others
|
|
875
|
+
- **Timeout**: `30` seconds
|
|
876
|
+
- **Refresh**: `10` seconds
|
|
877
|
+
- **Mode**: Offline (fast and reliable)
|
|
878
|
+
- **Types**: `[1, 2]` (V2 typeId: 1, V3 typeId: 2)
|
|
879
|
+
- **Enabled Sources**: `[1]` (BITZY sourceId: 1)
|
|
880
|
+
|
|
881
|
+
## **Development**
|
|
882
|
+
|
|
883
|
+
### **Building**
|
|
884
|
+
|
|
885
|
+
```bash
|
|
886
|
+
cd sdk
|
|
887
|
+
npm install
|
|
888
|
+
npm run build
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
### **Testing**
|
|
892
|
+
|
|
893
|
+
```bash
|
|
894
|
+
npm test
|
|
895
|
+
npm run type-check
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
## 📦 **Package Structure**
|
|
899
|
+
|
|
900
|
+
```
|
|
901
|
+
src/
|
|
902
|
+
├── common/
|
|
903
|
+
│ └── FetchSwapRoute.ts # Common functions
|
|
904
|
+
├── hooks/
|
|
905
|
+
│ └── useSwapV3Routes.ts # React hook
|
|
906
|
+
├── services/
|
|
907
|
+
│ └── SwapV3Service.ts # Core logic
|
|
908
|
+
├── types/
|
|
909
|
+
│ └── index.ts # TypeScript interfaces
|
|
910
|
+
├── utils/
|
|
911
|
+
│ └── PartCount.ts # Utility functions
|
|
912
|
+
└── index.ts # Main exports
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
## **Why This Design?**
|
|
916
|
+
|
|
917
|
+
- **Focused** - Just the essential swap functionality
|
|
918
|
+
- **Hot Reload** - Perfect for React development
|
|
919
|
+
- **Universal** - Common functions work everywhere
|
|
920
|
+
- **Lightweight** - Minimal dependencies
|
|
921
|
+
- **Type Safe** - Full TypeScript support
|
|
922
|
+
|
|
923
|
+
## 📄 **License**
|
|
924
|
+
|
|
925
|
+
MIT License - see LICENSE file for details.
|
|
926
|
+
|
|
927
|
+
## 🆘 **Support**
|
|
928
|
+
|
|
929
|
+
For questions and support:
|
|
930
|
+
- Create an issue on GitHub
|
|
931
|
+
- Check the examples folder
|
|
932
|
+
- Review the TypeScript types for guidance
|