ccxt 4.5.40 → 4.5.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/lighter.js +11 -0
  5. package/dist/cjs/src/ascendex.js +73 -1
  6. package/dist/cjs/src/base/Exchange.js +149 -17
  7. package/dist/cjs/src/base/functions/generic.js +1 -0
  8. package/dist/cjs/src/base/functions/io.js +160 -0
  9. package/dist/cjs/src/base/functions.js +6 -0
  10. package/dist/cjs/src/base/ws/Client.js +1 -0
  11. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  12. package/dist/cjs/src/binance.js +1 -0
  13. package/dist/cjs/src/bingx.js +13 -3
  14. package/dist/cjs/src/bitmex.js +20 -0
  15. package/dist/cjs/src/blofin.js +2 -2
  16. package/dist/cjs/src/bybit.js +1 -1
  17. package/dist/cjs/src/coinspot.js +7 -2
  18. package/dist/cjs/src/delta.js +1 -1
  19. package/dist/cjs/src/gate.js +11 -4
  20. package/dist/cjs/src/gemini.js +76 -1
  21. package/dist/cjs/src/htx.js +2 -2
  22. package/dist/cjs/src/hyperliquid.js +20 -7
  23. package/dist/cjs/src/independentreserve.js +7 -7
  24. package/dist/cjs/src/kraken.js +1 -1
  25. package/dist/cjs/src/krakenfutures.js +96 -5
  26. package/dist/cjs/src/kucoin.js +3 -3
  27. package/dist/cjs/src/kucoinfutures.js +1 -1
  28. package/dist/cjs/src/lighter.js +2931 -0
  29. package/dist/cjs/src/mexc.js +0 -1
  30. package/dist/cjs/src/phemex.js +1 -1
  31. package/dist/cjs/src/pro/binance.js +2 -2
  32. package/dist/cjs/src/pro/bingx.js +215 -2
  33. package/dist/cjs/src/pro/bitget.js +1 -0
  34. package/dist/cjs/src/pro/defx.js +1 -1
  35. package/dist/cjs/src/pro/kucoinfutures.js +1 -1
  36. package/dist/cjs/src/pro/lighter.js +787 -0
  37. package/dist/cjs/src/pro/mexc.js +1 -1
  38. package/dist/cjs/src/pro/paradex.js +1 -1
  39. package/dist/cjs/src/static_dependencies/ethers/abi-coder.js +1 -0
  40. package/dist/cjs/src/static_dependencies/ethers/address/address.js +1 -0
  41. package/dist/cjs/src/static_dependencies/ethers/coders/abstract-coder.js +1 -0
  42. package/dist/cjs/src/static_dependencies/ethers/coders/address.js +1 -0
  43. package/dist/cjs/src/static_dependencies/ethers/coders/array.js +1 -0
  44. package/dist/cjs/src/static_dependencies/ethers/coders/bytes.js +1 -0
  45. package/dist/cjs/src/static_dependencies/ethers/coders/fixed-bytes.js +1 -0
  46. package/dist/cjs/src/static_dependencies/ethers/coders/number.js +1 -0
  47. package/dist/cjs/src/static_dependencies/ethers/fragments.js +1 -0
  48. package/dist/cjs/src/static_dependencies/ethers/index.js +1 -0
  49. package/dist/cjs/src/static_dependencies/ethers/interface.js +1 -0
  50. package/dist/cjs/src/static_dependencies/ethers/typed.js +1 -0
  51. package/dist/cjs/src/static_dependencies/ethers/utils/index.js +1 -0
  52. package/dist/cjs/src/whitebit.js +118 -16
  53. package/dist/cjs/src/woo.js +1 -1
  54. package/js/ccxt.d.ts +8 -2
  55. package/js/ccxt.js +6 -2
  56. package/js/src/abstract/gemini.d.ts +27 -0
  57. package/js/src/abstract/lighter.d.ts +53 -0
  58. package/js/src/abstract/lighter.js +11 -0
  59. package/js/src/ascendex.d.ts +12 -1
  60. package/js/src/ascendex.js +73 -1
  61. package/js/src/base/Exchange.d.ts +18 -6
  62. package/js/src/base/Exchange.js +154 -21
  63. package/js/src/base/functions/generic.js +1 -0
  64. package/js/src/base/functions/io.d.ts +32 -0
  65. package/js/src/base/functions/io.js +137 -0
  66. package/js/src/base/functions.d.ts +1 -0
  67. package/js/src/base/functions.js +1 -0
  68. package/js/src/binance.d.ts +1 -0
  69. package/js/src/binance.js +1 -0
  70. package/js/src/bingx.js +13 -3
  71. package/js/src/bitmex.js +20 -0
  72. package/js/src/blofin.js +2 -2
  73. package/js/src/bybit.js +1 -1
  74. package/js/src/coinspot.js +7 -2
  75. package/js/src/delta.js +1 -1
  76. package/js/src/gate.d.ts +1 -0
  77. package/js/src/gate.js +11 -4
  78. package/js/src/gemini.d.ts +11 -0
  79. package/js/src/gemini.js +76 -1
  80. package/js/src/htx.js +2 -2
  81. package/js/src/hyperliquid.js +20 -7
  82. package/js/src/independentreserve.js +7 -7
  83. package/js/src/kraken.js +1 -1
  84. package/js/src/krakenfutures.d.ts +1 -1
  85. package/js/src/krakenfutures.js +96 -5
  86. package/js/src/kucoin.d.ts +3 -3
  87. package/js/src/kucoin.js +3 -3
  88. package/js/src/kucoinfutures.js +1 -1
  89. package/js/src/lighter.d.ts +424 -0
  90. package/js/src/lighter.js +2930 -0
  91. package/js/src/mexc.js +0 -1
  92. package/js/src/phemex.js +1 -1
  93. package/js/src/pro/binance.js +2 -2
  94. package/js/src/pro/bingx.d.ts +17 -1
  95. package/js/src/pro/bingx.js +216 -3
  96. package/js/src/pro/bitget.js +1 -0
  97. package/js/src/pro/defx.js +1 -1
  98. package/js/src/pro/kucoinfutures.js +1 -1
  99. package/js/src/pro/lighter.d.ts +161 -0
  100. package/js/src/pro/lighter.js +786 -0
  101. package/js/src/pro/mexc.js +1 -1
  102. package/js/src/pro/paradex.js +1 -1
  103. package/js/src/whitebit.d.ts +2 -1
  104. package/js/src/whitebit.js +118 -16
  105. package/js/src/woo.js +1 -1
  106. package/package.json +1 -1
@@ -79,8 +79,9 @@ export default class ascendex extends Exchange {
79
79
  'fetchMarkOHLCV': false,
80
80
  'fetchMySettlementHistory': false,
81
81
  'fetchOHLCV': true,
82
- 'fetchOpenInterest': false,
82
+ 'fetchOpenInterest': 'emulated',
83
83
  'fetchOpenInterestHistory': false,
84
+ 'fetchOpenInterests': true,
84
85
  'fetchOpenOrders': true,
85
86
  'fetchOption': false,
86
87
  'fetchOptionChain': false,
@@ -3602,6 +3603,77 @@ export default class ascendex extends Exchange {
3602
3603
  const leverages = this.safeList(data, 'contracts', []);
3603
3604
  return this.parseLeverages(leverages, symbols, 'symbol');
3604
3605
  }
3606
+ /**
3607
+ * @method
3608
+ * @name ascendex#fetchOpenInterests
3609
+ * @description Retrieves the open interest for a list of symbols
3610
+ * @see https://ascendex.github.io/ascendex-futures-pro-api-v2/#futures-pricing-data
3611
+ * @param {string[]} [symbols] a list of unified CCXT market symbols
3612
+ * @param {object} [params] exchange specific parameters
3613
+ * @returns {object[]} a list of [open interest structures]{@link https://docs.ccxt.com/?id=open-interest-structure}
3614
+ */
3615
+ async fetchOpenInterests(symbols = undefined, params = {}) {
3616
+ await this.loadMarkets();
3617
+ const request = {};
3618
+ let response = undefined;
3619
+ response = await this.v2PublicGetFuturesPricingData(this.extend(request, params));
3620
+ //
3621
+ // {
3622
+ // code: '0',
3623
+ // data: {
3624
+ // contracts: [
3625
+ // {
3626
+ // time: '1772138885616',
3627
+ // symbol: 'ZIL-PERP',
3628
+ // markPrice: '0.004167783',
3629
+ // indexPrice: '0.004168',
3630
+ // lastPrice: '0.00416',
3631
+ // openInterest: '7685003',
3632
+ // fundingRate: '0.0003',
3633
+ // nextFundingTime: '1772139600000'
3634
+ // },
3635
+ // ]
3636
+ // collaterals: [
3637
+ // { asset: 'TAO', referencePrice: '182.15' },
3638
+ // ...
3639
+ // ]
3640
+ // }
3641
+ // }
3642
+ //
3643
+ symbols = this.marketSymbols(symbols);
3644
+ const data = this.safeDict(response, 'data', {});
3645
+ const contracts = this.safeList(data, 'contracts', []);
3646
+ return this.parseOpenInterests(contracts, symbols);
3647
+ }
3648
+ parseOpenInterest(interest, market = undefined) {
3649
+ //
3650
+ // fetchOpenInterests
3651
+ //
3652
+ // {
3653
+ // time: '1772138885616',
3654
+ // symbol: 'ZIL-PERP',
3655
+ // markPrice: '0.004167783',
3656
+ // indexPrice: '0.004168',
3657
+ // lastPrice: '0.00416',
3658
+ // openInterest: '7685003',
3659
+ // fundingRate: '0.0003',
3660
+ // nextFundingTime: '1772139600000'
3661
+ // }
3662
+ //
3663
+ const marketId = this.safeString(interest, 'symbol');
3664
+ const timestamp = this.safeInteger(interest, 'time');
3665
+ const openInterest = this.safeNumber(interest, 'openInterest');
3666
+ return this.safeOpenInterest({
3667
+ 'info': interest,
3668
+ 'symbol': this.safeSymbol(marketId, market, undefined, 'swap'),
3669
+ 'baseVolume': openInterest,
3670
+ 'quoteVolume': undefined,
3671
+ 'openInterestAmount': openInterest,
3672
+ 'openInterestValue': undefined,
3673
+ 'timestamp': timestamp,
3674
+ 'datetime': this.iso8601(timestamp),
3675
+ }, market);
3676
+ }
3605
3677
  parseLeverage(leverage, market = undefined) {
3606
3678
  const marketId = this.safeString(leverage, 'symbol');
3607
3679
  const leverageValue = this.safeInteger(leverage, 'leverage');
@@ -208,7 +208,6 @@ export default class Exchange {
208
208
  isNode: boolean;
209
209
  extend: (...args: any[]) => any;
210
210
  clone: (x: any) => any;
211
- flatten: (x: any[], out?: any[]) => any[];
212
211
  unique: (x: any[]) => any[];
213
212
  indexBy: (x: Dictionary<any>, k: IndexType, out?: Dictionary<any>) => Dictionary<any>;
214
213
  indexBySafe: (x: Dictionary<any>, k: IndexType, out?: Dictionary<any>) => Dictionary<any>;
@@ -243,8 +242,6 @@ export default class Exchange {
243
242
  implodeParams: (string: string, params: any[] | Dictionary<any>) => string;
244
243
  extractParams: (string: string) => string[];
245
244
  json: (data: any, params?: any) => string;
246
- vwap: typeof functions.vwap;
247
- merge: (target: Dictionary<any>, ...args: any) => Dictionary<any>;
248
245
  binaryConcat: typeof import("../static_dependencies/noble-curves/abstract/utils.js").concatBytes;
249
246
  hash: (request: import("../static_dependencies/noble-hashes/utils.js").Input, hash: {
250
247
  (message: import("../static_dependencies/noble-hashes/utils.js").Input): Uint8Array;
@@ -270,8 +267,6 @@ export default class Exchange {
270
267
  safeStringUpper: (o: any, k: IndexType, $default?: string) => string;
271
268
  safeTimestamp: (o: any, k: IndexType, $default?: number) => number;
272
269
  binaryConcatArray: (arr: any[]) => Uint8Array;
273
- uuidv1: () => string;
274
- numberToLE: (n: number, padding: number) => Uint8Array;
275
270
  ymdhms: (timestamp: any, infix?: string) => string;
276
271
  yymmdd: (timestamp: any, infix?: string) => string;
277
272
  stringToBase64: (string: string) => string;
@@ -290,7 +285,6 @@ export default class Exchange {
290
285
  safeStringLower2: (o: any, k1: IndexType, k2: IndexType, $default?: string) => string;
291
286
  safeStringUpper2: (o: any, k1: IndexType, k2: IndexType, $default?: string) => string;
292
287
  isEmpty: (object: any[] | Dictionary<any>) => boolean;
293
- ordered: (x: any[] | Dictionary<any>) => any[] | Dictionary<any>;
294
288
  filterBy: (x: Dictionary<any>, k: string, value?: any, out?: Dictionary<any>[]) => Dictionary<any>[];
295
289
  uuid16: (a?: any) => string;
296
290
  urlencodeWithArrayRepeat: (object: object) => string;
@@ -313,7 +307,12 @@ export default class Exchange {
313
307
  crc32: typeof functions.crc32;
314
308
  packb: typeof functions.packb;
315
309
  urlencodeBase64: (payload: string | Uint8Array) => string;
310
+ readFile: typeof functions.readFile;
311
+ writeFile: typeof functions.writeFile;
312
+ existsFile: typeof functions.existsFile;
313
+ getTempDir: typeof functions.getTempDir;
316
314
  constructor(userConfig?: ConstructorArgs);
315
+ loadExchangeSpecificFiles(): Promise<void>;
317
316
  uuid5(namespace: string, name: string): string;
318
317
  encodeURIComponent(...args: any[]): string;
319
318
  checkRequiredVersion(requiredVersion: any, error?: boolean): boolean;
@@ -413,6 +412,19 @@ export default class Exchange {
413
412
  binaryLength(binary: Uint8Array): number;
414
413
  lockId(): any;
415
414
  unlockId(): any;
415
+ loadLighterLibrary(libraryPath: any, chainId: any, privateKey: any, apiKeyIndex: any, accountIndex: any): Promise<{}>;
416
+ lighterSignCreateGroupedOrders(signer: any, request: any): any[];
417
+ lighterSignCreateOrder(signer: any, request: any): any[];
418
+ checkLighterSignedError(result: any): void;
419
+ lighterSignCancelOrder(signer: any, request: any): any[];
420
+ lighterSignWithdraw(signer: any, request: any): any[];
421
+ lighterSignCreateSubAccount(signer: any, request: any): any[];
422
+ lighterSignCancelAllOrders(signer: any, request: any): any[];
423
+ lighterSignModifyOrder(signer: any, request: any): any[];
424
+ lighterSignTransfer(signer: any, request: any): any[];
425
+ lighterSignUpdateLeverage(signer: any, request: any): any[];
426
+ lighterCreateAuthToken(signer: any, request: any): string;
427
+ lighterSignUpdateMargin(signer: any, request: any): any[];
416
428
  describe(): any;
417
429
  safeBoolN(dictionaryOrList: any, keys: IndexType[], defaultValue?: boolean): boolean | undefined;
418
430
  safeBool2(dictionary: any, key1: IndexType, key2: IndexType, defaultValue?: boolean): boolean | undefined;
@@ -6,11 +6,12 @@
6
6
 
7
7
  // ----------------------------------------------------------------------------
8
8
  import * as functions from './functions.js';
9
- import {
10
- // keys as keysFunc,
11
- // values as valuesFunc,
12
- // inArray as inArrayFunc,
13
- vwap as vwapFunc, } from './functions.js';
9
+ // import {
10
+ // // keys as keysFunc,
11
+ // // values as valuesFunc,
12
+ // // inArray as inArrayFunc,
13
+ // // vwap as vwapFunc,
14
+ // } from './functions.js';
14
15
  // import exceptions from "./errors.js"
15
16
  import { // eslint-disable-line object-curly-newline
16
17
  ExchangeError, BadSymbol, NullResponse, InvalidAddress, InvalidOrder, NotSupported, OperationFailed, BadResponse, AuthenticationError, DDoSProtection, RequestTimeout, NetworkError, InvalidProxySettings, ExchangeNotAvailable, ArgumentsRequired, RateLimitExceeded, BadRequest, UnsubscribeError, ExchangeClosedByUser, } from './errors.js';
@@ -35,9 +36,9 @@ import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
35
36
  import { sha1 } from '../static_dependencies/noble-hashes/sha1.js';
36
37
  import { exportMnemonicAndPrivateKey, deriveHDKeyFromMnemonic } from '../static_dependencies/dydx-v4-client/onboarding.js';
37
38
  import { Long } from '../static_dependencies/dydx-v4-client/helpers.js';
38
- const { isNode, selfIsDefined, deepExtend, extend, clone, flatten, unique, indexBy, sortBy, sortBy2, safeFloat2, groupBy, aggregate, uuid, unCamelCase, precisionFromString, Throttler, capitalize, now, decimalToPrecision, safeValue, safeValue2, safeString, safeString2, seconds, milliseconds, binaryToBase16, numberToBE, base16ToBinary, iso8601, omit, isJsonEncodedObject, safeInteger, sum, omitZero, implodeParams, extractParams, json, merge, binaryConcat, hash,
39
+ const { isNode, selfIsDefined, deepExtend, extend, clone, unique, indexBy, sortBy, sortBy2, safeFloat2, groupBy, aggregate, uuid, unCamelCase, precisionFromString, Throttler, capitalize, now, decimalToPrecision, safeValue, safeValue2, safeString, safeString2, seconds, milliseconds, binaryToBase16, numberToBE, base16ToBinary, iso8601, omit, isJsonEncodedObject, safeInteger, sum, omitZero, implodeParams, extractParams, json, binaryConcat, hash,
39
40
  // ecdsa,
40
- arrayConcat, encode, urlencode, hmac, numberToString, roundTimeframe, parseTimeframe, safeInteger2, safeStringLower, parse8601, yyyymmdd, safeStringUpper, safeTimestamp, binaryConcatArray, uuidv1, numberToLE, ymdhms, stringToBase64, decode, uuid22, safeIntegerProduct2, safeIntegerProduct, safeStringLower2, yymmdd, base58ToBinary, binaryToBase58, safeTimestamp2, rawencode, keysort, sort, inArray, isEmpty, ordered, filterBy, uuid16, safeFloat, base64ToBinary, safeStringUpper2, urlencodeWithArrayRepeat, microseconds, binaryToBase64, strip, toArray, safeFloatN, safeIntegerN, safeIntegerProductN, safeTimestampN, safeValueN, safeStringN, safeStringLowerN, safeStringUpperN, urlencodeNested, urlencodeBase64, parseDate, ymd, base64ToString, crc32, packb, TRUNCATE, ROUND, DECIMAL_PLACES, NO_PADDING, TICK_SIZE, SIGNIFICANT_DIGITS, sleep, } = functions;
41
+ arrayConcat, encode, urlencode, hmac, numberToString, roundTimeframe, parseTimeframe, safeInteger2, safeStringLower, parse8601, yyyymmdd, safeStringUpper, safeTimestamp, binaryConcatArray, ymdhms, stringToBase64, decode, uuid22, safeIntegerProduct2, safeIntegerProduct, safeStringLower2, yymmdd, base58ToBinary, binaryToBase58, safeTimestamp2, rawencode, keysort, sort, inArray, isEmpty, filterBy, uuid16, safeFloat, base64ToBinary, safeStringUpper2, urlencodeWithArrayRepeat, microseconds, binaryToBase64, strip, toArray, safeFloatN, safeIntegerN, safeIntegerProductN, safeTimestampN, safeValueN, safeStringN, safeStringLowerN, safeStringUpperN, urlencodeNested, urlencodeBase64, parseDate, ymd, base64ToString, crc32, packb, TRUNCATE, ROUND, DECIMAL_PLACES, NO_PADDING, TICK_SIZE, SIGNIFICANT_DIGITS, sleep, readFile, writeFile, existsFile, getTempDir, } = functions;
41
42
  // ----------------------------------------------------------------------------
42
43
  let protobufMexc = undefined;
43
44
  let encodeAsAny = undefined;
@@ -47,14 +48,6 @@ let TxBody = undefined;
47
48
  let TxRaw = undefined;
48
49
  let SignDoc = undefined;
49
50
  let SignMode = undefined;
50
- (async () => {
51
- try {
52
- protobufMexc = await import('../protobuf/mexc/compiled.cjs');
53
- }
54
- catch (e) {
55
- // TODO: handle error
56
- }
57
- })();
58
51
  // -----------------------------------------------------------------------------
59
52
  /**
60
53
  * @class Exchange
@@ -172,7 +165,6 @@ export default class Exchange {
172
165
  this.isNode = isNode;
173
166
  this.extend = extend;
174
167
  this.clone = clone;
175
- this.flatten = flatten;
176
168
  this.unique = unique;
177
169
  this.indexBy = indexBy;
178
170
  this.indexBySafe = indexBy;
@@ -207,8 +199,6 @@ export default class Exchange {
207
199
  this.implodeParams = implodeParams;
208
200
  this.extractParams = extractParams;
209
201
  this.json = json;
210
- this.vwap = vwapFunc;
211
- this.merge = merge;
212
202
  this.binaryConcat = binaryConcat;
213
203
  this.hash = hash;
214
204
  this.arrayConcat = arrayConcat;
@@ -224,8 +214,6 @@ export default class Exchange {
224
214
  this.safeStringUpper = safeStringUpper;
225
215
  this.safeTimestamp = safeTimestamp;
226
216
  this.binaryConcatArray = binaryConcatArray;
227
- this.uuidv1 = uuidv1;
228
- this.numberToLE = numberToLE;
229
217
  this.ymdhms = ymdhms;
230
218
  this.yymmdd = yymmdd;
231
219
  this.stringToBase64 = stringToBase64;
@@ -244,7 +232,6 @@ export default class Exchange {
244
232
  this.safeStringLower2 = safeStringLower2;
245
233
  this.safeStringUpper2 = safeStringUpper2;
246
234
  this.isEmpty = isEmpty;
247
- this.ordered = ordered;
248
235
  this.filterBy = filterBy;
249
236
  this.uuid16 = uuid16;
250
237
  this.urlencodeWithArrayRepeat = urlencodeWithArrayRepeat;
@@ -267,6 +254,11 @@ export default class Exchange {
267
254
  this.crc32 = crc32;
268
255
  this.packb = packb;
269
256
  this.urlencodeBase64 = urlencodeBase64;
257
+ // io
258
+ this.readFile = readFile;
259
+ this.writeFile = writeFile;
260
+ this.existsFile = existsFile;
261
+ this.getTempDir = getTempDir;
270
262
  Object.assign(this, functions);
271
263
  //
272
264
  // if (isNode) {
@@ -382,6 +374,18 @@ export default class Exchange {
382
374
  if (this.safeBool(userConfig, 'sandbox') || this.safeBool(userConfig, 'testnet')) {
383
375
  this.setSandboxMode(true);
384
376
  }
377
+ // exchange specific libs
378
+ this.loadExchangeSpecificFiles();
379
+ }
380
+ async loadExchangeSpecificFiles() {
381
+ if (this.id === 'mexc') {
382
+ try {
383
+ protobufMexc = await import('../protobuf/mexc/compiled.cjs');
384
+ }
385
+ catch (e) {
386
+ // TODO: handle error
387
+ }
388
+ }
385
389
  }
386
390
  uuid5(namespace, name) {
387
391
  const nsBytes = namespace
@@ -681,6 +685,29 @@ export default class Exchange {
681
685
  }
682
686
  // set final headers
683
687
  headers = this.setHeaders(headers);
688
+ // multipart/form-data
689
+ const headersKeys = Object.keys(headers);
690
+ for (let i = 0; i < headersKeys.length; i++) {
691
+ const key = headersKeys[i];
692
+ if (key.toLowerCase() === 'content-type') {
693
+ let value = headers[key];
694
+ if (value === 'multipart/form-data') {
695
+ const bodyKeys = Object.keys(body);
696
+ const boundary = '--------------------------' + this.randomBytes(12);
697
+ const eol = '\r\n';
698
+ let newBody = '';
699
+ for (let j = 0; j < bodyKeys.length; j++) {
700
+ const bodyKey = bodyKeys[j];
701
+ newBody += '--' + boundary + eol + 'Content-Disposition: form-data; name="' + bodyKey + '"' + eol + eol + body[bodyKey] + eol;
702
+ }
703
+ newBody += '--' + boundary + '--' + eol;
704
+ value += '; boundary=' + boundary;
705
+ headers[key] = value;
706
+ body = newBody;
707
+ break;
708
+ }
709
+ }
710
+ }
684
711
  // log
685
712
  if (this.verbose) {
686
713
  this.log('fetch Request:\n', this.id, method, url, '\nRequestHeaders:\n', headers, '\nRequestBody:\n', body, '\n');
@@ -1565,6 +1592,112 @@ export default class Exchange {
1565
1592
  unlockId() {
1566
1593
  return undefined; // c# stub
1567
1594
  }
1595
+ async loadLighterLibrary(libraryPath, chainId, privateKey, apiKeyIndex, accountIndex) {
1596
+ // wasmExecPathExample: '/opt/homebrew/opt/go/libexec/lib/wasm/wasm_exec.js';
1597
+ // libraryPath eg: '/Users/cjg/Git/lighter-go/lighter.wasm';
1598
+ if (libraryPath === undefined || libraryPath === '') {
1599
+ throw new Error('loadLighterLibrary() requires "libraryPath" that should point to "lighter.wasm".\nYou can build it from source using the official Ligher SDK or download it here https://github.com/ccxt/lighter-wasm.\nExample: exchanges.options["libraryPath"] = "/user/cjg/Git/lighter-wasm/lighter.wasm"');
1600
+ }
1601
+ if (!isNode) {
1602
+ throw new NotSupported(this.id + ' loadLighterLibrary() is only supported in node environment.');
1603
+ }
1604
+ await functions.initFileSystem();
1605
+ const wasmExecPath = this.safeString(this.options, 'wasmExecPath');
1606
+ if (wasmExecPath === undefined || wasmExecPath === '') {
1607
+ throw new Error('loadLighterLibrary() requires "wasmExecPath" that should point to `wasm_exec.js`. You can check the location of the file locally if you have GO installed or download it here https://github.com/ccxt/lighter-wasm.\nExample: exchanges.options["wasmExecPath"] = "/opt/homebrew/opt/go/libexec/lib/wasm/wasm_exec.js"');
1608
+ }
1609
+ await import(wasmExecPath);
1610
+ const go = new globalThis.Go();
1611
+ // read wasm from disks
1612
+ const bytes = new Uint8Array(readFile(libraryPath, null)); // it should point to lighter.wasm
1613
+ const { instance } = await WebAssembly.instantiate(bytes, go.importObject);
1614
+ go.run(instance);
1615
+ // createCLient
1616
+ const url = this.implodeHostname(this.urls['api']['public']);
1617
+ const res = globalThis.CreateClient(url, privateKey, chainId, apiKeyIndex, accountIndex);
1618
+ this.checkLighterSignedError(res);
1619
+ return {}; // empty object we will read it from globalThis
1620
+ }
1621
+ // eslint-disable-next-line no-unused-vars
1622
+ lighterSignCreateGroupedOrders(signer, request) {
1623
+ const orders = request['orders'];
1624
+ const ordersArr = [];
1625
+ for (let i = 0; i < orders.length; i++) {
1626
+ const order = orders[i];
1627
+ ordersArr.push({
1628
+ 'MarketIndex': parseInt(order['market_index']),
1629
+ 'ClientOrderIndex': order['client_order_index'],
1630
+ 'BaseAmount': order['base_amount'],
1631
+ 'Price': order['avg_execution_price'],
1632
+ 'IsAsk': order['is_ask'],
1633
+ 'Type': order['order_type'],
1634
+ 'TimeInForce': order['time_in_force'],
1635
+ 'ReduceOnly': order['reduce_only'],
1636
+ 'TriggerPrice': order['trigger_price'],
1637
+ 'OrderExpiry': order['order_expiry'],
1638
+ });
1639
+ }
1640
+ const res = globalThis.SignCreateGroupedOrders(request['grouping_type'], ordersArr, orders.length, request['nonce'], request['api_key_index'], request['account_index']);
1641
+ this.checkLighterSignedError(res);
1642
+ return [res.txType, res.txInfo];
1643
+ }
1644
+ // eslint-disable-next-line no-unused-vars
1645
+ lighterSignCreateOrder(signer, request) {
1646
+ const res = (globalThis.SignCreateOrder(parseInt(request['market_index']), request['client_order_index'], request['base_amount'], request['avg_execution_price'], request['is_ask'], request['order_type'], request['time_in_force'], request['reduce_only'], request['trigger_price'], request['order_expiry'], request['nonce'], request['api_key_index'], request['account_index']));
1647
+ this.checkLighterSignedError(res);
1648
+ return [res.txType, res.txInfo];
1649
+ }
1650
+ checkLighterSignedError(result) {
1651
+ if ('error' in result) {
1652
+ throw new Error('Lighter signing error: ' + result.error);
1653
+ }
1654
+ }
1655
+ lighterSignCancelOrder(signer, request) {
1656
+ const res = (globalThis.SignCancelOrder(request['market_index'], request['order_index'], request['nonce'], request['api_key_index'], request['account_index']));
1657
+ this.checkLighterSignedError(res);
1658
+ return [res.txType, res.txInfo];
1659
+ }
1660
+ lighterSignWithdraw(signer, request) {
1661
+ const res = (globalThis.SignWithdraw(request['asset_index'], request['route_type'], request['amount'], request['nonce'], request['api_key_index'], request['account_index']));
1662
+ this.checkLighterSignedError(res);
1663
+ return [res.txType, res.txInfo];
1664
+ }
1665
+ // eslint-disable-next-line no-unused-vars
1666
+ lighterSignCreateSubAccount(signer, request) {
1667
+ const res = (globalThis.SignCreateSubAccount(request['nonce'], request['api_key_index'], request['account_index']));
1668
+ this.checkLighterSignedError(res);
1669
+ return [res.txType, res.txInfo];
1670
+ }
1671
+ lighterSignCancelAllOrders(signer, request) {
1672
+ const res = (globalThis.SignCancelAllOrders(request['time_in_force'], request['time'], request['nonce'], request['api_key_index'], request['account_index']));
1673
+ this.checkLighterSignedError(res);
1674
+ return [res.txType, res.txInfo];
1675
+ }
1676
+ lighterSignModifyOrder(signer, request) {
1677
+ const res = (globalThis.SignModifyOrder(request['market_index'], request['index'], request['base_amount'], request['price'], request['trigger_price'], request['nonce'], request['api_key_index'], request['account_index']));
1678
+ this.checkLighterSignedError(res);
1679
+ return [res.txType, res.txInfo];
1680
+ }
1681
+ lighterSignTransfer(signer, request) {
1682
+ const res = globalThis.SignTransfer(request['to_account_index'], request['asset_index'], request['from_route_type'], request['to_route_type'], request['amount'], request['usdc_fee'], request['memo'], request['nonce'], request['api_key_index'], request['account_index']);
1683
+ this.checkLighterSignedError(res);
1684
+ return [res.txType, res.txInfo];
1685
+ }
1686
+ lighterSignUpdateLeverage(signer, request) {
1687
+ const res = (globalThis.SignUpdateLeverage(request['market_index'], request['initial_margin_fraction'], request['margin_mode'], request['nonce'], request['api_key_index'], request['account_index']));
1688
+ this.checkLighterSignedError(res);
1689
+ return [res.txType, res.txInfo];
1690
+ }
1691
+ lighterCreateAuthToken(signer, request) {
1692
+ const res = globalThis.CreateAuthToken(request['deadline'], request['api_key_index'], request['account_index']);
1693
+ this.checkLighterSignedError(res);
1694
+ return res.authToken;
1695
+ }
1696
+ lighterSignUpdateMargin(signer, request) {
1697
+ const res = globalThis.SignUpdateMargin(request['market_index'], request['usdc_amount'], request['direction'], request['nonce'], request['api_key_index'], request['account_index']);
1698
+ this.checkLighterSignedError(res);
1699
+ return [res.txType, res.txInfo];
1700
+ }
1568
1701
  /* eslint-enable */
1569
1702
  // ------------------------------------------------------------------------
1570
1703
  // ########################################################################
@@ -176,6 +176,7 @@ const deepExtend = function (...args) {
176
176
  }
177
177
  return result;
178
178
  };
179
+ // better "merge" func resides in static_dependencies/qs/utils.js
179
180
  const merge = (target, ...args) => {
180
181
  // doesn't overwrite defined keys with undefined
181
182
  const overwrite = {};
@@ -0,0 +1,32 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /**
4
+ * Initialize synchronous file system module (Node.js only)
5
+ * Uses dynamic import to prevent bundling in browser builds
6
+ */
7
+ export declare function initFileSystem(): Promise<void>;
8
+ /**
9
+ * Get system temporary directory (Node.js only)
10
+ * @returns Temporary directory path with trailing slash, or undefined
11
+ */
12
+ export declare function getTempDir(): string | undefined;
13
+ /**
14
+ * Read file contents synchronously (Node.js only)
15
+ * @param path File path to read
16
+ * @param encoding File encoding (default: 'utf8')
17
+ * @returns File contents as string, or undefined in browser
18
+ */
19
+ export declare function readFile(path: string, encoding?: BufferEncoding): string | undefined | Buffer;
20
+ /**
21
+ * Write file contents synchronously (Node.js only)
22
+ * @param path File path to write
23
+ * @param data Data to write
24
+ * @param encoding File encoding (default: 'utf8')
25
+ */
26
+ export declare function writeFile(path: string, data: string, encoding?: BufferEncoding): boolean;
27
+ /**
28
+ * Check if file exists synchronously (Node.js only)
29
+ * @param path File path to check
30
+ * @returns true if file exists, false otherwise
31
+ */
32
+ export declare function existsFile(path: string): boolean;
@@ -0,0 +1,137 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ /* ------------------------------------------------------------------------ */
8
+ import { isNode } from './platform.js';
9
+ /* ------------------------------------------------------------------------ */
10
+ let fsSyncModule = null;
11
+ let osSyncModule = null;
12
+ let pathSyncModule = null;
13
+ /* ------------------------------------------------------------------------ */
14
+ /**
15
+ * Initialize synchronous file system module (Node.js only)
16
+ * Uses dynamic import to prevent bundling in browser builds
17
+ */
18
+ export async function initFileSystem() {
19
+ if (isNode) {
20
+ if (fsSyncModule === null) {
21
+ try {
22
+ // Dynamic import with webpackIgnore to prevent bundling
23
+ fsSyncModule = await import(/* webpackIgnore: true */ 'node:fs');
24
+ }
25
+ catch (e) { } // Silent fail in browser or if fs is unavailable
26
+ }
27
+ if (osSyncModule === null) {
28
+ try {
29
+ osSyncModule = await import(/* webpackIgnore: true */ 'node:os');
30
+ }
31
+ catch (e) { } // Silent fail in browser or if os is unavailable
32
+ }
33
+ if (pathSyncModule === null) {
34
+ try {
35
+ pathSyncModule = await import(/* webpackIgnore: true */ 'node:path');
36
+ }
37
+ catch (e) { } // Silent fail in browser or if path is unavailable
38
+ }
39
+ }
40
+ }
41
+ if (isNode) {
42
+ // Pre-initialize synchronous fs module for sync methods
43
+ initFileSystem();
44
+ }
45
+ /* ------------------------------------------------------------------------ */
46
+ /**
47
+ * Get system temporary directory (Node.js only)
48
+ * @returns Temporary directory path with trailing slash, or undefined
49
+ */
50
+ export function getTempDir() {
51
+ if (!isNode || osSyncModule === null) {
52
+ return undefined;
53
+ }
54
+ try {
55
+ const tmpDir = pathSyncModule.resolve(osSyncModule.tmpdir());
56
+ const sep = pathSyncModule ? pathSyncModule.sep : '/';
57
+ return tmpDir.endsWith(sep) ? tmpDir : tmpDir + sep;
58
+ }
59
+ catch (e) {
60
+ return undefined;
61
+ }
62
+ }
63
+ /**
64
+ * Check if file path is ccxt-cache file, so users are ensured there is no access possible to other files
65
+ * @param path File path to check
66
+ */
67
+ function ensureWhitelistedFile(filePath) {
68
+ if (pathSyncModule === null) {
69
+ throw new Error('path module is not available');
70
+ }
71
+ const sanitizedFilePath = pathSyncModule.resolve(filePath);
72
+ if ((sanitizedFilePath.startsWith(filePath) && sanitizedFilePath.endsWith('.ccxtfile')) || sanitizedFilePath.endsWith('.wasm')) {
73
+ return;
74
+ }
75
+ throw new Error('invalid file path: ' + filePath);
76
+ }
77
+ /* ------------------------------------------------------------------------ */
78
+ /**
79
+ * Read file contents synchronously (Node.js only)
80
+ * @param path File path to read
81
+ * @param encoding File encoding (default: 'utf8')
82
+ * @returns File contents as string, or undefined in browser
83
+ */
84
+ export function readFile(path, encoding = 'utf8') {
85
+ if (!isNode || fsSyncModule === null) {
86
+ // Sync module not initialized yet
87
+ return undefined;
88
+ }
89
+ ensureWhitelistedFile(path);
90
+ try {
91
+ return fsSyncModule.readFileSync(path, encoding);
92
+ }
93
+ catch (e) {
94
+ return undefined;
95
+ }
96
+ }
97
+ /* ------------------------------------------------------------------------ */
98
+ /**
99
+ * Write file contents synchronously (Node.js only)
100
+ * @param path File path to write
101
+ * @param data Data to write
102
+ * @param encoding File encoding (default: 'utf8')
103
+ */
104
+ export function writeFile(path, data, encoding = 'utf8') {
105
+ if (!isNode || fsSyncModule === null) {
106
+ return false;
107
+ }
108
+ ensureWhitelistedFile(path);
109
+ try {
110
+ fsSyncModule.writeFileSync(path, data, encoding);
111
+ return true;
112
+ }
113
+ catch (e) {
114
+ // Silent fail
115
+ return false;
116
+ }
117
+ }
118
+ /* ------------------------------------------------------------------------ */
119
+ /**
120
+ * Check if file exists synchronously (Node.js only)
121
+ * @param path File path to check
122
+ * @returns true if file exists, false otherwise
123
+ */
124
+ export function existsFile(path) {
125
+ if (!isNode || fsSyncModule === null) {
126
+ // Sync module not initialized yet
127
+ return false;
128
+ }
129
+ ensureWhitelistedFile(path);
130
+ try {
131
+ fsSyncModule.accessSync(path);
132
+ return true;
133
+ }
134
+ catch (e) {
135
+ return false;
136
+ }
137
+ }
@@ -8,3 +8,4 @@ export * from './functions/crypto.js';
8
8
  export * from './functions/time.js';
9
9
  export * from './functions/throttle.js';
10
10
  export * from './functions/misc.js';
11
+ export * from './functions/io.js';
@@ -15,4 +15,5 @@ export * from './functions/crypto.js';
15
15
  export * from './functions/time.js';
16
16
  export * from './functions/throttle.js';
17
17
  export * from './functions/misc.js';
18
+ export * from './functions/io.js';
18
19
  /* ------------------------------------------------------------------------ */
@@ -380,6 +380,7 @@ export default class binance extends Exchange {
380
380
  * @param {string} [params.stopLossOrTakeProfit] 'stopLoss' or 'takeProfit', required for spot trailing orders
381
381
  * @param {string} [params.positionSide] *swap and portfolio margin only* "BOTH" for one-way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
382
382
  * @param {bool} [params.hedged] *swap and portfolio margin only* true for hedged mode, false for one way mode, default is false
383
+ * @param {string} [params.clientOrderId] the clientOrderId of the order
383
384
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
384
385
  */
385
386
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: number, price?: Num, params?: {}): Promise<Order>;
package/js/src/binance.js CHANGED
@@ -6417,6 +6417,7 @@ export default class binance extends Exchange {
6417
6417
  * @param {string} [params.stopLossOrTakeProfit] 'stopLoss' or 'takeProfit', required for spot trailing orders
6418
6418
  * @param {string} [params.positionSide] *swap and portfolio margin only* "BOTH" for one-way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
6419
6419
  * @param {bool} [params.hedged] *swap and portfolio margin only* true for hedged mode, false for one way mode, default is false
6420
+ * @param {string} [params.clientOrderId] the clientOrderId of the order
6420
6421
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/?id=order-structure}
6421
6422
  */
6422
6423
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
package/js/src/bingx.js CHANGED
@@ -141,7 +141,17 @@ export default class bingx extends Exchange {
141
141
  'api': 'https://open-api.{hostname}/openApi',
142
142
  },
143
143
  'test': {
144
- 'swap': 'https://open-api-vst.{hostname}/openApi', // only swap is really "test" but since the API keys are the same, we want to keep all the functionalities when the user enables the sandboxmode
144
+ 'fund': 'https://open-api-vst.{hostname}/openApi',
145
+ 'spot': 'https://open-api-vst.{hostname}/openApi',
146
+ 'swap': 'https://open-api-vst.{hostname}/openApi',
147
+ 'contract': 'https://open-api-vst.{hostname}/openApi',
148
+ 'wallets': 'https://open-api-vst.{hostname}/openApi',
149
+ 'user': 'https://open-api-vst.{hostname}/openApi',
150
+ 'subAccount': 'https://open-api-vst.{hostname}/openApi',
151
+ 'account': 'https://open-api-vst.{hostname}/openApi',
152
+ 'copyTrading': 'https://open-api-vst.{hostname}/openApi',
153
+ 'cswap': 'https://open-api-vst.{hostname}/openApi',
154
+ 'api': 'https://open-api-vst.{hostname}/openApi',
145
155
  },
146
156
  'www': 'https://bingx.com/',
147
157
  'doc': 'https://bingx-api.github.io/docs/',
@@ -6841,10 +6851,10 @@ export default class bingx extends Exchange {
6841
6851
  let version = section[1];
6842
6852
  let access = section[2];
6843
6853
  const isSandbox = this.safeBool(this.options, 'sandboxMode', false);
6844
- if (isSandbox && (type !== 'swap')) {
6854
+ let url = this.implodeHostname(this.urls['api'][type]);
6855
+ if (isSandbox && url === undefined) {
6845
6856
  throw new NotSupported(this.id + ' does not have a testnet/sandbox URL for ' + type + ' endpoints');
6846
6857
  }
6847
- let url = this.implodeHostname(this.urls['api'][type]);
6848
6858
  path = this.implodeParams(path, params);
6849
6859
  const versionIsTransfer = (version === 'transfer');
6850
6860
  const versionIsAsset = (version === 'asset');