ccxt 4.5.40 → 4.5.42

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 (106) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/lighter.js +11 -0
  5. package/dist/cjs/src/ascendex.js +73 -1
  6. package/dist/cjs/src/base/Exchange.js +149 -17
  7. package/dist/cjs/src/base/functions/generic.js +1 -0
  8. package/dist/cjs/src/base/functions/io.js +160 -0
  9. package/dist/cjs/src/base/functions.js +6 -0
  10. package/dist/cjs/src/base/ws/Client.js +1 -0
  11. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  12. package/dist/cjs/src/binance.js +1 -0
  13. package/dist/cjs/src/bingx.js +13 -3
  14. package/dist/cjs/src/bitmex.js +20 -0
  15. package/dist/cjs/src/blofin.js +2 -2
  16. package/dist/cjs/src/bybit.js +1 -1
  17. package/dist/cjs/src/coinspot.js +7 -2
  18. package/dist/cjs/src/delta.js +1 -1
  19. package/dist/cjs/src/gate.js +11 -4
  20. package/dist/cjs/src/gemini.js +76 -1
  21. package/dist/cjs/src/htx.js +2 -2
  22. package/dist/cjs/src/hyperliquid.js +20 -7
  23. package/dist/cjs/src/independentreserve.js +7 -7
  24. package/dist/cjs/src/kraken.js +1 -1
  25. package/dist/cjs/src/krakenfutures.js +96 -5
  26. package/dist/cjs/src/kucoin.js +3 -3
  27. package/dist/cjs/src/kucoinfutures.js +1 -1
  28. package/dist/cjs/src/lighter.js +2931 -0
  29. package/dist/cjs/src/mexc.js +0 -1
  30. package/dist/cjs/src/phemex.js +1 -1
  31. package/dist/cjs/src/pro/binance.js +2 -2
  32. package/dist/cjs/src/pro/bingx.js +215 -2
  33. package/dist/cjs/src/pro/bitget.js +1 -0
  34. package/dist/cjs/src/pro/defx.js +1 -1
  35. package/dist/cjs/src/pro/kucoinfutures.js +1 -1
  36. package/dist/cjs/src/pro/lighter.js +787 -0
  37. package/dist/cjs/src/pro/mexc.js +1 -1
  38. package/dist/cjs/src/pro/paradex.js +1 -1
  39. package/dist/cjs/src/static_dependencies/ethers/abi-coder.js +1 -0
  40. package/dist/cjs/src/static_dependencies/ethers/address/address.js +1 -0
  41. package/dist/cjs/src/static_dependencies/ethers/coders/abstract-coder.js +1 -0
  42. package/dist/cjs/src/static_dependencies/ethers/coders/address.js +1 -0
  43. package/dist/cjs/src/static_dependencies/ethers/coders/array.js +1 -0
  44. package/dist/cjs/src/static_dependencies/ethers/coders/bytes.js +1 -0
  45. package/dist/cjs/src/static_dependencies/ethers/coders/fixed-bytes.js +1 -0
  46. package/dist/cjs/src/static_dependencies/ethers/coders/number.js +1 -0
  47. package/dist/cjs/src/static_dependencies/ethers/fragments.js +1 -0
  48. package/dist/cjs/src/static_dependencies/ethers/index.js +1 -0
  49. package/dist/cjs/src/static_dependencies/ethers/interface.js +1 -0
  50. package/dist/cjs/src/static_dependencies/ethers/typed.js +1 -0
  51. package/dist/cjs/src/static_dependencies/ethers/utils/index.js +1 -0
  52. package/dist/cjs/src/whitebit.js +118 -16
  53. package/dist/cjs/src/woo.js +1 -1
  54. package/js/ccxt.d.ts +8 -2
  55. package/js/ccxt.js +6 -2
  56. package/js/src/abstract/gemini.d.ts +27 -0
  57. package/js/src/abstract/lighter.d.ts +53 -0
  58. package/js/src/abstract/lighter.js +11 -0
  59. package/js/src/ascendex.d.ts +12 -1
  60. package/js/src/ascendex.js +73 -1
  61. package/js/src/base/Exchange.d.ts +18 -6
  62. package/js/src/base/Exchange.js +154 -21
  63. package/js/src/base/functions/generic.js +1 -0
  64. package/js/src/base/functions/io.d.ts +32 -0
  65. package/js/src/base/functions/io.js +137 -0
  66. package/js/src/base/functions.d.ts +1 -0
  67. package/js/src/base/functions.js +1 -0
  68. package/js/src/binance.d.ts +1 -0
  69. package/js/src/binance.js +1 -0
  70. package/js/src/bingx.js +13 -3
  71. package/js/src/bitmex.js +20 -0
  72. package/js/src/blofin.js +2 -2
  73. package/js/src/bybit.js +1 -1
  74. package/js/src/coinspot.js +7 -2
  75. package/js/src/delta.js +1 -1
  76. package/js/src/gate.d.ts +1 -0
  77. package/js/src/gate.js +11 -4
  78. package/js/src/gemini.d.ts +11 -0
  79. package/js/src/gemini.js +76 -1
  80. package/js/src/htx.js +2 -2
  81. package/js/src/hyperliquid.js +20 -7
  82. package/js/src/independentreserve.js +7 -7
  83. package/js/src/kraken.js +1 -1
  84. package/js/src/krakenfutures.d.ts +1 -1
  85. package/js/src/krakenfutures.js +96 -5
  86. package/js/src/kucoin.d.ts +3 -3
  87. package/js/src/kucoin.js +3 -3
  88. package/js/src/kucoinfutures.js +1 -1
  89. package/js/src/lighter.d.ts +424 -0
  90. package/js/src/lighter.js +2930 -0
  91. package/js/src/mexc.js +0 -1
  92. package/js/src/phemex.js +1 -1
  93. package/js/src/pro/binance.js +2 -2
  94. package/js/src/pro/bingx.d.ts +17 -1
  95. package/js/src/pro/bingx.js +216 -3
  96. package/js/src/pro/bitget.js +1 -0
  97. package/js/src/pro/defx.js +1 -1
  98. package/js/src/pro/kucoinfutures.js +1 -1
  99. package/js/src/pro/lighter.d.ts +161 -0
  100. package/js/src/pro/lighter.js +786 -0
  101. package/js/src/pro/mexc.js +1 -1
  102. package/js/src/pro/paradex.js +1 -1
  103. package/js/src/whitebit.d.ts +2 -1
  104. package/js/src/whitebit.js +118 -16
  105. package/js/src/woo.js +1 -1
  106. package/package.json +1 -1
@@ -0,0 +1,2930 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ // ---------------------------------------------------------------------------
8
+ import Exchange from './abstract/lighter.js';
9
+ import { ArgumentsRequired, BadRequest, ExchangeError, InvalidOrder, RateLimitExceeded } from './base/errors.js';
10
+ import { TICK_SIZE } from './base/functions/number.js';
11
+ import Precise from './base/Precise.js';
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * @class lighter
15
+ * @augments Exchange
16
+ */
17
+ export default class lighter extends Exchange {
18
+ describe() {
19
+ return this.deepExtend(super.describe(), {
20
+ 'id': 'lighter',
21
+ 'name': 'Lighter',
22
+ 'countries': [],
23
+ 'version': 'v1',
24
+ 'rateLimit': 1000,
25
+ 'certified': false,
26
+ 'pro': true,
27
+ 'dex': true,
28
+ 'has': {
29
+ 'CORS': undefined,
30
+ 'spot': false,
31
+ 'margin': false,
32
+ 'swap': true,
33
+ 'future': false,
34
+ 'option': false,
35
+ 'addMargin': true,
36
+ 'borrowCrossMargin': false,
37
+ 'borrowIsolatedMargin': false,
38
+ 'borrowMargin': false,
39
+ 'cancelAllOrders': true,
40
+ 'cancelAllOrdersAfter': true,
41
+ 'cancelOrder': true,
42
+ 'cancelOrders': false,
43
+ 'cancelOrdersForSymbols': false,
44
+ 'closeAllPositions': false,
45
+ 'closePosition': false,
46
+ 'createMarketBuyOrderWithCost': false,
47
+ 'createMarketOrderWithCost': false,
48
+ 'createMarketSellOrderWithCost': false,
49
+ 'createOrder': true,
50
+ 'createOrders': false,
51
+ 'createPostOnlyOrder': false,
52
+ 'createReduceOnlyOrder': false,
53
+ 'createStopOrder': false,
54
+ 'createTriggerOrder': false,
55
+ 'editOrder': true,
56
+ 'fetchAccounts': true,
57
+ 'fetchAllGreeks': false,
58
+ 'fetchBalance': true,
59
+ 'fetchBorrowInterest': false,
60
+ 'fetchBorrowRate': false,
61
+ 'fetchBorrowRateHistories': false,
62
+ 'fetchBorrowRateHistory': false,
63
+ 'fetchBorrowRates': false,
64
+ 'fetchBorrowRatesPerSymbol': false,
65
+ 'fetchCanceledAndClosedOrders': false,
66
+ 'fetchCanceledOrders': false,
67
+ 'fetchClosedOrders': true,
68
+ 'fetchCrossBorrowRate': false,
69
+ 'fetchCrossBorrowRates': false,
70
+ 'fetchCurrencies': true,
71
+ 'fetchDepositAddress': false,
72
+ 'fetchDepositAddresses': false,
73
+ 'fetchDeposits': true,
74
+ 'fetchDepositWithdrawFee': false,
75
+ 'fetchDepositWithdrawFees': false,
76
+ 'fetchFundingHistory': false,
77
+ 'fetchFundingRate': false,
78
+ 'fetchFundingRateHistory': false,
79
+ 'fetchFundingRates': true,
80
+ 'fetchGreeks': false,
81
+ 'fetchIndexOHLCV': false,
82
+ 'fetchIsolatedBorrowRate': false,
83
+ 'fetchIsolatedBorrowRates': false,
84
+ 'fetchLedger': false,
85
+ 'fetchLeverage': false,
86
+ 'fetchLeverageTiers': false,
87
+ 'fetchLiquidations': false,
88
+ 'fetchMarginMode': false,
89
+ 'fetchMarketLeverageTiers': false,
90
+ 'fetchMarkets': true,
91
+ 'fetchMarkOHLCV': false,
92
+ 'fetchMyLiquidations': false,
93
+ 'fetchMyTrades': true,
94
+ 'fetchOHLCV': true,
95
+ 'fetchOpenInterest': false,
96
+ 'fetchOpenInterestHistory': false,
97
+ 'fetchOpenInterests': false,
98
+ 'fetchOpenOrders': true,
99
+ 'fetchOption': false,
100
+ 'fetchOptionChain': false,
101
+ 'fetchOrder': false,
102
+ 'fetchOrderBook': true,
103
+ 'fetchOrders': false,
104
+ 'fetchOrderTrades': false,
105
+ 'fetchPosition': true,
106
+ 'fetchPositionMode': false,
107
+ 'fetchPositions': true,
108
+ 'fetchPositionsRisk': false,
109
+ 'fetchPremiumIndexOHLCV': false,
110
+ 'fetchStatus': true,
111
+ 'fetchTicker': true,
112
+ 'fetchTickers': true,
113
+ 'fetchTime': true,
114
+ 'fetchTrades': false,
115
+ 'fetchTradingFee': false,
116
+ 'fetchTradingFees': false,
117
+ 'fetchTransfer': false,
118
+ 'fetchTransfers': true,
119
+ 'fetchVolatilityHistory': false,
120
+ 'fetchWithdrawal': false,
121
+ 'fetchWithdrawals': true,
122
+ 'reduceMargin': true,
123
+ 'repayCrossMargin': false,
124
+ 'repayIsolatedMargin': false,
125
+ 'sandbox': true,
126
+ 'setLeverage': true,
127
+ 'setMargin': true,
128
+ 'setMarginMode': true,
129
+ 'setPositionMode': false,
130
+ 'transfer': true,
131
+ 'withdraw': true,
132
+ },
133
+ 'timeframes': {
134
+ '1m': '1m',
135
+ '5m': '5m',
136
+ '15m': '15m',
137
+ '30m': '30m',
138
+ '1h': '1h',
139
+ '4h': '4h',
140
+ '12h': '12h',
141
+ '1d': '1d',
142
+ '1w': '1w',
143
+ },
144
+ 'hostname': 'zklighter.elliot.ai',
145
+ 'urls': {
146
+ 'logo': 'https://github.com/user-attachments/assets/ff1aaf96-bffb-4545-a750-5eba716e75d0',
147
+ 'api': {
148
+ 'root': 'https://mainnet.{hostname}',
149
+ 'public': 'https://mainnet.{hostname}',
150
+ 'private': 'https://mainnet.{hostname}',
151
+ },
152
+ 'test': {
153
+ 'root': 'https://testnet.{hostname}',
154
+ 'public': 'https://testnet.{hostname}',
155
+ 'private': 'https://testnet.{hostname}',
156
+ },
157
+ 'www': 'https://lighter.xyz/',
158
+ 'doc': 'https://apidocs.lighter.xyz/',
159
+ 'fees': 'https://docs.lighter.xyz/perpetual-futures/fees',
160
+ 'referral': {
161
+ 'url': 'app.lighter.xyz/?referral=715955W9',
162
+ 'discount': 0.1, // user gets 10% of the points
163
+ },
164
+ },
165
+ 'api': {
166
+ 'root': {
167
+ 'get': {
168
+ // root
169
+ '': 1,
170
+ 'info': 1,
171
+ },
172
+ },
173
+ 'public': {
174
+ 'get': {
175
+ // account
176
+ 'account': 1,
177
+ 'accountsByL1Address': 1,
178
+ 'apikeys': 1,
179
+ // order
180
+ 'exchangeStats': 1,
181
+ 'assetDetails': 1,
182
+ 'orderBookDetails': 1,
183
+ 'orderBookOrders': 1,
184
+ 'orderBooks': 1,
185
+ 'recentTrades': 1,
186
+ // transaction
187
+ 'blockTxs': 1,
188
+ 'nextNonce': 1,
189
+ 'tx': 1,
190
+ 'txFromL1TxHash': 1,
191
+ 'txs': 1,
192
+ // announcement
193
+ 'announcement': 1,
194
+ // block
195
+ 'block': 1,
196
+ 'blocks': 1,
197
+ 'currentHeight': 1,
198
+ // candlestick
199
+ 'candles': 1,
200
+ 'fundings': 1,
201
+ // bridge
202
+ 'fastbridge/info': 1,
203
+ // funding
204
+ 'funding-rates': 1,
205
+ // info
206
+ 'withdrawalDelay': 1,
207
+ },
208
+ 'post': {
209
+ // transaction
210
+ 'sendTx': 1,
211
+ 'sendTxBatch': 1,
212
+ },
213
+ },
214
+ 'private': {
215
+ 'get': {
216
+ // account
217
+ 'accountLimits': 1,
218
+ 'accountMetadata': 1,
219
+ 'pnl': 1,
220
+ 'l1Metadata': 1,
221
+ 'liquidations': 1,
222
+ 'positionFunding': 1,
223
+ 'publicPoolsMetadata': 1,
224
+ // order
225
+ 'accountActiveOrders': 1,
226
+ 'accountInactiveOrders': 1,
227
+ 'export': 1,
228
+ 'trades': 1,
229
+ // transaction
230
+ 'accountTxs': 1,
231
+ 'deposit/history': 1,
232
+ 'transfer/history': 1,
233
+ 'withdraw/history': 1,
234
+ // referral
235
+ 'referral/points': 1,
236
+ // info
237
+ 'transferFeeInfo': 1,
238
+ },
239
+ 'post': {
240
+ // account
241
+ 'changeAccountTier': 1,
242
+ // notification
243
+ 'notification/ack': 1,
244
+ },
245
+ },
246
+ },
247
+ 'httpExceptions': {},
248
+ 'exceptions': {
249
+ 'exact': {
250
+ '21500': ExchangeError,
251
+ '21501': ExchangeError,
252
+ '21502': ExchangeError,
253
+ '21503': ExchangeError,
254
+ '21504': ExchangeError,
255
+ '21505': ExchangeError,
256
+ '21506': ExchangeError,
257
+ '21507': ExchangeError,
258
+ '21508': ExchangeError,
259
+ '21511': ExchangeError,
260
+ '21512': ExchangeError,
261
+ '21600': InvalidOrder,
262
+ '21601': InvalidOrder,
263
+ '21602': InvalidOrder,
264
+ '21603': InvalidOrder,
265
+ '21604': InvalidOrder,
266
+ '21605': InvalidOrder,
267
+ '21606': InvalidOrder,
268
+ '21607': InvalidOrder,
269
+ '21608': InvalidOrder,
270
+ '21611': InvalidOrder,
271
+ '21612': InvalidOrder,
272
+ '21613': InvalidOrder,
273
+ '21614': InvalidOrder,
274
+ '21700': InvalidOrder,
275
+ '21701': InvalidOrder,
276
+ '21702': InvalidOrder,
277
+ '21703': InvalidOrder,
278
+ '21704': InvalidOrder,
279
+ '21705': InvalidOrder,
280
+ '21706': InvalidOrder,
281
+ '21707': InvalidOrder,
282
+ '21708': InvalidOrder,
283
+ '21709': InvalidOrder,
284
+ '21710': InvalidOrder,
285
+ '21711': InvalidOrder,
286
+ '21712': InvalidOrder,
287
+ '21713': InvalidOrder,
288
+ '21714': InvalidOrder,
289
+ '21715': InvalidOrder,
290
+ '21716': InvalidOrder,
291
+ '21717': InvalidOrder,
292
+ '21718': InvalidOrder,
293
+ '21719': InvalidOrder,
294
+ '21720': InvalidOrder,
295
+ '21721': InvalidOrder,
296
+ '21722': InvalidOrder,
297
+ '21723': InvalidOrder,
298
+ '21724': InvalidOrder,
299
+ '21725': InvalidOrder,
300
+ '21726': InvalidOrder,
301
+ '21727': InvalidOrder,
302
+ '21728': InvalidOrder,
303
+ '21729': InvalidOrder,
304
+ '21730': InvalidOrder,
305
+ '21731': InvalidOrder,
306
+ '21732': InvalidOrder,
307
+ '21733': InvalidOrder,
308
+ '21734': InvalidOrder,
309
+ '21735': InvalidOrder,
310
+ '21736': InvalidOrder,
311
+ '21737': InvalidOrder,
312
+ '21738': InvalidOrder,
313
+ '21739': InvalidOrder,
314
+ '21740': InvalidOrder,
315
+ '21901': InvalidOrder,
316
+ '21902': InvalidOrder,
317
+ '21903': InvalidOrder,
318
+ '21904': InvalidOrder,
319
+ '21905': InvalidOrder,
320
+ '21906': InvalidOrder,
321
+ '23000': RateLimitExceeded,
322
+ '23001': RateLimitExceeded,
323
+ '23002': RateLimitExceeded,
324
+ '23003': RateLimitExceeded, // Too Many Connections!
325
+ },
326
+ 'broad': {},
327
+ },
328
+ 'fees': {
329
+ 'taker': 0,
330
+ 'maker': 0,
331
+ },
332
+ 'requiredCredentials': {
333
+ 'apiKey': false,
334
+ 'secret': false,
335
+ 'walletAddress': false,
336
+ 'privateKey': true,
337
+ 'password': false,
338
+ },
339
+ 'precisionMode': TICK_SIZE,
340
+ 'commonCurrencies': {},
341
+ 'options': {
342
+ 'defaultType': 'swap',
343
+ 'chainId': 304,
344
+ 'accountIndex': undefined,
345
+ 'apiKeyIndex': undefined,
346
+ 'wasmExecPath': undefined,
347
+ 'libraryPath': undefined, // users should set the path to the lighter signing library. It can be downloaded here https://github.com/elliottech/lighter-python/tree/main/lighter/signers, GO users don't need it
348
+ },
349
+ 'features': {
350
+ 'default': {
351
+ 'sandbox': true,
352
+ 'createOrder': {
353
+ 'timeInForce': {
354
+ 'IOC': true,
355
+ 'FOK': true,
356
+ 'PO': true,
357
+ 'GTD': false,
358
+ },
359
+ 'leverage': false,
360
+ 'marketBuyRequiresPrice': false,
361
+ 'marketBuyByCost': false,
362
+ 'selfTradePrevention': false,
363
+ 'trailing': false,
364
+ 'iceberg': false,
365
+ },
366
+ },
367
+ },
368
+ });
369
+ }
370
+ async loadAccount(chainId, privateKey, apiKeyIndex, accountIndex, params = {}) {
371
+ let signer = this.safeDict(this.options, 'signer');
372
+ if (signer !== undefined) {
373
+ return signer;
374
+ }
375
+ let libraryPath = undefined;
376
+ [libraryPath, params] = this.handleOptionAndParams(params, 'loadAccount', 'libraryPath');
377
+ signer = await this.loadLighterLibrary(libraryPath, chainId, privateKey, apiKeyIndex, accountIndex);
378
+ this.options['signer'] = signer;
379
+ return signer;
380
+ }
381
+ async handleAccountIndex(params, methodName1, optionName1, optionName2, defaultValue = undefined) {
382
+ let accountIndex = undefined;
383
+ [accountIndex, params] = this.handleOptionAndParams2(params, methodName1, optionName1, optionName2, defaultValue);
384
+ if (accountIndex === undefined) {
385
+ const walletAddress = this.walletAddress;
386
+ if (walletAddress === undefined) {
387
+ throw new ArgumentsRequired(this.id + ' ' + methodName1 + '() requires an ' + optionName1 + ' or ' + optionName2 + ' parameter or walletAddress to fetch accountIndex');
388
+ }
389
+ const res = await this.publicGetAccountsByL1Address({ 'l1_address': walletAddress });
390
+ //
391
+ // {
392
+ // "code": 200,
393
+ // "l1_address": "0xaaaabbbb....ccccdddd",
394
+ // "sub_accounts": [
395
+ // {
396
+ // "code": 0,
397
+ // "account_type": 0,
398
+ // "index": 666666,
399
+ // "l1_address": "0xaaaabbbb....ccccdddd",
400
+ // "cancel_all_time": 0,
401
+ // "total_order_count": 0,
402
+ // "total_isolated_order_count": 0,
403
+ // "pending_order_count": 0,
404
+ // "available_balance": "",
405
+ // "status": 0,
406
+ // "collateral": "40",
407
+ // "transaction_time": 0,
408
+ // "account_trading_mode": 0
409
+ // }
410
+ // ]
411
+ // }
412
+ //
413
+ const subAccounts = this.safeList(res, 'sub_accounts');
414
+ if (Array.isArray(subAccounts)) {
415
+ const account = this.safeDict(subAccounts, 0);
416
+ if (account === undefined) {
417
+ throw new ArgumentsRequired(this.id + ' ' + methodName1 + '() requires an ' + optionName1 + ' or ' + optionName2 + ' parameter');
418
+ }
419
+ accountIndex = account['index'];
420
+ this.options['accountIndex'] = accountIndex;
421
+ }
422
+ }
423
+ return [accountIndex, params];
424
+ }
425
+ async createSubAccount(name, params = {}) {
426
+ let apiKeyIndex = undefined;
427
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'createSubAccount', 'apiKeyIndex', 'api_key_index');
428
+ if (apiKeyIndex === undefined) {
429
+ throw new ArgumentsRequired(this.id + ' createSubAccount() requires an apiKeyIndex parameter');
430
+ }
431
+ let accountIndex = undefined;
432
+ [accountIndex, params] = await this.handleAccountIndex(params, 'createSubAccount', 'accountIndex', 'account_index');
433
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
434
+ const signRaw = {
435
+ 'nonce': nonce,
436
+ 'api_key_index': apiKeyIndex,
437
+ 'account_index': accountIndex,
438
+ };
439
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
440
+ const [txType, txInfo] = this.lighterSignCreateSubAccount(signer, this.extend(signRaw, params));
441
+ const request = {
442
+ 'tx_type': txType,
443
+ 'tx_info': txInfo,
444
+ };
445
+ return await this.publicPostSendTx(request);
446
+ }
447
+ createAuth(params = {}) {
448
+ // don't omit [accountIndex, apiKeyIndex], request may need them
449
+ let apiKeyIndex = this.safeInteger2(params, 'apiKeyIndex', 'api_key_index');
450
+ if (apiKeyIndex === undefined) {
451
+ const res = this.handleOptionAndParams2({}, 'createAuth', 'apiKeyIndex', 'api_key_index');
452
+ apiKeyIndex = this.safeInteger(res, 0);
453
+ }
454
+ let accountIndex = this.safeInteger2(params, 'accountIndex', 'account_index');
455
+ if (accountIndex === undefined) {
456
+ const res = this.handleOptionAndParams2({}, 'createAuth', 'accountIndex', 'account_index');
457
+ accountIndex = this.safeInteger(res, 0);
458
+ }
459
+ const rs = {
460
+ 'deadline': this.seconds() + 60,
461
+ 'api_key_index': apiKeyIndex,
462
+ 'account_index': accountIndex,
463
+ };
464
+ return this.lighterCreateAuthToken(this.safeValue(this.options, 'signer'), rs);
465
+ }
466
+ pow(n, m) {
467
+ let r = Precise.stringMul(n, '1');
468
+ const c = this.parseToInt(m);
469
+ if (c < 0) {
470
+ throw new BadRequest(this.id + ' pow() requires m > 0.');
471
+ }
472
+ if (c === 0) {
473
+ return '1';
474
+ }
475
+ if (c > 100) {
476
+ throw new BadRequest(this.id + ' pow() requires m < 100.');
477
+ }
478
+ for (let i = 1; i < c; i++) {
479
+ r = Precise.stringMul(r, n);
480
+ }
481
+ return r;
482
+ }
483
+ setSandboxMode(enable) {
484
+ super.setSandboxMode(enable);
485
+ this.options['sandboxMode'] = enable;
486
+ this.options['chainId'] = 300;
487
+ }
488
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
489
+ /**
490
+ * @method
491
+ * @ignore
492
+ * @name lighter#createOrderRequest
493
+ * @description helper function to build the request
494
+ * @param {string} symbol unified symbol of the market to create an order in
495
+ * @param {string} type 'market' or 'limit'
496
+ * @param {string} side 'buy' or 'sell'
497
+ * @param {float} amount how much you want to trade in units of the base currency
498
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
499
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
500
+ * @param {int} [params.nonce] nonce for the account
501
+ * @param {int} [params.apiKeyIndex] apiKeyIndex
502
+ * @param {int} [params.accountIndex] accountIndex
503
+ * @param {int} [params.orderExpiry] orderExpiry
504
+ * @returns {any[]} request to be sent to the exchange
505
+ */
506
+ if (price === undefined) {
507
+ throw new ArgumentsRequired(this.id + ' createOrder() requires a price argument');
508
+ }
509
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only', false); // default false
510
+ const orderType = type.toUpperCase();
511
+ const market = this.market(symbol);
512
+ const orderSide = side.toUpperCase();
513
+ const request = {
514
+ 'market_index': this.parseToInt(market['id']),
515
+ };
516
+ let nonce = undefined;
517
+ let apiKeyIndex = undefined;
518
+ let accountIndex = undefined;
519
+ let orderExpiry = undefined;
520
+ [apiKeyIndex, params] = this.handleOptionAndParams(params, 'createOrder', 'apiKeyIndex', 255);
521
+ if (apiKeyIndex === undefined) {
522
+ throw new ArgumentsRequired(this.id + ' createOrder() requires an apiKeyIndex parameter');
523
+ }
524
+ [accountIndex, params] = this.handleOptionAndParams2(params, 'createOrder', 'accountIndex', 'account_index');
525
+ [nonce, params] = this.handleOptionAndParams(params, 'createOrder', 'nonce');
526
+ [orderExpiry, params] = this.handleOptionAndParams(params, 'createOrder', 'orderExpiry', 0);
527
+ request['nonce'] = nonce;
528
+ request['api_key_index'] = apiKeyIndex;
529
+ request['account_index'] = accountIndex;
530
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
531
+ const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
532
+ const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
533
+ const stopLoss = this.safeValue(params, 'stopLoss');
534
+ const takeProfit = this.safeValue(params, 'takeProfit');
535
+ const hasStopLoss = (stopLoss !== undefined);
536
+ const hasTakeProfit = (takeProfit !== undefined);
537
+ const isConditional = (stopLossPrice || takeProfitPrice);
538
+ const isMarketOrder = (orderType === 'MARKET');
539
+ const timeInForce = this.safeStringLower(params, 'timeInForce', 'gtt');
540
+ const postOnly = this.isPostOnly(isMarketOrder, undefined, params);
541
+ params = this.omit(params, ['stopLoss', 'takeProfit', 'timeInForce']);
542
+ let orderTypeNum = undefined;
543
+ let timeInForceNum = undefined;
544
+ if (isMarketOrder) {
545
+ orderTypeNum = 1;
546
+ timeInForceNum = 0;
547
+ }
548
+ else {
549
+ orderTypeNum = 0;
550
+ }
551
+ if (orderSide === 'BUY') {
552
+ request['is_ask'] = 0;
553
+ }
554
+ else {
555
+ request['is_ask'] = 1;
556
+ }
557
+ if (postOnly) {
558
+ timeInForceNum = 2;
559
+ }
560
+ else {
561
+ if (!isMarketOrder) {
562
+ if (timeInForce === 'ioc') {
563
+ timeInForceNum = 0;
564
+ orderExpiry = 0;
565
+ }
566
+ else if (timeInForce === 'gtt') {
567
+ timeInForceNum = 1;
568
+ orderExpiry = -1;
569
+ }
570
+ }
571
+ }
572
+ const marketInfo = this.safeDict(market, 'info');
573
+ let amountStr = undefined;
574
+ const priceStr = this.priceToPrecision(symbol, price);
575
+ const amountScale = this.pow('10', marketInfo['size_decimals']);
576
+ const priceScale = this.pow('10', marketInfo['price_decimals']);
577
+ let triggerPriceStr = '0'; // default is 0
578
+ const defaultClientOrderId = this.randNumber(9); // c# only support int32 2147483647.
579
+ const clientOrderId = this.safeInteger2(params, 'client_order_index', 'clientOrderId', defaultClientOrderId);
580
+ params = this.omit(params, ['reduceOnly', 'reduce_only', 'timeInForce', 'postOnly', 'nonce', 'apiKeyIndex', 'stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'client_order_index', 'clientOrderId']);
581
+ if (isConditional) {
582
+ amountStr = this.numberToString(amount);
583
+ if (stopLossPrice !== undefined) {
584
+ if (isMarketOrder) {
585
+ orderTypeNum = 2;
586
+ }
587
+ else {
588
+ orderTypeNum = 3;
589
+ }
590
+ triggerPriceStr = this.priceToPrecision(symbol, stopLossPrice);
591
+ }
592
+ else if (takeProfitPrice !== undefined) {
593
+ if (isMarketOrder) {
594
+ orderTypeNum = 4;
595
+ }
596
+ else {
597
+ orderTypeNum = 5;
598
+ }
599
+ triggerPriceStr = this.priceToPrecision(symbol, takeProfitPrice);
600
+ }
601
+ }
602
+ else {
603
+ amountStr = this.amountToPrecision(symbol, amount);
604
+ }
605
+ request['order_expiry'] = orderExpiry;
606
+ request['order_type'] = orderTypeNum;
607
+ request['time_in_force'] = timeInForceNum;
608
+ request['reduce_only'] = (reduceOnly) ? 1 : 0;
609
+ request['client_order_index'] = clientOrderId;
610
+ request['base_amount'] = this.parseToInt(Precise.stringMul(amountStr, amountScale));
611
+ request['avg_execution_price'] = this.parseToInt(Precise.stringMul(priceStr, priceScale));
612
+ request['trigger_price'] = this.parseToInt(Precise.stringMul(triggerPriceStr, priceScale));
613
+ const orders = [];
614
+ orders.push(this.extend(request, params));
615
+ if (hasStopLoss || hasTakeProfit) {
616
+ // group order
617
+ orders[0]['client_order_index'] = 0; // client order index should be 0
618
+ let triggerOrderSide = '';
619
+ if (side === 'BUY') {
620
+ triggerOrderSide = 'sell';
621
+ }
622
+ else {
623
+ triggerOrderSide = 'buy';
624
+ }
625
+ const stopLossOrderTriggerPrice = this.safeNumberN(stopLoss, ['triggerPrice', 'stopPrice']);
626
+ const stopLossOrderType = this.safeString(stopLoss, 'type', 'limit');
627
+ const stopLossOrderLimitPrice = this.safeNumberN(stopLoss, ['price', 'stopLossPrice'], stopLossOrderTriggerPrice);
628
+ const takeProfitOrderTriggerPrice = this.safeNumberN(takeProfit, ['triggerPrice', 'stopPrice']);
629
+ const takeProfitOrderType = this.safeString(takeProfit, 'type', 'limit');
630
+ const takeProfitOrderLimitPrice = this.safeNumberN(takeProfit, ['price', 'takeProfitPrice'], takeProfitOrderTriggerPrice);
631
+ // amount should be 0 for child orders
632
+ if (stopLoss !== undefined) {
633
+ const orderObj = this.createOrderRequest(symbol, stopLossOrderType, triggerOrderSide, 0, stopLossOrderLimitPrice, this.extend(params, {
634
+ 'stopLossPrice': stopLossOrderTriggerPrice,
635
+ 'reduceOnly': true,
636
+ }))[0];
637
+ orderObj['client_order_index'] = 0;
638
+ orders.push(orderObj);
639
+ }
640
+ if (takeProfit !== undefined) {
641
+ const orderObj = this.createOrderRequest(symbol, takeProfitOrderType, triggerOrderSide, 0, takeProfitOrderLimitPrice, this.extend(params, {
642
+ 'takeProfitPrice': takeProfitOrderTriggerPrice,
643
+ 'reduceOnly': true,
644
+ }))[0];
645
+ orderObj['client_order_index'] = 0;
646
+ orders.push(orderObj);
647
+ }
648
+ }
649
+ return orders;
650
+ }
651
+ async fetchNonce(accountIndex, apiKeyIndex, params = {}) {
652
+ if ((accountIndex === undefined) || (apiKeyIndex === undefined)) {
653
+ throw new ArgumentsRequired(this.id + ' fetchNonce() requires accountIndex and apiKeyIndex.');
654
+ }
655
+ if ('nonce' in params) {
656
+ return this.safeInteger(params, 'nonce');
657
+ }
658
+ const nonceInOptions = this.safeInteger(this.options, 'nonce');
659
+ if (nonceInOptions !== undefined) {
660
+ return nonceInOptions;
661
+ }
662
+ const response = await this.publicGetNextNonce({ 'account_index': accountIndex, 'api_key_index': apiKeyIndex });
663
+ return this.safeInteger(response, 'nonce');
664
+ }
665
+ /**
666
+ * @method
667
+ * @name lighter#createOrder
668
+ * @description create a trade order
669
+ * @param {string} symbol unified symbol of the market to create an order in
670
+ * @param {string} type 'market' or 'limit'
671
+ * @param {string} side 'buy' or 'sell'
672
+ * @param {float} amount how much of currency you want to trade in units of base currency
673
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
674
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
675
+ * @param {string} [params.timeInForce] 'GTT' or 'IOC', default is 'GTT'
676
+ * @param {int} [params.clientOrderId] client order id, should be unique for each order, default is a random number
677
+ * @param {string} [params.triggerPrice] trigger price for stop loss or take profit orders, in units of the quote currency
678
+ * @param {boolean} [params.reduceOnly] whether the order is reduce only, default false
679
+ * @param {int} [params.nonce] nonce for the account
680
+ * @param {int} [params.apiKeyIndex] apiKeyIndex
681
+ * @param {int} [params.accountIndex] accountIndex
682
+ * @param {int} [params.orderExpiry] orderExpiry
683
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
684
+ */
685
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
686
+ await this.loadMarkets();
687
+ let accountIndex = undefined;
688
+ [accountIndex, params] = await this.handleAccountIndex(params, 'createOrder', 'accountIndex', 'account_index');
689
+ params['accountIndex'] = accountIndex;
690
+ const market = this.market(symbol);
691
+ let groupingType = undefined;
692
+ [groupingType, params] = this.handleOptionAndParams(params, 'createOrder', 'groupingType', 3); // default GROUPING_TYPE_ONE_TRIGGERS_A_ONE_CANCELS_THE_OTHER
693
+ const orderRequests = this.createOrderRequest(symbol, type, side, amount, price, params);
694
+ // for php
695
+ const totalOrderRequests = orderRequests.length;
696
+ let apiKeyIndex = undefined;
697
+ let order = undefined;
698
+ if (totalOrderRequests > 0) {
699
+ order = orderRequests[0];
700
+ apiKeyIndex = order['api_key_index'];
701
+ if (order['nonce'] === undefined) {
702
+ const nonceInOptions = this.safeInteger(this.options, 'nonce');
703
+ if (nonceInOptions !== undefined) {
704
+ order['nonce'] = nonceInOptions;
705
+ }
706
+ else {
707
+ order['nonce'] = await this.fetchNonce(accountIndex, apiKeyIndex);
708
+ }
709
+ }
710
+ }
711
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
712
+ let txType = undefined;
713
+ let txInfo = undefined;
714
+ if (totalOrderRequests < 2) {
715
+ [txType, txInfo] = this.lighterSignCreateOrder(signer, order);
716
+ }
717
+ else {
718
+ const signingPayload = {
719
+ 'grouping_type': groupingType,
720
+ 'orders': orderRequests,
721
+ 'nonce': order['nonce'],
722
+ 'api_key_index': apiKeyIndex,
723
+ 'account_index': accountIndex,
724
+ };
725
+ [txType, txInfo] = this.lighterSignCreateGroupedOrders(signer, signingPayload);
726
+ }
727
+ const request = {
728
+ 'tx_type': txType,
729
+ 'tx_info': txInfo,
730
+ };
731
+ const response = await this.publicPostSendTx(request);
732
+ //
733
+ // {
734
+ // "code": 200,
735
+ // "message": "{\"ratelimit\": \"didn't use volume quota\"}",
736
+ // "tx_hash": "txhash",
737
+ // "predicted_execution_time_ms": 1766088500120
738
+ // }
739
+ //
740
+ return this.parseOrder(this.deepExtend(response, order), market);
741
+ }
742
+ /**
743
+ * @method
744
+ * @name lighter#editOrder
745
+ * @description cancels an order and places a new order
746
+ * @param {string} id order id
747
+ * @param {string} symbol unified symbol of the market to create an order in
748
+ * @param {string} type 'market' or 'limit'
749
+ * @param {string} side 'buy' or 'sell'
750
+ * @param {float} amount how much of the currency you want to trade in units of the base currency
751
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
752
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
753
+ * @param {string} [params.accountIndex] account index
754
+ * @param {string} [params.apiKeyIndex] api key index
755
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
756
+ */
757
+ async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
758
+ let apiKeyIndex = undefined;
759
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'editOrder', 'apiKeyIndex', 'api_key_index');
760
+ if (apiKeyIndex === undefined) {
761
+ throw new ArgumentsRequired(this.id + ' editOrder() requires an apiKeyIndex parameter');
762
+ }
763
+ await this.loadMarkets();
764
+ let accountIndex = undefined;
765
+ [accountIndex, params] = await this.handleAccountIndex(params, 'editOrder', 'accountIndex', 'account_index');
766
+ const market = this.market(symbol);
767
+ const marketInfo = this.safeDict(market, 'info');
768
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
769
+ const amountScale = this.pow('10', marketInfo['size_decimals']);
770
+ const priceScale = this.pow('10', marketInfo['price_decimals']);
771
+ const triggerPrice = this.safeStringN(params, ['stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
772
+ params = this.omit(params, ['stopPrice', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice']);
773
+ let amountStr = undefined;
774
+ const priceStr = this.priceToPrecision(symbol, price);
775
+ let triggerPriceStr = '0'; // default is 0
776
+ if (triggerPrice !== undefined) {
777
+ amountStr = this.numberToString(amount);
778
+ triggerPriceStr = this.priceToPrecision(symbol, triggerPrice);
779
+ }
780
+ else {
781
+ amountStr = this.amountToPrecision(symbol, amount);
782
+ }
783
+ const signRaw = {
784
+ 'market_index': this.parseToInt(market['id']),
785
+ 'index': this.parseToInt(id),
786
+ 'base_amount': this.parseToInt(Precise.stringMul(amountStr, amountScale)),
787
+ 'price': this.parseToInt(Precise.stringMul(priceStr, priceScale)),
788
+ 'trigger_price': this.parseToInt(Precise.stringMul(triggerPriceStr, priceScale)),
789
+ 'nonce': nonce,
790
+ 'api_key_index': apiKeyIndex,
791
+ 'account_index': accountIndex,
792
+ };
793
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
794
+ const [txType, txInfo] = this.lighterSignModifyOrder(signer, this.extend(signRaw, params));
795
+ const request = {
796
+ 'tx_type': txType,
797
+ 'tx_info': txInfo,
798
+ };
799
+ const response = await this.publicPostSendTx(request);
800
+ return this.parseOrder(response, market);
801
+ }
802
+ /**
803
+ * @method
804
+ * @name lighter#fetchStatus
805
+ * @description the latest known information on the availability of the exchange API
806
+ * @see https://apidocs.lighter.xyz/reference/status
807
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
808
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
809
+ */
810
+ async fetchStatus(params = {}) {
811
+ const response = await this.rootGet(params);
812
+ //
813
+ // {
814
+ // "status": "1",
815
+ // "network_id": "1",
816
+ // "timestamp": "1717777777"
817
+ // }
818
+ //
819
+ const status = this.safeString(response, 'status');
820
+ return {
821
+ 'status': (status === '200') ? 'ok' : 'error',
822
+ 'updated': undefined,
823
+ 'eta': undefined,
824
+ 'url': undefined,
825
+ 'info': response,
826
+ };
827
+ }
828
+ /**
829
+ * @method
830
+ * @name lighter#fetchTime
831
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
832
+ * @see https://apidocs.lighter.xyz/reference/status
833
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
834
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
835
+ */
836
+ async fetchTime(params = {}) {
837
+ const response = await this.rootGet(params);
838
+ //
839
+ // {
840
+ // "status": "1",
841
+ // "network_id": "1",
842
+ // "timestamp": "1717777777"
843
+ // }
844
+ //
845
+ return this.safeTimestamp(response, 'timestamp');
846
+ }
847
+ /**
848
+ * @method
849
+ * @name lighter#fetchMarkets
850
+ * @description retrieves data on all markets for lighter
851
+ * @see https://apidocs.lighter.xyz/reference/orderbookdetails
852
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
853
+ * @returns {object[]} an array of objects representing market data
854
+ */
855
+ async fetchMarkets(params = {}) {
856
+ const response = await this.publicGetOrderBookDetails(params);
857
+ //
858
+ // {
859
+ // "code": 200,
860
+ // "order_book_details": [
861
+ // {
862
+ // "symbol": "ETH",
863
+ // "market_id": 0,
864
+ // "status": "active",
865
+ // "taker_fee": "0.0000",
866
+ // "maker_fee": "0.0000",
867
+ // "liquidation_fee": "1.0000",
868
+ // "min_base_amount": "0.0050",
869
+ // "min_quote_amount": "10.000000",
870
+ // "order_quote_limit": "",
871
+ // "supported_size_decimals": 4,
872
+ // "supported_price_decimals": 2,
873
+ // "supported_quote_decimals": 6,
874
+ // "size_decimals": 4,
875
+ // "price_decimals": 2,
876
+ // "quote_multiplier": 1,
877
+ // "default_initial_margin_fraction": 500,
878
+ // "min_initial_margin_fraction": 200,
879
+ // "maintenance_margin_fraction": 120,
880
+ // "closeout_margin_fraction": 80,
881
+ // "last_trade_price": 3550.69,
882
+ // "daily_trades_count": 1197349,
883
+ // "daily_base_token_volume": 481297.3509,
884
+ // "daily_quote_token_volume": 1671431095.263844,
885
+ // "daily_price_low": 3402.41,
886
+ // "daily_price_high": 3571.45,
887
+ // "daily_price_change": 0.5294300840859545,
888
+ // "open_interest": 39559.3278,
889
+ // "daily_chart": {},
890
+ // "market_config": {
891
+ // "market_margin_mode": 0,
892
+ // "insurance_fund_account_index": 281474976710655,
893
+ // "liquidation_mode": 0,
894
+ // "force_reduce_only": false,
895
+ // "trading_hours": ""
896
+ // }
897
+ // }
898
+ // ]
899
+ // }
900
+ //
901
+ const markets = this.safeList(response, 'order_book_details', []);
902
+ const result = [];
903
+ for (let i = 0; i < markets.length; i++) {
904
+ const market = markets[i];
905
+ const id = this.safeString(market, 'market_id');
906
+ const baseId = this.safeString(market, 'symbol');
907
+ const quoteId = 'USDC';
908
+ const settleId = 'USDC';
909
+ const base = this.safeCurrencyCode(baseId);
910
+ const quote = this.safeCurrencyCode(quoteId);
911
+ const settle = this.safeCurrencyCode(settleId);
912
+ const amountDecimals = this.safeString2(market, 'size_decimals', 'supported_size_decimals');
913
+ const priceDecimals = this.safeString2(market, 'price_decimals', 'supported_price_decimals');
914
+ const amountPrecision = (amountDecimals === undefined) ? undefined : this.parseNumber(this.parsePrecision(amountDecimals));
915
+ const pricePrecision = (priceDecimals === undefined) ? undefined : this.parseNumber(this.parsePrecision(priceDecimals));
916
+ const quoteMultiplier = this.safeNumber(market, 'quote_multiplier');
917
+ result.push({
918
+ 'id': id,
919
+ 'symbol': base + '/' + quote + ':' + settle,
920
+ 'base': base,
921
+ 'quote': quote,
922
+ 'settle': settle,
923
+ 'baseId': baseId,
924
+ 'quoteId': quoteId,
925
+ 'settleId': settleId,
926
+ 'type': 'swap',
927
+ 'spot': false,
928
+ 'margin': false,
929
+ 'swap': true,
930
+ 'future': false,
931
+ 'option': false,
932
+ 'active': this.safeString(market, 'status') === 'active',
933
+ 'contract': true,
934
+ 'linear': true,
935
+ 'inverse': false,
936
+ 'taker': this.safeNumber(market, 'taker_fee'),
937
+ 'maker': this.safeNumber(market, 'maker_fee'),
938
+ 'contractSize': quoteMultiplier,
939
+ 'expiry': undefined,
940
+ 'expiryDatetime': undefined,
941
+ 'strike': undefined,
942
+ 'optionType': undefined,
943
+ 'precision': {
944
+ 'amount': amountPrecision,
945
+ 'price': pricePrecision,
946
+ },
947
+ 'limits': {
948
+ 'leverage': {
949
+ 'min': undefined,
950
+ 'max': undefined,
951
+ },
952
+ 'amount': {
953
+ 'min': this.safeNumber(market, 'min_base_amount'),
954
+ 'max': undefined,
955
+ },
956
+ 'price': {
957
+ 'min': undefined,
958
+ 'max': undefined,
959
+ },
960
+ 'cost': {
961
+ 'min': this.safeNumber(market, 'min_quote_amount'),
962
+ 'max': undefined,
963
+ },
964
+ },
965
+ 'created': undefined,
966
+ 'info': market,
967
+ });
968
+ }
969
+ return result;
970
+ }
971
+ /**
972
+ * @method
973
+ * @name lighter#fetchCurrencies
974
+ * @description fetches all available currencies on an exchange
975
+ * @see https://apidocs.lighter.xyz/reference/assetdetails
976
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
977
+ * @returns {object} an associative dictionary of currencies
978
+ */
979
+ async fetchCurrencies(params = {}) {
980
+ const response = await this.publicGetAssetDetails(params);
981
+ //
982
+ // {
983
+ // "code": 200,
984
+ // "asset_details": [
985
+ // {
986
+ // "asset_id": 3,
987
+ // "symbol": "USDC",
988
+ // "l1_decimals": 6,
989
+ // "decimals": 6,
990
+ // "min_transfer_amount": "1.000000",
991
+ // "min_withdrawal_amount": "1.000000",
992
+ // "margin_mode": "enabled",
993
+ // "index_price": "1.000000",
994
+ // "l1_address": "0x95Fd23d5110f9D89A4b0B7d63D78F5B5Ea5074D1"
995
+ // }
996
+ // ]
997
+ // }
998
+ //
999
+ const data = this.safeList(response, 'asset_details', []);
1000
+ const result = {};
1001
+ for (let i = 0; i < data.length; i++) {
1002
+ const entry = data[i];
1003
+ const id = this.safeString(entry, 'asset_id');
1004
+ const code = this.safeCurrencyCode(this.safeString(entry, 'symbol'));
1005
+ const decimals = this.safeString(entry, 'decimals');
1006
+ const isUSDC = (code === 'USDC');
1007
+ let depositMin = undefined;
1008
+ let withdrawMin = undefined;
1009
+ if (isUSDC) {
1010
+ depositMin = this.safeNumber(entry, 'min_transfer_amount');
1011
+ withdrawMin = this.safeNumber(entry, 'min_withdrawal_amount');
1012
+ }
1013
+ result[code] = this.safeCurrencyStructure({
1014
+ 'id': id,
1015
+ 'name': code,
1016
+ 'code': code,
1017
+ 'precision': this.parseNumber('1e-' + decimals),
1018
+ 'active': true,
1019
+ 'fee': undefined,
1020
+ 'networks': {},
1021
+ 'deposit': isUSDC,
1022
+ 'withdraw': isUSDC,
1023
+ 'type': 'crypto',
1024
+ 'limits': {
1025
+ 'deposit': {
1026
+ 'min': depositMin,
1027
+ 'max': undefined,
1028
+ },
1029
+ 'withdraw': {
1030
+ 'min': withdrawMin,
1031
+ 'max': undefined,
1032
+ },
1033
+ },
1034
+ 'info': entry,
1035
+ });
1036
+ }
1037
+ return result;
1038
+ }
1039
+ /**
1040
+ * @method
1041
+ * @name lighter#fetchOrderBook
1042
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1043
+ * @see https://apidocs.lighter.xyz/reference/orderbookorders
1044
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1045
+ * @param {int} [limit] the maximum amount of order book entries to return
1046
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1047
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1048
+ */
1049
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
1050
+ if (symbol === undefined) {
1051
+ throw new ArgumentsRequired(this.id + ' fetchOrderBook() requires a symbol argument');
1052
+ }
1053
+ await this.loadMarkets();
1054
+ const market = this.market(symbol);
1055
+ const request = {
1056
+ 'market_id': market['id'],
1057
+ 'limit': 100,
1058
+ };
1059
+ if (limit !== undefined) {
1060
+ request['limit'] = Math.min(limit, 100);
1061
+ }
1062
+ const response = await this.publicGetOrderBookOrders(this.extend(request, params));
1063
+ //
1064
+ // {
1065
+ // "code": 200,
1066
+ // "total_asks": 1,
1067
+ // "asks": [
1068
+ // {
1069
+ // "order_index": 281475565888172,
1070
+ // "order_id": "281475565888172",
1071
+ // "owner_account_index": 134436,
1072
+ // "initial_base_amount": "0.2000",
1073
+ // "remaining_base_amount": "0.2000",
1074
+ // "price": "3430.00",
1075
+ // "order_expiry": 1765419046807
1076
+ // }
1077
+ // ],
1078
+ // "total_bids": 1,
1079
+ // "bids": [
1080
+ // {
1081
+ // "order_index": 562949401225099,
1082
+ // "order_id": "562949401225099",
1083
+ // "owner_account_index": 314236,
1084
+ // "initial_base_amount": "1.7361",
1085
+ // "remaining_base_amount": "1.3237",
1086
+ // "price": "3429.80",
1087
+ // "order_expiry": 1765419047587
1088
+ // }
1089
+ // ]
1090
+ // }
1091
+ //
1092
+ const result = this.parseOrderBook(response, market['symbol'], undefined, 'bids', 'asks', 'price', 'remaining_base_amount');
1093
+ return result;
1094
+ }
1095
+ parseTicker(ticker, market = undefined) {
1096
+ //
1097
+ // fetchTicker, fetchTickers
1098
+ // {
1099
+ // "symbol": "ETH",
1100
+ // "market_id": 0,
1101
+ // "status": "active",
1102
+ // "taker_fee": "0.0000",
1103
+ // "maker_fee": "0.0000",
1104
+ // "liquidation_fee": "1.0000",
1105
+ // "min_base_amount": "0.0050",
1106
+ // "min_quote_amount": "10.000000",
1107
+ // "order_quote_limit": "",
1108
+ // "supported_size_decimals": 4,
1109
+ // "supported_price_decimals": 2,
1110
+ // "supported_quote_decimals": 6,
1111
+ // "size_decimals": 4,
1112
+ // "price_decimals": 2,
1113
+ // "quote_multiplier": 1,
1114
+ // "default_initial_margin_fraction": 500,
1115
+ // "min_initial_margin_fraction": 200,
1116
+ // "maintenance_margin_fraction": 120,
1117
+ // "closeout_margin_fraction": 80,
1118
+ // "last_trade_price": 3550.69,
1119
+ // "daily_trades_count": 1197349,
1120
+ // "daily_base_token_volume": 481297.3509,
1121
+ // "daily_quote_token_volume": 1671431095.263844,
1122
+ // "daily_price_low": 3402.41,
1123
+ // "daily_price_high": 3571.45,
1124
+ // "daily_price_change": 0.5294300840859545,
1125
+ // "open_interest": 39559.3278,
1126
+ // "daily_chart": {},
1127
+ // "market_config": {
1128
+ // "market_margin_mode": 0,
1129
+ // "insurance_fund_account_index": 281474976710655,
1130
+ // "liquidation_mode": 0,
1131
+ // "force_reduce_only": false,
1132
+ // "trading_hours": ""
1133
+ // }
1134
+ // }
1135
+ //
1136
+ // watchTicker, watchTickers
1137
+ // {
1138
+ // "market_id": 0,
1139
+ // "index_price": "3015.56",
1140
+ // "mark_price": "3013.91",
1141
+ // "open_interest": "122736286.659423",
1142
+ // "open_interest_limit": "72057594037927936.000000",
1143
+ // "funding_clamp_small": "0.0500",
1144
+ // "funding_clamp_big": "4.0000",
1145
+ // "last_trade_price": "3013.13",
1146
+ // "current_funding_rate": "0.0012",
1147
+ // "funding_rate": "0.0012",
1148
+ // "funding_timestamp": 1763532000004,
1149
+ // "daily_base_token_volume": 643235.2763,
1150
+ // "daily_quote_token_volume": 1983505435.673896,
1151
+ // "daily_price_low": 2977.42,
1152
+ // "daily_price_high": 3170.81,
1153
+ // "daily_price_change": -0.3061987051035322
1154
+ // }
1155
+ //
1156
+ const marketId = this.safeString(ticker, 'market_id');
1157
+ market = this.safeMarket(marketId, market);
1158
+ const symbol = market['symbol'];
1159
+ const last = this.safeString(ticker, 'last_trade_price');
1160
+ const high = this.safeString(ticker, 'daily_price_high');
1161
+ const low = this.safeString(ticker, 'daily_price_low');
1162
+ const baseVolume = this.safeString(ticker, 'daily_base_token_volume');
1163
+ const quoteVolume = this.safeString(ticker, 'daily_quote_token_volume');
1164
+ const change = this.safeString(ticker, 'daily_price_change');
1165
+ const openInterest = this.safeString(ticker, 'open_interest');
1166
+ return this.safeTicker({
1167
+ 'symbol': symbol,
1168
+ 'timestamp': undefined,
1169
+ 'datetime': undefined,
1170
+ 'high': high,
1171
+ 'low': low,
1172
+ 'bid': undefined,
1173
+ 'bidVolume': undefined,
1174
+ 'ask': undefined,
1175
+ 'askVolume': undefined,
1176
+ 'vwap': undefined,
1177
+ 'open': undefined,
1178
+ 'close': last,
1179
+ 'last': last,
1180
+ 'previousClose': undefined,
1181
+ 'change': undefined,
1182
+ 'percentage': change,
1183
+ 'average': undefined,
1184
+ 'baseVolume': baseVolume,
1185
+ 'quoteVolume': quoteVolume,
1186
+ 'markPrice': this.safeString(ticker, 'mark_price'),
1187
+ 'indexPrice': this.safeString(ticker, 'index_price'),
1188
+ 'openInterest': openInterest,
1189
+ 'info': ticker,
1190
+ }, market);
1191
+ }
1192
+ /**
1193
+ * @method
1194
+ * @name lighter#fetchTicker
1195
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1196
+ * @see https://apidocs.lighter.xyz/reference/orderbookdetails
1197
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
1198
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1199
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1200
+ */
1201
+ async fetchTicker(symbol, params = {}) {
1202
+ if (symbol === undefined) {
1203
+ throw new ArgumentsRequired(this.id + ' fetchTicker() requires a symbol argument');
1204
+ }
1205
+ await this.loadMarkets();
1206
+ const market = this.market(symbol);
1207
+ const request = {
1208
+ 'market_id': market['id'],
1209
+ };
1210
+ const response = await this.publicGetOrderBookDetails(this.extend(request, params));
1211
+ //
1212
+ // {
1213
+ // "code": 200,
1214
+ // "order_book_details": [
1215
+ // {
1216
+ // "symbol": "ETH",
1217
+ // "market_id": 0,
1218
+ // "status": "active",
1219
+ // "taker_fee": "0.0000",
1220
+ // "maker_fee": "0.0000",
1221
+ // "liquidation_fee": "1.0000",
1222
+ // "min_base_amount": "0.0050",
1223
+ // "min_quote_amount": "10.000000",
1224
+ // "order_quote_limit": "",
1225
+ // "supported_size_decimals": 4,
1226
+ // "supported_price_decimals": 2,
1227
+ // "supported_quote_decimals": 6,
1228
+ // "size_decimals": 4,
1229
+ // "price_decimals": 2,
1230
+ // "quote_multiplier": 1,
1231
+ // "default_initial_margin_fraction": 500,
1232
+ // "min_initial_margin_fraction": 200,
1233
+ // "maintenance_margin_fraction": 120,
1234
+ // "closeout_margin_fraction": 80,
1235
+ // "last_trade_price": 3550.69,
1236
+ // "daily_trades_count": 1197349,
1237
+ // "daily_base_token_volume": 481297.3509,
1238
+ // "daily_quote_token_volume": 1671431095.263844,
1239
+ // "daily_price_low": 3402.41,
1240
+ // "daily_price_high": 3571.45,
1241
+ // "daily_price_change": 0.5294300840859545,
1242
+ // "open_interest": 39559.3278,
1243
+ // "daily_chart": {},
1244
+ // "market_config": {
1245
+ // "market_margin_mode": 0,
1246
+ // "insurance_fund_account_index": 281474976710655,
1247
+ // "liquidation_mode": 0,
1248
+ // "force_reduce_only": false,
1249
+ // "trading_hours": ""
1250
+ // }
1251
+ // }
1252
+ // ]
1253
+ // }
1254
+ //
1255
+ const data = this.safeList(response, 'order_book_details', []);
1256
+ const first = this.safeDict(data, 0, {});
1257
+ return this.parseTicker(first, market);
1258
+ }
1259
+ /**
1260
+ * @method
1261
+ * @name lighter#fetchTickers
1262
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1263
+ * @see https://apidocs.lighter.xyz/reference/orderbookdetails
1264
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1265
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1266
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1267
+ */
1268
+ async fetchTickers(symbols = undefined, params = {}) {
1269
+ await this.loadMarkets();
1270
+ symbols = this.marketSymbols(symbols);
1271
+ const response = await this.publicGetOrderBookDetails(params);
1272
+ const tickers = this.safeList(response, 'order_book_details', []);
1273
+ return this.parseTickers(tickers, symbols);
1274
+ }
1275
+ parseOHLCV(ohlcv, market = undefined) {
1276
+ //
1277
+ // {
1278
+ // "t": 1767700500000,
1279
+ // "o": 3236.86,
1280
+ // "h": 3237.78,
1281
+ // "l": 3235.36,
1282
+ // "c": 3235.39,
1283
+ // "v": 55.1632,
1284
+ // "V": 178530.793575,
1285
+ // "i": 779870452,
1286
+ // "C": "string",
1287
+ // "H": "string",
1288
+ // "L": "string",
1289
+ // "O": "string"
1290
+ // }
1291
+ //
1292
+ return [
1293
+ this.safeInteger(ohlcv, 't'),
1294
+ this.safeNumber(ohlcv, 'o'),
1295
+ this.safeNumber(ohlcv, 'h'),
1296
+ this.safeNumber(ohlcv, 'l'),
1297
+ this.safeNumber(ohlcv, 'c'),
1298
+ this.safeNumber(ohlcv, 'v'),
1299
+ ];
1300
+ }
1301
+ /**
1302
+ * @method
1303
+ * @name lighter#fetchOHLCV
1304
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1305
+ * @see https://apidocs.lighter.xyz/reference/candles
1306
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1307
+ * @param {string} timeframe the length of time each candle represents
1308
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1309
+ * @param {int} [limit] the maximum amount of candles to fetch
1310
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1311
+ * @param {int} [params.until] timestamp in ms of the latest candle to fetch
1312
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1313
+ */
1314
+ async fetchOHLCV(symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
1315
+ if (symbol === undefined) {
1316
+ throw new ArgumentsRequired(this.id + ' fetchOHLCV() requires a symbol argument');
1317
+ }
1318
+ await this.loadMarkets();
1319
+ const market = this.market(symbol);
1320
+ const until = this.safeInteger(params, 'until');
1321
+ params = this.omit(params, ['until']);
1322
+ const now = this.milliseconds();
1323
+ let startTs = undefined;
1324
+ let endTs = undefined;
1325
+ if (since !== undefined) {
1326
+ startTs = since;
1327
+ if (until !== undefined) {
1328
+ endTs = until;
1329
+ }
1330
+ else if (limit !== undefined) {
1331
+ const duration = this.parseTimeframe(timeframe);
1332
+ endTs = this.sum(since, duration * limit * 1000);
1333
+ }
1334
+ else {
1335
+ endTs = now;
1336
+ }
1337
+ }
1338
+ else {
1339
+ endTs = (until !== undefined) ? until : now;
1340
+ const defaultLimit = 100;
1341
+ if (limit !== undefined) {
1342
+ startTs = endTs - this.parseTimeframe(timeframe) * 1000 * limit;
1343
+ }
1344
+ else {
1345
+ startTs = endTs - this.parseTimeframe(timeframe) * 1000 * defaultLimit;
1346
+ }
1347
+ }
1348
+ const request = {
1349
+ 'market_id': market['id'],
1350
+ 'count_back': 0,
1351
+ 'resolution': this.safeString(this.timeframes, timeframe, timeframe),
1352
+ 'start_timestamp': startTs,
1353
+ 'end_timestamp': endTs,
1354
+ };
1355
+ const response = await this.publicGetCandles(this.extend(request, params));
1356
+ //
1357
+ // {
1358
+ // "code": 200,
1359
+ // "r": "1m",
1360
+ // "c": [
1361
+ // {
1362
+ // "t": 1767700500000,
1363
+ // "o": 3236.86,
1364
+ // "h": 3237.78,
1365
+ // "l": 3235.36,
1366
+ // "c": 3235.39,
1367
+ // "v": 55.1632,
1368
+ // "V": 178530.793575,
1369
+ // "i": 779870452,
1370
+ // "C": "string",
1371
+ // "H": "string",
1372
+ // "L": "string",
1373
+ // "O": "string"
1374
+ // }
1375
+ // ]
1376
+ // }
1377
+ //
1378
+ const ohlcvs = this.safeList(response, 'c', []);
1379
+ return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
1380
+ }
1381
+ parseFundingRate(contract, market = undefined) {
1382
+ //
1383
+ // {
1384
+ // "market_id": 0,
1385
+ // "exchange": "lighter",
1386
+ // "symbol": "ETH",
1387
+ // "rate": 0.00009599999999999999
1388
+ // }
1389
+ //
1390
+ const marketId = this.safeString(contract, 'market_id');
1391
+ return {
1392
+ 'info': contract,
1393
+ 'symbol': this.safeSymbol(marketId, market),
1394
+ 'markPrice': undefined,
1395
+ 'indexPrice': undefined,
1396
+ 'interestRate': undefined,
1397
+ 'estimatedSettlePrice': undefined,
1398
+ 'timestamp': undefined,
1399
+ 'datetime': undefined,
1400
+ 'fundingRate': this.safeNumber(contract, 'rate'),
1401
+ 'fundingTimestamp': undefined,
1402
+ 'fundingDatetime': undefined,
1403
+ 'nextFundingRate': undefined,
1404
+ 'nextFundingTimestamp': undefined,
1405
+ 'nextFundingDatetime': undefined,
1406
+ 'previousFundingRate': undefined,
1407
+ 'previousFundingTimestamp': undefined,
1408
+ 'previousFundingDatetime': undefined,
1409
+ 'interval': undefined,
1410
+ };
1411
+ }
1412
+ /**
1413
+ * @method
1414
+ * @name lighter#fetchFundingRates
1415
+ * @description fetch the current funding rate for multiple symbols
1416
+ * @see https://apidocs.lighter.xyz/reference/funding-rates
1417
+ * @param {string[]} [symbols] list of unified market symbols
1418
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1419
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1420
+ */
1421
+ async fetchFundingRates(symbols = undefined, params = {}) {
1422
+ await this.loadMarkets();
1423
+ const response = await this.publicGetFundingRates(this.extend(params));
1424
+ //
1425
+ // {
1426
+ // "code": 200,
1427
+ // "funding_rates": [
1428
+ // {
1429
+ // "market_id": 0,
1430
+ // "exchange": "lighter",
1431
+ // "symbol": "ETH",
1432
+ // "rate": 0.00009599999999999999
1433
+ // }
1434
+ // ]
1435
+ // }
1436
+ //
1437
+ const data = this.safeList(response, 'funding_rates', []);
1438
+ const result = [];
1439
+ for (let i = 0; i < data.length; i++) {
1440
+ const exchange = this.safeString(data[i], 'exchange');
1441
+ if (exchange === 'lighter') {
1442
+ result.push(data[i]);
1443
+ }
1444
+ }
1445
+ return this.parseFundingRates(result, symbols);
1446
+ }
1447
+ /**
1448
+ * @method
1449
+ * @name ligher#fetchBalance
1450
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1451
+ * @see https://apidocs.lighter.xyz/reference/account-1
1452
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1453
+ * @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
1454
+ * @param {string} [params.value] fetch balance value, account index or l1 address
1455
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
1456
+ */
1457
+ async fetchBalance(params = {}) {
1458
+ await this.loadMarkets();
1459
+ let accountIndex = undefined;
1460
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchBalance', 'accountIndex', 'account_index');
1461
+ const defaultType = this.safeString2(this.options, 'fetchBalance', 'defaultType', 'spot');
1462
+ const type = this.safeString(params, 'type', defaultType);
1463
+ const request = {
1464
+ 'by': this.safeString(params, 'by', 'index'),
1465
+ 'value': accountIndex,
1466
+ };
1467
+ const response = await this.publicGetAccount(this.extend(request, params));
1468
+ //
1469
+ // {
1470
+ // "code": "200",
1471
+ // "total": "1",
1472
+ // "accounts": [
1473
+ // {
1474
+ // "code": "0",
1475
+ // "account_type": "0",
1476
+ // "index": "1077",
1477
+ // "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
1478
+ // "cancel_all_time": "0",
1479
+ // "total_order_count": "1",
1480
+ // "total_isolated_order_count": "0",
1481
+ // "pending_order_count": "0",
1482
+ // "available_balance": "7996.489834",
1483
+ // "status": "1",
1484
+ // "collateral": "9000.000000",
1485
+ // "account_index": "1077",
1486
+ // "name": "",
1487
+ // "description": "",
1488
+ // "can_invite": true,
1489
+ // "referral_points_percentage": "",
1490
+ // "positions": [],
1491
+ // "assets": [
1492
+ // {
1493
+ // "symbol": "ETH",
1494
+ // "asset_id": "1",
1495
+ // "balance": "3.00000000",
1496
+ // "locked_balance": "0.00000000"
1497
+ // },
1498
+ // {
1499
+ // "symbol": "USDC",
1500
+ // "asset_id": "3",
1501
+ // "balance": "1000.000000",
1502
+ // "locked_balance": "0.000000"
1503
+ // }
1504
+ // ],
1505
+ // "total_asset_value": "9536.789088",
1506
+ // "cross_asset_value": "9536.789088",
1507
+ // "shares": []
1508
+ // }
1509
+ // ]
1510
+ // }
1511
+ //
1512
+ const result = { 'info': response };
1513
+ const accounts = this.safeList(response, 'accounts', []);
1514
+ for (let i = 0; i < accounts.length; i++) {
1515
+ const account = accounts[i];
1516
+ if (type === 'spot') {
1517
+ const assets = this.safeList(account, 'assets', []);
1518
+ for (let j = 0; j < assets.length; j++) {
1519
+ const asset = assets[j];
1520
+ const codeId = this.safeString(asset, 'symbol');
1521
+ const code = this.safeCurrencyCode(codeId);
1522
+ const balance = this.safeDict(result, code, this.account());
1523
+ balance['total'] = Precise.stringAdd(balance['total'], this.safeString(asset, 'balance'));
1524
+ balance['used'] = Precise.stringAdd(balance['used'], this.safeString(asset, 'locked_balance'));
1525
+ result[code] = balance;
1526
+ }
1527
+ }
1528
+ else {
1529
+ const perpUSDC = this.safeString(account, 'collateral');
1530
+ const perpBalance = this.safeDict(result, 'USDC(PERP)', this.account());
1531
+ perpBalance['total'] = Precise.stringAdd(perpBalance['total'], perpUSDC);
1532
+ result['USDC'] = perpBalance;
1533
+ }
1534
+ }
1535
+ return this.safeBalance(result);
1536
+ }
1537
+ /**
1538
+ * @method
1539
+ * @name lighter#fetchPosition
1540
+ * @description fetch data on an open position
1541
+ * @see https://apidocs.lighter.xyz/reference/account-1
1542
+ * @param {string} symbol unified market symbol of the market the position is held in
1543
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1544
+ * @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
1545
+ * @param {string} [params.value] fetch balance value, account index or l1 address
1546
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/?id=position-structure}
1547
+ */
1548
+ async fetchPosition(symbol, params = {}) {
1549
+ const positions = await this.fetchPositions([symbol], params);
1550
+ return this.safeDict(positions, 0, {});
1551
+ }
1552
+ /**
1553
+ * @method
1554
+ * @name lighter#fetchPositions
1555
+ * @description fetch all open positions
1556
+ * @see https://apidocs.lighter.xyz/reference/account-1
1557
+ * @param {string[]} [symbols] list of unified market symbols
1558
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1559
+ * @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
1560
+ * @param {string} [params.value] fetch balance value, account index or l1 address
1561
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/?id=position-structure}
1562
+ */
1563
+ async fetchPositions(symbols = undefined, params = {}) {
1564
+ await this.loadMarkets();
1565
+ let accountIndex = undefined;
1566
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchPositions', 'accountIndex', 'account_index');
1567
+ const request = {
1568
+ 'by': this.safeString(params, 'by', 'index'),
1569
+ 'value': accountIndex,
1570
+ };
1571
+ const response = await this.publicGetAccount(this.extend(request, params));
1572
+ //
1573
+ // {
1574
+ // "code": 200,
1575
+ // "total": 2,
1576
+ // "accounts": [
1577
+ // {
1578
+ // "code": 0,
1579
+ // "account_type": 0,
1580
+ // "index": 1077,
1581
+ // "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
1582
+ // "cancel_all_time": 0,
1583
+ // "total_order_count": 0,
1584
+ // "total_isolated_order_count": 0,
1585
+ // "pending_order_count": 0,
1586
+ // "available_balance": "12582.743947",
1587
+ // "status": 1,
1588
+ // "collateral": "9100.242706",
1589
+ // "account_index": 1077,
1590
+ // "name": "",
1591
+ // "description": "",
1592
+ // "can_invite": true,
1593
+ // "referral_points_percentage": "",
1594
+ // "positions": [
1595
+ // {
1596
+ // "market_id": 0,
1597
+ // "symbol": "ETH",
1598
+ // "initial_margin_fraction": "5.00",
1599
+ // "open_order_count": 0,
1600
+ // "pending_order_count": 0,
1601
+ // "position_tied_order_count": 0,
1602
+ // "sign": 1,
1603
+ // "position": "18.0193",
1604
+ // "avg_entry_price": "2669.84",
1605
+ // "position_value": "54306.566340",
1606
+ // "unrealized_pnl": "6197.829558",
1607
+ // "realized_pnl": "0.000000",
1608
+ // "liquidation_price": "2191.1107231380406",
1609
+ // "margin_mode": 0,
1610
+ // "allocated_margin": "0.000000"
1611
+ // }
1612
+ // ],
1613
+ // "assets": [],
1614
+ // "total_asset_value": "15298.072264000002",
1615
+ // "cross_asset_value": "15298.072264000002",
1616
+ // "shares": []
1617
+ // }
1618
+ // ]
1619
+ // }
1620
+ //
1621
+ const allPositions = [];
1622
+ const accounts = this.safeList(response, 'accounts', []);
1623
+ for (let i = 0; i < accounts.length; i++) {
1624
+ const account = accounts[i];
1625
+ const positions = this.safeList(account, 'positions', []);
1626
+ for (let j = 0; j < positions.length; j++) {
1627
+ allPositions.push(positions[j]);
1628
+ }
1629
+ }
1630
+ return this.parsePositions(allPositions, symbols);
1631
+ }
1632
+ parsePosition(position, market = undefined) {
1633
+ //
1634
+ // {
1635
+ // "market_id": 0,
1636
+ // "symbol": "ETH",
1637
+ // "initial_margin_fraction": "5.00",
1638
+ // "open_order_count": 0,
1639
+ // "pending_order_count": 0,
1640
+ // "position_tied_order_count": 0,
1641
+ // "sign": 1,
1642
+ // "position": "18.0193",
1643
+ // "avg_entry_price": "2669.84",
1644
+ // "position_value": "54306.566340",
1645
+ // "unrealized_pnl": "6197.829558",
1646
+ // "realized_pnl": "0.000000",
1647
+ // "liquidation_price": "2191.1107231380406",
1648
+ // "margin_mode": 0,
1649
+ // "allocated_margin": "0.000000"
1650
+ // }
1651
+ //
1652
+ const marketId = this.safeString(position, 'market_id');
1653
+ market = this.safeMarket(marketId, market);
1654
+ const sign = this.safeInteger(position, 'sign');
1655
+ let side = undefined;
1656
+ if (sign !== undefined) {
1657
+ side = (sign === 1) ? 'long' : 'short';
1658
+ }
1659
+ const marginModeId = this.safeInteger(position, 'margin_mode');
1660
+ let marginMode = undefined;
1661
+ if (marginModeId !== undefined) {
1662
+ marginMode = (marginModeId === 0) ? 'cross' : 'isolated';
1663
+ }
1664
+ const imfStr = this.safeString(position, 'initial_margin_fraction');
1665
+ let leverage = undefined;
1666
+ if (imfStr !== undefined) {
1667
+ const imf = this.parseToInt(imfStr);
1668
+ if (imf > 0) {
1669
+ leverage = 100 / imf;
1670
+ }
1671
+ }
1672
+ return this.safePosition({
1673
+ 'info': position,
1674
+ 'id': undefined,
1675
+ 'symbol': market['symbol'],
1676
+ 'timestamp': undefined,
1677
+ 'datetime': undefined,
1678
+ 'isolated': (marginMode === 'isolated'),
1679
+ 'hedged': undefined,
1680
+ 'side': side,
1681
+ 'contracts': this.safeNumber(position, 'position'),
1682
+ 'contractSize': undefined,
1683
+ 'entryPrice': this.safeNumber(position, 'avg_entry_price'),
1684
+ 'markPrice': undefined,
1685
+ 'notional': this.safeNumber(position, 'position_value'),
1686
+ 'leverage': leverage,
1687
+ 'collateral': this.safeNumber(position, 'allocated_margin'),
1688
+ 'initialMargin': undefined,
1689
+ 'maintenanceMargin': undefined,
1690
+ 'initialMarginPercentage': undefined,
1691
+ 'maintenanceMarginPercentage': undefined,
1692
+ 'unrealizedPnl': this.safeNumber(position, 'unrealized_pnl'),
1693
+ 'liquidationPrice': this.safeNumber(position, 'liquidation_price'),
1694
+ 'marginMode': marginMode,
1695
+ 'percentage': undefined,
1696
+ });
1697
+ }
1698
+ /**
1699
+ * @method
1700
+ * @name lighter#fetchAccounts
1701
+ * @description fetch all the accounts associated with a profile
1702
+ * @see https://apidocs.lighter.xyz/reference/account-1
1703
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1704
+ * @param {string} [params.by] fetch balance by 'index' or 'l1_address', defaults to 'index'
1705
+ * @param {string} [params.value] fetch balance value, account index or l1 address
1706
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/?id=accounts-structure} indexed by the account type
1707
+ */
1708
+ async fetchAccounts(params = {}) {
1709
+ await this.loadMarkets();
1710
+ let accountIndex = undefined;
1711
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchAccounts', 'accountIndex', 'account_index');
1712
+ const request = {
1713
+ 'by': this.safeString(params, 'by', 'index'),
1714
+ 'value': accountIndex,
1715
+ };
1716
+ const response = await this.publicGetAccount(this.extend(request, params));
1717
+ //
1718
+ // {
1719
+ // "code": "200",
1720
+ // "total": "1",
1721
+ // "accounts": [
1722
+ // {
1723
+ // "code": "0",
1724
+ // "account_type": "0",
1725
+ // "index": "1077",
1726
+ // "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
1727
+ // "cancel_all_time": "0",
1728
+ // "total_order_count": "1",
1729
+ // "total_isolated_order_count": "0",
1730
+ // "pending_order_count": "0",
1731
+ // "available_balance": "7996.489834",
1732
+ // "status": "1",
1733
+ // "collateral": "9000.000000",
1734
+ // "account_index": "1077",
1735
+ // "name": "",
1736
+ // "description": "",
1737
+ // "can_invite": true,
1738
+ // "referral_points_percentage": "",
1739
+ // "positions": [],
1740
+ // "assets": [],
1741
+ // "total_asset_value": "9536.789088",
1742
+ // "cross_asset_value": "9536.789088",
1743
+ // "shares": []
1744
+ // }
1745
+ // ]
1746
+ // }
1747
+ //
1748
+ const accounts = this.safeList(response, 'accounts', []);
1749
+ return this.parseAccounts(accounts, params);
1750
+ }
1751
+ parseAccount(account) {
1752
+ //
1753
+ // {
1754
+ // "code": "0",
1755
+ // "account_type": "0",
1756
+ // "index": "1077",
1757
+ // "l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
1758
+ // "cancel_all_time": "0",
1759
+ // "total_order_count": "1",
1760
+ // "total_isolated_order_count": "0",
1761
+ // "pending_order_count": "0",
1762
+ // "available_balance": "7996.489834",
1763
+ // "status": "1",
1764
+ // "collateral": "9000.000000",
1765
+ // "account_index": "1077",
1766
+ // "name": "",
1767
+ // "description": "",
1768
+ // "can_invite": true,
1769
+ // "referral_points_percentage": "",
1770
+ // "positions": [],
1771
+ // "assets": [],
1772
+ // "total_asset_value": "9536.789088",
1773
+ // "cross_asset_value": "9536.789088",
1774
+ // "shares": []
1775
+ // }
1776
+ //
1777
+ const accountType = this.safeString(account, 'account_type');
1778
+ return {
1779
+ 'id': this.safeString(account, 'account_index'),
1780
+ 'type': (accountType === '0') ? 'main' : 'subaccount',
1781
+ 'code': undefined,
1782
+ 'info': account,
1783
+ };
1784
+ }
1785
+ /**
1786
+ * @method
1787
+ * @name lighter#fetchOpenOrders
1788
+ * @description fetch all unfilled currently open orders
1789
+ * @see https://apidocs.lighter.xyz/reference/accountactiveorders
1790
+ * @param {string} symbol unified market symbol
1791
+ * @param {int} [since] the earliest time in ms to fetch open orders for
1792
+ * @param {int} [limit] the maximum number of open orders structures to retrieve
1793
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1794
+ * @param {string} [params.accountIndex] account index
1795
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
1796
+ */
1797
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1798
+ if (symbol === undefined) {
1799
+ throw new ArgumentsRequired(this.id + ' fetchOpenOrders() requires a symbol argument');
1800
+ }
1801
+ await this.loadMarkets();
1802
+ let accountIndex = undefined;
1803
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchOpenOrders', 'accountIndex', 'account_index');
1804
+ let apiKeyIndex = undefined;
1805
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchOpenOrders', 'apiKeyIndex', 'api_key_index');
1806
+ if (apiKeyIndex === undefined) {
1807
+ throw new ArgumentsRequired(this.id + ' fetchOpenOrders() requires an apiKeyIndex parameter');
1808
+ }
1809
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
1810
+ const market = this.market(symbol);
1811
+ const request = {
1812
+ 'market_id': market['id'],
1813
+ 'account_index': accountIndex,
1814
+ };
1815
+ const response = await this.privateGetAccountActiveOrders(this.extend(request, params));
1816
+ //
1817
+ // {
1818
+ // "code": 200,
1819
+ // "orders": [
1820
+ // {
1821
+ // "order_index": 281474977354074,
1822
+ // "client_order_index": 0,
1823
+ // "order_id": "281474977354074",
1824
+ // "client_order_id": "0",
1825
+ // "market_index": 0,
1826
+ // "owner_account_index": 1077,
1827
+ // "initial_base_amount": "36.0386",
1828
+ // "price": "2221.60",
1829
+ // "nonce": 643418,
1830
+ // "remaining_base_amount": "0.0000",
1831
+ // "is_ask": true,
1832
+ // "base_size": 0,
1833
+ // "base_price": 222160,
1834
+ // "filled_base_amount": "0.0000",
1835
+ // "filled_quote_amount": "0.000000",
1836
+ // "side": "",
1837
+ // "type": "market",
1838
+ // "time_in_force": "immediate-or-cancel",
1839
+ // "reduce_only": false,
1840
+ // "trigger_price": "0.00",
1841
+ // "order_expiry": 0,
1842
+ // "status": "canceled-margin-not-allowed",
1843
+ // "trigger_status": "na",
1844
+ // "trigger_time": 0,
1845
+ // "parent_order_index": 0,
1846
+ // "parent_order_id": "0",
1847
+ // "to_trigger_order_id_0": "0",
1848
+ // "to_trigger_order_id_1": "0",
1849
+ // "to_cancel_order_id_0": "0",
1850
+ // "block_height": 102202,
1851
+ // "timestamp": 1766387932,
1852
+ // "created_at": 1766387932,
1853
+ // "updated_at": 1766387932
1854
+ // }
1855
+ // ]
1856
+ // }
1857
+ //
1858
+ const data = this.safeList(response, 'orders', []);
1859
+ return this.parseOrders(data, market, since, limit);
1860
+ }
1861
+ /**
1862
+ * @method
1863
+ * @name lighter#fetchClosedOrders
1864
+ * @description fetch all unfilled currently closed orders
1865
+ * @see https://apidocs.lighter.xyz/reference/accountinactiveorders
1866
+ * @param {string} symbol unified market symbol
1867
+ * @param {int} [since] the earliest time in ms to fetch open orders for
1868
+ * @param {int} [limit] the maximum number of open orders structures to retrieve
1869
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1870
+ * @param {string} [params.accountIndex] account index
1871
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
1872
+ */
1873
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1874
+ if (symbol === undefined) {
1875
+ throw new ArgumentsRequired(this.id + ' fetchClosedOrders() requires a symbol argument');
1876
+ }
1877
+ await this.loadMarkets();
1878
+ let accountIndex = undefined;
1879
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchClosedOrders', 'accountIndex', 'account_index');
1880
+ let apiKeyIndex = undefined;
1881
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchClosedOrders', 'apiKeyIndex', 'api_key_index');
1882
+ if (apiKeyIndex === undefined) {
1883
+ throw new ArgumentsRequired(this.id + ' fetchClosedOrders() requires an apiKeyIndex parameter');
1884
+ }
1885
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
1886
+ const market = this.market(symbol);
1887
+ const request = {
1888
+ 'market_id': market['id'],
1889
+ 'account_index': accountIndex,
1890
+ 'limit': 100, // required, max 100
1891
+ };
1892
+ if (limit !== undefined) {
1893
+ request['limit'] = Math.min(limit, 100);
1894
+ }
1895
+ const response = await this.privateGetAccountInactiveOrders(this.extend(request, params));
1896
+ //
1897
+ // {
1898
+ // "code": 200,
1899
+ // "orders": [
1900
+ // {
1901
+ // "order_index": 281474977354074,
1902
+ // "client_order_index": 0,
1903
+ // "order_id": "281474977354074",
1904
+ // "client_order_id": "0",
1905
+ // "market_index": 0,
1906
+ // "owner_account_index": 1077,
1907
+ // "initial_base_amount": "36.0386",
1908
+ // "price": "2221.60",
1909
+ // "nonce": 643418,
1910
+ // "remaining_base_amount": "0.0000",
1911
+ // "is_ask": true,
1912
+ // "base_size": 0,
1913
+ // "base_price": 222160,
1914
+ // "filled_base_amount": "0.0000",
1915
+ // "filled_quote_amount": "0.000000",
1916
+ // "side": "",
1917
+ // "type": "market",
1918
+ // "time_in_force": "immediate-or-cancel",
1919
+ // "reduce_only": false,
1920
+ // "trigger_price": "0.00",
1921
+ // "order_expiry": 0,
1922
+ // "status": "canceled-margin-not-allowed",
1923
+ // "trigger_status": "na",
1924
+ // "trigger_time": 0,
1925
+ // "parent_order_index": 0,
1926
+ // "parent_order_id": "0",
1927
+ // "to_trigger_order_id_0": "0",
1928
+ // "to_trigger_order_id_1": "0",
1929
+ // "to_cancel_order_id_0": "0",
1930
+ // "block_height": 102202,
1931
+ // "timestamp": 1766387932,
1932
+ // "created_at": 1766387932,
1933
+ // "updated_at": 1766387932
1934
+ // }
1935
+ // ]
1936
+ // }
1937
+ //
1938
+ const data = this.safeList(response, 'orders', []);
1939
+ return this.parseOrders(data, market, since, limit);
1940
+ }
1941
+ parseOrder(order, market = undefined) {
1942
+ //
1943
+ // {
1944
+ // "order_index": 281474977354074,
1945
+ // "client_order_index": 0,
1946
+ // "order_id": "281474977354074",
1947
+ // "client_order_id": "0",
1948
+ // "market_index": 0,
1949
+ // "owner_account_index": 1077,
1950
+ // "initial_base_amount": "36.0386",
1951
+ // "price": "2221.60",
1952
+ // "nonce": 643418,
1953
+ // "remaining_base_amount": "0.0000",
1954
+ // "is_ask": true,
1955
+ // "base_size": 0,
1956
+ // "base_price": 222160,
1957
+ // "filled_base_amount": "0.0000",
1958
+ // "filled_quote_amount": "0.000000",
1959
+ // "side": "",
1960
+ // "type": "market",
1961
+ // "time_in_force": "immediate-or-cancel",
1962
+ // "reduce_only": false,
1963
+ // "trigger_price": "0.00",
1964
+ // "order_expiry": 0,
1965
+ // "status": "canceled-margin-not-allowed",
1966
+ // "trigger_status": "na",
1967
+ // "trigger_time": 0,
1968
+ // "parent_order_index": 0,
1969
+ // "parent_order_id": "0",
1970
+ // "to_trigger_order_id_0": "0",
1971
+ // "to_trigger_order_id_1": "0",
1972
+ // "to_cancel_order_id_0": "0",
1973
+ // "block_height": 102202,
1974
+ // "timestamp": 1766387932,
1975
+ // "created_at": 1766387932,
1976
+ // "updated_at": 1766387932
1977
+ // }
1978
+ //
1979
+ const marketId = this.safeString(order, 'market_index');
1980
+ market = this.safeMarket(marketId, market);
1981
+ const timestamp = this.safeTimestamp(order, 'timestamp');
1982
+ const isAsk = this.safeBool(order, 'is_ask');
1983
+ let side = undefined;
1984
+ if (isAsk !== undefined) {
1985
+ side = isAsk ? 'sell' : 'buy';
1986
+ }
1987
+ const type = this.safeString(order, 'type');
1988
+ const triggerPrice = this.parseNumber(this.omitZero(this.safeString(order, 'trigger_price')));
1989
+ let stopLossPrice = undefined;
1990
+ let takeProfitPrice = undefined;
1991
+ if (type !== undefined) {
1992
+ if (type.indexOf('stop-loss') >= 0) {
1993
+ stopLossPrice = triggerPrice;
1994
+ }
1995
+ if (type.indexOf('take-profit') >= 0) {
1996
+ takeProfitPrice = triggerPrice;
1997
+ }
1998
+ }
1999
+ const tif = this.safeString(order, 'time_in_force');
2000
+ const status = this.safeString(order, 'status');
2001
+ return this.safeOrder({
2002
+ 'info': order,
2003
+ 'id': this.safeString(order, 'order_id'),
2004
+ 'clientOrderId': this.omitZero(this.safeString2(order, 'client_order_id', 'client_order_index')),
2005
+ 'timestamp': timestamp,
2006
+ 'datetime': this.iso8601(timestamp),
2007
+ 'lastTradeTimestamp': undefined,
2008
+ 'lastUpdateTimestamp': this.safeTimestamp(order, 'updated_at'),
2009
+ 'symbol': market['symbol'],
2010
+ 'type': this.parseOrderType(type),
2011
+ 'timeInForce': this.parseOrderTimeInForeces(tif),
2012
+ 'postOnly': undefined,
2013
+ 'reduceOnly': this.safeBool(order, 'reduce_only'),
2014
+ 'side': side,
2015
+ 'price': this.safeString(order, 'price'),
2016
+ 'triggerPrice': triggerPrice,
2017
+ 'stopLossPrice': stopLossPrice,
2018
+ 'takeProfitPrice': takeProfitPrice,
2019
+ 'amount': this.safeString(order, 'initial_base_amount'),
2020
+ 'cost': this.safeString(order, 'filled_quote_amount'),
2021
+ 'average': undefined,
2022
+ 'filled': this.safeString(order, 'filled_base_amount'),
2023
+ 'remaining': this.safeString(order, 'remaining_base_amount'),
2024
+ 'status': this.parseOrderStatus(status),
2025
+ 'fee': undefined,
2026
+ 'trades': undefined,
2027
+ }, market);
2028
+ }
2029
+ parseOrderStatus(status) {
2030
+ const statuses = {
2031
+ 'in-progress': 'open',
2032
+ 'pending': 'open',
2033
+ 'open': 'open',
2034
+ 'filled': 'closed',
2035
+ 'canceled': 'canceled',
2036
+ 'canceled-post-only': 'canceled',
2037
+ 'canceled-reduce-only': 'canceled',
2038
+ 'canceled-position-not-allowed': 'rejected',
2039
+ 'canceled-margin-not-allowed': 'rejected',
2040
+ 'canceled-too-much-slippage': 'canceled',
2041
+ 'canceled-not-enough-liquidity': 'canceled',
2042
+ 'canceled-self-trade': 'canceled',
2043
+ 'canceled-expired': 'expired',
2044
+ 'canceled-oco': 'canceled',
2045
+ 'canceled-child': 'canceled',
2046
+ 'canceled-liquidation': 'canceled',
2047
+ };
2048
+ return this.safeString(statuses, status, status);
2049
+ }
2050
+ parseOrderType(status) {
2051
+ const statuses = {
2052
+ 'limit': 'limit',
2053
+ 'market': 'market',
2054
+ 'stop-loss': 'market',
2055
+ 'stop-loss-limit': 'limit',
2056
+ 'take-profit': 'market',
2057
+ 'take-profit-limit': 'limit',
2058
+ 'twap': 'twap',
2059
+ 'twap-sub': 'twap',
2060
+ 'liquidation': 'market',
2061
+ };
2062
+ return this.safeString(statuses, status, status);
2063
+ }
2064
+ parseOrderTimeInForeces(tif) {
2065
+ const timeInForces = {
2066
+ 'good-till-time': 'GTC',
2067
+ 'immediate-or-cancel': 'IOC',
2068
+ 'post-only': 'PO',
2069
+ 'Unknown': undefined,
2070
+ };
2071
+ return this.safeString(timeInForces, tif, tif);
2072
+ }
2073
+ /**
2074
+ * @method
2075
+ * @name lighter#transfer
2076
+ * @description transfer currency internally between wallets on the same account
2077
+ * @param {string} code unified currency code
2078
+ * @param {float} amount amount to transfer
2079
+ * @param {string} fromAccount account to transfer from (spot, perp)
2080
+ * @param {string} toAccount account to transfer to (spot, perp)
2081
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2082
+ * @param {string} [params.accountIndex] account index
2083
+ * @param {string} [params.toAccountIndex] to account index, defaults to fromAccountIndex
2084
+ * @param {string} [params.apiKeyIndex] api key index
2085
+ * @param {string} [params.memo] hex encoding memo
2086
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
2087
+ */
2088
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
2089
+ let apiKeyIndex = undefined;
2090
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'transfer', 'apiKeyIndex', 'api_key_index');
2091
+ if (apiKeyIndex === undefined) {
2092
+ throw new ArgumentsRequired(this.id + ' transfer() requires an apiKeyIndex parameter');
2093
+ }
2094
+ await this.loadMarkets();
2095
+ let accountIndex = undefined;
2096
+ [accountIndex, params] = await this.handleAccountIndex(params, 'transfer', 'accountIndex', 'account_index');
2097
+ let toAccountIndex = undefined;
2098
+ [toAccountIndex, params] = this.handleOptionAndParams2(params, 'transfer', 'toAccountIndex', 'to_account_index', accountIndex);
2099
+ const currency = this.currency(code);
2100
+ if (currency['code'] === 'USDC') {
2101
+ amount = this.parseToInt(Precise.stringMul(this.pow('10', '6'), this.currencyToPrecision(code, amount)));
2102
+ }
2103
+ else if (currency['code'] === 'ETH') {
2104
+ amount = this.parseToInt(Precise.stringMul(this.pow('10', '8'), this.currencyToPrecision(code, amount)));
2105
+ }
2106
+ else {
2107
+ throw new ExchangeError(this.id + ' transfer() only supports USDC and ETH transfers');
2108
+ }
2109
+ const fromRouteType = (fromAccount === 'perp') ? 0 : 1; // 0: perp, 1: spot
2110
+ const toRouteType = (toAccount === 'perp') ? 0 : 1;
2111
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2112
+ const memo = this.safeString(params, 'memo', '0x000000000000000000000000000000');
2113
+ params = this.omit(params, ['memo']);
2114
+ const signRaw = {
2115
+ 'to_account_index': toAccountIndex,
2116
+ 'asset_index': this.parseToInt(currency['id']),
2117
+ 'from_route_type': fromRouteType,
2118
+ 'to_route_type': toRouteType,
2119
+ 'amount': amount,
2120
+ 'usdc_fee': 0,
2121
+ 'memo': memo,
2122
+ 'nonce': nonce,
2123
+ 'api_key_index': apiKeyIndex,
2124
+ 'account_index': accountIndex,
2125
+ };
2126
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2127
+ const [txType, txInfo] = this.lighterSignTransfer(signer, this.extend(signRaw, params));
2128
+ const request = {
2129
+ 'tx_type': txType,
2130
+ 'tx_info': txInfo,
2131
+ };
2132
+ const response = await this.publicPostSendTx(request);
2133
+ return this.parseTransfer(response);
2134
+ }
2135
+ /**
2136
+ * @method
2137
+ * @name lighter#fetchTransfers
2138
+ * @description fetch a history of internal transfers made on an account
2139
+ * @see https://apidocs.lighter.xyz/reference/transfer_history
2140
+ * @param {string} code unified currency code of the currency transferred
2141
+ * @param {int} [since] the earliest time in ms to fetch transfers for
2142
+ * @param {int} [limit] the maximum number of transfers structures to retrieve
2143
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2144
+ * @param {string} [params.accountIndex] account index
2145
+ * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/?id=transfer-structure}
2146
+ */
2147
+ async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
2148
+ let accountIndex = undefined;
2149
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchTransfers', 'accountIndex', 'account_index');
2150
+ const request = {
2151
+ 'account_index': accountIndex,
2152
+ };
2153
+ let apiKeyIndex = undefined;
2154
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchTransfers', 'apiKeyIndex', 'api_key_index');
2155
+ if (apiKeyIndex === undefined) {
2156
+ throw new ArgumentsRequired(this.id + ' fetchTransfers() requires an apiKeyIndex parameter');
2157
+ }
2158
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2159
+ let currency = undefined;
2160
+ if (code !== undefined) {
2161
+ currency = this.currency(code);
2162
+ }
2163
+ const response = await this.privateGetTransferHistory(this.extend(request, params));
2164
+ //
2165
+ // {
2166
+ // "code": 200,
2167
+ // "transfers": [
2168
+ // {
2169
+ // "id": "3085014",
2170
+ // "asset_id": 3,
2171
+ // "amount": "11.000000",
2172
+ // "fee": "0.000000",
2173
+ // "timestamp": 1766387292752,
2174
+ // "type": "L2TransferOutflow",
2175
+ // "from_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
2176
+ // "to_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
2177
+ // "from_account_index": 1077,
2178
+ // "to_account_index": 281474976710608,
2179
+ // "from_route": "spot",
2180
+ // "to_route": "spot",
2181
+ // "tx_hash": "d8e96178273d0938f9ede556edffc0aab8def9ec70c46a65791905291a2f5792af18625406102c80"
2182
+ // }
2183
+ // ],
2184
+ // "cursor": "eyJpbmRleCI6MzA4NDkxNX0="
2185
+ // }
2186
+ //
2187
+ const rows = this.safeList(response, 'transfers', []);
2188
+ return this.parseTransfers(rows, currency, since, limit, params);
2189
+ }
2190
+ parseTransfer(transfer, currency = undefined) {
2191
+ //
2192
+ // {
2193
+ // "id": "3085014",
2194
+ // "asset_id": 3,
2195
+ // "amount": "11.000000",
2196
+ // "fee": "0.000000",
2197
+ // "timestamp": 1766387292752,
2198
+ // "type": "L2TransferOutflow",
2199
+ // "from_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
2200
+ // "to_l1_address": "0x15f43D1f2DeE81424aFd891943262aa90F22cc2A",
2201
+ // "from_account_index": 1077,
2202
+ // "to_account_index": 281474976710608,
2203
+ // "from_route": "spot",
2204
+ // "to_route": "spot",
2205
+ // "tx_hash": "d8e96178273d0938f9ede556edffc0aab8def9ec70c46a65791905291a2f5792af18625406102c80"
2206
+ // }
2207
+ //
2208
+ const currencyId = this.safeString(transfer, 'asset_id');
2209
+ const code = this.safeCurrencyCode(currencyId, currency);
2210
+ const timestamp = this.safeInteger(transfer, 'timestamp');
2211
+ const fromAccount = this.safeDict(transfer, 'from', {});
2212
+ const toAccount = this.safeDict(transfer, 'to', {});
2213
+ return {
2214
+ 'id': this.safeString(transfer, 'id'),
2215
+ 'timestamp': timestamp,
2216
+ 'datetime': this.iso8601(timestamp),
2217
+ 'currency': code,
2218
+ 'amount': this.safeNumber(transfer, 'amount'),
2219
+ 'fromAccount': this.safeString(fromAccount, 'from_account_index'),
2220
+ 'toAccount': this.safeString(toAccount, 'to_account_index'),
2221
+ 'status': undefined,
2222
+ 'info': transfer,
2223
+ };
2224
+ }
2225
+ /**
2226
+ * @method
2227
+ * @name lighter#fetchDeposits
2228
+ * @description fetch all deposits made to an account
2229
+ * @see https://apidocs.lighter.xyz/reference/deposit_history
2230
+ * @param {string} [code] unified currency code
2231
+ * @param {int} [since] the earliest time in ms to fetch deposits for
2232
+ * @param {int} [limit] the maximum number of deposits structures to retrieve
2233
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2234
+ * @param {string} [params.accountIndex] account index
2235
+ * @param {string} [params.address] l1_address
2236
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/?id=transaction-structure}
2237
+ */
2238
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
2239
+ let address = undefined;
2240
+ [address, params] = this.handleOptionAndParams2(params, 'fetchDeposits', 'address', 'l1_address');
2241
+ if (address === undefined) {
2242
+ throw new ArgumentsRequired(this.id + ' fetchDeposits() requires an address parameter');
2243
+ }
2244
+ await this.loadMarkets();
2245
+ let accountIndex = undefined;
2246
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchDeposits', 'accountIndex', 'account_index');
2247
+ const request = {
2248
+ 'account_index': accountIndex,
2249
+ 'l1_address': address,
2250
+ };
2251
+ let apiKeyIndex = undefined;
2252
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchDeposits', 'apiKeyIndex', 'api_key_index');
2253
+ if (apiKeyIndex === undefined) {
2254
+ throw new ArgumentsRequired(this.id + ' fetchDeposits() requires an apiKeyIndex parameter');
2255
+ }
2256
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2257
+ let currency = undefined;
2258
+ if (code !== undefined) {
2259
+ currency = this.currency(code);
2260
+ request['coin'] = currency['id'];
2261
+ }
2262
+ const response = await this.privateGetDepositHistory(this.extend(request, params));
2263
+ //
2264
+ // {
2265
+ // "code": 200,
2266
+ // "deposits": [
2267
+ // {
2268
+ // "id": "2901843",
2269
+ // "asset_id": 5,
2270
+ // "amount": "100000.0",
2271
+ // "timestamp": 1766112729741,
2272
+ // "status": "completed",
2273
+ // "l1_tx_hash": "0xa24d83d58e1fd72b2a44a12d1ec766fb061fa0b806de2fed940b5d8ecd50744d"
2274
+ // }
2275
+ // ],
2276
+ // "cursor": "eyJpbmRleCI6MjkwMTg0MH0="
2277
+ // }
2278
+ //
2279
+ const data = this.safeList(response, 'deposits', []);
2280
+ return this.parseTransactions(data, currency, since, limit);
2281
+ }
2282
+ /**
2283
+ * @method
2284
+ * @name lighter#fetchWithdrawals
2285
+ * @description fetch all withdrawals made from an account
2286
+ * @see https://apidocs.lighter.xyz/reference/withdraw_history
2287
+ * @param {string} [code] unified currency code
2288
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
2289
+ * @param {int} [limit] the maximum number of withdrawals structures to retrieve
2290
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2291
+ * @param {string} [params.accountIndex] account index
2292
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/?id=transaction-structure}
2293
+ */
2294
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2295
+ await this.loadMarkets();
2296
+ let accountIndex = undefined;
2297
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchWithdrawals', 'accountIndex', 'account_index');
2298
+ const request = {
2299
+ 'account_index': accountIndex,
2300
+ };
2301
+ let apiKeyIndex = undefined;
2302
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchWithdrawals', 'apiKeyIndex', 'api_key_index');
2303
+ if (apiKeyIndex === undefined) {
2304
+ throw new ArgumentsRequired(this.id + ' fetchWithdrawals() requires an apiKeyIndex parameter');
2305
+ }
2306
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2307
+ let currency = undefined;
2308
+ if (code !== undefined) {
2309
+ currency = this.currency(code);
2310
+ request['coin'] = currency['id'];
2311
+ }
2312
+ const response = await this.privateGetWithdrawHistory(this.extend(request, params));
2313
+ //
2314
+ // {
2315
+ // "code": "200",
2316
+ // "message": "string",
2317
+ // "withdraws": [
2318
+ // {
2319
+ // "id": "string",
2320
+ // "amount": "0.1",
2321
+ // "timestamp": "1640995200",
2322
+ // "status": "failed",
2323
+ // "type": "secure",
2324
+ // "l1_tx_hash": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
2325
+ // }
2326
+ // ],
2327
+ // "cursor": "string"
2328
+ // }
2329
+ //
2330
+ const data = this.safeList(response, 'withdraws', []);
2331
+ return this.parseTransactions(data, currency, since, limit);
2332
+ }
2333
+ parseTransaction(transaction, currency = undefined) {
2334
+ //
2335
+ // fetchDeposits
2336
+ // {
2337
+ // "id": "2901843",
2338
+ // "asset_id": 5,
2339
+ // "amount": "100000.0",
2340
+ // "timestamp": 1766112729741,
2341
+ // "status": "completed",
2342
+ // "l1_tx_hash": "0xa24d83d58e1fd72b2a44a12d1ec766fb061fa0b806de2fed940b5d8ecd50744d",
2343
+ // }
2344
+ //
2345
+ // fetchWithdrawals
2346
+ // {
2347
+ // "id": "string",
2348
+ // "amount": "0.1",
2349
+ // "timestamp": "1640995200",
2350
+ // "status": "failed",
2351
+ // "type": "secure",
2352
+ // "l1_tx_hash": "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"
2353
+ // }
2354
+ //
2355
+ let type = this.safeString(transaction, 'type');
2356
+ if (type === undefined) {
2357
+ type = 'deposit';
2358
+ }
2359
+ else {
2360
+ type = 'withdrawal';
2361
+ }
2362
+ const timestamp = this.safeInteger(transaction, 'timestamp');
2363
+ const status = this.safeString(transaction, 'status');
2364
+ return {
2365
+ 'info': transaction,
2366
+ 'id': this.safeString(transaction, 'id'),
2367
+ 'txid': this.safeString(transaction, 'l1_tx_hash'),
2368
+ 'type': type,
2369
+ 'currency': this.safeCurrencyCode(this.safeString(transaction, 'asset_id'), currency),
2370
+ 'network': undefined,
2371
+ 'amount': this.safeNumber(transaction, 'amount'),
2372
+ 'status': this.parseTransactionStatus(status),
2373
+ 'timestamp': timestamp,
2374
+ 'datetime': this.iso8601(timestamp),
2375
+ 'address': undefined,
2376
+ 'addressFrom': undefined,
2377
+ 'addressTo': undefined,
2378
+ 'tag': undefined,
2379
+ 'tagFrom': undefined,
2380
+ 'tagTo': undefined,
2381
+ 'updated': undefined,
2382
+ 'comment': undefined,
2383
+ 'fee': undefined,
2384
+ 'internal': undefined,
2385
+ };
2386
+ }
2387
+ parseTransactionStatus(status) {
2388
+ const statuses = {
2389
+ 'failed': 'failed',
2390
+ 'pending': 'pending',
2391
+ 'completed': 'ok',
2392
+ 'claimable': 'ok',
2393
+ };
2394
+ return this.safeString(statuses, status, status);
2395
+ }
2396
+ /**
2397
+ * @method
2398
+ * @name lighter#withdraw
2399
+ * @description make a withdrawal
2400
+ * @param {string} code unified currency code
2401
+ * @param {float} amount the amount to withdraw
2402
+ * @param {string} address the address to withdraw to
2403
+ * @param {string} [tag]
2404
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2405
+ * @param {string} [params.accountIndex] account index
2406
+ * @param {string} [params.apiKeyIndex] api key index
2407
+ * @param {int} [params.routeType] wallet type, 0: perp, 1: spot, default is 0
2408
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/?id=transaction-structure}
2409
+ */
2410
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
2411
+ let apiKeyIndex = undefined;
2412
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'withdraw', 'apiKeyIndex', 'api_key_index');
2413
+ if (apiKeyIndex === undefined) {
2414
+ throw new ArgumentsRequired(this.id + ' withdraw() requires an apiKeyIndex parameter');
2415
+ }
2416
+ await this.loadMarkets();
2417
+ let accountIndex = undefined;
2418
+ [accountIndex, params] = await this.handleAccountIndex(params, 'withdraw', 'accountIndex', 'account_index');
2419
+ const currency = this.currency(code);
2420
+ if (currency['code'] === 'USDC') {
2421
+ amount = this.parseToInt(Precise.stringMul(this.pow('10', '6'), this.currencyToPrecision(code, amount)));
2422
+ }
2423
+ else if (currency['code'] === 'ETH') {
2424
+ amount = this.parseToInt(Precise.stringMul(this.pow('10', '8'), this.currencyToPrecision(code, amount)));
2425
+ }
2426
+ else {
2427
+ throw new ExchangeError(this.id + ' withdraw() only supports USDC and ETH transfers');
2428
+ }
2429
+ const routeType = this.safeInteger(params, 'routeType', 0); // 0: perp, 1: spot
2430
+ params = this.omit(params, 'routeType');
2431
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2432
+ const signRaw = {
2433
+ 'asset_index': this.parseToInt(currency['id']),
2434
+ 'route_type': routeType,
2435
+ 'amount': amount,
2436
+ 'nonce': nonce,
2437
+ 'api_key_index': apiKeyIndex,
2438
+ 'account_index': accountIndex,
2439
+ };
2440
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2441
+ const [txType, txInfo] = this.lighterSignWithdraw(signer, this.extend(signRaw, params));
2442
+ const request = {
2443
+ 'tx_type': txType,
2444
+ 'tx_info': txInfo,
2445
+ };
2446
+ const response = await this.publicPostSendTx(request);
2447
+ return this.parseTransaction(response);
2448
+ }
2449
+ /**
2450
+ * @method
2451
+ * @name lighter#fetchMyTrades
2452
+ * @description fetch all trades made by the user
2453
+ * @see https://apidocs.lighter.xyz/reference/trades
2454
+ * @param {string} [symbol] unified market symbol
2455
+ * @param {int} [since] the earliest time in ms to fetch trades for
2456
+ * @param {int} [limit] the maximum number of trades structures to retrieve
2457
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2458
+ * @param {string} [params.accountIndex] account index
2459
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=trade-structure}
2460
+ */
2461
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2462
+ await this.loadMarkets();
2463
+ let accountIndex = undefined;
2464
+ [accountIndex, params] = await this.handleAccountIndex(params, 'fetchMyTrades', 'accountIndex', 'account_index');
2465
+ let apiKeyIndex = undefined;
2466
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'fetchMyTrades', 'apiKeyIndex', 'api_key_index');
2467
+ if (apiKeyIndex === undefined) {
2468
+ throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires an apiKeyIndex parameter');
2469
+ }
2470
+ await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2471
+ const request = {
2472
+ 'sort_by': 'block_height',
2473
+ 'limit': 100,
2474
+ 'account_index': accountIndex,
2475
+ };
2476
+ if (limit !== undefined) {
2477
+ request['limit'] = Math.min(limit, 100);
2478
+ }
2479
+ let market = undefined;
2480
+ if (symbol !== undefined) {
2481
+ market = this.market(symbol);
2482
+ request['market_id'] = market['id'];
2483
+ }
2484
+ const response = await this.privateGetTrades(this.extend(request, params));
2485
+ //
2486
+ // {
2487
+ // "code": 200,
2488
+ // "trades": [
2489
+ // {
2490
+ // "trade_id": 17609,
2491
+ // "tx_hash": "99ffeaa3899fbaa51043840ddf762fd18c182a33b5125092105bee57af11fab04edf5fd90e969abd",
2492
+ // "type": "trade",
2493
+ // "market_id": 0,
2494
+ // "size": "10.2304",
2495
+ // "price": "2958.75",
2496
+ // "usd_amount": "30269.196000",
2497
+ // "ask_id": 281474977339869,
2498
+ // "bid_id": 562949952870533,
2499
+ // "ask_client_id": 0,
2500
+ // "bid_client_id": 0,
2501
+ // "ask_account_id": 20,
2502
+ // "bid_account_id": 1077,
2503
+ // "is_maker_ask": true,
2504
+ // "block_height": 102070,
2505
+ // "timestamp": 1766386112741,
2506
+ // "taker_position_size_before": "0.0000",
2507
+ // "taker_entry_quote_before": "0.000000",
2508
+ // "taker_position_sign_changed": true,
2509
+ // "maker_position_size_before": "-1856.8547",
2510
+ // "maker_entry_quote_before": "5491685.069325",
2511
+ // "maker_initial_margin_fraction_before": 500
2512
+ // }
2513
+ // ]
2514
+ // }
2515
+ //
2516
+ const data = this.safeList(response, 'trades', []);
2517
+ for (let i = 0; i < data.length; i++) {
2518
+ data[i]['account_index'] = accountIndex;
2519
+ }
2520
+ return this.parseTrades(data, market, since, limit, params);
2521
+ }
2522
+ parseTrade(trade, market = undefined) {
2523
+ //
2524
+ // {
2525
+ // "trade_id": 17609,
2526
+ // "tx_hash": "99ffeaa3899fbaa51043840ddf762fd18c182a33b5125092105bee57af11fab04edf5fd90e969abd",
2527
+ // "type": "trade",
2528
+ // "market_id": 0,
2529
+ // "size": "10.2304",
2530
+ // "price": "2958.75",
2531
+ // "usd_amount": "30269.196000",
2532
+ // "ask_id": 281474977339869,
2533
+ // "bid_id": 562949952870533,
2534
+ // "ask_client_id": 0,
2535
+ // "bid_client_id": 0,
2536
+ // "ask_account_id": 20,
2537
+ // "bid_account_id": 1077,
2538
+ // "is_maker_ask": true,
2539
+ // "block_height": 102070,
2540
+ // "timestamp": 1766386112741,
2541
+ // "taker_position_size_before": "0.0000",
2542
+ // "taker_entry_quote_before": "0.000000",
2543
+ // "taker_position_sign_changed": true,
2544
+ // "maker_position_size_before": "-1856.8547",
2545
+ // "maker_entry_quote_before": "5491685.069325",
2546
+ // "maker_initial_margin_fraction_before": 500
2547
+ // }
2548
+ //
2549
+ const marketId = this.safeString(trade, 'market_id');
2550
+ market = this.safeMarket(marketId, market);
2551
+ const timestamp = this.safeInteger(trade, 'timestamp');
2552
+ const accountIndex = this.safeString(trade, 'account_index');
2553
+ const askAccountId = this.safeString(trade, 'ask_account_id');
2554
+ const bidAccountId = this.safeString(trade, 'bid_account_id');
2555
+ const isMakerAsk = this.safeBool(trade, 'is_maker_ask');
2556
+ let side = undefined;
2557
+ let orderId = undefined;
2558
+ if (accountIndex !== undefined) {
2559
+ if (accountIndex === askAccountId) {
2560
+ side = 'sell';
2561
+ orderId = this.safeString(trade, 'ask_id');
2562
+ }
2563
+ else if (accountIndex === bidAccountId) {
2564
+ side = 'buy';
2565
+ orderId = this.safeString(trade, 'bid_id');
2566
+ }
2567
+ }
2568
+ let takerOrMaker = undefined;
2569
+ if (side !== undefined && isMakerAsk !== undefined) {
2570
+ const isMaker = (side === 'sell') ? isMakerAsk : !isMakerAsk;
2571
+ takerOrMaker = isMaker ? 'maker' : 'taker';
2572
+ }
2573
+ return this.safeTrade({
2574
+ 'info': trade,
2575
+ 'id': this.safeString(trade, 'trade_id'),
2576
+ 'timestamp': timestamp,
2577
+ 'datetime': this.iso8601(timestamp),
2578
+ 'symbol': market['symbol'],
2579
+ 'order': orderId,
2580
+ 'type': this.safeString(trade, 'type'),
2581
+ 'side': side,
2582
+ 'takerOrMaker': takerOrMaker,
2583
+ 'price': this.safeString(trade, 'price'),
2584
+ 'amount': this.safeString(trade, 'size'),
2585
+ 'cost': this.safeString(trade, 'usd_amount'),
2586
+ 'fee': undefined,
2587
+ }, market);
2588
+ }
2589
+ /**
2590
+ * @method
2591
+ * @name lighter#setLeverage
2592
+ * @description set the level of leverage for a market
2593
+ * @param {float} leverage the rate of leverage
2594
+ * @param {string} symbol unified market symbol
2595
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2596
+ * @param {string} [params.accountIndex] account index
2597
+ * @param {string} [params.apiKeyIndex] api key index
2598
+ * @param {string} [params.marginMode] margin mode, 'cross' or 'isolated'
2599
+ * @returns {object} response from the exchange
2600
+ */
2601
+ async setLeverage(leverage, symbol = undefined, params = {}) {
2602
+ if (symbol === undefined) {
2603
+ throw new ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
2604
+ }
2605
+ let marginMode = undefined;
2606
+ [marginMode, params] = this.handleOptionAndParams2(params, 'setLeverage', 'marginMode', 'margin_mode');
2607
+ if (marginMode === undefined) {
2608
+ throw new ArgumentsRequired(this.id + ' setLeverage() requires an marginMode parameter');
2609
+ }
2610
+ return await this.modifyLeverageAndMarginMode(leverage, marginMode, symbol, params);
2611
+ }
2612
+ /**
2613
+ * @method
2614
+ * @name lighter#setMarginMode
2615
+ * @description set margin mode to 'cross' or 'isolated'
2616
+ * @param {string} marginMode 'cross' or 'isolated'
2617
+ * @param {string} symbol unified market symbol
2618
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2619
+ * @param {string} [params.accountIndex] account index
2620
+ * @param {string} [params.apiKeyIndex] api key index
2621
+ * @param {int} [params.leverage] required leverage
2622
+ * @returns {object} response from the exchange
2623
+ */
2624
+ async setMarginMode(marginMode, symbol = undefined, params = {}) {
2625
+ if (marginMode === undefined) {
2626
+ throw new ArgumentsRequired(this.id + ' setMarginMode() requires an marginMode parameter');
2627
+ }
2628
+ let leverage = undefined;
2629
+ [leverage, params] = this.handleOptionAndParams(params, 'setMarginMode', 'leverage', 'leverage');
2630
+ if (leverage === undefined) {
2631
+ throw new ArgumentsRequired(this.id + ' setMarginMode() requires an leverage parameter');
2632
+ }
2633
+ return await this.modifyLeverageAndMarginMode(leverage, marginMode, symbol, params);
2634
+ }
2635
+ async modifyLeverageAndMarginMode(leverage, marginMode, symbol = undefined, params = {}) {
2636
+ if ((marginMode !== 'cross') && (marginMode !== 'isolated')) {
2637
+ throw new BadRequest(this.id + ' modifyLeverageAndMarginMode() requires a marginMode parameter that must be either cross or isolated');
2638
+ }
2639
+ let apiKeyIndex = undefined;
2640
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'modifyLeverageAndMarginMode', 'apiKeyIndex', 'api_key_index');
2641
+ if (apiKeyIndex === undefined) {
2642
+ throw new ArgumentsRequired(this.id + ' modifyLeverageAndMarginMode() requires an apiKeyIndex parameter');
2643
+ }
2644
+ if (symbol === undefined) {
2645
+ throw new ArgumentsRequired(this.id + ' modifyLeverageAndMarginMode() requires a symbol argument');
2646
+ }
2647
+ await this.loadMarkets();
2648
+ let accountIndex = undefined;
2649
+ [accountIndex, params] = await this.handleAccountIndex(params, 'modifyLeverageAndMarginMode', 'accountIndex', 'account_index');
2650
+ const market = this.market(symbol);
2651
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2652
+ const signRaw = {
2653
+ 'market_index': this.parseToInt(market['id']),
2654
+ 'initial_margin_fraction': this.parseToInt(10000 / leverage),
2655
+ 'margin_mode': (marginMode === 'cross') ? 0 : 1,
2656
+ 'nonce': nonce,
2657
+ 'api_key_index': apiKeyIndex,
2658
+ 'account_index': accountIndex,
2659
+ };
2660
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2661
+ const [txType, txInfo] = this.lighterSignUpdateLeverage(signer, this.extend(signRaw, params));
2662
+ const request = {
2663
+ 'tx_type': txType,
2664
+ 'tx_info': txInfo,
2665
+ };
2666
+ return await this.publicPostSendTx(request);
2667
+ }
2668
+ /**
2669
+ * @method
2670
+ * @name lighter#cancelOrder
2671
+ * @description cancels an open order
2672
+ * @param {string} id order id
2673
+ * @param {string} symbol unified symbol of the market the order was made in
2674
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2675
+ * @param {string} [params.accountIndex] account index
2676
+ * @param {string} [params.apiKeyIndex] api key index
2677
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
2678
+ */
2679
+ async cancelOrder(id, symbol = undefined, params = {}) {
2680
+ let apiKeyIndex = undefined;
2681
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelOrder', 'apiKeyIndex', 'api_key_index');
2682
+ if (apiKeyIndex === undefined) {
2683
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires an apiKeyIndex parameter');
2684
+ }
2685
+ if (symbol === undefined) {
2686
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
2687
+ }
2688
+ const clientOrderId = this.safeString2(params, 'client_order_index', 'clientOrderId');
2689
+ params = this.omit(params, ['client_order_index', 'clientOrderId']);
2690
+ await this.loadMarkets();
2691
+ let accountIndex = undefined;
2692
+ [accountIndex, params] = await this.handleAccountIndex(params, 'cancelOrder', 'accountIndex', 'account_index');
2693
+ const market = this.market(symbol);
2694
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2695
+ const signRaw = {
2696
+ 'market_index': this.parseToInt(market['id']),
2697
+ 'nonce': nonce,
2698
+ 'api_key_index': apiKeyIndex,
2699
+ 'account_index': accountIndex,
2700
+ };
2701
+ if (clientOrderId !== undefined) {
2702
+ signRaw['order_index'] = this.parseToInt(clientOrderId);
2703
+ }
2704
+ else if (id !== undefined) {
2705
+ signRaw['order_index'] = this.parseToInt(id);
2706
+ }
2707
+ else {
2708
+ throw new ArgumentsRequired(this.id + ' cancelOrder requires order id or client order id');
2709
+ }
2710
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2711
+ const [txType, txInfo] = this.lighterSignCancelOrder(signer, this.extend(signRaw, params));
2712
+ const request = {
2713
+ 'tx_type': txType,
2714
+ 'tx_info': txInfo,
2715
+ };
2716
+ const response = await this.publicPostSendTx(request);
2717
+ return this.parseOrder(response, market);
2718
+ }
2719
+ /**
2720
+ * @method
2721
+ * @name lighter#cancelAllOrders
2722
+ * @description cancel all open orders
2723
+ * @param {string} [symbol] unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
2724
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2725
+ * @param {string} [params.accountIndex] account index
2726
+ * @param {string} [params.apiKeyIndex] api key index
2727
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
2728
+ */
2729
+ async cancelAllOrders(symbol = undefined, params = {}) {
2730
+ let apiKeyIndex = undefined;
2731
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelAllOrders', 'apiKeyIndex', 'api_key_index');
2732
+ if (apiKeyIndex === undefined) {
2733
+ throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires an apiKeyIndex parameter');
2734
+ }
2735
+ let accountIndex = undefined;
2736
+ [accountIndex, params] = await this.handleAccountIndex(params, 'cancelAllOrders', 'accountIndex', 'account_index');
2737
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex, params);
2738
+ const signRaw = {
2739
+ 'time_in_force': 0,
2740
+ 'time': 0,
2741
+ 'nonce': nonce,
2742
+ 'api_key_index': apiKeyIndex,
2743
+ 'account_index': accountIndex,
2744
+ };
2745
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2746
+ const [txType, txInfo] = this.lighterSignCancelAllOrders(signer, this.extend(signRaw, params));
2747
+ const request = {
2748
+ 'tx_type': txType,
2749
+ 'tx_info': txInfo,
2750
+ };
2751
+ const response = await this.publicPostSendTx(request);
2752
+ return this.parseOrders([response]);
2753
+ }
2754
+ /**
2755
+ * @method
2756
+ * @name lighter#cancelAllOrdersAfter
2757
+ * @description dead man's switch, cancel all orders after the given timeout
2758
+ * @param {number} timeout time in milliseconds, 0 represents cancel the timer
2759
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2760
+ * @returns {object} the api result
2761
+ */
2762
+ async cancelAllOrdersAfter(timeout, params = {}) {
2763
+ if ((timeout < 300000) || (timeout > 1296000000)) {
2764
+ throw new BadRequest(this.id + ' timeout should be between 5 minutes and 15 days.');
2765
+ }
2766
+ let apiKeyIndex = undefined;
2767
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'cancelOrder', 'apiKeyIndex', 'api_key_index');
2768
+ if (apiKeyIndex === undefined) {
2769
+ throw new ArgumentsRequired(this.id + ' cancelAllOrdersAfter() requires an apiKeyIndex parameter');
2770
+ }
2771
+ let accountIndex = undefined;
2772
+ [accountIndex, params] = await this.handleAccountIndex(params, 'cancelAllOrdersAfter', 'accountIndex', 'account_index');
2773
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2774
+ const signRaw = {
2775
+ 'time_in_force': 1,
2776
+ 'time': this.milliseconds() + timeout,
2777
+ 'nonce': nonce,
2778
+ 'api_key_index': apiKeyIndex,
2779
+ 'account_index': accountIndex,
2780
+ };
2781
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2782
+ const [txType, txInfo] = this.lighterSignCancelAllOrders(signer, this.extend(signRaw, params));
2783
+ const request = {
2784
+ 'tx_type': txType,
2785
+ 'tx_info': txInfo,
2786
+ };
2787
+ const response = await this.publicPostSendTx(request);
2788
+ return response;
2789
+ }
2790
+ /**
2791
+ * @method
2792
+ * @name lighter#addMargin
2793
+ * @description add margin
2794
+ * @param {string} symbol unified market symbol
2795
+ * @param {float} amount amount of margin to add
2796
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2797
+ * @returns {object} a [margin structure]{@link https://docs.ccxt.com/?id=add-margin-structure}
2798
+ */
2799
+ async addMargin(symbol, amount, params = {}) {
2800
+ const request = {
2801
+ 'direction': 1,
2802
+ };
2803
+ return await this.setMargin(symbol, amount, this.extend(request, params));
2804
+ }
2805
+ /**
2806
+ * @method
2807
+ * @name lighter#reduceMargin
2808
+ * @description remove margin from a position
2809
+ * @param {string} symbol unified market symbol
2810
+ * @param {float} amount the amount of margin to remove
2811
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2812
+ * @returns {object} a [margin structure]{@link https://docs.ccxt.com/?id=reduce-margin-structure}
2813
+ */
2814
+ async reduceMargin(symbol, amount, params = {}) {
2815
+ const request = {
2816
+ 'direction': 0,
2817
+ };
2818
+ return await this.setMargin(symbol, amount, this.extend(request, params));
2819
+ }
2820
+ /**
2821
+ * @method
2822
+ * @name lighter#setMargin
2823
+ * @description Either adds or reduces margin in an isolated position in order to set the margin to a specific value
2824
+ * @param {string} symbol unified market symbol of the market to set margin in
2825
+ * @param {float} amount the amount to set the margin to
2826
+ * @param {object} [params] parameters specific to the bingx api endpoint
2827
+ * @param {string} [params.accountIndex] account index
2828
+ * @param {string} [params.apiKeyIndex] api key index
2829
+ * @returns {object} A [margin structure]{@link https://docs.ccxt.com/?id=add-margin-structure}
2830
+ */
2831
+ async setMargin(symbol, amount, params = {}) {
2832
+ let apiKeyIndex = undefined;
2833
+ [apiKeyIndex, params] = this.handleOptionAndParams2(params, 'setMargin', 'apiKeyIndex', 'api_key_index');
2834
+ if (apiKeyIndex === undefined) {
2835
+ throw new ArgumentsRequired(this.id + ' setMargin() requires an apiKeyIndex parameter');
2836
+ }
2837
+ const direction = this.safeInteger(params, 'direction'); // 1 increase margin 0 decrease margin
2838
+ if (direction === undefined) {
2839
+ throw new ArgumentsRequired(this.id + ' setMargin() requires a direction parameter either 1 (increase margin) or 0 (decrease margin)');
2840
+ }
2841
+ if (!this.inArray(direction, [0, 1])) {
2842
+ throw new ArgumentsRequired(this.id + ' setMargin() requires a direction parameter either 1 (increase margin) or 0 (decrease margin)');
2843
+ }
2844
+ if (symbol === undefined) {
2845
+ throw new ArgumentsRequired(this.id + ' setMargin() requires a symbol argument');
2846
+ }
2847
+ await this.loadMarkets();
2848
+ let accountIndex = undefined;
2849
+ [accountIndex, params] = await this.handleAccountIndex(params, 'setMargin', 'accountIndex', 'account_index');
2850
+ const market = this.market(symbol);
2851
+ const nonce = await this.fetchNonce(accountIndex, apiKeyIndex);
2852
+ const signRaw = {
2853
+ 'market_index': this.parseToInt(market['id']),
2854
+ 'usdc_amount': this.parseToInt(Precise.stringMul(this.pow('10', '6'), this.currencyToPrecision('USDC', amount))),
2855
+ 'direction': direction,
2856
+ 'nonce': nonce,
2857
+ 'api_key_index': apiKeyIndex,
2858
+ 'account_index': accountIndex,
2859
+ };
2860
+ const signer = await this.loadAccount(this.options['chainId'], this.privateKey, apiKeyIndex, accountIndex, params);
2861
+ const [txType, txInfo] = this.lighterSignUpdateMargin(signer, this.extend(signRaw, params));
2862
+ const request = {
2863
+ 'tx_type': txType,
2864
+ 'tx_info': txInfo,
2865
+ };
2866
+ const response = await this.publicPostSendTx(request);
2867
+ return this.parseMarginModification(response, market);
2868
+ }
2869
+ parseMarginModification(data, market = undefined) {
2870
+ const timestamp = this.safeInteger(data, 'predicted_execution_time_ms');
2871
+ return {
2872
+ 'info': data,
2873
+ 'symbol': this.safeString(market, 'symbol'),
2874
+ 'type': undefined,
2875
+ 'marginMode': undefined,
2876
+ 'amount': undefined,
2877
+ 'total': undefined,
2878
+ 'code': 'USDC',
2879
+ 'status': undefined,
2880
+ 'timestamp': timestamp,
2881
+ 'datetime': this.iso8601(timestamp),
2882
+ };
2883
+ }
2884
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2885
+ let url = undefined;
2886
+ if (api === 'root') {
2887
+ url = this.implodeHostname(this.urls['api']['public']);
2888
+ }
2889
+ else {
2890
+ url = this.implodeHostname(this.urls['api'][api]) + '/api/' + this.version + '/' + path;
2891
+ }
2892
+ if (api === 'private') {
2893
+ headers = {
2894
+ 'Authorization': this.createAuth(params),
2895
+ };
2896
+ }
2897
+ if (Object.keys(params).length) {
2898
+ if (method === 'POST') {
2899
+ headers = {
2900
+ 'Content-Type': 'multipart/form-data',
2901
+ };
2902
+ body = params;
2903
+ }
2904
+ else {
2905
+ url += '?' + this.rawencode(params);
2906
+ }
2907
+ }
2908
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2909
+ }
2910
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2911
+ if (!response) {
2912
+ return undefined; // fallback to default error handler
2913
+ }
2914
+ //
2915
+ // {
2916
+ // "code": "200",
2917
+ // "message": "string"
2918
+ // }
2919
+ //
2920
+ const code = this.safeString(response, 'code');
2921
+ const message = this.safeString(response, 'msg');
2922
+ if (code !== undefined && code !== '0' && code !== '200') {
2923
+ const feedback = this.id + ' ' + body;
2924
+ this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
2925
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
2926
+ throw new ExchangeError(feedback); // unknown message
2927
+ }
2928
+ return undefined;
2929
+ }
2930
+ }