@runesx/api-client 0.3.0 → 0.5.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 +603 -418
- package/package.json +7 -7
- package/src/api.mjs +387 -4
- package/src/index.mjs +118 -12
- package/src/socket.mjs +204 -115
- package/src/store/coinStore.mjs +1 -1
- package/src/store/exchangeConfigStore.mjs +48 -0
- package/src/store/marketStore.mjs +57 -0
- package/src/store/orderbookStore.mjs +99 -0
- package/src/store/poolStore.mjs +1 -1
- package/src/store/userSharesStore.mjs +1 -1
- package/src/store/walletStore.mjs +1 -1
- package/src/utils/liquidityUtils.mjs +2 -3
- package/src/utils/priceUtils.mjs +2 -1
- package/src/utils/safeBigNumber.mjs +11 -0
- package/src/utils/swapUtils.mjs +1159 -129
- package/src/waitForStores.mjs +41 -6
- package/src/workers/swapWorker.mjs +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runesx/api-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "A Node.js client for interacting with the RunesX platform API and WebSocket",
|
|
5
5
|
"main": "src/index.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -13,23 +13,23 @@
|
|
|
13
13
|
"test": "jest"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"axios": "^1.13.
|
|
17
|
-
"bignumber.js": "^
|
|
16
|
+
"axios": "^1.13.6",
|
|
17
|
+
"bignumber.js": "^10.0.2",
|
|
18
18
|
"socket.io-client": "^4.8.3"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@eslint/js": "^9.11.1",
|
|
22
22
|
"@semantic-release/changelog": "^6.0.3",
|
|
23
23
|
"@semantic-release/git": "^10.0.1",
|
|
24
|
-
"@semantic-release/npm": "^13.1.
|
|
24
|
+
"@semantic-release/npm": "^13.1.5",
|
|
25
25
|
"dotenv": "^17.3.1",
|
|
26
26
|
"eslint": "^9.11.1",
|
|
27
27
|
"eslint-plugin-import": "^2.30.0",
|
|
28
28
|
"eslint-plugin-n": "^17.24.0",
|
|
29
29
|
"eslint-plugin-promise": "^7.1.0",
|
|
30
|
-
"globals": "^17.
|
|
31
|
-
"jest": "^30.
|
|
32
|
-
"nodemon": "^3.1.
|
|
30
|
+
"globals": "^17.4.0",
|
|
31
|
+
"jest": "^30.3.0",
|
|
32
|
+
"nodemon": "^3.1.14",
|
|
33
33
|
"semantic-release": "^25.0.3"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
package/src/api.mjs
CHANGED
|
@@ -12,6 +12,154 @@ export function createApi(config) {
|
|
|
12
12
|
},
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
+
// ---- Public endpoints (no auth required) ----
|
|
16
|
+
|
|
17
|
+
async function getStatus() {
|
|
18
|
+
try {
|
|
19
|
+
const response = await api.get('/status');
|
|
20
|
+
return response.data;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch status');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function getCoins() {
|
|
27
|
+
try {
|
|
28
|
+
const response = await api.get('/coins');
|
|
29
|
+
return response.data;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch coins');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function getCoin(ticker) {
|
|
36
|
+
try {
|
|
37
|
+
const response = await api.get(`/coins/${encodeURIComponent(ticker)}`);
|
|
38
|
+
return response.data;
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch coin');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function getPools() {
|
|
45
|
+
try {
|
|
46
|
+
const response = await api.get('/pools');
|
|
47
|
+
return response.data.data;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pools');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function getPoolByPair(tickerA, tickerB) {
|
|
54
|
+
try {
|
|
55
|
+
const response = await api.get(`/pools/${encodeURIComponent(tickerA)}/${encodeURIComponent(tickerB)}`);
|
|
56
|
+
return response.data.data;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pool');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function getPoolLiquidityShares(poolId) {
|
|
63
|
+
try {
|
|
64
|
+
const response = await api.get(`/pools/liquidity-shares/${encodeURIComponent(poolId)}`);
|
|
65
|
+
return response.data.data;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pool liquidity shares');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function getPrices() {
|
|
72
|
+
try {
|
|
73
|
+
const response = await api.get('/price');
|
|
74
|
+
return response.data;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch prices');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function getPrice(ticker) {
|
|
81
|
+
try {
|
|
82
|
+
const response = await api.get(`/price/${encodeURIComponent(ticker)}`);
|
|
83
|
+
return response.data;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch price');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function getCandlesticks(poolId, timeframe, from, to) {
|
|
90
|
+
try {
|
|
91
|
+
const response = await api.get(`/candlesticks/${encodeURIComponent(poolId)}/${encodeURIComponent(timeframe)}/${encodeURIComponent(from)}/${encodeURIComponent(to)}`);
|
|
92
|
+
return response.data.data;
|
|
93
|
+
} catch (error) {
|
|
94
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch candlesticks');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function getVolumeTotal() {
|
|
99
|
+
try {
|
|
100
|
+
const response = await api.get('/volume/total');
|
|
101
|
+
return response.data;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch total volume');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function getVolumePool(poolId) {
|
|
108
|
+
try {
|
|
109
|
+
const response = await api.get(`/volume/pool/${encodeURIComponent(poolId)}`);
|
|
110
|
+
return response.data;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pool volume');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function getBucketsPools() {
|
|
117
|
+
try {
|
|
118
|
+
const response = await api.get('/buckets/pools');
|
|
119
|
+
return response.data;
|
|
120
|
+
} catch (error) {
|
|
121
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pool buckets');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function getRecentOperations({ operationType, limit } = {}) {
|
|
126
|
+
try {
|
|
127
|
+
const params = {};
|
|
128
|
+
if (operationType) { params.operationType = operationType; }
|
|
129
|
+
if (limit) { params.limit = limit; }
|
|
130
|
+
const response = await api.get('/operations/recent', { params });
|
|
131
|
+
return response.data;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch recent operations');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function getPoolOperations(poolId, { operationType, limit } = {}) {
|
|
138
|
+
try {
|
|
139
|
+
const params = {};
|
|
140
|
+
if (operationType) { params.operationType = operationType; }
|
|
141
|
+
if (limit) { params.limit = limit; }
|
|
142
|
+
const response = await api.get(`/operations/pool/${encodeURIComponent(poolId)}`, { params });
|
|
143
|
+
return response.data;
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pool operations');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function getYardMessages({ before, limit } = {}) {
|
|
150
|
+
try {
|
|
151
|
+
const params = {};
|
|
152
|
+
if (before) { params.before = before; }
|
|
153
|
+
if (limit) { params.limit = limit; }
|
|
154
|
+
const response = await api.get('/yard/messages', { params });
|
|
155
|
+
return response.data;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch yard messages');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ---- Private endpoints (auth required) ----
|
|
162
|
+
|
|
15
163
|
async function getWallets() {
|
|
16
164
|
try {
|
|
17
165
|
const response = await api.get('/wallets');
|
|
@@ -21,6 +169,15 @@ export function createApi(config) {
|
|
|
21
169
|
}
|
|
22
170
|
}
|
|
23
171
|
|
|
172
|
+
async function getLiquidityShares() {
|
|
173
|
+
try {
|
|
174
|
+
const response = await api.get('/liquidity/shares');
|
|
175
|
+
return response.data.data;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch liquidity shares');
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
24
181
|
async function postSwap({ amountIn, path, minAmountOut, idempotencyKey }) {
|
|
25
182
|
try {
|
|
26
183
|
const key = idempotencyKey || randomUUID();
|
|
@@ -66,14 +223,240 @@ export function createApi(config) {
|
|
|
66
223
|
}
|
|
67
224
|
}
|
|
68
225
|
|
|
69
|
-
async function
|
|
226
|
+
async function getDepositAddress(chainName) {
|
|
70
227
|
try {
|
|
71
|
-
const response = await api.get(
|
|
228
|
+
const response = await api.get(`/deposit/address/${encodeURIComponent(chainName)}`);
|
|
72
229
|
return response.data.data;
|
|
73
230
|
} catch (error) {
|
|
74
|
-
throw new Error(error.response?.data?.error || 'Failed to
|
|
231
|
+
throw new Error(error.response?.data?.error || 'Failed to get deposit address');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function getAllDepositAddresses() {
|
|
236
|
+
try {
|
|
237
|
+
const response = await api.get('/deposit/all-addresses');
|
|
238
|
+
return response.data.data;
|
|
239
|
+
} catch (error) {
|
|
240
|
+
throw new Error(error.response?.data?.error || 'Failed to get deposit addresses');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async function initiateWithdraw({ ticker, chain, address, amount, memo, idempotencyKey }) {
|
|
245
|
+
try {
|
|
246
|
+
const key = idempotencyKey || randomUUID();
|
|
247
|
+
const body = { ticker, chain, address, amount };
|
|
248
|
+
if (memo !== undefined && memo !== null) {
|
|
249
|
+
body.memo = memo;
|
|
250
|
+
}
|
|
251
|
+
const response = await api.post('/withdraw', body, {
|
|
252
|
+
headers: { 'x-idempotency-key': key },
|
|
253
|
+
});
|
|
254
|
+
return response.data;
|
|
255
|
+
} catch (error) {
|
|
256
|
+
throw new Error(error.response?.data?.error || 'Failed to initiate withdrawal');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async function verifyWithdrawPin({ pendingWithdrawalId, pinCode }) {
|
|
261
|
+
try {
|
|
262
|
+
const response = await api.post('/withdraw/verify-pin', { pendingWithdrawalId, pinCode });
|
|
263
|
+
return response.data;
|
|
264
|
+
} catch (error) {
|
|
265
|
+
throw new Error(error.response?.data?.error || 'Failed to verify withdrawal PIN');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async function sendWithdrawEmailPin({ pendingWithdrawalId }) {
|
|
270
|
+
try {
|
|
271
|
+
const response = await api.post('/withdraw/send-email-pin', { pendingWithdrawalId });
|
|
272
|
+
return response.data;
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new Error(error.response?.data?.error || 'Failed to send withdrawal email PIN');
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function verifyWithdrawEmailPin({ pendingWithdrawalId, emailPinCode }) {
|
|
279
|
+
try {
|
|
280
|
+
const response = await api.post('/withdraw/verify-email-pin', { pendingWithdrawalId, emailPinCode });
|
|
281
|
+
return response.data;
|
|
282
|
+
} catch (error) {
|
|
283
|
+
throw new Error(error.response?.data?.error || 'Failed to verify withdrawal email PIN');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function verifyWithdraw2FA({ pendingWithdrawalId, twoFactorToken }) {
|
|
288
|
+
try {
|
|
289
|
+
const response = await api.post('/withdraw/verify-2fa', { pendingWithdrawalId, twoFactorToken });
|
|
290
|
+
return response.data;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
throw new Error(error.response?.data?.error || 'Failed to verify withdrawal 2FA');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function getPendingWithdrawals() {
|
|
297
|
+
try {
|
|
298
|
+
const response = await api.get('/withdraw/pending');
|
|
299
|
+
return response.data;
|
|
300
|
+
} catch (error) {
|
|
301
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch pending withdrawals');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function cancelWithdrawal({ pendingWithdrawalId }) {
|
|
306
|
+
try {
|
|
307
|
+
const response = await api.post('/withdraw/cancel', { pendingWithdrawalId });
|
|
308
|
+
return response.data;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
throw new Error(error.response?.data?.error || 'Failed to cancel withdrawal');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function getTransactionHistory({ page, limit, type, status } = {}) {
|
|
315
|
+
try {
|
|
316
|
+
const params = {};
|
|
317
|
+
if (page) { params.page = page; }
|
|
318
|
+
if (limit) { params.limit = limit; }
|
|
319
|
+
if (type) { params.type = type; }
|
|
320
|
+
if (status) { params.status = status; }
|
|
321
|
+
const response = await api.get('/transactions/history', { params });
|
|
322
|
+
return response.data;
|
|
323
|
+
} catch (error) {
|
|
324
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch transaction history');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
async function getUserOperations({ operationType, poolId, startTime, endTime, page, limit } = {}) {
|
|
329
|
+
try {
|
|
330
|
+
const params = {};
|
|
331
|
+
if (operationType) { params.operationType = operationType; }
|
|
332
|
+
if (poolId) { params.poolId = poolId; }
|
|
333
|
+
if (startTime) { params.startTime = startTime; }
|
|
334
|
+
if (endTime) { params.endTime = endTime; }
|
|
335
|
+
if (page) { params.page = page; }
|
|
336
|
+
if (limit) { params.limit = limit; }
|
|
337
|
+
const response = await api.get('/operations/user', { params });
|
|
338
|
+
return response.data;
|
|
339
|
+
} catch (error) {
|
|
340
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch user operations');
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ---- Orders endpoints ----
|
|
345
|
+
|
|
346
|
+
async function placeOrder({ pair, side, price, quantity, timeInForce, inverted, idempotencyKey }) {
|
|
347
|
+
try {
|
|
348
|
+
const key = idempotencyKey || randomUUID();
|
|
349
|
+
const body = { pair, side, price, quantity, timeInForce };
|
|
350
|
+
if (inverted !== undefined && inverted !== null) {
|
|
351
|
+
body.inverted = inverted;
|
|
352
|
+
}
|
|
353
|
+
const response = await api.post('/orders', body, {
|
|
354
|
+
headers: { 'x-idempotency-key': key },
|
|
355
|
+
});
|
|
356
|
+
return response.data;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
throw new Error(error.response?.data?.error || 'Failed to place order');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function cancelOrder(orderId, { idempotencyKey } = {}) {
|
|
363
|
+
try {
|
|
364
|
+
const headers = {};
|
|
365
|
+
if (idempotencyKey) {
|
|
366
|
+
headers['x-idempotency-key'] = idempotencyKey;
|
|
367
|
+
}
|
|
368
|
+
const response = await api.delete(`/orders/${encodeURIComponent(orderId)}`, { headers });
|
|
369
|
+
return response.data;
|
|
370
|
+
} catch (error) {
|
|
371
|
+
throw new Error(error.response?.data?.error || 'Failed to cancel order');
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async function getOrders({ pair, status, limit, offset } = {}) {
|
|
376
|
+
try {
|
|
377
|
+
const params = {};
|
|
378
|
+
if (pair) { params.pair = pair; }
|
|
379
|
+
if (status) { params.status = status; }
|
|
380
|
+
if (limit) { params.limit = limit; }
|
|
381
|
+
if (offset !== undefined && offset !== null) { params.offset = offset; }
|
|
382
|
+
const response = await api.get('/orders', { params });
|
|
383
|
+
return response.data;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch orders');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function getOrderBookApi(pair, { levels } = {}) {
|
|
390
|
+
try {
|
|
391
|
+
const params = {};
|
|
392
|
+
if (levels) { params.levels = levels; }
|
|
393
|
+
const response = await api.get(`/orders/book/${encodeURIComponent(pair)}`, { params });
|
|
394
|
+
return response.data;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch order book');
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function getTrades(pair, { limit } = {}) {
|
|
401
|
+
try {
|
|
402
|
+
const params = {};
|
|
403
|
+
if (limit) { params.limit = limit; }
|
|
404
|
+
const response = await api.get(`/orders/trades/${encodeURIComponent(pair)}`, { params });
|
|
405
|
+
return response.data;
|
|
406
|
+
} catch (error) {
|
|
407
|
+
throw new Error(error.response?.data?.error || 'Failed to fetch trades');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async function deleteYardMessage(messageId) {
|
|
412
|
+
try {
|
|
413
|
+
const response = await api.delete(`/yard/messages/${encodeURIComponent(messageId)}`);
|
|
414
|
+
return response.data;
|
|
415
|
+
} catch (error) {
|
|
416
|
+
throw new Error(error.response?.data?.error || 'Failed to delete yard message');
|
|
75
417
|
}
|
|
76
418
|
}
|
|
77
419
|
|
|
78
|
-
return {
|
|
420
|
+
return {
|
|
421
|
+
// Public
|
|
422
|
+
getStatus,
|
|
423
|
+
getCoins,
|
|
424
|
+
getCoin,
|
|
425
|
+
getPools,
|
|
426
|
+
getPoolByPair,
|
|
427
|
+
getPoolLiquidityShares,
|
|
428
|
+
getPrices,
|
|
429
|
+
getPrice,
|
|
430
|
+
getCandlesticks,
|
|
431
|
+
getVolumeTotal,
|
|
432
|
+
getVolumePool,
|
|
433
|
+
getBucketsPools,
|
|
434
|
+
getRecentOperations,
|
|
435
|
+
getPoolOperations,
|
|
436
|
+
getYardMessages,
|
|
437
|
+
// Private
|
|
438
|
+
getWallets,
|
|
439
|
+
getLiquidityShares,
|
|
440
|
+
postSwap,
|
|
441
|
+
depositLiquidity,
|
|
442
|
+
withdrawLiquidity,
|
|
443
|
+
getDepositAddress,
|
|
444
|
+
getAllDepositAddresses,
|
|
445
|
+
initiateWithdraw,
|
|
446
|
+
verifyWithdrawPin,
|
|
447
|
+
sendWithdrawEmailPin,
|
|
448
|
+
verifyWithdrawEmailPin,
|
|
449
|
+
verifyWithdraw2FA,
|
|
450
|
+
getPendingWithdrawals,
|
|
451
|
+
cancelWithdrawal,
|
|
452
|
+
getTransactionHistory,
|
|
453
|
+
getUserOperations,
|
|
454
|
+
deleteYardMessage,
|
|
455
|
+
// Orders
|
|
456
|
+
placeOrder,
|
|
457
|
+
cancelOrder,
|
|
458
|
+
getOrders,
|
|
459
|
+
getOrderBookApi,
|
|
460
|
+
getTrades,
|
|
461
|
+
};
|
|
79
462
|
}
|
package/src/index.mjs
CHANGED
|
@@ -7,6 +7,9 @@ import { getCoins, getCoinByTicker } from './store/coinStore.mjs';
|
|
|
7
7
|
import { getChains, getChainByName } from './store/chainStore.mjs';
|
|
8
8
|
import { getWallets as getWalletsStore, getWalletByTicker } from './store/walletStore.mjs';
|
|
9
9
|
import { getUserShares, getUserShareByPoolId } from './store/userSharesStore.mjs';
|
|
10
|
+
import { getAllOrderBooks, getOrderBook, getOrderBookPairs, getUserOrders } from './store/orderbookStore.mjs';
|
|
11
|
+
import { getMarkets, getMarketByCoinKey, getMarketByCoins } from './store/marketStore.mjs';
|
|
12
|
+
import { getClobFees } from './store/exchangeConfigStore.mjs';
|
|
10
13
|
import { waitForStores } from './waitForStores.mjs';
|
|
11
14
|
import { estimateLiquidityFrontend, checkRunesLiquidityFrontend, calculateShareAmounts, estimateDepositShares } from './utils/liquidityUtils.mjs';
|
|
12
15
|
import { estimateSwap } from './utils/swapUtils.mjs';
|
|
@@ -14,7 +17,7 @@ import { createPriceUtils } from './utils/priceUtils.mjs';
|
|
|
14
17
|
|
|
15
18
|
export function createRunesXClient(options = {}) {
|
|
16
19
|
const config = createConfig(options);
|
|
17
|
-
let
|
|
20
|
+
let socketHandler = null;
|
|
18
21
|
let initialized = false;
|
|
19
22
|
const api = createApi(config);
|
|
20
23
|
|
|
@@ -22,10 +25,10 @@ export function createRunesXClient(options = {}) {
|
|
|
22
25
|
if (!config.apiKey) {
|
|
23
26
|
throw new Error('API_KEY is required');
|
|
24
27
|
}
|
|
25
|
-
|
|
26
|
-
const { pools, coins, chains, wallets, userShares } = await waitForStores(socket);
|
|
28
|
+
socketHandler = setupSocket(config);
|
|
29
|
+
const { pools, coins, chains, wallets, userShares, orderbooks } = await waitForStores(socketHandler.socket);
|
|
27
30
|
initialized = true;
|
|
28
|
-
return { pools, coins, chains, wallets, userShares };
|
|
31
|
+
return { pools, coins, chains, wallets, userShares, orderbooks };
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
function ensureInitialized() {
|
|
@@ -36,10 +39,14 @@ export function createRunesXClient(options = {}) {
|
|
|
36
39
|
|
|
37
40
|
return {
|
|
38
41
|
initialize,
|
|
42
|
+
|
|
43
|
+
// Raw socket access
|
|
39
44
|
getSocket: () => {
|
|
40
45
|
ensureInitialized();
|
|
41
|
-
return socket;
|
|
46
|
+
return socketHandler.socket;
|
|
42
47
|
},
|
|
48
|
+
|
|
49
|
+
// ---- Store accessors (real-time data from WebSocket) ----
|
|
43
50
|
getPools,
|
|
44
51
|
getPool,
|
|
45
52
|
getCoins,
|
|
@@ -50,20 +57,120 @@ export function createRunesXClient(options = {}) {
|
|
|
50
57
|
getWalletByTicker,
|
|
51
58
|
getUserShares,
|
|
52
59
|
getUserShareByPoolId,
|
|
60
|
+
getAllOrderBooks,
|
|
61
|
+
getOrderBook,
|
|
62
|
+
getOrderBookPairs,
|
|
63
|
+
getUserOrders,
|
|
64
|
+
getMarkets,
|
|
65
|
+
getMarketByCoins,
|
|
66
|
+
|
|
67
|
+
// ---- Event callbacks ----
|
|
68
|
+
on: (event, callback) => {
|
|
69
|
+
ensureInitialized();
|
|
70
|
+
socketHandler.on(event, callback);
|
|
71
|
+
},
|
|
72
|
+
off: (event, callback) => {
|
|
73
|
+
ensureInitialized();
|
|
74
|
+
socketHandler.off(event, callback);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// ---- Socket emit convenience methods ----
|
|
78
|
+
joinCandlesticks: (poolId, timeframe) => {
|
|
79
|
+
ensureInitialized();
|
|
80
|
+
socketHandler.joinCandlesticks(poolId, timeframe);
|
|
81
|
+
},
|
|
82
|
+
leaveCandlesticks: (poolId, timeframe) => {
|
|
83
|
+
ensureInitialized();
|
|
84
|
+
socketHandler.leaveCandlesticks(poolId, timeframe);
|
|
85
|
+
},
|
|
86
|
+
sendYardMessage: (text) => {
|
|
87
|
+
ensureInitialized();
|
|
88
|
+
socketHandler.sendYardMessage(text);
|
|
89
|
+
},
|
|
90
|
+
deleteMessage: (messageId) => {
|
|
91
|
+
ensureInitialized();
|
|
92
|
+
socketHandler.deleteMessage(messageId);
|
|
93
|
+
},
|
|
94
|
+
markYardRead: () => {
|
|
95
|
+
ensureInitialized();
|
|
96
|
+
socketHandler.markYardRead();
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// ---- Trading API (auth required, scope: swap) ----
|
|
53
100
|
postSwap: api.postSwap,
|
|
101
|
+
|
|
102
|
+
// ---- Liquidity API (auth required, scope: liquidity_deposit/liquidity_withdraw) ----
|
|
54
103
|
depositLiquidity: api.depositLiquidity,
|
|
55
104
|
withdrawLiquidity: api.withdrawLiquidity,
|
|
105
|
+
getLiquidityShares: api.getLiquidityShares,
|
|
106
|
+
|
|
107
|
+
// ---- Wallet API (auth required, scope: read) ----
|
|
56
108
|
getWalletsApi: api.getWallets,
|
|
109
|
+
|
|
110
|
+
// ---- Deposit API (auth required) ----
|
|
111
|
+
getDepositAddress: api.getDepositAddress,
|
|
112
|
+
getAllDepositAddresses: api.getAllDepositAddresses,
|
|
113
|
+
|
|
114
|
+
// ---- Withdrawal API (auth required, scope: wallet_withdraw) ----
|
|
115
|
+
initiateWithdraw: api.initiateWithdraw,
|
|
116
|
+
verifyWithdrawPin: api.verifyWithdrawPin,
|
|
117
|
+
sendWithdrawEmailPin: api.sendWithdrawEmailPin,
|
|
118
|
+
verifyWithdrawEmailPin: api.verifyWithdrawEmailPin,
|
|
119
|
+
verifyWithdraw2FA: api.verifyWithdraw2FA,
|
|
120
|
+
getPendingWithdrawals: api.getPendingWithdrawals,
|
|
121
|
+
cancelWithdrawal: api.cancelWithdrawal,
|
|
122
|
+
|
|
123
|
+
// ---- Transaction history (auth required, scope: read) ----
|
|
124
|
+
getTransactionHistory: api.getTransactionHistory,
|
|
125
|
+
|
|
126
|
+
// ---- Operations API (public + auth) ----
|
|
127
|
+
getRecentOperations: api.getRecentOperations,
|
|
128
|
+
getUserOperations: api.getUserOperations,
|
|
129
|
+
getPoolOperations: api.getPoolOperations,
|
|
130
|
+
|
|
131
|
+
// ---- Public market data API ----
|
|
132
|
+
getStatus: api.getStatus,
|
|
133
|
+
getCoinsApi: api.getCoins,
|
|
134
|
+
getCoinApi: api.getCoin,
|
|
135
|
+
getPoolsApi: api.getPools,
|
|
136
|
+
getPoolByPair: api.getPoolByPair,
|
|
137
|
+
getPoolLiquidityShares: api.getPoolLiquidityShares,
|
|
138
|
+
getPrices: api.getPrices,
|
|
139
|
+
getPrice: api.getPrice,
|
|
140
|
+
getCandlesticks: api.getCandlesticks,
|
|
141
|
+
getVolumeTotal: api.getVolumeTotal,
|
|
142
|
+
getVolumePool: api.getVolumePool,
|
|
143
|
+
getBucketsPools: api.getBucketsPools,
|
|
144
|
+
|
|
145
|
+
// ---- Orders API (auth required for place/cancel/getOrders, public for book/trades) ----
|
|
146
|
+
placeOrder: api.placeOrder,
|
|
147
|
+
cancelOrder: api.cancelOrder,
|
|
148
|
+
getOrders: api.getOrders,
|
|
149
|
+
getOrderBookApi: api.getOrderBookApi,
|
|
150
|
+
getTrades: api.getTrades,
|
|
151
|
+
|
|
152
|
+
// ---- Yard (chat) API ----
|
|
153
|
+
getYardMessages: api.getYardMessages,
|
|
154
|
+
deleteYardMessage: api.deleteYardMessage,
|
|
155
|
+
|
|
156
|
+
// ---- Client-side estimation utilities ----
|
|
57
157
|
estimateSwap: (inputCoin, outputCoin, amountIn, maxHops = 6, algorithm = 'dfs') =>
|
|
58
|
-
estimateSwap(inputCoin, outputCoin, amountIn, getPools(), getCoins(), maxHops, algorithm),
|
|
158
|
+
estimateSwap(inputCoin, outputCoin, amountIn, getPools(), getCoins(), maxHops, algorithm, getAllOrderBooks(), getUserOrders(), getClobFees(), getMarketByCoinKey()),
|
|
59
159
|
estimateLiquidityFrontend,
|
|
60
160
|
estimateDepositShares: ({ pool, amountA, amountB, slippagePercent } = {}) =>
|
|
61
161
|
estimateDepositShares({ pool, amountA, amountB, slippagePercent }),
|
|
62
162
|
checkRunesLiquidityFrontend: (coinA, coinB) =>
|
|
63
163
|
checkRunesLiquidityFrontend(coinA, coinB, getPools(), getCoins()),
|
|
64
164
|
calculateShareAmounts: () => calculateShareAmounts({ userShares: getUserShares(), pools: getPools() }),
|
|
165
|
+
|
|
166
|
+
// ---- Price utilities ----
|
|
167
|
+
utils: {
|
|
168
|
+
...createPriceUtils(),
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// ---- Pool monitoring ----
|
|
65
172
|
monitorPool: (poolId, interval = 10000) => {
|
|
66
|
-
setInterval(() => {
|
|
173
|
+
return setInterval(() => {
|
|
67
174
|
const pool = getPool(poolId);
|
|
68
175
|
if (pool) {
|
|
69
176
|
console.log(`Monitoring pool ${poolId} (${pool.coinA.ticker}/${pool.coinB.ticker}):`, {
|
|
@@ -77,12 +184,11 @@ export function createRunesXClient(options = {}) {
|
|
|
77
184
|
}
|
|
78
185
|
}, interval);
|
|
79
186
|
},
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
},
|
|
187
|
+
|
|
188
|
+
// ---- Disconnect ----
|
|
83
189
|
disconnect: () => {
|
|
84
|
-
if (
|
|
85
|
-
socket.disconnect();
|
|
190
|
+
if (socketHandler) {
|
|
191
|
+
socketHandler.socket.disconnect();
|
|
86
192
|
}
|
|
87
193
|
},
|
|
88
194
|
};
|