ccxt 4.3.51 → 4.3.53

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.
Files changed (45) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/vertex.js +9 -0
  5. package/dist/cjs/src/base/Precise.js +10 -0
  6. package/dist/cjs/src/base/functions/type.js +43 -10
  7. package/dist/cjs/src/binance.js +2 -2
  8. package/dist/cjs/src/bybit.js +6 -0
  9. package/dist/cjs/src/hyperliquid.js +27 -26
  10. package/dist/cjs/src/krakenfutures.js +1 -0
  11. package/dist/cjs/src/okx.js +1 -0
  12. package/dist/cjs/src/pro/okx.js +1 -1
  13. package/dist/cjs/src/pro/probit.js +8 -3
  14. package/dist/cjs/src/pro/vertex.js +978 -0
  15. package/dist/cjs/src/probit.js +10 -5
  16. package/dist/cjs/src/static_dependencies/ethers/hash/typed-data.js +1 -1
  17. package/dist/cjs/src/vertex.js +2941 -0
  18. package/js/ccxt.d.ts +8 -2
  19. package/js/ccxt.js +6 -2
  20. package/js/src/abstract/okx.d.ts +1 -0
  21. package/js/src/abstract/vertex.d.ts +22 -0
  22. package/js/src/abstract/vertex.js +11 -0
  23. package/js/src/base/Exchange.d.ts +1 -1
  24. package/js/src/base/Precise.d.ts +2 -0
  25. package/js/src/base/Precise.js +10 -0
  26. package/js/src/base/functions/type.js +43 -10
  27. package/js/src/binance.d.ts +1 -11
  28. package/js/src/binance.js +2 -2
  29. package/js/src/bitget.d.ts +1 -1
  30. package/js/src/bitmart.d.ts +1 -1
  31. package/js/src/bybit.js +6 -0
  32. package/js/src/coinex.d.ts +1 -1
  33. package/js/src/htx.d.ts +1 -1
  34. package/js/src/hyperliquid.js +27 -26
  35. package/js/src/krakenfutures.js +1 -0
  36. package/js/src/okx.js +1 -0
  37. package/js/src/pro/okx.js +1 -1
  38. package/js/src/pro/probit.js +8 -3
  39. package/js/src/pro/vertex.d.ts +39 -0
  40. package/js/src/pro/vertex.js +979 -0
  41. package/js/src/probit.js +11 -6
  42. package/js/src/static_dependencies/ethers/hash/typed-data.js +1 -1
  43. package/js/src/vertex.d.ts +112 -0
  44. package/js/src/vertex.js +2942 -0
  45. package/package.json +1 -1
@@ -0,0 +1,2941 @@
1
+ 'use strict';
2
+
3
+ var vertex$1 = require('./abstract/vertex.js');
4
+ var errors = require('./base/errors.js');
5
+ var Precise = require('./base/Precise.js');
6
+ var number = require('./base/functions/number.js');
7
+ var sha3 = require('./static_dependencies/noble-hashes/sha3.js');
8
+ var secp256k1 = require('./static_dependencies/noble-curves/secp256k1.js');
9
+ var crypto = require('./base/functions/crypto.js');
10
+
11
+ // ---------------------------------------------------------------------------
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * @class vertex
15
+ * @augments Exchange
16
+ */
17
+ class vertex extends vertex$1 {
18
+ describe() {
19
+ return this.deepExtend(super.describe(), {
20
+ 'id': 'vertex',
21
+ 'name': 'Vertex',
22
+ 'countries': [],
23
+ 'version': 'v1',
24
+ 'rateLimit': 50,
25
+ 'certified': false,
26
+ 'pro': true,
27
+ 'dex': true,
28
+ 'has': {
29
+ 'CORS': undefined,
30
+ 'spot': true,
31
+ 'margin': false,
32
+ 'swap': true,
33
+ 'future': true,
34
+ 'option': false,
35
+ 'addMargin': false,
36
+ 'borrowCrossMargin': false,
37
+ 'borrowIsolatedMargin': false,
38
+ 'cancelAllOrders': true,
39
+ 'cancelAllOrdersAfter': false,
40
+ 'cancelOrder': true,
41
+ 'cancelOrders': true,
42
+ 'cancelOrdersForSymbols': false,
43
+ 'closeAllPositions': false,
44
+ 'closePosition': false,
45
+ 'createMarketBuyOrderWithCost': false,
46
+ 'createMarketOrderWithCost': false,
47
+ 'createMarketSellOrderWithCost': false,
48
+ 'createOrder': true,
49
+ 'createOrders': true,
50
+ 'createReduceOnlyOrder': true,
51
+ 'editOrder': false,
52
+ 'fetchAccounts': false,
53
+ 'fetchBalance': true,
54
+ 'fetchBorrowInterest': false,
55
+ 'fetchBorrowRateHistories': false,
56
+ 'fetchBorrowRateHistory': false,
57
+ 'fetchCanceledOrders': false,
58
+ 'fetchClosedOrders': false,
59
+ 'fetchCrossBorrowRate': false,
60
+ 'fetchCrossBorrowRates': false,
61
+ 'fetchCurrencies': true,
62
+ 'fetchDepositAddress': false,
63
+ 'fetchDepositAddresses': false,
64
+ 'fetchDeposits': false,
65
+ 'fetchDepositWithdrawFee': false,
66
+ 'fetchDepositWithdrawFees': false,
67
+ 'fetchFundingHistory': false,
68
+ 'fetchFundingRate': true,
69
+ 'fetchFundingRateHistory': false,
70
+ 'fetchFundingRates': true,
71
+ 'fetchIndexOHLCV': false,
72
+ 'fetchIsolatedBorrowRate': false,
73
+ 'fetchIsolatedBorrowRates': false,
74
+ 'fetchLedger': false,
75
+ 'fetchLeverage': false,
76
+ 'fetchLeverageTiers': false,
77
+ 'fetchLiquidations': false,
78
+ 'fetchMarginMode': undefined,
79
+ 'fetchMarketLeverageTiers': false,
80
+ 'fetchMarkets': true,
81
+ 'fetchMarkOHLCV': false,
82
+ 'fetchMyLiquidations': false,
83
+ 'fetchMyTrades': true,
84
+ 'fetchOHLCV': true,
85
+ 'fetchOpenInterest': true,
86
+ 'fetchOpenInterestHistory': false,
87
+ 'fetchOpenOrders': true,
88
+ 'fetchOrder': true,
89
+ 'fetchOrderBook': true,
90
+ 'fetchOrders': true,
91
+ 'fetchOrderTrades': false,
92
+ 'fetchPosition': false,
93
+ 'fetchPositionMode': false,
94
+ 'fetchPositions': true,
95
+ 'fetchPositionsRisk': false,
96
+ 'fetchPremiumIndexOHLCV': false,
97
+ 'fetchStatus': true,
98
+ 'fetchTicker': false,
99
+ 'fetchTickers': true,
100
+ 'fetchTime': true,
101
+ 'fetchTrades': true,
102
+ 'fetchTradingFee': false,
103
+ 'fetchTradingFees': true,
104
+ 'fetchTransfer': false,
105
+ 'fetchTransfers': false,
106
+ 'fetchWithdrawal': false,
107
+ 'fetchWithdrawals': false,
108
+ 'reduceMargin': false,
109
+ 'repayCrossMargin': false,
110
+ 'repayIsolatedMargin': false,
111
+ 'sandbox': true,
112
+ 'setLeverage': false,
113
+ 'setMarginMode': false,
114
+ 'setPositionMode': false,
115
+ 'transfer': false,
116
+ 'withdraw': true,
117
+ },
118
+ 'timeframes': {
119
+ '1m': 60,
120
+ '5m': 300,
121
+ '15m': 900,
122
+ '1h': 3600,
123
+ '2h': 7200,
124
+ '4h': 14400,
125
+ '1d': 86400,
126
+ '1w': 604800,
127
+ '1M': 604800,
128
+ },
129
+ 'hostname': 'vertexprotocol.com',
130
+ 'urls': {
131
+ 'logo': 'https://github.com/ccxt/ccxt/assets/43336371/bd04a0fa-3b48-47b6-9d8b-124954d520a8',
132
+ 'api': {
133
+ 'v1': {
134
+ 'archive': 'https://archive.prod.{hostname}/v1',
135
+ 'gateway': 'https://gateway.prod.{hostname}/v1',
136
+ 'trigger': 'https://trigger.prod.{hostname}/v1',
137
+ },
138
+ 'v2': {
139
+ 'archive': 'https://archive.prod.{hostname}/v2',
140
+ 'gateway': 'https://gateway.prod.{hostname}/v2',
141
+ },
142
+ },
143
+ 'test': {
144
+ 'v1': {
145
+ 'archive': 'https://archive.sepolia-test.{hostname}/v1',
146
+ 'gateway': 'https://gateway.sepolia-test.{hostname}/v1',
147
+ 'trigger': 'https://trigger.sepolia-test.{hostname}/v1',
148
+ },
149
+ 'v2': {
150
+ 'archive': 'https://archive.sepolia-test.{hostname}/v2',
151
+ 'gateway': 'https://gateway.sepolia-test.{hostname}/v2',
152
+ },
153
+ },
154
+ 'www': 'https://vertexprotocol.com/',
155
+ 'doc': 'https://docs.vertexprotocol.com/',
156
+ 'fees': 'https://docs.vertexprotocol.com/basics/fees',
157
+ 'referral': 'https://app.vertexprotocol.com?referrer=0xCfC9BaB96a2eA3d3c3F031c005e82E1D9F295aC1',
158
+ },
159
+ 'api': {
160
+ 'v1': {
161
+ 'archive': {
162
+ 'post': {
163
+ '': 1,
164
+ },
165
+ },
166
+ 'gateway': {
167
+ 'get': {
168
+ 'query': 1,
169
+ 'symbols': 1,
170
+ 'time': 1,
171
+ },
172
+ 'post': {
173
+ 'query': 1,
174
+ 'execute': 1,
175
+ },
176
+ },
177
+ 'trigger': {
178
+ 'post': {
179
+ 'execute': 1,
180
+ 'query': 1,
181
+ },
182
+ },
183
+ },
184
+ 'v2': {
185
+ 'archive': {
186
+ 'get': {
187
+ 'tickers': 1,
188
+ 'contracts': 1,
189
+ 'trades': 1,
190
+ 'vrtx': 1,
191
+ },
192
+ },
193
+ 'gateway': {
194
+ 'get': {
195
+ 'assets': 0.6667,
196
+ 'pairs': 1,
197
+ 'orderbook': 1,
198
+ },
199
+ },
200
+ },
201
+ },
202
+ 'fees': {
203
+ 'swap': {
204
+ 'taker': this.parseNumber('0.0002'),
205
+ 'maker': this.parseNumber('0.0002'),
206
+ },
207
+ 'spot': {
208
+ 'taker': this.parseNumber('0.0002'),
209
+ 'maker': this.parseNumber('0.0002'),
210
+ },
211
+ },
212
+ 'requiredCredentials': {
213
+ 'apiKey': false,
214
+ 'secret': false,
215
+ 'walletAddress': true,
216
+ 'privateKey': true,
217
+ },
218
+ 'exceptions': {
219
+ 'exact': {
220
+ '1000': errors.RateLimitExceeded,
221
+ '1015': errors.RateLimitExceeded,
222
+ '1001': errors.PermissionDenied,
223
+ '1002': errors.PermissionDenied,
224
+ '1003': errors.PermissionDenied,
225
+ '2000': errors.InvalidOrder,
226
+ '2001': errors.InvalidOrder,
227
+ '2002': errors.InvalidOrder,
228
+ '2003': errors.InvalidOrder,
229
+ '2004': errors.InvalidOrder,
230
+ '2005': errors.InvalidOrder,
231
+ '2006': errors.InvalidOrder,
232
+ '2007': errors.InvalidOrder,
233
+ '2008': errors.InvalidOrder,
234
+ '2009': errors.InvalidOrder,
235
+ '2010': errors.InvalidOrder,
236
+ '2011': errors.BadRequest,
237
+ '2012': errors.BadRequest,
238
+ '2013': errors.InvalidOrder,
239
+ '2014': errors.PermissionDenied,
240
+ '2015': errors.InvalidOrder,
241
+ '2016': errors.InvalidOrder,
242
+ '2017': errors.InvalidOrder,
243
+ '2019': errors.InvalidOrder,
244
+ '2020': errors.InvalidOrder,
245
+ '2021': errors.InvalidOrder,
246
+ '2022': errors.InvalidOrder,
247
+ '2023': errors.InvalidOrder,
248
+ '2024': errors.InsufficientFunds,
249
+ '2025': errors.InsufficientFunds,
250
+ '2026': errors.BadRequest,
251
+ '2027': errors.AuthenticationError,
252
+ '2028': errors.AuthenticationError,
253
+ '2029': errors.AuthenticationError,
254
+ '2030': errors.BadRequest,
255
+ '2031': errors.InvalidOrder,
256
+ '2033': errors.InvalidOrder,
257
+ '2034': errors.InvalidOrder,
258
+ '2035': errors.InvalidOrder,
259
+ '2036': errors.InvalidOrder,
260
+ '2037': errors.InvalidOrder,
261
+ '2038': errors.InvalidOrder,
262
+ '2039': errors.InvalidOrder,
263
+ '2040': errors.InvalidOrder,
264
+ '2041': errors.InvalidOrder,
265
+ '2042': errors.InvalidOrder,
266
+ '2043': errors.InvalidOrder,
267
+ '2044': errors.InvalidOrder,
268
+ '2045': errors.InvalidOrder,
269
+ '2046': errors.InvalidOrder,
270
+ '2047': errors.InvalidOrder,
271
+ '2048': errors.InvalidOrder,
272
+ '2049': errors.ExchangeError,
273
+ '2050': errors.PermissionDenied,
274
+ '2051': errors.InvalidOrder,
275
+ '2052': errors.InvalidOrder,
276
+ '2053': errors.InvalidOrder,
277
+ '2054': errors.InvalidOrder,
278
+ '2055': errors.InvalidOrder,
279
+ '2056': errors.InvalidOrder,
280
+ '2057': errors.InvalidOrder,
281
+ '2058': errors.InvalidOrder,
282
+ '2059': errors.InvalidOrder,
283
+ '2060': errors.InvalidOrder,
284
+ '2061': errors.InvalidOrder,
285
+ '2062': errors.InvalidOrder,
286
+ '2063': errors.InvalidOrder,
287
+ '2064': errors.InvalidOrder,
288
+ '2065': errors.InvalidOrder,
289
+ '2066': errors.InvalidOrder,
290
+ '2067': errors.InvalidOrder,
291
+ '2068': errors.InvalidOrder,
292
+ '2069': errors.InvalidOrder,
293
+ '2070': errors.InvalidOrder,
294
+ '2071': errors.InvalidOrder,
295
+ '2072': errors.InvalidOrder,
296
+ '2073': errors.InvalidOrder,
297
+ '2074': errors.InvalidOrder,
298
+ '2075': errors.InvalidOrder,
299
+ '2076': errors.InvalidOrder,
300
+ '3000': errors.BadRequest,
301
+ '3001': errors.BadRequest,
302
+ '3002': errors.BadRequest,
303
+ '3003': errors.BadRequest,
304
+ '4000': errors.BadRequest,
305
+ '4001': errors.ExchangeError,
306
+ '4002': errors.ExchangeError,
307
+ '4003': errors.ExchangeError,
308
+ '4004': errors.InvalidOrder,
309
+ '5000': errors.ExchangeError,
310
+ },
311
+ 'broad': {},
312
+ },
313
+ 'precisionMode': number.TICK_SIZE,
314
+ 'commonCurrencies': {},
315
+ 'options': {
316
+ 'defaultType': 'swap',
317
+ 'sandboxMode': false,
318
+ 'timeDifference': 0,
319
+ 'brokerId': 5930043274845996,
320
+ },
321
+ });
322
+ }
323
+ setSandboxMode(enabled) {
324
+ super.setSandboxMode(enabled);
325
+ this.options['sandboxMode'] = enabled;
326
+ }
327
+ convertToX18(num) {
328
+ if (typeof num === 'string') {
329
+ return Precise["default"].stringMul(num, '1000000000000000000');
330
+ }
331
+ const numStr = this.numberToString(num);
332
+ return Precise["default"].stringMul(numStr, '1000000000000000000');
333
+ }
334
+ convertFromX18(num) {
335
+ if (typeof num === 'string') {
336
+ return Precise["default"].stringDiv(num, '1000000000000000000');
337
+ }
338
+ const numStr = this.numberToString(num);
339
+ return Precise["default"].stringDiv(numStr, '1000000000000000000');
340
+ }
341
+ async fetchCurrencies(params = {}) {
342
+ /**
343
+ * @method
344
+ * @name vertex#fetchCurrencies
345
+ * @description fetches all available currencies on an exchange
346
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/assets
347
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
348
+ * @returns {object} an associative dictionary of currencies
349
+ */
350
+ const request = {};
351
+ const response = await this.v2GatewayGetAssets(this.extend(request, params));
352
+ //
353
+ // [
354
+ // {
355
+ // "product_id": 2,
356
+ // "ticker_id": "BTC-PERP_USDC",
357
+ // "market_type": "perp",
358
+ // "name": "Bitcoin Perp",
359
+ // "symbol": "BTC-PERP",
360
+ // "maker_fee": 0.0002,
361
+ // "taker_fee": 0,
362
+ // "can_withdraw": false,
363
+ // "can_deposit": false
364
+ // },
365
+ // {
366
+ // "product_id": 1,
367
+ // "ticker_id": "BTC_USDC",
368
+ // "market_type": "spot",
369
+ // "name": "Bitcoin",
370
+ // "symbol": "BTC",
371
+ // "taker_fee": 0.0003,
372
+ // "maker_fee": 0,
373
+ // "can_withdraw": true,
374
+ // "can_deposit": true
375
+ // }
376
+ // ]
377
+ //
378
+ const result = {};
379
+ for (let i = 0; i < response.length; i++) {
380
+ const data = this.safeDict(response, i, {});
381
+ const tickerId = this.safeString(data, 'ticker_id');
382
+ if ((tickerId !== undefined) && (tickerId.indexOf('PERP') > 0)) {
383
+ continue;
384
+ }
385
+ const id = this.safeString(data, 'product_id');
386
+ const name = this.safeString(data, 'symbol');
387
+ const code = this.safeCurrencyCode(name);
388
+ result[code] = {
389
+ 'id': id,
390
+ 'name': name,
391
+ 'code': code,
392
+ 'precision': undefined,
393
+ 'info': data,
394
+ 'active': undefined,
395
+ 'deposit': this.safeBool(data, 'can_deposit'),
396
+ 'withdraw': this.safeBool(data, 'can_withdraw'),
397
+ 'networks': undefined,
398
+ 'fee': undefined,
399
+ 'limits': undefined,
400
+ };
401
+ }
402
+ return result;
403
+ }
404
+ parseMarket(market) {
405
+ //
406
+ // {
407
+ // "type": "spot",
408
+ // "product_id": 3,
409
+ // "symbol": "WETH",
410
+ // "price_increment_x18": "100000000000000000",
411
+ // "size_increment": "10000000000000000",
412
+ // "min_size": "100000000000000000",
413
+ // "min_depth_x18": "5000000000000000000000",
414
+ // "max_spread_rate_x18": "2000000000000000",
415
+ // "maker_fee_rate_x18": "0",
416
+ // "taker_fee_rate_x18": "300000000000000",
417
+ // "long_weight_initial_x18": "900000000000000000",
418
+ // "long_weight_maintenance_x18": "950000000000000000"
419
+ // }
420
+ //
421
+ const marketType = this.safeString(market, 'type');
422
+ const quoteId = 'USDC';
423
+ const quote = this.safeCurrencyCode(quoteId);
424
+ const baseId = this.safeString(market, 'symbol');
425
+ const base = this.safeCurrencyCode(baseId);
426
+ const settleId = quoteId;
427
+ const settle = this.safeCurrencyCode(settleId);
428
+ let symbol = base + '/' + quote;
429
+ const spot = marketType === 'spot';
430
+ const contract = !spot;
431
+ const swap = !spot;
432
+ if (swap) {
433
+ const splitSymbol = base.split('-');
434
+ symbol = splitSymbol[0] + '/' + quote + ':' + settle;
435
+ }
436
+ const priceIncrementX18 = this.safeString(market, 'price_increment_x18');
437
+ const sizeIncrementX18 = this.safeString(market, 'size_increment');
438
+ const minSizeX18 = this.safeString(market, 'min_size');
439
+ const takerX18 = this.safeNumber(market, 'taker_fee_rate_x18');
440
+ const makerX18 = this.safeNumber(market, 'maker_fee_rate_x18');
441
+ const isInverse = (spot) ? undefined : false;
442
+ const isLinear = (spot) ? undefined : true;
443
+ const contractSize = (spot) ? undefined : this.parseNumber('1');
444
+ return {
445
+ 'id': this.safeString(market, 'product_id'),
446
+ 'symbol': symbol,
447
+ 'base': base,
448
+ 'quote': quote,
449
+ 'settle': (spot) ? undefined : settle,
450
+ 'baseId': baseId,
451
+ 'quoteId': quoteId,
452
+ 'settleId': (spot) ? undefined : settleId,
453
+ 'type': (spot) ? 'spot' : 'swap',
454
+ 'spot': spot,
455
+ 'margin': undefined,
456
+ 'swap': swap,
457
+ 'future': false,
458
+ 'option': false,
459
+ 'active': true,
460
+ 'contract': contract,
461
+ 'linear': isLinear,
462
+ 'inverse': isInverse,
463
+ 'taker': this.parseNumber(this.convertFromX18(takerX18)),
464
+ 'maker': this.parseNumber(this.convertFromX18(makerX18)),
465
+ 'contractSize': contractSize,
466
+ 'expiry': undefined,
467
+ 'expiryDatetime': undefined,
468
+ 'strike': undefined,
469
+ 'optionType': undefined,
470
+ 'precision': {
471
+ 'amount': this.parseNumber(this.convertFromX18(sizeIncrementX18)),
472
+ 'price': this.parseNumber(this.convertFromX18(priceIncrementX18)),
473
+ },
474
+ 'limits': {
475
+ 'leverage': {
476
+ 'min': undefined,
477
+ 'max': undefined,
478
+ },
479
+ 'amount': {
480
+ 'min': this.parseNumber(this.convertFromX18(minSizeX18)),
481
+ 'max': undefined,
482
+ },
483
+ 'price': {
484
+ 'min': undefined,
485
+ 'max': undefined,
486
+ },
487
+ 'cost': {
488
+ 'min': undefined,
489
+ 'max': undefined,
490
+ },
491
+ },
492
+ 'created': undefined,
493
+ 'info': market,
494
+ };
495
+ }
496
+ async fetchMarkets(params = {}) {
497
+ /**
498
+ * @method
499
+ * @name vertex#fetchMarkets
500
+ * @description retrieves data on all markets for vertex
501
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/symbols
502
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
503
+ * @returns {object[]} an array of objects representing market data
504
+ */
505
+ const request = {
506
+ 'type': 'symbols',
507
+ };
508
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
509
+ //
510
+ // {
511
+ // "status": "success",
512
+ // "data": {
513
+ // "symbols": {
514
+ // "WETH": {
515
+ // "type": "spot",
516
+ // "product_id": 3,
517
+ // "symbol": "WETH",
518
+ // "price_increment_x18": "100000000000000000",
519
+ // "size_increment": "10000000000000000",
520
+ // "min_size": "100000000000000000",
521
+ // "min_depth_x18": "5000000000000000000000",
522
+ // "max_spread_rate_x18": "2000000000000000",
523
+ // "maker_fee_rate_x18": "0",
524
+ // "taker_fee_rate_x18": "300000000000000",
525
+ // "long_weight_initial_x18": "900000000000000000",
526
+ // "long_weight_maintenance_x18": "950000000000000000"
527
+ // }
528
+ // }
529
+ // },
530
+ // "request_type": "query_symbols"
531
+ // }
532
+ //
533
+ const data = this.safeDict(response, 'data', {});
534
+ const markets = this.safeDict(data, 'symbols', {});
535
+ const symbols = Object.keys(markets);
536
+ const result = [];
537
+ for (let i = 0; i < symbols.length; i++) {
538
+ const symbol = symbols[i];
539
+ const rawMarket = this.safeDict(markets, symbol, {});
540
+ result.push(this.parseMarket(rawMarket));
541
+ }
542
+ return result;
543
+ }
544
+ async fetchTime(params = {}) {
545
+ /**
546
+ * @method
547
+ * @name vertex#fetchTime
548
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
549
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
550
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
551
+ */
552
+ const response = await this.v1GatewayGetTime(params);
553
+ // 1717481623452
554
+ return this.parseNumber(response);
555
+ }
556
+ async fetchStatus(params = {}) {
557
+ /**
558
+ * @method
559
+ * @name vertex#fetchStatus
560
+ * @description the latest known information on the availability of the exchange API
561
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/status
562
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
563
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
564
+ */
565
+ const request = {
566
+ 'type': 'status',
567
+ };
568
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
569
+ //
570
+ // {
571
+ // "status": "success",
572
+ // "data": "active",
573
+ // "request_type": "query_status",
574
+ // }
575
+ //
576
+ let status = this.safeString(response, 'data');
577
+ if (status === 'active') {
578
+ status = 'ok';
579
+ }
580
+ else {
581
+ status = 'error';
582
+ }
583
+ return {
584
+ 'status': status,
585
+ 'updated': undefined,
586
+ 'eta': undefined,
587
+ 'url': undefined,
588
+ 'info': response,
589
+ };
590
+ }
591
+ parseTrade(trade, market = undefined) {
592
+ //
593
+ // {
594
+ // "ticker_id": "ARB_USDC",
595
+ // "trade_id": 999994,
596
+ // "price": 1.1366122408151016,
597
+ // "base_filled": 175,
598
+ // "quote_filled": -198.90714214264278,
599
+ // "timestamp": 1691068943,
600
+ // "trade_type": "buy"
601
+ // }
602
+ // fetchMytrades
603
+ // {
604
+ // "digest": "0x80ce789702b670b7d33f2aa67e12c85f124395c3f9acdb422dde3b4973ccd50c",
605
+ // "order": {
606
+ // "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
607
+ // "priceX18": "27544000000000000000000",
608
+ // "amount": "2000000000000000000",
609
+ // "expiration": "4611686020107119633",
610
+ // "nonce": "1761322608857448448"
611
+ // },
612
+ // "base_filled": "736000000000000000",
613
+ // "quote_filled": "-20276464287857571514302",
614
+ // "fee": "4055287857571514302",
615
+ // "sequencer_fee": "0"
616
+ // "cumulative_fee": "4055287857571514302",
617
+ // "cumulative_base_filled": "736000000000000000",
618
+ // "cumulative_quote_filled": "-20276464287857571514302",
619
+ // "submission_idx": "563012",
620
+ // "pre_balance": {
621
+ // "base": {
622
+ // "perp": {
623
+ // "product_id": 2,
624
+ // "lp_balance": {
625
+ // "amount": "0",
626
+ // "last_cumulative_funding_x18": "1823351297710837"
627
+ // },
628
+ // "balance": {
629
+ // "amount": "2686684000000000000000",
630
+ // "v_quote_balance": "-76348662407149297671587247",
631
+ // "last_cumulative_funding_x18": "134999841911604906604576"
632
+ // }
633
+ // }
634
+ // },
635
+ // "quote": null
636
+ // },
637
+ // "post_balance": {
638
+ // "base": {
639
+ // "perp": {
640
+ // "product_id": 2,
641
+ // "lp_balance": {
642
+ // "amount": "0",
643
+ // "last_cumulative_funding_x18": "1823351297710837"
644
+ // },
645
+ // "balance": {
646
+ // "amount": "2686013000000000000000",
647
+ // "v_quote_balance": "-76328351274188497671587247",
648
+ // "last_cumulative_funding_x18": "134999841911604906604576"
649
+ // }
650
+ // }
651
+ // },
652
+ // "quote": null
653
+ // }
654
+ // }
655
+ let price = undefined;
656
+ let amount = undefined;
657
+ let side = undefined;
658
+ let fee = undefined;
659
+ const id = this.safeString2(trade, 'trade_id', 'submission_idx');
660
+ const order = this.safeString(trade, 'digest');
661
+ const timestamp = this.safeTimestamp(trade, 'timestamp');
662
+ if (timestamp === undefined) {
663
+ // fetchMyTrades
664
+ const baseBalance = this.safeDict(this.safeDict(trade, 'pre_balance', {}), 'base', {});
665
+ let marketId = undefined;
666
+ if ('perp' in baseBalance) {
667
+ marketId = this.safeString(this.safeDict(baseBalance, 'perp', {}), 'product_id');
668
+ }
669
+ else {
670
+ marketId = this.safeString(this.safeDict(baseBalance, 'spot', {}), 'product_id');
671
+ }
672
+ market = this.safeMarket(marketId);
673
+ const subOrder = this.safeDict(trade, 'order', {});
674
+ price = this.convertFromX18(this.safeString(subOrder, 'priceX18'));
675
+ amount = this.convertFromX18(this.safeString(trade, 'base_filled'));
676
+ fee = {
677
+ 'cost': this.convertFromX18(this.safeString(trade, 'fee')),
678
+ 'currency': undefined,
679
+ };
680
+ if (Precise["default"].stringLt(amount, '0')) {
681
+ side = 'sell';
682
+ }
683
+ else {
684
+ side = 'buy';
685
+ }
686
+ }
687
+ else {
688
+ const tickerId = this.safeString(trade, 'ticker_id');
689
+ const splitTickerId = tickerId.split('_');
690
+ const splitSymbol = splitTickerId[0].split('-');
691
+ const marketId = splitSymbol[0] + splitTickerId[1];
692
+ market = this.safeMarket(marketId, market);
693
+ price = this.safeString(trade, 'price');
694
+ amount = this.safeString(trade, 'base_filled');
695
+ side = this.safeStringLower(trade, 'trade_type');
696
+ }
697
+ amount = Precise["default"].stringAbs(amount);
698
+ const symbol = market['symbol'];
699
+ return this.safeTrade({
700
+ 'id': id,
701
+ 'timestamp': timestamp,
702
+ 'datetime': this.iso8601(timestamp),
703
+ 'symbol': symbol,
704
+ 'side': side,
705
+ 'price': price,
706
+ 'amount': amount,
707
+ 'cost': undefined,
708
+ 'order': order,
709
+ 'takerOrMaker': undefined,
710
+ 'type': undefined,
711
+ 'fee': fee,
712
+ 'info': trade,
713
+ }, market);
714
+ }
715
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
716
+ /**
717
+ * @method
718
+ * @name vertex#fetchTrades
719
+ * @description get the list of most recent trades for a particular symbol
720
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/trades
721
+ * @param {string} symbol unified symbol of the market to fetch trades for
722
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
723
+ * @param {int} [limit] the maximum amount of trades to fetch
724
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
725
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
726
+ */
727
+ await this.loadMarkets();
728
+ const market = this.market(symbol);
729
+ const marketId = market['baseId'] + '_USDC';
730
+ const request = {
731
+ 'ticker_id': marketId,
732
+ };
733
+ if (limit !== undefined) {
734
+ request['limit'] = limit;
735
+ }
736
+ const response = await this.v2ArchiveGetTrades(this.extend(request, params));
737
+ //
738
+ // [
739
+ // {
740
+ // "ticker_id": "ARB_USDC",
741
+ // "trade_id": 999994,
742
+ // "price": 1.1366122408151016,
743
+ // "base_filled": 175,
744
+ // "quote_filled": -198.90714214264278,
745
+ // "timestamp": 1691068943,
746
+ // "trade_type": "buy"
747
+ // },
748
+ // {
749
+ // "ticker_id": "ARB_USDC",
750
+ // "trade_id": 999978,
751
+ // "price": 1.136512210806099,
752
+ // "base_filled": 175,
753
+ // "quote_filled": -198.8896368910673,
754
+ // "timestamp": 1691068882,
755
+ // "trade_type": "buy"
756
+ // }
757
+ // ]
758
+ //
759
+ return this.parseTrades(response, market, since, limit);
760
+ }
761
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
762
+ /**
763
+ * @method
764
+ * @name vertex#fetchMyTrades
765
+ * @description fetch all trades made by the user
766
+ * @see https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/matches
767
+ * @param {string} symbol unified market symbol
768
+ * @param {int} [since] the earliest time in ms to fetch trades for
769
+ * @param {int} [limit] the maximum number of trades structures to retrieve
770
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
771
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
772
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
773
+ */
774
+ await this.loadMarkets();
775
+ let userAddress = undefined;
776
+ [userAddress, params] = this.handlePublicAddress('fetchMyTrades', params);
777
+ let market = undefined;
778
+ const matchesRequest = {
779
+ 'subaccount': this.convertAddressToSender(userAddress),
780
+ };
781
+ if (symbol !== undefined) {
782
+ market = this.market(symbol);
783
+ matchesRequest['product_ids'] = [this.parseToNumeric(market['id'])];
784
+ }
785
+ const until = this.safeInteger(params, 'until');
786
+ if (until !== undefined) {
787
+ params = this.omit(params, 'until');
788
+ matchesRequest['max_time'] = until;
789
+ }
790
+ if (limit !== undefined) {
791
+ matchesRequest['limit'] = limit;
792
+ }
793
+ const request = {
794
+ 'matches': matchesRequest,
795
+ };
796
+ const response = await this.v1ArchivePost(this.extend(request, params));
797
+ //
798
+ // {
799
+ // "matches": [
800
+ // {
801
+ // "digest": "0x80ce789702b670b7d33f2aa67e12c85f124395c3f9acdb422dde3b4973ccd50c",
802
+ // "order": {
803
+ // "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
804
+ // "priceX18": "27544000000000000000000",
805
+ // "amount": "2000000000000000000",
806
+ // "expiration": "4611686020107119633",
807
+ // "nonce": "1761322608857448448"
808
+ // },
809
+ // "base_filled": "736000000000000000",
810
+ // "quote_filled": "-20276464287857571514302",
811
+ // "fee": "4055287857571514302",
812
+ // "sequencer_fee": "0"
813
+ // "cumulative_fee": "4055287857571514302",
814
+ // "cumulative_base_filled": "736000000000000000",
815
+ // "cumulative_quote_filled": "-20276464287857571514302",
816
+ // "submission_idx": "563012",
817
+ // "pre_balance": {
818
+ // "base": {
819
+ // "perp": {
820
+ // "product_id": 2,
821
+ // "lp_balance": {
822
+ // "amount": "0",
823
+ // "last_cumulative_funding_x18": "1823351297710837"
824
+ // },
825
+ // "balance": {
826
+ // "amount": "2686684000000000000000",
827
+ // "v_quote_balance": "-76348662407149297671587247",
828
+ // "last_cumulative_funding_x18": "134999841911604906604576"
829
+ // }
830
+ // }
831
+ // },
832
+ // "quote": null
833
+ // },
834
+ // "post_balance": {
835
+ // "base": {
836
+ // "perp": {
837
+ // "product_id": 2,
838
+ // "lp_balance": {
839
+ // "amount": "0",
840
+ // "last_cumulative_funding_x18": "1823351297710837"
841
+ // },
842
+ // "balance": {
843
+ // "amount": "2686013000000000000000",
844
+ // "v_quote_balance": "-76328351274188497671587247",
845
+ // "last_cumulative_funding_x18": "134999841911604906604576"
846
+ // }
847
+ // }
848
+ // },
849
+ // "quote": null
850
+ // }
851
+ // },
852
+ // {
853
+ // "digest": "0x0f6e5a0434e36d8e6d4fed950d3624b0d8c91a8a84efd156bb25c1382561c0c2",
854
+ // "order": {
855
+ // "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
856
+ // "priceX18": "27540000000000000000000",
857
+ // "amount": "2000000000000000000",
858
+ // "expiration": "4611686020107119623",
859
+ // "nonce": "1761322602510417920"
860
+ // },
861
+ // "base_filled": "723999999999999999",
862
+ // "quote_filled": "-19944943483044913474043",
863
+ // "fee": "5983483044913474042",
864
+ // "cumulative_fee": "11958484645393618085",
865
+ // "cumulative_base_filled": "1446999999999999998",
866
+ // "cumulative_quote_filled": "-39861640484645393618087",
867
+ // "submission_idx": "563011",
868
+ // "pre_balance": {
869
+ // "base": {
870
+ // "perp": {
871
+ // "product_id": 2,
872
+ // "lp_balance": {
873
+ // "amount": "0",
874
+ // "last_cumulative_funding_x18": "1823351297710837"
875
+ // },
876
+ // "balance": {
877
+ // "amount": "2686684000000000000000",
878
+ // "v_quote_balance": "-76348662407149297671587247",
879
+ // "last_cumulative_funding_x18": "134999841911604906604576"
880
+ // }
881
+ // }
882
+ // },
883
+ // "quote": null
884
+ // },
885
+ // "post_balance": {
886
+ // "base": {
887
+ // "perp": {
888
+ // "product_id": 2,
889
+ // "lp_balance": {
890
+ // "amount": "0",
891
+ // "last_cumulative_funding_x18": "1823351297710837"
892
+ // },
893
+ // "balance": {
894
+ // "amount": "2686013000000000000000",
895
+ // "v_quote_balance": "-76328351274188497671587247",
896
+ // "last_cumulative_funding_x18": "134999841911604906604576"
897
+ // }
898
+ // }
899
+ // },
900
+ // "quote": null
901
+ // }
902
+ // }
903
+ // ],
904
+ // "txs": [
905
+ // {
906
+ // "tx": {
907
+ // "match_orders": {
908
+ // "product_id": 2,
909
+ // "amm": true,
910
+ // "taker": {
911
+ // "order": {
912
+ // "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
913
+ // "price_x18": "27544000000000000000000",
914
+ // "amount": "2000000000000000000",
915
+ // "expiration": 4611686020107120000,
916
+ // "nonce": 1761322608857448400
917
+ // },
918
+ // "signature": "0xe8fa7151bde348afa3b46dc52798046b7c8318f1b0a7f689710debbc094658cc1bf5a7e478ccc8278b625da0b9402c86b580d2e31e13831337dfd6153f4b37811b"
919
+ // },
920
+ // "maker": {
921
+ // "order": {
922
+ // "sender": "0xebdbbcdbd2646c5f23a1e0806027eee5f71b074664656661756c740000000000",
923
+ // "price_x18": "27544000000000000000000",
924
+ // "amount": "-736000000000000000",
925
+ // "expiration": 1679731669,
926
+ // "nonce": 1761322585591644200
927
+ // },
928
+ // "signature": "0x47f9d47f0777f3ca0b13f07b7682dbeea098c0e377b87dcb025754fe34c900e336b8c7744e021fb9c46a4f8c6a1478bafa28bf0d023ae496aa3efa4d8e81df181c"
929
+ // }
930
+ // }
931
+ // },
932
+ // "submission_idx": "563012",
933
+ // "timestamp": "1679728133"
934
+ // },
935
+ // {
936
+ // "tx": {
937
+ // "match_orders": {
938
+ // "product_id": 1,
939
+ // "amm": true,
940
+ // "taker": {
941
+ // "order": {
942
+ // "sender": "0x12a0b4888021576eb10a67616dd3dd3d9ce206b664656661756c740000000000",
943
+ // "price_x18": "27540000000000000000000",
944
+ // "amount": "2000000000000000000",
945
+ // "expiration": 4611686020107120000,
946
+ // "nonce": 1761322602510418000
947
+ // },
948
+ // "signature": "0x826c68f1a3f76d9ffbe8041f8d45e969d31f1ab6f2ae2f6379d1493e479e56436091d6cf4c72e212dd2f1d2fa17c627c4c21bd6d281c77172b8af030488478b71c"
949
+ // },
950
+ // "maker": {
951
+ // "order": {
952
+ // "sender": "0xf8d240d9514c9a4715d66268d7af3b53d619642564656661756c740000000000",
953
+ // "price_x18": "27540000000000000000000",
954
+ // "amount": "-724000000000000000",
955
+ // "expiration": 1679731656,
956
+ // "nonce": 1761322565506171000
957
+ // },
958
+ // "signature": "0xd8b6505b8d9b8c3cbfe793080976388035682c02a27893fb26b48a5b2bfe943f4162dea3a42e24e0dff5e2f74fbf77e33d83619140a2a581117c55e6cc236bdb1c"
959
+ // }
960
+ // }
961
+ // },
962
+ // "submission_idx": "563011",
963
+ // "timestamp": "1679728127"
964
+ // }
965
+ // ]
966
+ // }
967
+ //
968
+ const trades = this.safeList(response, 'matches', []);
969
+ return this.parseTrades(trades, market, since, limit, params);
970
+ }
971
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
972
+ /**
973
+ * @method
974
+ * @name vertex#fetchOrderBook
975
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
976
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/orderbook
977
+ * @param {string} symbol unified symbol of the market to fetch the order book for
978
+ * @param {int} [limit] the maximum amount of order book entries to return
979
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
980
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
981
+ */
982
+ await this.loadMarkets();
983
+ const market = this.market(symbol);
984
+ const marketId = market['baseId'] + '_USDC';
985
+ if (limit === undefined) {
986
+ limit = 100;
987
+ }
988
+ const request = {
989
+ 'ticker_id': marketId,
990
+ 'depth': limit,
991
+ };
992
+ const response = await this.v2GatewayGetOrderbook(this.extend(request, params));
993
+ //
994
+ // {
995
+ // "ticker_id": "ETH-PERP_USDC",
996
+ // "bids": [
997
+ // [
998
+ // 1612.3,
999
+ // 0.31
1000
+ // ],
1001
+ // [
1002
+ // 1612.0,
1003
+ // 0.93
1004
+ // ],
1005
+ // [
1006
+ // 1611.5,
1007
+ // 1.55
1008
+ // ],
1009
+ // [
1010
+ // 1610.8,
1011
+ // 2.17
1012
+ // ]
1013
+ // ],
1014
+ // "asks": [
1015
+ // [
1016
+ // 1612.9,
1017
+ // 0.93
1018
+ // ],
1019
+ // [
1020
+ // 1613.4,
1021
+ // 1.55
1022
+ // ],
1023
+ // [
1024
+ // 1614.1,
1025
+ // 2.17
1026
+ // ]
1027
+ // ],
1028
+ // "timestamp": 1694375362016
1029
+ // }
1030
+ //
1031
+ const timestamp = this.safeInteger(response, 'timestamp');
1032
+ return this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks');
1033
+ }
1034
+ async fetchTradingFees(params = {}) {
1035
+ /**
1036
+ * @method
1037
+ * @name vertex#fetchTradingFees
1038
+ * @description fetch the trading fees for multiple markets
1039
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/fee-rates
1040
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1041
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
1042
+ * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
1043
+ */
1044
+ await this.loadMarkets();
1045
+ let userAddress = undefined;
1046
+ [userAddress, params] = this.handlePublicAddress('fetchTradingFees', params);
1047
+ const request = {
1048
+ 'type': 'fee_rates',
1049
+ 'sender': this.convertAddressToSender(userAddress),
1050
+ };
1051
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
1052
+ //
1053
+ // {
1054
+ // "status": "success",
1055
+ // "data": {
1056
+ // "taker_fee_rates_x18": [
1057
+ // "0",
1058
+ // "300000000000000",
1059
+ // "200000000000000",
1060
+ // "300000000000000",
1061
+ // "200000000000000"
1062
+ // ],
1063
+ // "maker_fee_rates_x18": [
1064
+ // "0",
1065
+ // "0",
1066
+ // "0",
1067
+ // "0",
1068
+ // "0"
1069
+ // ],
1070
+ // "liquidation_sequencer_fee": "250000000000000000",
1071
+ // "health_check_sequencer_fee": "100000000000000000",
1072
+ // "taker_sequencer_fee": "25000000000000000",
1073
+ // "withdraw_sequencer_fees": [
1074
+ // "10000000000000000",
1075
+ // "40000000000000",
1076
+ // "0",
1077
+ // "600000000000000",
1078
+ // "0"
1079
+ // ]
1080
+ // },
1081
+ // "request_type": "query_fee_rates",
1082
+ // }
1083
+ //
1084
+ const data = this.safeDict(response, 'data', {});
1085
+ const maker = this.safeList(data, 'maker_fee_rates_x18', []);
1086
+ const taker = this.safeList(data, 'taker_fee_rates_x18', []);
1087
+ const result = {};
1088
+ for (let i = 0; i < taker.length; i++) {
1089
+ const market = this.safeMarket(this.numberToString(i));
1090
+ if (market['id'] === undefined) {
1091
+ continue;
1092
+ }
1093
+ const symbol = market['symbol'];
1094
+ result[symbol] = {
1095
+ 'info': response,
1096
+ 'symbol': symbol,
1097
+ 'maker': this.parseNumber(this.convertFromX18(maker[i])),
1098
+ 'taker': this.parseNumber(this.convertFromX18(taker[i])),
1099
+ 'percentage': true,
1100
+ 'tierBased': false,
1101
+ };
1102
+ }
1103
+ return result;
1104
+ }
1105
+ parseOHLCV(ohlcv, market = undefined) {
1106
+ // example response in fetchOHLCV
1107
+ return [
1108
+ this.safeTimestamp(ohlcv, 'timestamp'),
1109
+ this.parseNumber(this.convertFromX18(this.safeString(ohlcv, 'open_x18'))),
1110
+ this.parseNumber(this.convertFromX18(this.safeString(ohlcv, 'high_x18'))),
1111
+ this.parseNumber(this.convertFromX18(this.safeString(ohlcv, 'low_x18'))),
1112
+ this.parseNumber(this.convertFromX18(this.safeString(ohlcv, 'close_x18'))),
1113
+ this.parseNumber(this.convertFromX18(this.safeString(ohlcv, 'volume'))),
1114
+ ];
1115
+ }
1116
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1117
+ /**
1118
+ * @method
1119
+ * @name vertex#fetchOHLCV
1120
+ * @see https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/candlesticks
1121
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1122
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1123
+ * @param {string} timeframe the length of time each candle represents
1124
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1125
+ * @param {int} [limit] max=1000, max=100 when since is defined and is less than (now - (999 * (timeframe in ms)))
1126
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1127
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1128
+ */
1129
+ await this.loadMarkets();
1130
+ const market = this.market(symbol);
1131
+ const ohlcvRequest = {
1132
+ 'product_id': this.parseToInt(market['id']),
1133
+ 'granularity': this.safeInteger(this.timeframes, timeframe),
1134
+ };
1135
+ const until = this.safeInteger(params, 'until');
1136
+ if (until !== undefined) {
1137
+ params = this.omit(params, 'until');
1138
+ ohlcvRequest['max_time'] = until;
1139
+ }
1140
+ if (limit !== undefined) {
1141
+ ohlcvRequest['limit'] = Math.min(limit, 1000);
1142
+ }
1143
+ const request = {
1144
+ 'candlesticks': ohlcvRequest,
1145
+ };
1146
+ const response = await this.v1ArchivePost(this.extend(request, params));
1147
+ //
1148
+ // {
1149
+ // "candlesticks": [
1150
+ // {
1151
+ // "product_id": 1,
1152
+ // "granularity": 60,
1153
+ // "submission_idx": "627709",
1154
+ // "timestamp": "1680118140",
1155
+ // "open_x18": "27235000000000000000000",
1156
+ // "high_x18": "27298000000000000000000",
1157
+ // "low_x18": "27235000000000000000000",
1158
+ // "close_x18": "27298000000000000000000",
1159
+ // "volume": "1999999999999999998"
1160
+ // },
1161
+ // {
1162
+ // "product_id": 1,
1163
+ // "granularity": 60,
1164
+ // "submission_idx": "627699",
1165
+ // "timestamp": "1680118080",
1166
+ // "open_x18": "27218000000000000000000",
1167
+ // "high_x18": "27245000000000000000000",
1168
+ // "low_x18": "27218000000000000000000",
1169
+ // "close_x18": "27245000000000000000000",
1170
+ // "volume": "11852999999999999995"
1171
+ // }
1172
+ // ]
1173
+ // }
1174
+ //
1175
+ const rows = this.safeList(response, 'candlesticks', []);
1176
+ return this.parseOHLCVs(rows, market, timeframe, since, limit);
1177
+ }
1178
+ parseFundingRate(ticker, market = undefined) {
1179
+ //
1180
+ // {
1181
+ // "product_id": 4,
1182
+ // "funding_rate_x18": "2447900598160952",
1183
+ // "update_time": "1680116326"
1184
+ // }
1185
+ //
1186
+ // {
1187
+ // "ETH-PERP_USDC": {
1188
+ // "ticker_id": "ETH-PERP_USDC",
1189
+ // "base_currency": "ETH-PERP",
1190
+ // "quote_currency": "USDC",
1191
+ // "last_price": 1620.3,
1192
+ // "base_volume": 1309.2,
1193
+ // "quote_volume": 2117828.093867611,
1194
+ // "product_type": "perpetual",
1195
+ // "contract_price": 1620.372642114429,
1196
+ // "contract_price_currency": "USD",
1197
+ // "open_interest": 1635.2,
1198
+ // "open_interest_usd": 2649633.3443855145,
1199
+ // "index_price": 1623.293496279935,
1200
+ // "mark_price": 1623.398589416731,
1201
+ // "funding_rate": 0.000068613217104332,
1202
+ // "next_funding_rate_timestamp": 1694379600,
1203
+ // "price_change_percent_24h": -0.6348599635253989
1204
+ // }
1205
+ // }
1206
+ //
1207
+ let fundingRate = this.safeNumber(ticker, 'funding_rate');
1208
+ if (fundingRate === undefined) {
1209
+ const fundingRateX18 = this.safeString(ticker, 'funding_rate_x18');
1210
+ fundingRate = this.parseNumber(this.convertFromX18(fundingRateX18));
1211
+ }
1212
+ const fundingTimestamp = this.safeTimestamp2(ticker, 'update_time', 'next_funding_rate_timestamp');
1213
+ const markPrice = this.safeNumber(ticker, 'mark_price');
1214
+ const indexPrice = this.safeNumber(ticker, 'index_price');
1215
+ return {
1216
+ 'info': ticker,
1217
+ 'symbol': market['symbol'],
1218
+ 'markPrice': markPrice,
1219
+ 'indexPrice': indexPrice,
1220
+ 'interestRate': undefined,
1221
+ 'estimatedSettlePrice': undefined,
1222
+ 'timestamp': undefined,
1223
+ 'datetime': undefined,
1224
+ 'fundingRate': fundingRate,
1225
+ 'fundingTimestamp': fundingTimestamp,
1226
+ 'fundingDatetime': this.iso8601(fundingTimestamp),
1227
+ 'nextFundingRate': undefined,
1228
+ 'nextFundingTimestamp': undefined,
1229
+ 'nextFundingDatetime': undefined,
1230
+ 'previousFundingRate': undefined,
1231
+ 'previousFundingTimestamp': undefined,
1232
+ 'previousFundingDatetime': undefined,
1233
+ };
1234
+ }
1235
+ async fetchFundingRate(symbol, params = {}) {
1236
+ /**
1237
+ * @method
1238
+ * @name vertex#fetchFundingRate
1239
+ * @description fetch the current funding rate
1240
+ * @see https://docs.vertexprotocol.com/developer-resources/api/archive-indexer/funding-rate
1241
+ * @param {string} symbol unified market symbol
1242
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1243
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1244
+ */
1245
+ await this.loadMarkets();
1246
+ const market = this.market(symbol);
1247
+ const request = {
1248
+ 'funding_rate': {
1249
+ 'product_id': this.parseToInt(market['id']),
1250
+ },
1251
+ };
1252
+ const response = await this.v1ArchivePost(this.extend(request, params));
1253
+ //
1254
+ // {
1255
+ // "product_id": 4,
1256
+ // "funding_rate_x18": "2447900598160952",
1257
+ // "update_time": "1680116326"
1258
+ // }
1259
+ //
1260
+ return this.parseFundingRate(response, market);
1261
+ }
1262
+ async fetchFundingRates(symbols = undefined, params = {}) {
1263
+ /**
1264
+ * @method
1265
+ * @name vertex#fetchFundingRates
1266
+ * @description fetches funding rates for multiple markets
1267
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/contracts
1268
+ * @param {string[]} symbols unified symbols of the markets to fetch the funding rates for, all market funding rates are returned if not assigned
1269
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1270
+ * @returns {object} an array of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1271
+ */
1272
+ await this.loadMarkets();
1273
+ const request = {};
1274
+ if (symbols !== undefined) {
1275
+ symbols = this.marketSymbols(symbols);
1276
+ }
1277
+ const response = await this.v2ArchiveGetContracts(this.extend(request, params));
1278
+ //
1279
+ // {
1280
+ // "ETH-PERP_USDC": {
1281
+ // "ticker_id": "ETH-PERP_USDC",
1282
+ // "base_currency": "ETH-PERP",
1283
+ // "quote_currency": "USDC",
1284
+ // "last_price": 1620.3,
1285
+ // "base_volume": 1309.2,
1286
+ // "quote_volume": 2117828.093867611,
1287
+ // "product_type": "perpetual",
1288
+ // "contract_price": 1620.372642114429,
1289
+ // "contract_price_currency": "USD",
1290
+ // "open_interest": 1635.2,
1291
+ // "open_interest_usd": 2649633.3443855145,
1292
+ // "index_price": 1623.293496279935,
1293
+ // "mark_price": 1623.398589416731,
1294
+ // "funding_rate": 0.000068613217104332,
1295
+ // "next_funding_rate_timestamp": 1694379600,
1296
+ // "price_change_percent_24h": -0.6348599635253989
1297
+ // }
1298
+ // }
1299
+ //
1300
+ const keys = Object.keys(response);
1301
+ const fundingRates = {};
1302
+ for (let i = 0; i < keys.length; i++) {
1303
+ const tickerId = keys[i];
1304
+ const parsedTickerId = tickerId.split('-');
1305
+ const data = response[tickerId];
1306
+ const marketId = parsedTickerId[0] + '/USDC:USDC';
1307
+ const market = this.market(marketId);
1308
+ const ticker = this.parseFundingRate(data, market);
1309
+ const symbol = ticker['symbol'];
1310
+ fundingRates[symbol] = ticker;
1311
+ }
1312
+ return this.filterByArray(fundingRates, 'symbol', symbols);
1313
+ }
1314
+ parseOpenInterest(interest, market = undefined) {
1315
+ //
1316
+ // {
1317
+ // "ETH-PERP_USDC": {
1318
+ // "ticker_id": "ETH-PERP_USDC",
1319
+ // "base_currency": "ETH-PERP",
1320
+ // "quote_currency": "USDC",
1321
+ // "last_price": 1620.3,
1322
+ // "base_volume": 1309.2,
1323
+ // "quote_volume": 2117828.093867611,
1324
+ // "product_type": "perpetual",
1325
+ // "contract_price": 1620.372642114429,
1326
+ // "contract_price_currency": "USD",
1327
+ // "open_interest": 1635.2,
1328
+ // "open_interest_usd": 2649633.3443855145,
1329
+ // "index_price": 1623.293496279935,
1330
+ // "mark_price": 1623.398589416731,
1331
+ // "funding_rate": 0.000068613217104332,
1332
+ // "next_funding_rate_timestamp": 1694379600,
1333
+ // "price_change_percent_24h": -0.6348599635253989
1334
+ // }
1335
+ // }
1336
+ //
1337
+ const value = this.safeNumber(interest, 'open_interest_usd');
1338
+ return this.safeOpenInterest({
1339
+ 'symbol': market['symbol'],
1340
+ 'openInterestAmount': undefined,
1341
+ 'openInterestValue': value,
1342
+ 'timestamp': undefined,
1343
+ 'datetime': undefined,
1344
+ 'info': interest,
1345
+ }, market);
1346
+ }
1347
+ async fetchOpenInterest(symbol, params = {}) {
1348
+ /**
1349
+ * @method
1350
+ * @name vertex#fetchOpenInterest
1351
+ * @description Retrieves the open interest of a derivative trading pair
1352
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/contracts
1353
+ * @param {string} symbol Unified CCXT market symbol
1354
+ * @param {object} [params] exchange specific parameters
1355
+ * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
1356
+ */
1357
+ await this.loadMarkets();
1358
+ const market = this.market(symbol);
1359
+ if (!market['contract']) {
1360
+ throw new errors.BadRequest(this.id + ' fetchOpenInterest() supports contract markets only');
1361
+ }
1362
+ const request = {};
1363
+ const response = await this.v2ArchiveGetContracts(this.extend(request, params));
1364
+ //
1365
+ // {
1366
+ // "ETH-PERP_USDC": {
1367
+ // "ticker_id": "ETH-PERP_USDC",
1368
+ // "base_currency": "ETH-PERP",
1369
+ // "quote_currency": "USDC",
1370
+ // "last_price": 1620.3,
1371
+ // "base_volume": 1309.2,
1372
+ // "quote_volume": 2117828.093867611,
1373
+ // "product_type": "perpetual",
1374
+ // "contract_price": 1620.372642114429,
1375
+ // "contract_price_currency": "USD",
1376
+ // "open_interest": 1635.2,
1377
+ // "open_interest_usd": 2649633.3443855145,
1378
+ // "index_price": 1623.293496279935,
1379
+ // "mark_price": 1623.398589416731,
1380
+ // "funding_rate": 0.000068613217104332,
1381
+ // "next_funding_rate_timestamp": 1694379600,
1382
+ // "price_change_percent_24h": -0.6348599635253989
1383
+ // }
1384
+ // }
1385
+ //
1386
+ const tickerId = market['base'] + '_USDC';
1387
+ const openInterest = this.safeDict(response, tickerId, {});
1388
+ return this.parseOpenInterest(openInterest, market);
1389
+ }
1390
+ parseTicker(ticker, market = undefined) {
1391
+ //
1392
+ // {
1393
+ // "ticker_id": "BTC_USDC",
1394
+ // "base_currency": "BTC",
1395
+ // "quote_currency": "USDC",
1396
+ // "last_price": 25728.0,
1397
+ // "base_volume": 552.048,
1398
+ // "quote_volume": 14238632.207250029,
1399
+ // "price_change_percent_24h": -0.6348599635253989
1400
+ // }
1401
+ //
1402
+ const base = this.safeString(ticker, 'base_currency');
1403
+ const quote = this.safeString(ticker, 'quote_currency');
1404
+ let marketId = base + '/' + quote;
1405
+ if (base.indexOf('PERP') > 0) {
1406
+ marketId = marketId.replace('-PERP', '') + ':USDC';
1407
+ }
1408
+ market = this.market(marketId);
1409
+ const last = this.safeString(ticker, 'last_price');
1410
+ return this.safeTicker({
1411
+ 'symbol': market['symbol'],
1412
+ 'timestamp': undefined,
1413
+ 'datetime': undefined,
1414
+ 'high': undefined,
1415
+ 'low': undefined,
1416
+ 'bid': undefined,
1417
+ 'bidVolume': undefined,
1418
+ 'ask': undefined,
1419
+ 'askVolume': undefined,
1420
+ 'vwap': undefined,
1421
+ 'open': undefined,
1422
+ 'close': last,
1423
+ 'last': last,
1424
+ 'previousClose': undefined,
1425
+ 'change': undefined,
1426
+ 'percentage': this.safeString(ticker, 'price_change_percent_24h'),
1427
+ 'average': undefined,
1428
+ 'baseVolume': this.safeString(ticker, 'base_volume'),
1429
+ 'quoteVolume': this.safeString(ticker, 'quote_volume'),
1430
+ 'info': ticker,
1431
+ }, market);
1432
+ }
1433
+ async fetchTickers(symbols = undefined, params = {}) {
1434
+ /**
1435
+ * @method
1436
+ * @name vertex#fetchTickers
1437
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1438
+ * @see https://docs.vertexprotocol.com/developer-resources/api/v2/tickers
1439
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1440
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1441
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1442
+ */
1443
+ await this.loadMarkets();
1444
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
1445
+ const request = {};
1446
+ const response = await this.v2ArchiveGetTickers(this.extend(request, params));
1447
+ //
1448
+ // {
1449
+ // "ETH_USDC": {
1450
+ // "ticker_id": "ETH_USDC",
1451
+ // "base_currency": "ETH",
1452
+ // "quote_currency": "USDC",
1453
+ // "last_price": 1619.1,
1454
+ // "base_volume": 1428.32,
1455
+ // "quote_volume": 2310648.316391866,
1456
+ // "price_change_percent_24h": -1.0509394462969588
1457
+ // },
1458
+ // "BTC_USDC": {
1459
+ // "ticker_id": "BTC_USDC",
1460
+ // "base_currency": "BTC",
1461
+ // "quote_currency": "USDC",
1462
+ // "last_price": 25728.0,
1463
+ // "base_volume": 552.048,
1464
+ // "quote_volume": 14238632.207250029,
1465
+ // "price_change_percent_24h": -0.6348599635253989
1466
+ // }
1467
+ // }
1468
+ //
1469
+ const tickers = Object.values(response);
1470
+ return this.parseTickers(tickers, symbols);
1471
+ }
1472
+ async queryContracts(params = {}) {
1473
+ // query contract addresses for sending order
1474
+ const cachedContracts = this.safeDict(this.options, 'v1contracts');
1475
+ if (cachedContracts !== undefined) {
1476
+ return cachedContracts;
1477
+ }
1478
+ const request = {
1479
+ 'type': 'contracts',
1480
+ };
1481
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
1482
+ const data = this.safeDict(response, 'data', {});
1483
+ this.options['v1contracts'] = data;
1484
+ return data;
1485
+ }
1486
+ nonce() {
1487
+ return this.milliseconds() - this.options['timeDifference'];
1488
+ }
1489
+ hashMessage(message) {
1490
+ return '0x' + this.hash(message, sha3.keccak_256, 'hex');
1491
+ }
1492
+ signHash(hash, privateKey) {
1493
+ const signature = crypto.ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1.secp256k1, undefined);
1494
+ const r = signature['r'];
1495
+ const s = signature['s'];
1496
+ const v = this.intToBase16(this.sum(27, signature['v']));
1497
+ return '0x' + r.padStart(64, '0') + s.padStart(64, '0') + v;
1498
+ }
1499
+ signMessage(message, privateKey) {
1500
+ return this.signHash(this.hashMessage(message), privateKey.slice(-64));
1501
+ }
1502
+ buildSig(chainId, messageTypes, message, verifyingContractAddress = '') {
1503
+ const domain = {
1504
+ 'chainId': chainId,
1505
+ 'name': 'Vertex',
1506
+ 'verifyingContract': verifyingContractAddress,
1507
+ 'version': '0.0.1',
1508
+ };
1509
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, message);
1510
+ const signature = this.signMessage(msg, this.privateKey);
1511
+ return signature;
1512
+ }
1513
+ buildCreateOrderSig(message, chainId, verifyingContractAddress) {
1514
+ const messageTypes = {
1515
+ 'Order': [
1516
+ { 'name': 'sender', 'type': 'bytes32' },
1517
+ { 'name': 'priceX18', 'type': 'int128' },
1518
+ { 'name': 'amount', 'type': 'int128' },
1519
+ { 'name': 'expiration', 'type': 'uint64' },
1520
+ { 'name': 'nonce', 'type': 'uint64' },
1521
+ ],
1522
+ };
1523
+ return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
1524
+ }
1525
+ buildListTriggerTxSig(message, chainId, verifyingContractAddress) {
1526
+ const messageTypes = {
1527
+ 'ListTriggerOrders': [
1528
+ { 'name': 'sender', 'type': 'bytes32' },
1529
+ { 'name': 'recvTime', 'type': 'uint64' },
1530
+ ],
1531
+ };
1532
+ return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
1533
+ }
1534
+ buildCancelAllOrdersSig(message, chainId, verifyingContractAddress) {
1535
+ const messageTypes = {
1536
+ 'CancellationProducts': [
1537
+ { 'name': 'sender', 'type': 'bytes32' },
1538
+ { 'name': 'productIds', 'type': 'uint32[]' },
1539
+ { 'name': 'nonce', 'type': 'uint64' },
1540
+ ],
1541
+ };
1542
+ return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
1543
+ }
1544
+ buildCancelOrdersSig(message, chainId, verifyingContractAddress) {
1545
+ const messageTypes = {
1546
+ 'Cancellation': [
1547
+ { 'name': 'sender', 'type': 'bytes32' },
1548
+ { 'name': 'productIds', 'type': 'uint32[]' },
1549
+ { 'name': 'digests', 'type': 'bytes32[]' },
1550
+ { 'name': 'nonce', 'type': 'uint64' },
1551
+ ],
1552
+ };
1553
+ return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
1554
+ }
1555
+ buildWithdrawSig(message, chainId, verifyingContractAddress) {
1556
+ const messageTypes = {
1557
+ 'WithdrawCollateral': [
1558
+ { 'name': 'sender', 'type': 'bytes32' },
1559
+ { 'name': 'productId', 'type': 'uint32' },
1560
+ { 'name': 'amount', 'type': 'uint128' },
1561
+ { 'name': 'nonce', 'type': 'uint64' },
1562
+ ],
1563
+ };
1564
+ return this.buildSig(chainId, messageTypes, message, verifyingContractAddress);
1565
+ }
1566
+ convertAddressToSender(address) {
1567
+ const sender = address + '64656661756c74';
1568
+ return sender.padEnd(66, '0');
1569
+ }
1570
+ getNonce(now, expiration) {
1571
+ if (now === undefined) {
1572
+ now = this.nonce();
1573
+ }
1574
+ // nonce = ((now + expiration) << 20) + 1000
1575
+ // 1 << 20 = 1048576
1576
+ return Precise["default"].stringAdd(Precise["default"].stringMul(Precise["default"].stringAdd(this.numberToString(now), this.numberToString(expiration)), '1048576'), '1000');
1577
+ }
1578
+ getExpiration(now, timeInForce, postOnly, reduceOnly) {
1579
+ let expiration = Precise["default"].stringAdd(this.numberToString(now), '86400');
1580
+ if (timeInForce === 'ioc') {
1581
+ // 1 << 62 = 4611686018427387904
1582
+ expiration = Precise["default"].stringOr(expiration, '4611686018427387904');
1583
+ }
1584
+ else if (timeInForce === 'fok') {
1585
+ // 2 << 62 = 9223372036854775808
1586
+ expiration = Precise["default"].stringOr(expiration, '9223372036854775808');
1587
+ }
1588
+ else if (postOnly) {
1589
+ // 3 << 62 = 13835058055282163712
1590
+ expiration = Precise["default"].stringOr(expiration, '13835058055282163712');
1591
+ }
1592
+ if (reduceOnly) {
1593
+ // 1 << 61 = 2305843009213693952
1594
+ expiration = Precise["default"].stringOr(expiration, '2305843009213693952');
1595
+ }
1596
+ return expiration;
1597
+ }
1598
+ getAmount(amount, side) {
1599
+ let amountString = this.numberToString(amount);
1600
+ if (side === 'sell') {
1601
+ if (amount > 0) {
1602
+ // amount *= -1;
1603
+ amountString = Precise["default"].stringMul(amountString, '-1');
1604
+ }
1605
+ }
1606
+ else {
1607
+ if (amount < 0) {
1608
+ // amount *= -1;
1609
+ amountString = Precise["default"].stringMul(amountString, '-1');
1610
+ }
1611
+ }
1612
+ return amountString;
1613
+ }
1614
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1615
+ /**
1616
+ * @method
1617
+ * @name vertex#createOrder
1618
+ * @description create a trade order
1619
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/place-order
1620
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/place-order
1621
+ * @param {string} symbol unified symbol of the market to create an order in
1622
+ * @param {string} type 'market' or 'limit'
1623
+ * @param {string} side 'buy' or 'sell'
1624
+ * @param {float} amount how much of currency you want to trade in units of base currency
1625
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1626
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1627
+ * @param {string} [params.timeInForce] ioc, fok
1628
+ * @param {bool} [params.postOnly] true or false whether the order is post-only
1629
+ * @param {bool} [params.reduceOnly] true or false whether the order is reduce-only, only works for ioc and fok order
1630
+ * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
1631
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1632
+ */
1633
+ this.checkRequiredCredentials();
1634
+ const marketType = type.toLowerCase();
1635
+ const isMarketOrder = marketType === 'market';
1636
+ if (isMarketOrder && price === undefined) {
1637
+ throw new errors.ArgumentsRequired(this.id + ' createOrder() requires a price argument for market order');
1638
+ }
1639
+ await this.loadMarkets();
1640
+ const market = this.market(symbol);
1641
+ const marketId = this.parseToInt(market['id']);
1642
+ const contracts = await this.queryContracts();
1643
+ const chainId = this.safeString(contracts, 'chain_id');
1644
+ const bookAddresses = this.safeList(contracts, 'book_addrs', []);
1645
+ const verifyingContractAddress = this.safeString(bookAddresses, marketId);
1646
+ const defaultTimeInForce = (isMarketOrder) ? 'fok' : undefined;
1647
+ const timeInForce = this.safeStringLower(params, 'timeInForce', defaultTimeInForce);
1648
+ const postOnly = this.safeBool(params, 'postOnly', false);
1649
+ const reduceOnly = this.safeBool(params, 'reduceOnly', false);
1650
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1651
+ const stopLossPrice = this.safeString(params, 'stopLossPrice', triggerPrice);
1652
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
1653
+ const isTrigger = (stopLossPrice || takeProfitPrice);
1654
+ const now = this.nonce();
1655
+ let nonce = this.getNonce(now, 90000);
1656
+ if (postOnly && reduceOnly) {
1657
+ throw new errors.NotSupported(this.id + ' reduceOnly not supported when postOnly is enabled');
1658
+ }
1659
+ const expiration = this.getExpiration(now, timeInForce, postOnly, reduceOnly);
1660
+ if (isTrigger) {
1661
+ // 1 << 63 = 9223372036854775808
1662
+ nonce = Precise["default"].stringOr(nonce, '9223372036854775808');
1663
+ }
1664
+ const amountString = this.getAmount(amount, side);
1665
+ const order = {
1666
+ 'sender': this.convertAddressToSender(this.walletAddress),
1667
+ 'priceX18': this.convertToX18(this.priceToPrecision(symbol, price)),
1668
+ 'amount': this.convertToX18(this.amountToPrecision(symbol, amountString)),
1669
+ 'expiration': expiration,
1670
+ 'nonce': nonce,
1671
+ };
1672
+ const request = {
1673
+ 'place_order': {
1674
+ 'product_id': marketId,
1675
+ 'order': {
1676
+ 'sender': order['sender'],
1677
+ 'priceX18': order['priceX18'],
1678
+ 'amount': order['amount'],
1679
+ 'expiration': this.numberToString(order['expiration']),
1680
+ 'nonce': order['nonce'],
1681
+ },
1682
+ 'signature': this.buildCreateOrderSig(order, chainId, verifyingContractAddress),
1683
+ 'id': this.safeInteger(this.options, 'brokerId', 5930043274845996),
1684
+ },
1685
+ };
1686
+ params = this.omit(params, ['timeInForce', 'reduceOnly', 'postOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice']);
1687
+ let response = undefined;
1688
+ if (isTrigger) {
1689
+ const trigger = {};
1690
+ if (stopLossPrice !== undefined) {
1691
+ trigger['last_price_below'] = this.convertToX18(stopLossPrice);
1692
+ }
1693
+ else if (takeProfitPrice !== undefined) {
1694
+ trigger['last_price_above'] = this.convertToX18(takeProfitPrice);
1695
+ }
1696
+ request['place_order']['trigger'] = trigger;
1697
+ response = await this.v1TriggerPostExecute(this.extend(request, params));
1698
+ }
1699
+ else {
1700
+ response = await this.v1GatewayPostExecute(this.extend(request, params));
1701
+ }
1702
+ //
1703
+ // {
1704
+ // "status": "success",
1705
+ // "signature": {signature},
1706
+ // "data": {
1707
+ // "digest": {order digest}
1708
+ // },
1709
+ // "request_type": "execute_place_order"
1710
+ // "id": 100
1711
+ // }
1712
+ //
1713
+ const data = this.safeDict(response, 'data', {});
1714
+ return this.safeOrder({
1715
+ 'id': this.safeString(data, 'digest'),
1716
+ });
1717
+ }
1718
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
1719
+ /**
1720
+ * @method
1721
+ * @name vertex#editOrder
1722
+ * @description edit a trade order
1723
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-and-place
1724
+ * @param {string} id cancel order id
1725
+ * @param {string} symbol unified symbol of the market to create an order in
1726
+ * @param {string} type 'market' or 'limit'
1727
+ * @param {string} side 'buy' or 'sell'
1728
+ * @param {float} amount how much of currency you want to trade in units of base currency
1729
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
1730
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1731
+ * @param {string} [params.timeInForce] ioc, fok
1732
+ * @param {bool} [params.postOnly] true or false whether the order is post-only
1733
+ * @param {bool} [params.reduceOnly] true or false whether the order is reduce-only, only works for ioc and fok order
1734
+ * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
1735
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1736
+ */
1737
+ this.checkRequiredCredentials();
1738
+ const marketType = type.toLowerCase();
1739
+ const isMarketOrder = marketType === 'market';
1740
+ if (isMarketOrder && price === undefined) {
1741
+ throw new errors.ArgumentsRequired(this.id + ' editOrder() requires a price argument for market order');
1742
+ }
1743
+ await this.loadMarkets();
1744
+ const market = this.market(symbol);
1745
+ const marketId = this.parseToInt(market['id']);
1746
+ const defaultTimeInForce = (isMarketOrder) ? 'fok' : undefined;
1747
+ const timeInForce = this.safeStringLower(params, 'timeInForce', defaultTimeInForce);
1748
+ const postOnly = this.safeBool(params, 'postOnly', false);
1749
+ const reduceOnly = this.safeBool(params, 'reduceOnly', false);
1750
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1751
+ const stopLossPrice = this.safeString(params, 'stopLossPrice', triggerPrice);
1752
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
1753
+ const isTrigger = (stopLossPrice || takeProfitPrice);
1754
+ const contracts = await this.queryContracts();
1755
+ const chainId = this.safeString(contracts, 'chain_id');
1756
+ const bookAddresses = this.safeList(contracts, 'book_addrs', []);
1757
+ const verifyingContractAddressOrder = this.safeString(bookAddresses, marketId);
1758
+ const verifyingContractAddressCancel = this.safeString(contracts, 'endpoint_addr');
1759
+ const now = this.nonce();
1760
+ const nonce = this.getNonce(now, 90000);
1761
+ const sender = this.convertAddressToSender(this.walletAddress);
1762
+ if (postOnly && reduceOnly) {
1763
+ throw new errors.NotSupported(this.id + ' reduceOnly not supported when postOnly is enabled');
1764
+ }
1765
+ if (isTrigger) {
1766
+ throw new errors.NotSupported(this.id + ' editOrder() not supported for trigger order');
1767
+ }
1768
+ const expiration = this.getExpiration(now, timeInForce, postOnly, reduceOnly);
1769
+ const amountString = this.getAmount(amount, side);
1770
+ const order = {
1771
+ 'sender': sender,
1772
+ 'priceX18': this.convertToX18(this.priceToPrecision(symbol, price)),
1773
+ 'amount': this.convertToX18(this.amountToPrecision(symbol, amountString)),
1774
+ 'expiration': expiration,
1775
+ 'nonce': nonce,
1776
+ };
1777
+ const cancels = {
1778
+ 'sender': sender,
1779
+ 'productIds': [marketId],
1780
+ 'digests': [id],
1781
+ 'nonce': nonce,
1782
+ };
1783
+ const request = {
1784
+ 'cancel_and_place': {
1785
+ 'cancel_tx': {
1786
+ 'sender': cancels['sender'],
1787
+ 'productIds': cancels['productIds'],
1788
+ 'digests': cancels['digests'],
1789
+ 'nonce': this.numberToString(cancels['nonce']),
1790
+ },
1791
+ 'cancel_signature': this.buildCancelOrdersSig(cancels, chainId, verifyingContractAddressCancel),
1792
+ 'place_order': {
1793
+ 'product_id': marketId,
1794
+ 'order': {
1795
+ 'sender': order['sender'],
1796
+ 'priceX18': order['priceX18'],
1797
+ 'amount': order['amount'],
1798
+ 'expiration': this.numberToString(order['expiration']),
1799
+ 'nonce': order['nonce'],
1800
+ },
1801
+ 'signature': this.buildCreateOrderSig(order, chainId, verifyingContractAddressOrder),
1802
+ 'id': this.safeInteger(this.options, 'brokerId', 5930043274845996),
1803
+ },
1804
+ },
1805
+ };
1806
+ params = this.omit(params, ['timeInForce', 'reduceOnly', 'postOnly', 'triggerPrice', 'stopPrice', 'stopLossPrice', 'takeProfitPrice']);
1807
+ const response = await this.v1GatewayPostExecute(this.extend(request, params));
1808
+ //
1809
+ // {
1810
+ // "status": "success",
1811
+ // "signature": {signature},
1812
+ // "data": {
1813
+ // "digest": {order digest}
1814
+ // },
1815
+ // "request_type": "execute_cancel_and_place"
1816
+ // }
1817
+ //
1818
+ const data = this.safeDict(response, 'data', {});
1819
+ return this.safeOrder({
1820
+ 'id': this.safeString(data, 'digest'),
1821
+ });
1822
+ }
1823
+ parseOrderStatus(status) {
1824
+ if (status !== undefined) {
1825
+ const statuses = {
1826
+ 'pending': 'open',
1827
+ };
1828
+ if (typeof status === 'string') {
1829
+ return this.safeString(statuses, status, status);
1830
+ }
1831
+ const statusCancelled = this.safeDict(status, 'cancelled');
1832
+ if (statusCancelled !== undefined) {
1833
+ return 'canceled';
1834
+ }
1835
+ const statusTriggered = this.safeDict(status, 'triggered', {});
1836
+ const triggeredStatus = this.safeString(statusTriggered, 'status', 'failure');
1837
+ if (triggeredStatus === 'success') {
1838
+ return 'closed';
1839
+ }
1840
+ return 'canceled';
1841
+ }
1842
+ return status;
1843
+ }
1844
+ parseOrder(order, market = undefined) {
1845
+ //
1846
+ // {
1847
+ // "product_id": 1,
1848
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
1849
+ // "price_x18": "1000000000000000000",
1850
+ // "amount": "1000000000000000000",
1851
+ // "expiration": "2000000000",
1852
+ // "nonce": "1",
1853
+ // "unfilled_amount": "1000000000000000000",
1854
+ // "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
1855
+ // "placed_at": 1681951347,
1856
+ // "order_type": "ioc"
1857
+ // }
1858
+ // stop order
1859
+ // {
1860
+ // "order": {
1861
+ // "order": {
1862
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
1863
+ // "priceX18": "1000000000000000000",
1864
+ // "amount": "1000000000000000000",
1865
+ // "expiration": "2000000000",
1866
+ // "nonce": "1",
1867
+ // },
1868
+ // "signature": "0x...",
1869
+ // "product_id": 1,
1870
+ // "spot_leverage": true,
1871
+ // "trigger": {
1872
+ // "price_above": "1000000000000000000"
1873
+ // },
1874
+ // "digest": "0x..."
1875
+ // },
1876
+ // "status": "pending",
1877
+ // "updated_at": 1688768157050
1878
+ // }
1879
+ //
1880
+ let marketId = this.safeString(order, 'product_id');
1881
+ let timestamp = this.safeTimestamp(order, 'placed_at');
1882
+ let amount = this.safeString(order, 'amount');
1883
+ let price = this.safeString(order, 'price_x18');
1884
+ const remaining = this.safeString(order, 'unfilled_amount');
1885
+ let triggerPriceNum = undefined;
1886
+ const status = this.safeValue(order, 'status');
1887
+ if (status !== undefined) {
1888
+ // trigger order
1889
+ const outerOrder = this.safeDict(order, 'order', {});
1890
+ const innerOrder = this.safeDict(outerOrder, 'order', {});
1891
+ marketId = this.safeString(outerOrder, 'product_id');
1892
+ amount = this.safeString(innerOrder, 'amount');
1893
+ price = this.safeString(innerOrder, 'priceX18');
1894
+ timestamp = this.safeTimestamp(order, 'updated_at');
1895
+ const trigger = this.safeDict(outerOrder, 'trigger', {});
1896
+ const triggerPrice = this.safeStringN(trigger, ['price_above', 'price_below', 'last_price_above', 'last_price_below']);
1897
+ if (triggerPrice !== undefined) {
1898
+ triggerPriceNum = this.parseToNumeric(this.convertFromX18(triggerPrice));
1899
+ }
1900
+ }
1901
+ market = this.safeMarket(marketId, market);
1902
+ const symbol = market['symbol'];
1903
+ let priceNum = undefined;
1904
+ if (price !== undefined) {
1905
+ priceNum = this.parseToNumeric(this.convertFromX18(price));
1906
+ }
1907
+ let amountNum = undefined;
1908
+ if (amount !== undefined) {
1909
+ amountNum = this.parseToNumeric(this.convertFromX18(amount));
1910
+ }
1911
+ let remainingNum = undefined;
1912
+ if (remaining !== undefined) {
1913
+ remainingNum = this.parseToNumeric(this.convertFromX18(remaining));
1914
+ }
1915
+ let side = undefined;
1916
+ if (amountNum !== undefined && remainingNum !== undefined) {
1917
+ side = (amountNum < 0 || remainingNum < 0) ? 'sell' : 'buy';
1918
+ }
1919
+ const tif = this.parseTimeInForce(this.safeString(order, 'order_type'));
1920
+ const isPostOnly = (tif === 'PO');
1921
+ return this.safeOrder({
1922
+ 'info': order,
1923
+ 'id': this.safeString(order, 'digest'),
1924
+ 'clientOrderId': undefined,
1925
+ 'timestamp': timestamp,
1926
+ 'datetime': this.iso8601(timestamp),
1927
+ 'lastTradeTimestamp': undefined,
1928
+ 'lastUpdateTimestamp': undefined,
1929
+ 'symbol': symbol,
1930
+ 'type': undefined,
1931
+ 'timeInForce': tif,
1932
+ 'postOnly': isPostOnly,
1933
+ 'reduceOnly': undefined,
1934
+ 'side': side,
1935
+ 'price': priceNum,
1936
+ 'triggerPrice': triggerPriceNum,
1937
+ 'amount': amountNum,
1938
+ 'cost': undefined,
1939
+ 'average': undefined,
1940
+ 'filled': undefined,
1941
+ 'remaining': remainingNum,
1942
+ 'status': this.parseOrderStatus(status),
1943
+ 'fee': undefined,
1944
+ 'trades': undefined,
1945
+ }, market);
1946
+ }
1947
+ parseTimeInForce(timeInForce) {
1948
+ const timeInForces = {
1949
+ 'POST_ONLY': 'PO',
1950
+ };
1951
+ return this.safeStringUpper(timeInForces, timeInForce, timeInForce);
1952
+ }
1953
+ async fetchOrder(id, symbol = undefined, params = {}) {
1954
+ /**
1955
+ * @method
1956
+ * @name vertex#fetchOrder
1957
+ * @description fetches information on an order made by the user
1958
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/order
1959
+ * @param {string} symbol unified symbol of the market the order was made in
1960
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1961
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1962
+ */
1963
+ await this.loadMarkets();
1964
+ const market = this.market(symbol);
1965
+ const request = {
1966
+ 'type': 'order',
1967
+ 'product_id': this.parseToInt(market['id']),
1968
+ 'digest': id,
1969
+ };
1970
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
1971
+ //
1972
+ // {
1973
+ // "status": "success",
1974
+ // "data": {
1975
+ // "product_id": 1,
1976
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
1977
+ // "price_x18": "1000000000000000000",
1978
+ // "amount": "1000000000000000000",
1979
+ // "expiration": "2000000000",
1980
+ // "nonce": "1",
1981
+ // "unfilled_amount": "1000000000000000000",
1982
+ // "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
1983
+ // "placed_at": 1681951347,
1984
+ // "order_type": "ioc"
1985
+ // },
1986
+ // "request_type": "query_order",
1987
+ // }
1988
+ //
1989
+ const data = this.safeDict(response, 'data');
1990
+ return this.parseOrder(data, market);
1991
+ }
1992
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1993
+ /**
1994
+ * @method
1995
+ * @name vertex#fetchOpenOrders
1996
+ * @description fetch all unfilled currently open orders
1997
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/orders
1998
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/queries/list-trigger-orders
1999
+ * @param {string} symbol unified market symbol
2000
+ * @param {int} [since] the earliest time in ms to fetch open orders for
2001
+ * @param {int} [limit] the maximum number of open orders structures to retrieve
2002
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2003
+ * @param {boolean} [params.stop] whether the order is a stop/algo order
2004
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
2005
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2006
+ */
2007
+ this.checkRequiredCredentials();
2008
+ await this.loadMarkets();
2009
+ let userAddress = undefined;
2010
+ [userAddress, params] = this.handlePublicAddress('fetchOpenOrders', params);
2011
+ const request = {};
2012
+ let market = undefined;
2013
+ const stop = this.safeBool2(params, 'stop', 'trigger');
2014
+ params = this.omit(params, ['stop', 'trigger']);
2015
+ if (symbol !== undefined) {
2016
+ market = this.market(symbol);
2017
+ request['product_id'] = this.parseToNumeric(market['id']);
2018
+ }
2019
+ let response = undefined;
2020
+ if (stop) {
2021
+ const contracts = await this.queryContracts();
2022
+ const chainId = this.safeString(contracts, 'chain_id');
2023
+ const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
2024
+ const tx = {
2025
+ 'sender': this.convertAddressToSender(userAddress),
2026
+ 'recvTime': this.nonce() + 90000,
2027
+ };
2028
+ request['signature'] = this.buildListTriggerTxSig(tx, chainId, verifyingContractAddress);
2029
+ request['tx'] = {
2030
+ 'sender': tx['sender'],
2031
+ 'recvTime': this.numberToString(tx['recvTime']),
2032
+ };
2033
+ request['type'] = 'list_trigger_orders';
2034
+ request['pending'] = true;
2035
+ const until = this.safeInteger(params, 'until');
2036
+ params = this.omit(params, 'until');
2037
+ if (until !== undefined) {
2038
+ request['max_update_time'] = until;
2039
+ }
2040
+ if (limit !== undefined) {
2041
+ request['limit'] = limit;
2042
+ }
2043
+ response = await this.v1TriggerPostQuery(this.extend(request, params));
2044
+ //
2045
+ // {
2046
+ // "status": "success",
2047
+ // "data": {
2048
+ // "orders": [
2049
+ // {
2050
+ // "order": {
2051
+ // "order": {
2052
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
2053
+ // "priceX18": "1000000000000000000",
2054
+ // "amount": "1000000000000000000",
2055
+ // "expiration": "2000000000",
2056
+ // "nonce": "1",
2057
+ // },
2058
+ // "signature": "0x...",
2059
+ // "product_id": 1,
2060
+ // "spot_leverage": true,
2061
+ // "trigger": {
2062
+ // "price_above": "1000000000000000000"
2063
+ // },
2064
+ // "digest": "0x..."
2065
+ // },
2066
+ // "status": "pending",
2067
+ // "updated_at": 1688768157050
2068
+ // }
2069
+ // ]
2070
+ // },
2071
+ // "request_type": "query_list_trigger_orders"
2072
+ // }
2073
+ //
2074
+ }
2075
+ else {
2076
+ this.checkRequiredArgument('fetchOpenOrders', symbol, 'symbol');
2077
+ request['type'] = 'subaccount_orders';
2078
+ request['sender'] = this.convertAddressToSender(userAddress);
2079
+ response = await this.v1GatewayPostQuery(this.extend(request, params));
2080
+ //
2081
+ // {
2082
+ // "status": "success",
2083
+ // "data": {
2084
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
2085
+ // "product_id": 1,
2086
+ // "orders": [
2087
+ // {
2088
+ // "product_id": 1,
2089
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
2090
+ // "price_x18": "1000000000000000000",
2091
+ // "amount": "1000000000000000000",
2092
+ // "expiration": "2000000000",
2093
+ // "nonce": "1",
2094
+ // "order_type": "default",
2095
+ // "unfilled_amount": "1000000000000000000",
2096
+ // "digest": "0x0000000000000000000000000000000000000000000000000000000000000000",
2097
+ // "placed_at": 1682437739,
2098
+ // "order_type": "ioc"
2099
+ // }
2100
+ // ]
2101
+ // },
2102
+ // "request_type": "query_subaccount_orders"
2103
+ // }
2104
+ //
2105
+ }
2106
+ const data = this.safeDict(response, 'data', {});
2107
+ const orders = this.safeList(data, 'orders');
2108
+ return this.parseOrders(orders, market, since, limit);
2109
+ }
2110
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2111
+ /**
2112
+ * @method
2113
+ * @name vertex#fetchOrders
2114
+ * @description fetches information on multiple orders made by the user
2115
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/queries/list-trigger-orders
2116
+ * @param {string} symbol unified market symbol
2117
+ * @param {int} [since] the earliest time in ms to fetch open orders for
2118
+ * @param {int} [limit] the maximum number of open orders structures to retrieve
2119
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2120
+ * @param {boolean} [params.stop] whether the order is a stop/algo order
2121
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
2122
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2123
+ */
2124
+ this.checkRequiredCredentials();
2125
+ const stop = this.safeBool2(params, 'stop', 'trigger');
2126
+ params = this.omit(params, ['stop', 'trigger']);
2127
+ if (!stop) {
2128
+ throw new errors.NotSupported(this.id + ' fetchOrders only support trigger orders');
2129
+ }
2130
+ let userAddress = undefined;
2131
+ [userAddress, params] = this.handlePublicAddress('fetchOrders', params);
2132
+ await this.loadMarkets();
2133
+ let market = undefined;
2134
+ const request = {
2135
+ 'type': 'list_trigger_orders',
2136
+ 'pending': false,
2137
+ };
2138
+ if (symbol !== undefined) {
2139
+ market = this.market(symbol);
2140
+ request['product_id'] = this.parseToNumeric(market['id']);
2141
+ }
2142
+ const contracts = await this.queryContracts();
2143
+ const chainId = this.safeString(contracts, 'chain_id');
2144
+ const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
2145
+ const tx = {
2146
+ 'sender': this.convertAddressToSender(userAddress),
2147
+ 'recvTime': this.nonce() + 90000,
2148
+ };
2149
+ request['signature'] = this.buildListTriggerTxSig(tx, chainId, verifyingContractAddress);
2150
+ request['tx'] = {
2151
+ 'sender': tx['sender'],
2152
+ 'recvTime': this.numberToString(tx['recvTime']),
2153
+ };
2154
+ const until = this.safeInteger(params, 'until');
2155
+ params = this.omit(params, 'until');
2156
+ if (until !== undefined) {
2157
+ request['max_update_time'] = until;
2158
+ }
2159
+ if (limit !== undefined) {
2160
+ request['limit'] = limit;
2161
+ }
2162
+ const response = await this.v1TriggerPostQuery(this.extend(request, params));
2163
+ //
2164
+ // {
2165
+ // "status": "success",
2166
+ // "data": {
2167
+ // "orders": [
2168
+ // {
2169
+ // "order": {
2170
+ // "order": {
2171
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43000000000000000000000000",
2172
+ // "priceX18": "1000000000000000000",
2173
+ // "amount": "1000000000000000000",
2174
+ // "expiration": "2000000000",
2175
+ // "nonce": "1",
2176
+ // },
2177
+ // "signature": "0x...",
2178
+ // "product_id": 1,
2179
+ // "spot_leverage": true,
2180
+ // "trigger": {
2181
+ // "price_above": "1000000000000000000"
2182
+ // },
2183
+ // "digest": "0x..."
2184
+ // },
2185
+ // "status": "pending",
2186
+ // "updated_at": 1688768157050
2187
+ // }
2188
+ // ]
2189
+ // },
2190
+ // "request_type": "query_list_trigger_orders"
2191
+ // }
2192
+ //
2193
+ const data = this.safeDict(response, 'data', {});
2194
+ const orders = this.safeList(data, 'orders');
2195
+ return this.parseOrders(orders, market, since, limit);
2196
+ }
2197
+ async cancelAllOrders(symbol = undefined, params = {}) {
2198
+ /**
2199
+ * @method
2200
+ * @name vertex#cancelAllOrders
2201
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-product-orders
2202
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-product-orders
2203
+ * @description cancel all open orders in a market
2204
+ * @param {string} symbol unified market symbol
2205
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2206
+ * @param {boolean} [params.stop] whether the order is a stop/algo order
2207
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2208
+ */
2209
+ this.checkRequiredCredentials();
2210
+ await this.loadMarkets();
2211
+ if (symbol === undefined) {
2212
+ throw new errors.ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
2213
+ }
2214
+ const market = this.market(symbol);
2215
+ const marketId = market['id'];
2216
+ const contracts = await this.queryContracts();
2217
+ const chainId = this.safeString(contracts, 'chain_id');
2218
+ const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
2219
+ const now = this.nonce();
2220
+ const nonce = this.getNonce(now, 90000);
2221
+ const cancels = {
2222
+ 'sender': this.convertAddressToSender(this.walletAddress),
2223
+ 'productIds': [
2224
+ this.parseToNumeric(marketId),
2225
+ ],
2226
+ 'nonce': nonce,
2227
+ };
2228
+ const request = {
2229
+ 'cancel_product_orders': {
2230
+ 'tx': {
2231
+ 'sender': cancels['sender'],
2232
+ 'productIds': cancels['productIds'],
2233
+ 'nonce': this.numberToString(cancels['nonce']),
2234
+ },
2235
+ 'signature': this.buildCancelAllOrdersSig(cancels, chainId, verifyingContractAddress),
2236
+ },
2237
+ };
2238
+ const stop = this.safeBool2(params, 'stop', 'trigger');
2239
+ params = this.omit(params, ['stop', 'trigger']);
2240
+ let response = undefined;
2241
+ if (stop) {
2242
+ response = await this.v1TriggerPostExecute(this.extend(request, params));
2243
+ //
2244
+ // {
2245
+ // "status": "success",
2246
+ // "signature": {signature},
2247
+ // "request_type": "execute_cancel_product_orders"
2248
+ // }
2249
+ //
2250
+ }
2251
+ else {
2252
+ response = await this.v1GatewayPostExecute(this.extend(request, params));
2253
+ //
2254
+ // {
2255
+ // "status": "success",
2256
+ // "signature": {signature},
2257
+ // "data": {
2258
+ // "cancelled_orders": [
2259
+ // {
2260
+ // "product_id": 2,
2261
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
2262
+ // "price_x18": "20000000000000000000000",
2263
+ // "amount": "-100000000000000000",
2264
+ // "expiration": "1686332748",
2265
+ // "order_type": "post_only",
2266
+ // "nonce": "1768248100142339392",
2267
+ // "unfilled_amount": "-100000000000000000",
2268
+ // "digest": "0x3195a7929feb8307edecf9c045j5ced68925108f0aa305f0ee5773854159377c",
2269
+ // "placed_at": 1686332708
2270
+ // },
2271
+ // ...
2272
+ // ]
2273
+ // },
2274
+ // "request_type": "execute_cancel_product_orders"
2275
+ // }
2276
+ //
2277
+ }
2278
+ return response;
2279
+ }
2280
+ async cancelOrder(id, symbol = undefined, params = {}) {
2281
+ /**
2282
+ * @method
2283
+ * @name vertex#cancelOrder
2284
+ * @description cancels an open order
2285
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-orders
2286
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-orders
2287
+ * @param {string} id order id
2288
+ * @param {string} symbol unified symbol of the market the order was made in
2289
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2290
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2291
+ */
2292
+ return await this.cancelOrders([id], symbol, params);
2293
+ }
2294
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2295
+ /**
2296
+ * @method
2297
+ * @name vertex#cancelOrders
2298
+ * @description cancel multiple orders
2299
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/executes/cancel-orders
2300
+ * @see https://docs.vertexprotocol.com/developer-resources/api/trigger/executes/cancel-orders
2301
+ * @param {string[]} ids order ids
2302
+ * @param {string} [symbol] unified market symbol
2303
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2304
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2305
+ */
2306
+ this.checkRequiredCredentials();
2307
+ if (symbol === undefined) {
2308
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
2309
+ }
2310
+ await this.loadMarkets();
2311
+ const market = this.market(symbol);
2312
+ const marketId = market['id'];
2313
+ const contracts = await this.queryContracts();
2314
+ const chainId = this.safeString(contracts, 'chain_id');
2315
+ const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
2316
+ const now = this.nonce();
2317
+ const nonce = this.getNonce(now, 90000);
2318
+ const cancels = {
2319
+ 'sender': this.convertAddressToSender(this.walletAddress),
2320
+ 'productIds': [],
2321
+ 'digests': ids,
2322
+ 'nonce': nonce,
2323
+ };
2324
+ const marketIdNum = this.parseToNumeric(marketId);
2325
+ for (let i = 0; i < ids.length; i++) {
2326
+ cancels['productIds'].push(marketIdNum);
2327
+ }
2328
+ const request = {
2329
+ 'cancel_orders': {
2330
+ 'tx': {
2331
+ 'sender': cancels['sender'],
2332
+ 'productIds': cancels['productIds'],
2333
+ 'digests': cancels['digests'],
2334
+ 'nonce': this.numberToString(cancels['nonce']),
2335
+ },
2336
+ 'signature': this.buildCancelOrdersSig(cancels, chainId, verifyingContractAddress),
2337
+ },
2338
+ };
2339
+ const stop = this.safeBool2(params, 'stop', 'trigger');
2340
+ params = this.omit(params, ['stop', 'trigger']);
2341
+ let response = undefined;
2342
+ if (stop) {
2343
+ response = await this.v1TriggerPostExecute(this.extend(request, params));
2344
+ //
2345
+ // {
2346
+ // "status": "success",
2347
+ // "signature": {signature},
2348
+ // "request_type": "execute_cancel_orders"
2349
+ // }
2350
+ //
2351
+ }
2352
+ else {
2353
+ response = await this.v1GatewayPostExecute(this.extend(request, params));
2354
+ //
2355
+ // {
2356
+ // "status": "success",
2357
+ // "signature": {signature},
2358
+ // "data": {
2359
+ // "cancelled_orders": [
2360
+ // {
2361
+ // "product_id": 2,
2362
+ // "sender": "0x7a5ec2748e9065794491a8d29dcf3f9edb8d7c43746573743000000000000000",
2363
+ // "price_x18": "20000000000000000000000",
2364
+ // "amount": "-100000000000000000",
2365
+ // "expiration": "1686332748",
2366
+ // "order_type": "post_only",
2367
+ // "nonce": "1768248100142339392",
2368
+ // "unfilled_amount": "-100000000000000000",
2369
+ // "digest": "0x3195a7929feb8307edecf9c045j5ced68925108f0aa305f0ee5773854159377c",
2370
+ // "placed_at": 1686332708
2371
+ // },
2372
+ // ...
2373
+ // ]
2374
+ // },
2375
+ // "request_type": "execute_cancel_orders"
2376
+ // }
2377
+ //
2378
+ }
2379
+ return response;
2380
+ }
2381
+ async fetchBalance(params = {}) {
2382
+ /**
2383
+ * @method
2384
+ * @name vertex#fetchBalance
2385
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
2386
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/subaccount-info
2387
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2388
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
2389
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
2390
+ */
2391
+ let userAddress = undefined;
2392
+ [userAddress, params] = this.handlePublicAddress('fetchBalance', params);
2393
+ const request = {
2394
+ 'type': 'subaccount_info',
2395
+ 'subaccount': this.convertAddressToSender(userAddress),
2396
+ };
2397
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
2398
+ //
2399
+ // {
2400
+ // "status": "success",
2401
+ // "data": {
2402
+ // "subaccount": "0x265167ddfac55365d6ff07fc5943276319aa6b9f64656661756c740000000000",
2403
+ // "exists": true,
2404
+ // "healths": [
2405
+ // {
2406
+ // "assets": "75323297691833342306",
2407
+ // "liabilities": "46329556869051092241",
2408
+ // "health": "28993740822782250065"
2409
+ // },
2410
+ // {
2411
+ // "assets": "75323297691833342306",
2412
+ // "liabilities": "35968911700887320741",
2413
+ // "health": "39354385990946021565"
2414
+ // },
2415
+ // {
2416
+ // "assets": "80796966663601107565",
2417
+ // "liabilities": "0",
2418
+ // "health": "80796966663601107565"
2419
+ // }
2420
+ // ],
2421
+ // "health_contributions": [
2422
+ // [
2423
+ // "75323297691833340000",
2424
+ // "75323297691833340000",
2425
+ // "75323297691833340000"
2426
+ // ],
2427
+ // [
2428
+ // "0",
2429
+ // "0",
2430
+ // "0"
2431
+ // ],
2432
+ // [
2433
+ // "0",
2434
+ // "0",
2435
+ // "0"
2436
+ // ],
2437
+ // [
2438
+ // "0",
2439
+ // "0",
2440
+ // "0"
2441
+ // ],
2442
+ // [
2443
+ // "-46329556869051090000",
2444
+ // "-35968911700887323000",
2445
+ // "5473668971767765000"
2446
+ // ]
2447
+ // ],
2448
+ // "spot_count": 3,
2449
+ // "perp_count": 2,
2450
+ // "spot_balances": [
2451
+ // {
2452
+ // "product_id": 1,
2453
+ // "lp_balance": {
2454
+ // "amount": "0"
2455
+ // },
2456
+ // "balance": {
2457
+ // "amount": "0",
2458
+ // "last_cumulative_multiplier_x18": "1003419811982007193"
2459
+ // }
2460
+ // },
2461
+ // {
2462
+ // "product_id": 3,
2463
+ // "lp_balance": {
2464
+ // "amount": "0"
2465
+ // },
2466
+ // "balance": {
2467
+ // "amount": "0",
2468
+ // "last_cumulative_multiplier_x18": "1007584195035969404"
2469
+ // }
2470
+ // },
2471
+ // {
2472
+ // "product_id": 0,
2473
+ // "lp_balance": {
2474
+ // "amount": "0"
2475
+ // },
2476
+ // "balance": {
2477
+ // "amount": "75323297691833342306",
2478
+ // "last_cumulative_multiplier_x18": "1000000002391497578"
2479
+ // }
2480
+ // }
2481
+ // ],
2482
+ // "perp_balances": [
2483
+ // {
2484
+ // "product_id": 2,
2485
+ // "lp_balance": {
2486
+ // "amount": "0",
2487
+ // "last_cumulative_funding_x18": "-284321955122859921"
2488
+ // },
2489
+ // "balance": {
2490
+ // "amount": "0",
2491
+ // "v_quote_balance": "0",
2492
+ // "last_cumulative_funding_x18": "6363466629611946777168"
2493
+ // }
2494
+ // },
2495
+ // {
2496
+ // "product_id": 4,
2497
+ // "lp_balance": {
2498
+ // "amount": "0",
2499
+ // "last_cumulative_funding_x18": "-90979748449893411"
2500
+ // },
2501
+ // "balance": {
2502
+ // "amount": "-200000000000000000",
2503
+ // "v_quote_balance": "419899475698318625259",
2504
+ // "last_cumulative_funding_x18": "141182516563970577208"
2505
+ // }
2506
+ // }
2507
+ // ],
2508
+ // "spot_products": [
2509
+ // {
2510
+ // "product_id": 1,
2511
+ // "oracle_price_x18": "30217830336443750750000",
2512
+ // "risk": {
2513
+ // "long_weight_initial_x18": "750000000000000000",
2514
+ // "short_weight_initial_x18": "1250000000000000000",
2515
+ // "long_weight_maintenance_x18": "800000000000000000",
2516
+ // "short_weight_maintenance_x18": "1200000000000000000",
2517
+ // "large_position_penalty_x18": "0"
2518
+ // },
2519
+ // "config": {
2520
+ // "token": "0x5cc7c91690b2cbaee19a513473d73403e13fb431",
2521
+ // "interest_inflection_util_x18": "800000000000000000",
2522
+ // "interest_floor_x18": "10000000000000000",
2523
+ // "interest_small_cap_x18": "40000000000000000",
2524
+ // "interest_large_cap_x18": "1000000000000000000"
2525
+ // },
2526
+ // "state": {
2527
+ // "cumulative_deposits_multiplier_x18": "1001304691727847318",
2528
+ // "cumulative_borrows_multiplier_x18": "1003419811982007193",
2529
+ // "total_deposits_normalized": "213107447159798397806318",
2530
+ // "total_borrows_normalized": "4907820740150097483532"
2531
+ // },
2532
+ // "lp_state": {
2533
+ // "supply": "1304981417419495030893348",
2534
+ // "quote": {
2535
+ // "amount": "2048495687410669565222259",
2536
+ // "last_cumulative_multiplier_x18": "1000000002391497578"
2537
+ // },
2538
+ // "base": {
2539
+ // "amount": "67623029247538886515",
2540
+ // "last_cumulative_multiplier_x18": "1001304691727847318"
2541
+ // }
2542
+ // },
2543
+ // "book_info": {
2544
+ // "size_increment": "1000000000000000",
2545
+ // "price_increment_x18": "1000000000000000000",
2546
+ // "min_size": "10000000000000000",
2547
+ // "collected_fees": "8865582805773573662738183",
2548
+ // "lp_spread_x18": "3000000000000000"
2549
+ // }
2550
+ // },
2551
+ // {
2552
+ // "product_id": 3,
2553
+ // "oracle_price_x18": "2075217009708333333333",
2554
+ // "risk": {
2555
+ // "long_weight_initial_x18": "750000000000000000",
2556
+ // "short_weight_initial_x18": "1250000000000000000",
2557
+ // "long_weight_maintenance_x18": "800000000000000000",
2558
+ // "short_weight_maintenance_x18": "1200000000000000000",
2559
+ // "large_position_penalty_x18": "0"
2560
+ // },
2561
+ // "config": {
2562
+ // "token": "0xcc59686e3a32fb104c8ff84dd895676265efb8a6",
2563
+ // "interest_inflection_util_x18": "800000000000000000",
2564
+ // "interest_floor_x18": "10000000000000000",
2565
+ // "interest_small_cap_x18": "40000000000000000",
2566
+ // "interest_large_cap_x18": "1000000000000000000"
2567
+ // },
2568
+ // "state": {
2569
+ // "cumulative_deposits_multiplier_x18": "1003722507760089346",
2570
+ // "cumulative_borrows_multiplier_x18": "1007584195035969404",
2571
+ // "total_deposits_normalized": "232750303205807326418622",
2572
+ // "total_borrows_normalized": "110730726549469855171025"
2573
+ // },
2574
+ // "lp_state": {
2575
+ // "supply": "902924999999999999774268",
2576
+ // "quote": {
2577
+ // "amount": "1165328092090344104989049",
2578
+ // "last_cumulative_multiplier_x18": "1000000002391497578"
2579
+ // },
2580
+ // "base": {
2581
+ // "amount": "563265647183403990588",
2582
+ // "last_cumulative_multiplier_x18": "1003722507760089346"
2583
+ // }
2584
+ // },
2585
+ // "book_info": {
2586
+ // "size_increment": "10000000000000000",
2587
+ // "price_increment_x18": "100000000000000000",
2588
+ // "min_size": "100000000000000000",
2589
+ // "collected_fees": "1801521329724633001446457",
2590
+ // "lp_spread_x18": "3000000000000000"
2591
+ // }
2592
+ // },
2593
+ // {
2594
+ // "product_id": 0,
2595
+ // "oracle_price_x18": "1000000000000000000",
2596
+ // "risk": {
2597
+ // "long_weight_initial_x18": "1000000000000000000",
2598
+ // "short_weight_initial_x18": "1000000000000000000",
2599
+ // "long_weight_maintenance_x18": "1000000000000000000",
2600
+ // "short_weight_maintenance_x18": "1000000000000000000",
2601
+ // "large_position_penalty_x18": "0"
2602
+ // },
2603
+ // "config": {
2604
+ // "token": "0x179522635726710dd7d2035a81d856de4aa7836c",
2605
+ // "interest_inflection_util_x18": "800000000000000000",
2606
+ // "interest_floor_x18": "10000000000000000",
2607
+ // "interest_small_cap_x18": "40000000000000000",
2608
+ // "interest_large_cap_x18": "1000000000000000000"
2609
+ // },
2610
+ // "state": {
2611
+ // "cumulative_deposits_multiplier_x18": "1000000002391497578",
2612
+ // "cumulative_borrows_multiplier_x18": "1001593395547514024",
2613
+ // "total_deposits_normalized": "60000256267437588885818752247843",
2614
+ // "total_borrows_normalized": "391445043137305055810336885"
2615
+ // },
2616
+ // "lp_state": {
2617
+ // "supply": "0",
2618
+ // "quote": {
2619
+ // "amount": "0",
2620
+ // "last_cumulative_multiplier_x18": "0"
2621
+ // },
2622
+ // "base": {
2623
+ // "amount": "0",
2624
+ // "last_cumulative_multiplier_x18": "0"
2625
+ // }
2626
+ // },
2627
+ // "book_info": {
2628
+ // "size_increment": "0",
2629
+ // "price_increment_x18": "0",
2630
+ // "min_size": "0",
2631
+ // "collected_fees": "0",
2632
+ // "lp_spread_x18": "0"
2633
+ // }
2634
+ // }
2635
+ // ],
2636
+ // "perp_products": [
2637
+ // {
2638
+ // "product_id": 2,
2639
+ // "oracle_price_x18": "30219079716463070000000",
2640
+ // "risk": {
2641
+ // "long_weight_initial_x18": "875000000000000000",
2642
+ // "short_weight_initial_x18": "1125000000000000000",
2643
+ // "long_weight_maintenance_x18": "900000000000000000",
2644
+ // "short_weight_maintenance_x18": "1100000000000000000",
2645
+ // "large_position_penalty_x18": "0"
2646
+ // },
2647
+ // "state": {
2648
+ // "cumulative_funding_long_x18": "6363466629611946777168",
2649
+ // "cumulative_funding_short_x18": "6363466629611946777168",
2650
+ // "available_settle": "100612314098927536086702448",
2651
+ // "open_interest": "57975708279961875623240"
2652
+ // },
2653
+ // "lp_state": {
2654
+ // "supply": "783207415944433511804197",
2655
+ // "last_cumulative_funding_x18": "6363466629611946777168",
2656
+ // "cumulative_funding_per_lp_x18": "-284321955122859921",
2657
+ // "base": "37321000000000000000",
2658
+ // "quote": "1150991638943862165224593"
2659
+ // },
2660
+ // "book_info": {
2661
+ // "size_increment": "1000000000000000",
2662
+ // "price_increment_x18": "1000000000000000000",
2663
+ // "min_size": "10000000000000000",
2664
+ // "collected_fees": "7738341933653651206856235",
2665
+ // "lp_spread_x18": "3000000000000000"
2666
+ // }
2667
+ // },
2668
+ // {
2669
+ // "product_id": 4,
2670
+ // "oracle_price_x18": "2072129033632754300000",
2671
+ // "risk": {
2672
+ // "long_weight_initial_x18": "875000000000000000",
2673
+ // "short_weight_initial_x18": "1125000000000000000",
2674
+ // "long_weight_maintenance_x18": "900000000000000000",
2675
+ // "short_weight_maintenance_x18": "1100000000000000000",
2676
+ // "large_position_penalty_x18": "0"
2677
+ // },
2678
+ // "state": {
2679
+ // "cumulative_funding_long_x18": "141182516563970577208",
2680
+ // "cumulative_funding_short_x18": "141182516563970577208",
2681
+ // "available_settle": "33807443862986950288685582",
2682
+ // "open_interest": "316343836992291503987611"
2683
+ // },
2684
+ // "lp_state": {
2685
+ // "supply": "541756546038144467864559",
2686
+ // "last_cumulative_funding_x18": "141182516563970577208",
2687
+ // "cumulative_funding_per_lp_x18": "-90979748449893411",
2688
+ // "base": "362320000000000000000",
2689
+ // "quote": "750080187685127907834038"
2690
+ // },
2691
+ // "book_info": {
2692
+ // "size_increment": "10000000000000000",
2693
+ // "price_increment_x18": "100000000000000000",
2694
+ // "min_size": "100000000000000000",
2695
+ // "collected_fees": "1893278317732551619694831",
2696
+ // "lp_spread_x18": "3000000000000000"
2697
+ // }
2698
+ // }
2699
+ // ]
2700
+ // },
2701
+ // "request_type": "query_subaccount_info"
2702
+ // }
2703
+ //
2704
+ const data = this.safeDict(response, 'data', {});
2705
+ const balances = this.safeList(data, 'spot_balances', []);
2706
+ const result = { 'info': response };
2707
+ for (let i = 0; i < balances.length; i++) {
2708
+ const balance = balances[i];
2709
+ const marketId = this.safeString(balance, 'product_id');
2710
+ const market = this.safeMarket(marketId);
2711
+ const isUsdcMarketId = marketId === '0';
2712
+ if (market['id'] === undefined && !isUsdcMarketId) {
2713
+ continue;
2714
+ }
2715
+ const baseId = (isUsdcMarketId) ? 'USDC' : this.safeString(market, 'baseId');
2716
+ const code = this.safeCurrencyCode(baseId);
2717
+ const account = this.account();
2718
+ const tokenBalance = this.safeDict(balance, 'balance', {});
2719
+ const total = this.convertFromX18(this.safeString(tokenBalance, 'amount'));
2720
+ account['total'] = total;
2721
+ result[code] = account;
2722
+ }
2723
+ return this.safeBalance(result);
2724
+ }
2725
+ parsePosition(position, market = undefined) {
2726
+ //
2727
+ // {
2728
+ // "product_id": 2,
2729
+ // "lp_balance": {
2730
+ // "amount": "0",
2731
+ // "last_cumulative_funding_x18": "-284321955122859921"
2732
+ // },
2733
+ // "balance": {
2734
+ // "amount": "0",
2735
+ // "v_quote_balance": "0",
2736
+ // "last_cumulative_funding_x18": "6363466629611946777168"
2737
+ // }
2738
+ // },
2739
+ // {
2740
+ // "product_id": 4,
2741
+ // "lp_balance": {
2742
+ // "amount": "0",
2743
+ // "last_cumulative_funding_x18": "-90979748449893411"
2744
+ // },
2745
+ // "balance": {
2746
+ // "amount": "-200000000000000000",
2747
+ // "v_quote_balance": "419899475698318625259",
2748
+ // "last_cumulative_funding_x18": "141182516563970577208"
2749
+ // }
2750
+ // }
2751
+ //
2752
+ const marketId = this.safeString(position, 'product_id');
2753
+ market = this.safeMarket(marketId);
2754
+ const balance = this.safeDict(position, 'balance', {});
2755
+ const contractSize = this.convertFromX18(this.safeString(balance, 'amount'));
2756
+ let side = 'buy';
2757
+ if (Precise["default"].stringLt(contractSize, '1')) {
2758
+ side = 'sell';
2759
+ }
2760
+ return this.safePosition({
2761
+ 'info': position,
2762
+ 'id': undefined,
2763
+ 'symbol': this.safeString(market, 'symbol'),
2764
+ 'timestamp': undefined,
2765
+ 'datetime': undefined,
2766
+ 'lastUpdateTimestamp': undefined,
2767
+ 'initialMargin': undefined,
2768
+ 'initialMarginPercentage': undefined,
2769
+ 'maintenanceMargin': undefined,
2770
+ 'maintenanceMarginPercentage': undefined,
2771
+ 'entryPrice': undefined,
2772
+ 'notional': undefined,
2773
+ 'leverage': undefined,
2774
+ 'unrealizedPnl': undefined,
2775
+ 'contracts': undefined,
2776
+ 'contractSize': this.parseToNumeric(contractSize),
2777
+ 'marginRatio': undefined,
2778
+ 'liquidationPrice': undefined,
2779
+ 'markPrice': undefined,
2780
+ 'lastPrice': undefined,
2781
+ 'collateral': undefined,
2782
+ 'marginMode': 'cross',
2783
+ 'marginType': undefined,
2784
+ 'side': side,
2785
+ 'percentage': undefined,
2786
+ 'hedged': undefined,
2787
+ 'stopLossPrice': undefined,
2788
+ 'takeProfitPrice': undefined,
2789
+ });
2790
+ }
2791
+ async fetchPositions(symbols = undefined, params = {}) {
2792
+ /**
2793
+ * @method
2794
+ * @name vertex#fetchPositions
2795
+ * @description fetch all open positions
2796
+ * @see https://docs.vertexprotocol.com/developer-resources/api/gateway/queries/subaccount-info
2797
+ * @param {string[]} [symbols] list of unified market symbols
2798
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2799
+ * @param {string} [params.user] user address, will default to this.walletAddress if not provided
2800
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
2801
+ */
2802
+ let userAddress = undefined;
2803
+ [userAddress, params] = this.handlePublicAddress('fetchPositions', params);
2804
+ const request = {
2805
+ 'type': 'subaccount_info',
2806
+ 'subaccount': this.convertAddressToSender(userAddress),
2807
+ };
2808
+ const response = await this.v1GatewayGetQuery(this.extend(request, params));
2809
+ // the response is the same as fetchBalance
2810
+ const data = this.safeDict(response, 'data', {});
2811
+ const positions = this.safeList(data, 'perp_balances', []);
2812
+ symbols = this.marketSymbols(symbols);
2813
+ const result = [];
2814
+ for (let i = 0; i < positions.length; i++) {
2815
+ const position = this.extend(this.parsePosition(positions[i], undefined), params);
2816
+ if (position['contractSize'] === 0) {
2817
+ continue;
2818
+ }
2819
+ result.push(position);
2820
+ }
2821
+ return this.filterByArrayPositions(result, 'symbol', symbols, false);
2822
+ }
2823
+ async queryNonces() {
2824
+ const request = {
2825
+ 'type': 'nonces',
2826
+ 'address': this.walletAddress,
2827
+ };
2828
+ const response = await this.v1GatewayGetQuery(request);
2829
+ //
2830
+ // {
2831
+ // "status":"success",
2832
+ // "data":{
2833
+ // "tx_nonce": 0,
2834
+ // "order_nonce": 1753048133299863552
2835
+ // },
2836
+ // "request_type": "query_nonces",
2837
+ // }
2838
+ //
2839
+ return this.safeDict(response, 'data', {});
2840
+ }
2841
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
2842
+ /**
2843
+ * @method
2844
+ * @name vertex#withdraw
2845
+ * @description make a withdrawal
2846
+ * @see https://docs.vertexprotocol.com/developer-resources/api/withdrawing-on-chain
2847
+ * @param {string} code unified currency code
2848
+ * @param {float} amount the amount to withdraw
2849
+ * @param {string} address the address to withdraw to
2850
+ * @param {string} tag
2851
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2852
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2853
+ */
2854
+ this.checkRequiredCredentials();
2855
+ await this.loadMarkets();
2856
+ const currency = this.currency(code);
2857
+ const contracts = await this.queryContracts();
2858
+ const chainId = this.safeString(contracts, 'chain_id');
2859
+ const verifyingContractAddress = this.safeString(contracts, 'endpoint_addr');
2860
+ const nonces = await this.queryNonces();
2861
+ const nonce = this.safeNumber(nonces, 'tx_nonce');
2862
+ const withdraw = {
2863
+ 'sender': this.convertAddressToSender(this.walletAddress),
2864
+ 'productId': this.parseToNumeric(currency['id']),
2865
+ 'amount': amount.toString(),
2866
+ 'nonce': nonce,
2867
+ };
2868
+ const request = {
2869
+ 'withdraw_collateral': {
2870
+ 'tx': {
2871
+ 'sender': withdraw['sender'],
2872
+ 'productId': withdraw['productId'],
2873
+ 'amount': withdraw['amount'],
2874
+ 'nonce': this.numberToString(withdraw['nonce']),
2875
+ },
2876
+ 'signature': this.buildWithdrawSig(withdraw, chainId, verifyingContractAddress),
2877
+ },
2878
+ };
2879
+ const response = await this.v1GatewayPostExecute(this.extend(request, params));
2880
+ //
2881
+ // {
2882
+ // "status": "success",
2883
+ // "signature": {signature},
2884
+ // "request_type": "execute_withdraw_collateral"
2885
+ // }
2886
+ //
2887
+ return response;
2888
+ }
2889
+ handlePublicAddress(methodName, params) {
2890
+ let userAux = undefined;
2891
+ [userAux, params] = this.handleOptionAndParams(params, methodName, 'user');
2892
+ let user = userAux;
2893
+ [user, params] = this.handleOptionAndParams(params, methodName, 'address', userAux);
2894
+ if ((user !== undefined) && (user !== '')) {
2895
+ return [user, params];
2896
+ }
2897
+ if ((this.walletAddress !== undefined) && (this.walletAddress !== '')) {
2898
+ return [this.walletAddress, params];
2899
+ }
2900
+ throw new errors.ArgumentsRequired(this.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set');
2901
+ }
2902
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2903
+ if (!response) {
2904
+ return undefined; // fallback to default error handler
2905
+ }
2906
+ //
2907
+ //
2908
+ const status = this.safeString(response, 'status', '');
2909
+ if (status === 'failure') {
2910
+ const message = this.safeString(response, 'error');
2911
+ const feedback = this.id + ' ' + body;
2912
+ const errorCode = this.safeString(response, 'error_code');
2913
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
2914
+ this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
2915
+ throw new errors.ExchangeError(feedback);
2916
+ }
2917
+ return undefined;
2918
+ }
2919
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2920
+ const version = this.safeString(api, 0);
2921
+ const type = this.safeString(api, 1);
2922
+ let url = this.implodeHostname(this.urls['api'][version][type]);
2923
+ if (version !== 'v1' || type !== 'archive') {
2924
+ url = url + '/' + path;
2925
+ }
2926
+ if (method === 'POST') {
2927
+ headers = {
2928
+ 'Content-Type': 'application/json',
2929
+ };
2930
+ body = this.json(params);
2931
+ }
2932
+ else {
2933
+ if (Object.keys(params).length) {
2934
+ url += '?' + this.urlencode(params);
2935
+ }
2936
+ }
2937
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2938
+ }
2939
+ }
2940
+
2941
+ module.exports = vertex;