@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 +336 -0
- package/dist/index.cjs +1592 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +927 -0
- package/dist/index.d.ts +927 -0
- package/dist/index.js +1533 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
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
|