@provable-games/ekubo-sdk 0.1.0

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,336 @@
1
+ # Ekubo SDK
2
+
3
+ A standalone TypeScript SDK for Ekubo DEX routing and quotes on Starknet.
4
+
5
+ ## Features
6
+
7
+ - **Quote fetching** with retry logic, timeout, and abort support
8
+ - **Symbol or address input** - Accept "ETH" or "0x049d36..." interchangeably
9
+ - **Configurable polling** for real-time quote updates
10
+ - **Swap call generation** for `multihop_swap` and `multi_multihop_swap`
11
+ - **Dynamic token list** - Fetch tokens from API or use built-in registry
12
+ - **Protocol statistics** - TVL, volume, top pairs
13
+ - **Multi-chain support** - Mainnet and Sepolia
14
+ - **Tree-shakeable** - Import only what you need
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install ekubo-sdk
20
+ # or
21
+ pnpm add ekubo-sdk
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Using EkuboClient (Recommended)
27
+
28
+ ```typescript
29
+ import { createEkuboClient } from 'ekubo-sdk';
30
+
31
+ const client = createEkuboClient({ chain: 'mainnet' });
32
+
33
+ // Fetch a quote using symbols
34
+ const quote = await client.getQuote({
35
+ amount: 1000000000000000000n, // 1 ETH
36
+ tokenFrom: 'ETH',
37
+ tokenTo: 'STRK',
38
+ });
39
+
40
+ console.log('Expected STRK:', quote.total);
41
+ console.log('Price impact:', quote.impact);
42
+
43
+ // Generate swap calls
44
+ const { allCalls } = client.generateSwapCalls({
45
+ sellToken: 'ETH',
46
+ buyToken: 'STRK',
47
+ minimumReceived: quote.total * 99n / 100n, // 1% slippage
48
+ quote,
49
+ });
50
+
51
+ // Execute with starknet.js or your wallet
52
+ await account.execute(allCalls);
53
+ ```
54
+
55
+ ### Direct Function Imports (Tree-Shakeable)
56
+
57
+ ```typescript
58
+ import {
59
+ fetchSwapQuote,
60
+ generateSwapCalls,
61
+ CHAIN_IDS
62
+ } from 'ekubo-sdk';
63
+
64
+ // Fetch quote
65
+ const quote = await fetchSwapQuote({
66
+ amount: 1000000000000000000n,
67
+ tokenFrom: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
68
+ tokenTo: '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',
69
+ chainId: CHAIN_IDS.MAINNET,
70
+ });
71
+
72
+ // Generate calls
73
+ const { allCalls } = generateSwapCalls({
74
+ sellToken: '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7',
75
+ buyToken: '0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d',
76
+ minimumReceived: quote.total * 99n / 100n,
77
+ quote,
78
+ chainId: CHAIN_IDS.MAINNET,
79
+ });
80
+ ```
81
+
82
+ ## Quote Polling
83
+
84
+ For real-time quote updates:
85
+
86
+ ```typescript
87
+ const client = createEkuboClient({ chain: 'mainnet' });
88
+
89
+ const poller = client.createQuotePoller(
90
+ { amount: 1n * 10n ** 18n, tokenFrom: 'ETH', tokenTo: 'STRK' },
91
+ {
92
+ onQuote: (quote) => {
93
+ console.log('New quote:', quote.total);
94
+ },
95
+ onError: (err) => {
96
+ console.error('Quote error:', err);
97
+ },
98
+ onStop: (reason) => {
99
+ console.log('Polling stopped:', reason);
100
+ },
101
+ },
102
+ { interval: 5000 } // Poll every 5 seconds
103
+ );
104
+
105
+ poller.start();
106
+
107
+ // Later...
108
+ poller.stop();
109
+ ```
110
+
111
+ ## Token Management
112
+
113
+ ### Static Registry (Built-in)
114
+
115
+ ```typescript
116
+ import { resolveToken, MAINNET_TOKENS, TokenRegistry } from 'ekubo-sdk';
117
+
118
+ // Resolve symbol to address
119
+ const ethAddress = resolveToken('ETH');
120
+ const strkAddress = resolveToken('strk'); // case-insensitive
121
+
122
+ // Use custom tokens
123
+ const registry = new TokenRegistry([
124
+ { symbol: 'MYTOKEN', address: '0x123...', decimals: 18 }
125
+ ]);
126
+
127
+ const address = resolveToken('MYTOKEN', registry);
128
+ ```
129
+
130
+ ### Dynamic Token List (From API)
131
+
132
+ ```typescript
133
+ const client = createEkuboClient({ chain: 'mainnet' });
134
+
135
+ // Fetch all tokens from Ekubo API
136
+ const tokens = await client.fetchTokens();
137
+ console.log(`Found ${tokens.length} tokens`);
138
+
139
+ // Fetch specific token metadata
140
+ const ethInfo = await client.fetchToken('ETH');
141
+ console.log(ethInfo?.name, ethInfo?.decimals);
142
+
143
+ // Sync API tokens to local registry for symbol resolution
144
+ await client.syncTokensFromApi();
145
+
146
+ // Now you can use any token symbol from the API
147
+ const quote = await client.getQuote({
148
+ amount: 1n * 10n ** 18n,
149
+ tokenFrom: 'SOME_NEW_TOKEN',
150
+ tokenTo: 'USDC',
151
+ });
152
+ ```
153
+
154
+ ### Built-in Tokens
155
+
156
+ ETH, STRK, USDC, USDC.e, USDT, DAI, WBTC, LORDS, wstETH, EKUBO, ZEND, NSTR
157
+
158
+ ## Protocol Statistics
159
+
160
+ ```typescript
161
+ const client = createEkuboClient({ chain: 'mainnet' });
162
+
163
+ // Protocol-wide stats
164
+ const tvl = await client.getTvl();
165
+ console.log('Total TVL:', tvl.tvl_usd);
166
+
167
+ const volume = await client.getVolume();
168
+ console.log('24h Volume:', volume.volume_24h_usd);
169
+
170
+ // Top trading pairs
171
+ const pairs = await client.getTopPairs();
172
+ for (const pair of pairs.slice(0, 5)) {
173
+ console.log(`${pair.token0}/${pair.token1}: $${pair.volume_24h_usd}`);
174
+ }
175
+
176
+ // Pair-specific stats
177
+ const ethStrkTvl = await client.getPairTvl('ETH', 'STRK');
178
+ const ethStrkVolume = await client.getPairVolume('ETH', 'STRK');
179
+ const ethStrkPools = await client.getPairPools('ETH', 'STRK');
180
+ ```
181
+
182
+ ## Configuration
183
+
184
+ ```typescript
185
+ const client = createEkuboClient({
186
+ // Chain selection
187
+ chain: 'mainnet', // or 'sepolia'
188
+
189
+ // Or use custom chain ID
190
+ chainId: '23448594291968334',
191
+
192
+ // Custom API URLs
193
+ quoterApiUrl: 'https://prod-api-quoter.ekubo.org',
194
+ apiUrl: 'https://prod-api.ekubo.org',
195
+
196
+ // Custom router address
197
+ routerAddress: '0x...',
198
+
199
+ // Default slippage (5%)
200
+ defaultSlippagePercent: 5n,
201
+
202
+ // Fetch configuration
203
+ fetch: {
204
+ timeout: 10000,
205
+ maxRetries: 3,
206
+ baseBackoff: 1000,
207
+ maxBackoff: 5000,
208
+ },
209
+
210
+ // Polling configuration
211
+ polling: {
212
+ interval: 5000,
213
+ maxConsecutiveErrors: 3,
214
+ },
215
+
216
+ // Custom tokens (added to built-in registry)
217
+ customTokens: [
218
+ { symbol: 'MYTOKEN', address: '0x...', decimals: 18 }
219
+ ],
220
+ });
221
+ ```
222
+
223
+ ## Error Handling
224
+
225
+ ```typescript
226
+ import {
227
+ InsufficientLiquidityError,
228
+ RateLimitError,
229
+ TokenNotFoundError,
230
+ } from 'ekubo-sdk';
231
+
232
+ try {
233
+ const quote = await client.getQuote({
234
+ amount: 1n * 10n ** 30n, // Very large amount
235
+ tokenFrom: 'ETH',
236
+ tokenTo: 'STRK',
237
+ });
238
+ } catch (error) {
239
+ if (error instanceof InsufficientLiquidityError) {
240
+ console.log('Not enough liquidity for this swap');
241
+ } else if (error instanceof RateLimitError) {
242
+ console.log('Rate limited, try again later');
243
+ } else if (error instanceof TokenNotFoundError) {
244
+ console.log('Unknown token symbol');
245
+ }
246
+ }
247
+ ```
248
+
249
+ ## API Reference
250
+
251
+ ### EkuboClient Methods
252
+
253
+ #### Swap Quotes
254
+ | Method | Description |
255
+ |--------|-------------|
256
+ | `getQuote(params)` | Fetch a swap quote |
257
+ | `getUsdcPrice(token, amount)` | Get token price in USDC |
258
+ | `getPriceHistory(token, otherToken)` | Fetch price history |
259
+
260
+ #### Swap Execution
261
+ | Method | Description |
262
+ |--------|-------------|
263
+ | `generateSwapCalls(params)` | Generate swap transaction calls |
264
+ | `prepareSwapCalls(params)` | Generate calls with ERC20 approval |
265
+
266
+ #### Polling
267
+ | Method | Description |
268
+ |--------|-------------|
269
+ | `createQuotePoller(params, callbacks)` | Create a quote polling instance |
270
+
271
+ #### Token Management
272
+ | Method | Description |
273
+ |--------|-------------|
274
+ | `resolveToken(identifier)` | Resolve symbol/address to address |
275
+ | `registerToken(token)` | Register a custom token locally |
276
+ | `fetchTokens()` | Fetch all tokens from API |
277
+ | `fetchToken(address)` | Fetch single token metadata |
278
+ | `fetchTokensBatch(addresses)` | Fetch multiple tokens |
279
+ | `syncTokensFromApi()` | Sync API tokens to local registry |
280
+
281
+ #### Protocol Statistics
282
+ | Method | Description |
283
+ |--------|-------------|
284
+ | `getTvl()` | Fetch protocol TVL |
285
+ | `getVolume()` | Fetch protocol volume |
286
+ | `getTopPairs()` | Fetch top trading pairs |
287
+ | `getPairTvl(tokenA, tokenB)` | Fetch pair TVL history |
288
+ | `getPairVolume(tokenA, tokenB)` | Fetch pair volume history |
289
+ | `getPairPools(tokenA, tokenB)` | Fetch pools for a pair |
290
+
291
+ ### Standalone Functions
292
+
293
+ | Function | Description |
294
+ |----------|-------------|
295
+ | `fetchSwapQuote(params)` | Fetch quote from Ekubo API |
296
+ | `fetchSwapQuoteInUsdc(params)` | Fetch token price in USDC |
297
+ | `getPriceHistory(params)` | Fetch price history |
298
+ | `fetchTokens(params)` | Fetch all tokens |
299
+ | `fetchToken(params)` | Fetch single token |
300
+ | `fetchTokensBatch(params)` | Fetch multiple tokens |
301
+ | `fetchTopPairs(params)` | Fetch top pairs |
302
+ | `fetchTvl(params)` | Fetch protocol TVL |
303
+ | `fetchVolume(params)` | Fetch protocol volume |
304
+ | `fetchPairTvl(params)` | Fetch pair TVL |
305
+ | `fetchPairVolume(params)` | Fetch pair volume |
306
+ | `fetchPairPools(params)` | Fetch pair pools |
307
+ | `generateSwapCalls(params)` | Generate swap calls |
308
+ | `prepareSwapCalls(params)` | Generate calls with approval |
309
+ | `resolveToken(identifier, registry?)` | Resolve token identifier |
310
+
311
+ ## Chain IDs
312
+
313
+ ```typescript
314
+ import { CHAIN_IDS, STARKNET_CHAIN_IDS } from 'ekubo-sdk';
315
+
316
+ // Ekubo API format (decimal)
317
+ CHAIN_IDS.MAINNET // "23448594291968334"
318
+ CHAIN_IDS.SEPOLIA // "393402133025997798000961"
319
+
320
+ // Starknet.js format (hex)
321
+ STARKNET_CHAIN_IDS.SN_MAIN // "0x534e5f4d41494e"
322
+ STARKNET_CHAIN_IDS.SN_SEPOLIA // "0x534e5f5345504f4c4941"
323
+ ```
324
+
325
+ ## API URLs
326
+
327
+ ```typescript
328
+ import { API_URLS } from 'ekubo-sdk';
329
+
330
+ API_URLS.QUOTER // "https://prod-api-quoter.ekubo.org" - Swap quotes
331
+ API_URLS.API // "https://prod-api.ekubo.org" - Tokens, prices, stats
332
+ ```
333
+
334
+ ## License
335
+
336
+ MIT