@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/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