ccxt 4.5.39 → 4.5.41

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