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