ccxt 4.2.98 → 4.2.100

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.
package/dist/cjs/ccxt.js CHANGED
@@ -182,7 +182,7 @@ var woo$1 = require('./src/pro/woo.js');
182
182
 
183
183
  //-----------------------------------------------------------------------------
184
184
  // this is updated by vss.js when building
185
- const version = '4.2.98';
185
+ const version = '4.2.100';
186
186
  Exchange["default"].ccxtVersion = version;
187
187
  const exchanges = {
188
188
  'ace': ace,
@@ -358,7 +358,7 @@ class ascendex extends ascendex$1 {
358
358
  '300013': errors.InvalidOrder,
359
359
  '300014': errors.InvalidOrder,
360
360
  '300020': errors.InvalidOrder,
361
- '300021': errors.InvalidOrder,
361
+ '300021': errors.AccountSuspended,
362
362
  '300031': errors.InvalidOrder,
363
363
  '310001': errors.InsufficientFunds,
364
364
  '310002': errors.InvalidOrder,
@@ -1458,6 +1458,7 @@ class coinbase extends coinbase$1 {
1458
1458
  const contractExpiryType = this.safeString(futureProductDetails, 'contract_expiry_type');
1459
1459
  const contractSize = this.safeNumber(futureProductDetails, 'contract_size');
1460
1460
  const contractExpire = this.safeString(futureProductDetails, 'contract_expiry');
1461
+ const expireTimestamp = this.parse8601(contractExpire);
1461
1462
  const isSwap = (contractExpiryType === 'PERPETUAL');
1462
1463
  const baseId = this.safeString(futureProductDetails, 'contract_root_unit');
1463
1464
  const quoteId = this.safeString(market, 'quote_currency_id');
@@ -1472,7 +1473,7 @@ class coinbase extends coinbase$1 {
1472
1473
  }
1473
1474
  else {
1474
1475
  type = 'future';
1475
- symbol = symbol + ':' + quote + '-' + this.yymmdd(contractExpire);
1476
+ symbol = symbol + ':' + quote + '-' + this.yymmdd(expireTimestamp);
1476
1477
  }
1477
1478
  const takerFeeRate = this.safeNumber(feeTier, 'taker_fee_rate');
1478
1479
  const makerFeeRate = this.safeNumber(feeTier, 'maker_fee_rate');
@@ -1500,7 +1501,7 @@ class coinbase extends coinbase$1 {
1500
1501
  'taker': taker,
1501
1502
  'maker': maker,
1502
1503
  'contractSize': contractSize,
1503
- 'expiry': this.parse8601(contractExpire),
1504
+ 'expiry': expireTimestamp,
1504
1505
  'expiryDatetime': contractExpire,
1505
1506
  'strike': undefined,
1506
1507
  'optionType': undefined,
@@ -4287,6 +4288,33 @@ class coinbase extends coinbase$1 {
4287
4288
  'takeProfitPrice': undefined,
4288
4289
  });
4289
4290
  }
4291
+ createAuthToken(seconds, method = undefined, url = undefined) {
4292
+ // it may not work for v2
4293
+ let uri = undefined;
4294
+ if (url !== undefined) {
4295
+ uri = method + ' ' + url.replace('https://', '');
4296
+ const quesPos = uri.indexOf('?');
4297
+ // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4298
+ // Also it's not possible that the question mark is first character, only check > 0 here.
4299
+ if (quesPos > 0) {
4300
+ uri = uri.slice(0, quesPos);
4301
+ }
4302
+ }
4303
+ const nonce = this.randomBytes(16);
4304
+ const request = {
4305
+ 'aud': ['retail_rest_api_proxy'],
4306
+ 'iss': 'coinbase-cloud',
4307
+ 'nbf': seconds,
4308
+ 'exp': seconds + 120,
4309
+ 'sub': this.apiKey,
4310
+ 'iat': seconds,
4311
+ };
4312
+ if (uri !== undefined) {
4313
+ request['uri'] = uri;
4314
+ }
4315
+ const token = rsa.jwt(request, this.encode(this.secret), sha256.sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4316
+ return token;
4317
+ }
4290
4318
  sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
4291
4319
  const version = api[0];
4292
4320
  const signed = api[1] === 'private';
@@ -4336,25 +4364,26 @@ class coinbase extends coinbase$1 {
4336
4364
  if (this.apiKey.startsWith('-----BEGIN')) {
4337
4365
  throw new errors.ArgumentsRequired(this.id + ' apiKey should contain the name (eg: organizations/3b910e93....) and not the public key');
4338
4366
  }
4339
- // it may not work for v2
4340
- let uri = method + ' ' + url.replace('https://', '');
4341
- const quesPos = uri.indexOf('?');
4342
- // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4343
- // Also it's not possible that the question mark is first character, only check > 0 here.
4344
- if (quesPos > 0) {
4345
- uri = uri.slice(0, quesPos);
4346
- }
4347
- const nonce = this.randomBytes(16);
4348
- const request = {
4349
- 'aud': ['retail_rest_api_proxy'],
4350
- 'iss': 'coinbase-cloud',
4351
- 'nbf': seconds,
4352
- 'exp': seconds + 120,
4353
- 'sub': this.apiKey,
4354
- 'uri': uri,
4355
- 'iat': seconds,
4356
- };
4357
- const token = rsa.jwt(request, this.encode(this.secret), sha256.sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4367
+ // // it may not work for v2
4368
+ // let uri = method + ' ' + url.replace ('https://', '');
4369
+ // const quesPos = uri.indexOf ('?');
4370
+ // // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4371
+ // // Also it's not possible that the question mark is first character, only check > 0 here.
4372
+ // if (quesPos > 0) {
4373
+ // uri = uri.slice (0, quesPos);
4374
+ // }
4375
+ // const nonce = this.randomBytes (16);
4376
+ // const request = {
4377
+ // 'aud': [ 'retail_rest_api_proxy' ],
4378
+ // 'iss': 'coinbase-cloud',
4379
+ // 'nbf': seconds,
4380
+ // 'exp': seconds + 120,
4381
+ // 'sub': this.apiKey,
4382
+ // 'uri': uri,
4383
+ // 'iat': seconds,
4384
+ // };
4385
+ const token = this.createAuthToken(seconds, method, url);
4386
+ // const token = jwt (request, this.encode (this.secret), sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4358
4387
  authorizationString = 'Bearer ' + token;
4359
4388
  }
4360
4389
  else {
@@ -1551,9 +1551,10 @@ class kraken extends kraken$1 {
1551
1551
  // }
1552
1552
  //
1553
1553
  const description = this.safeDict(order, 'descr', {});
1554
+ const orderDescriptionObj = this.safeDict(order, 'descr'); // can be null
1554
1555
  let orderDescription = undefined;
1555
- if (description !== undefined) {
1556
- orderDescription = this.safeString(description, 'order');
1556
+ if (orderDescriptionObj !== undefined) {
1557
+ orderDescription = this.safeString(orderDescriptionObj, 'order');
1557
1558
  }
1558
1559
  else {
1559
1560
  orderDescription = this.safeString(order, 'descr');
@@ -1628,8 +1629,8 @@ class kraken extends kraken$1 {
1628
1629
  }
1629
1630
  const status = this.parseOrderStatus(this.safeString(order, 'status'));
1630
1631
  let id = this.safeString2(order, 'id', 'txid');
1631
- if ((id === undefined) || (id.slice(0, 1) === '[')) {
1632
- const txid = this.safeValue(order, 'txid');
1632
+ if ((id === undefined) || (id.startsWith('['))) {
1633
+ const txid = this.safeList(order, 'txid');
1633
1634
  id = this.safeString(txid, 0);
1634
1635
  }
1635
1636
  const clientOrderId = this.safeString(order, 'userref');
@@ -1197,10 +1197,10 @@ class kucoin extends kucoin$1 {
1197
1197
  // }
1198
1198
  //
1199
1199
  const responses = await Promise.all(promises);
1200
- const currenciesResponse = this.safeValue(responses, 0, {});
1201
- const currenciesData = this.safeValue(currenciesResponse, 'data', []);
1202
- const additionalResponse = this.safeValue(responses, 1, {});
1203
- const additionalData = this.safeValue(additionalResponse, 'data', []);
1200
+ const currenciesResponse = this.safeDict(responses, 0, {});
1201
+ const currenciesData = this.safeList(currenciesResponse, 'data', []);
1202
+ const additionalResponse = this.safeDict(responses, 1, {});
1203
+ const additionalData = this.safeList(additionalResponse, 'data', []);
1204
1204
  const additionalDataGrouped = this.groupBy(additionalData, 'currency');
1205
1205
  const result = {};
1206
1206
  for (let i = 0; i < currenciesData.length; i++) {
@@ -1212,7 +1212,7 @@ class kucoin extends kucoin$1 {
1212
1212
  let isDepositEnabled = undefined;
1213
1213
  const networks = {};
1214
1214
  const chains = this.safeList(entry, 'chains', []);
1215
- const extraChainsData = this.indexBy(this.safeValue(additionalDataGrouped, id, []), 'chain');
1215
+ const extraChainsData = this.indexBy(this.safeList(additionalDataGrouped, id, []), 'chain');
1216
1216
  const rawPrecision = this.safeString(entry, 'precision');
1217
1217
  const precision = this.parseNumber(this.parsePrecision(rawPrecision));
1218
1218
  const chainsLength = chains.length;
@@ -1353,7 +1353,7 @@ class kucoin extends kucoin$1 {
1353
1353
  request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
1354
1354
  }
1355
1355
  const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
1356
- const data = this.safeValue(response, 'data');
1356
+ const data = this.safeDict(response, 'data', {});
1357
1357
  const withdrawFees = {};
1358
1358
  withdrawFees[code] = this.safeNumber(data, 'withdrawMinFee');
1359
1359
  return {
@@ -75,15 +75,36 @@ class coinbase extends coinbase$1 {
75
75
  }
76
76
  const url = this.urls['api']['ws'];
77
77
  const timestamp = this.numberToString(this.seconds());
78
+ const isCloudAPiKey = (this.apiKey.indexOf('organizations/') >= 0) || (this.secret.startsWith('-----BEGIN'));
78
79
  const auth = timestamp + name + productIds.join(',');
79
80
  const subscribe = {
80
81
  'type': 'subscribe',
81
82
  'product_ids': productIds,
82
83
  'channel': name,
83
- 'api_key': this.apiKey,
84
- 'timestamp': timestamp,
85
- 'signature': this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256),
84
+ // 'api_key': this.apiKey,
85
+ // 'timestamp': timestamp,
86
+ // 'signature': this.hmac (this.encode (auth), this.encode (this.secret), sha256),
86
87
  };
88
+ if (!isCloudAPiKey) {
89
+ subscribe['api_key'] = this.apiKey;
90
+ subscribe['timestamp'] = timestamp;
91
+ subscribe['signature'] = this.hmac(this.encode(auth), this.encode(this.secret), sha256.sha256);
92
+ }
93
+ else {
94
+ if (this.apiKey.startsWith('-----BEGIN')) {
95
+ throw new errors.ArgumentsRequired(this.id + ' apiKey should contain the name (eg: organizations/3b910e93....) and not the public key');
96
+ }
97
+ const currentToken = this.safeString(this.options, 'wsToken');
98
+ const tokenTimestamp = this.safeInteger(this.options, 'wsTokenTimestamp', 0);
99
+ const seconds = this.seconds();
100
+ if (currentToken === undefined || tokenTimestamp + 120 < seconds) {
101
+ // we should generate new token
102
+ const token = this.createAuthToken(seconds);
103
+ this.options['wsToken'] = token;
104
+ this.options['wsTokenTimestamp'] = seconds;
105
+ }
106
+ subscribe['jwt'] = this.safeString(this.options, 'wsToken');
107
+ }
87
108
  return await this.watch(url, messageHash, subscribe, messageHash);
88
109
  }
89
110
  async watchTicker(symbol, params = {}) {
package/js/ccxt.d.ts CHANGED
@@ -4,7 +4,7 @@ import * as functions from './src/base/functions.js';
4
4
  import * as errors from './src/base/errors.js';
5
5
  import type { Market, Trade, Fee, Ticker, OrderBook, Order, Transaction, Tickers, Currency, Balance, DepositAddress, WithdrawalResponse, DepositAddressResponse, OHLCV, Balances, PartialBalances, Dictionary, MinMax, Position, FundingRateHistory, Liquidation, FundingHistory, MarginMode, Greeks, Leverage, Leverages, Option, OptionChain, Conversion } from './src/base/types.js';
6
6
  import { BaseError, ExchangeError, AuthenticationError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, OperationRejected, NoChange, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, AddressPending, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, ContractUnavailable, NotSupported, ProxyError, ExchangeClosedByUser, OperationFailed, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout } from './src/base/errors.js';
7
- declare const version = "4.2.97";
7
+ declare const version = "4.2.99";
8
8
  import ace from './src/ace.js';
9
9
  import alpaca from './src/alpaca.js';
10
10
  import ascendex from './src/ascendex.js';
package/js/ccxt.js CHANGED
@@ -38,7 +38,7 @@ import * as errors from './src/base/errors.js';
38
38
  import { BaseError, ExchangeError, AuthenticationError, PermissionDenied, AccountNotEnabled, AccountSuspended, ArgumentsRequired, BadRequest, BadSymbol, OperationRejected, NoChange, MarginModeAlreadySet, BadResponse, NullResponse, InsufficientFunds, InvalidAddress, AddressPending, InvalidOrder, OrderNotFound, OrderNotCached, CancelPending, OrderImmediatelyFillable, OrderNotFillable, DuplicateOrderId, ContractUnavailable, NotSupported, ProxyError, ExchangeClosedByUser, OperationFailed, NetworkError, DDoSProtection, RateLimitExceeded, ExchangeNotAvailable, OnMaintenance, InvalidNonce, RequestTimeout } from './src/base/errors.js';
39
39
  //-----------------------------------------------------------------------------
40
40
  // this is updated by vss.js when building
41
- const version = '4.2.98';
41
+ const version = '4.2.100';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import Exchange from './abstract/ascendex.js';
9
- import { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest, NotSupported } from './base/errors.js';
9
+ import { ArgumentsRequired, AuthenticationError, ExchangeError, AccountSuspended, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest, NotSupported } from './base/errors.js';
10
10
  import { Precise } from './base/Precise.js';
11
11
  import { TICK_SIZE } from './base/functions/number.js';
12
12
  import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
@@ -361,7 +361,7 @@ export default class ascendex extends Exchange {
361
361
  '300013': InvalidOrder,
362
362
  '300014': InvalidOrder,
363
363
  '300020': InvalidOrder,
364
- '300021': InvalidOrder,
364
+ '300021': AccountSuspended,
365
365
  '300031': InvalidOrder,
366
366
  '310001': InsufficientFunds,
367
367
  '310002': InvalidOrder,
@@ -108,6 +108,7 @@ export default class coinbase extends Exchange {
108
108
  fetchPositions(symbols?: Strings, params?: {}): Promise<import("./base/types.js").Position[]>;
109
109
  fetchPosition(symbol: string, params?: {}): Promise<import("./base/types.js").Position>;
110
110
  parsePosition(position: any, market?: Market): import("./base/types.js").Position;
111
+ createAuthToken(seconds: Int, method?: Str, url?: Str): string;
111
112
  sign(path: any, api?: any[], method?: string, params?: {}, headers?: any, body?: any): {
112
113
  url: string;
113
114
  method: string;
@@ -1461,6 +1461,7 @@ export default class coinbase extends Exchange {
1461
1461
  const contractExpiryType = this.safeString(futureProductDetails, 'contract_expiry_type');
1462
1462
  const contractSize = this.safeNumber(futureProductDetails, 'contract_size');
1463
1463
  const contractExpire = this.safeString(futureProductDetails, 'contract_expiry');
1464
+ const expireTimestamp = this.parse8601(contractExpire);
1464
1465
  const isSwap = (contractExpiryType === 'PERPETUAL');
1465
1466
  const baseId = this.safeString(futureProductDetails, 'contract_root_unit');
1466
1467
  const quoteId = this.safeString(market, 'quote_currency_id');
@@ -1475,7 +1476,7 @@ export default class coinbase extends Exchange {
1475
1476
  }
1476
1477
  else {
1477
1478
  type = 'future';
1478
- symbol = symbol + ':' + quote + '-' + this.yymmdd(contractExpire);
1479
+ symbol = symbol + ':' + quote + '-' + this.yymmdd(expireTimestamp);
1479
1480
  }
1480
1481
  const takerFeeRate = this.safeNumber(feeTier, 'taker_fee_rate');
1481
1482
  const makerFeeRate = this.safeNumber(feeTier, 'maker_fee_rate');
@@ -1503,7 +1504,7 @@ export default class coinbase extends Exchange {
1503
1504
  'taker': taker,
1504
1505
  'maker': maker,
1505
1506
  'contractSize': contractSize,
1506
- 'expiry': this.parse8601(contractExpire),
1507
+ 'expiry': expireTimestamp,
1507
1508
  'expiryDatetime': contractExpire,
1508
1509
  'strike': undefined,
1509
1510
  'optionType': undefined,
@@ -4290,6 +4291,33 @@ export default class coinbase extends Exchange {
4290
4291
  'takeProfitPrice': undefined,
4291
4292
  });
4292
4293
  }
4294
+ createAuthToken(seconds, method = undefined, url = undefined) {
4295
+ // it may not work for v2
4296
+ let uri = undefined;
4297
+ if (url !== undefined) {
4298
+ uri = method + ' ' + url.replace('https://', '');
4299
+ const quesPos = uri.indexOf('?');
4300
+ // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4301
+ // Also it's not possible that the question mark is first character, only check > 0 here.
4302
+ if (quesPos > 0) {
4303
+ uri = uri.slice(0, quesPos);
4304
+ }
4305
+ }
4306
+ const nonce = this.randomBytes(16);
4307
+ const request = {
4308
+ 'aud': ['retail_rest_api_proxy'],
4309
+ 'iss': 'coinbase-cloud',
4310
+ 'nbf': seconds,
4311
+ 'exp': seconds + 120,
4312
+ 'sub': this.apiKey,
4313
+ 'iat': seconds,
4314
+ };
4315
+ if (uri !== undefined) {
4316
+ request['uri'] = uri;
4317
+ }
4318
+ const token = jwt(request, this.encode(this.secret), sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4319
+ return token;
4320
+ }
4293
4321
  sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
4294
4322
  const version = api[0];
4295
4323
  const signed = api[1] === 'private';
@@ -4339,25 +4367,26 @@ export default class coinbase extends Exchange {
4339
4367
  if (this.apiKey.startsWith('-----BEGIN')) {
4340
4368
  throw new ArgumentsRequired(this.id + ' apiKey should contain the name (eg: organizations/3b910e93....) and not the public key');
4341
4369
  }
4342
- // it may not work for v2
4343
- let uri = method + ' ' + url.replace('https://', '');
4344
- const quesPos = uri.indexOf('?');
4345
- // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4346
- // Also it's not possible that the question mark is first character, only check > 0 here.
4347
- if (quesPos > 0) {
4348
- uri = uri.slice(0, quesPos);
4349
- }
4350
- const nonce = this.randomBytes(16);
4351
- const request = {
4352
- 'aud': ['retail_rest_api_proxy'],
4353
- 'iss': 'coinbase-cloud',
4354
- 'nbf': seconds,
4355
- 'exp': seconds + 120,
4356
- 'sub': this.apiKey,
4357
- 'uri': uri,
4358
- 'iat': seconds,
4359
- };
4360
- const token = jwt(request, this.encode(this.secret), sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4370
+ // // it may not work for v2
4371
+ // let uri = method + ' ' + url.replace ('https://', '');
4372
+ // const quesPos = uri.indexOf ('?');
4373
+ // // Due to we use mb_strpos, quesPos could be false in php. In that case, the quesPos >= 0 is true
4374
+ // // Also it's not possible that the question mark is first character, only check > 0 here.
4375
+ // if (quesPos > 0) {
4376
+ // uri = uri.slice (0, quesPos);
4377
+ // }
4378
+ // const nonce = this.randomBytes (16);
4379
+ // const request = {
4380
+ // 'aud': [ 'retail_rest_api_proxy' ],
4381
+ // 'iss': 'coinbase-cloud',
4382
+ // 'nbf': seconds,
4383
+ // 'exp': seconds + 120,
4384
+ // 'sub': this.apiKey,
4385
+ // 'uri': uri,
4386
+ // 'iat': seconds,
4387
+ // };
4388
+ const token = this.createAuthToken(seconds, method, url);
4389
+ // const token = jwt (request, this.encode (this.secret), sha256, false, { 'kid': this.apiKey, 'nonce': nonce, 'alg': 'ES256' });
4361
4390
  authorizationString = 'Bearer ' + token;
4362
4391
  }
4363
4392
  else {
package/js/src/kraken.js CHANGED
@@ -1554,9 +1554,10 @@ export default class kraken extends Exchange {
1554
1554
  // }
1555
1555
  //
1556
1556
  const description = this.safeDict(order, 'descr', {});
1557
+ const orderDescriptionObj = this.safeDict(order, 'descr'); // can be null
1557
1558
  let orderDescription = undefined;
1558
- if (description !== undefined) {
1559
- orderDescription = this.safeString(description, 'order');
1559
+ if (orderDescriptionObj !== undefined) {
1560
+ orderDescription = this.safeString(orderDescriptionObj, 'order');
1560
1561
  }
1561
1562
  else {
1562
1563
  orderDescription = this.safeString(order, 'descr');
@@ -1631,8 +1632,8 @@ export default class kraken extends Exchange {
1631
1632
  }
1632
1633
  const status = this.parseOrderStatus(this.safeString(order, 'status'));
1633
1634
  let id = this.safeString2(order, 'id', 'txid');
1634
- if ((id === undefined) || (id.slice(0, 1) === '[')) {
1635
- const txid = this.safeValue(order, 'txid');
1635
+ if ((id === undefined) || (id.startsWith('['))) {
1636
+ const txid = this.safeList(order, 'txid');
1636
1637
  id = this.safeString(txid, 0);
1637
1638
  }
1638
1639
  const clientOrderId = this.safeString(order, 'userref');
package/js/src/kucoin.js CHANGED
@@ -1200,10 +1200,10 @@ export default class kucoin extends Exchange {
1200
1200
  // }
1201
1201
  //
1202
1202
  const responses = await Promise.all(promises);
1203
- const currenciesResponse = this.safeValue(responses, 0, {});
1204
- const currenciesData = this.safeValue(currenciesResponse, 'data', []);
1205
- const additionalResponse = this.safeValue(responses, 1, {});
1206
- const additionalData = this.safeValue(additionalResponse, 'data', []);
1203
+ const currenciesResponse = this.safeDict(responses, 0, {});
1204
+ const currenciesData = this.safeList(currenciesResponse, 'data', []);
1205
+ const additionalResponse = this.safeDict(responses, 1, {});
1206
+ const additionalData = this.safeList(additionalResponse, 'data', []);
1207
1207
  const additionalDataGrouped = this.groupBy(additionalData, 'currency');
1208
1208
  const result = {};
1209
1209
  for (let i = 0; i < currenciesData.length; i++) {
@@ -1215,7 +1215,7 @@ export default class kucoin extends Exchange {
1215
1215
  let isDepositEnabled = undefined;
1216
1216
  const networks = {};
1217
1217
  const chains = this.safeList(entry, 'chains', []);
1218
- const extraChainsData = this.indexBy(this.safeValue(additionalDataGrouped, id, []), 'chain');
1218
+ const extraChainsData = this.indexBy(this.safeList(additionalDataGrouped, id, []), 'chain');
1219
1219
  const rawPrecision = this.safeString(entry, 'precision');
1220
1220
  const precision = this.parseNumber(this.parsePrecision(rawPrecision));
1221
1221
  const chainsLength = chains.length;
@@ -1356,7 +1356,7 @@ export default class kucoin extends Exchange {
1356
1356
  request['chain'] = this.networkCodeToId(networkCode).toLowerCase();
1357
1357
  }
1358
1358
  const response = await this.privateGetWithdrawalsQuotas(this.extend(request, params));
1359
- const data = this.safeValue(response, 'data');
1359
+ const data = this.safeDict(response, 'data', {});
1360
1360
  const withdrawFees = {};
1361
1361
  withdrawFees[code] = this.safeNumber(data, 'withdrawMinFee');
1362
1362
  return {
@@ -6,7 +6,7 @@
6
6
 
7
7
  // ---------------------------------------------------------------------------
8
8
  import coinbaseRest from '../coinbase.js';
9
- import { ExchangeError } from '../base/errors.js';
9
+ import { ArgumentsRequired, ExchangeError } from '../base/errors.js';
10
10
  import { ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
11
  import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
12
12
  // ---------------------------------------------------------------------------
@@ -78,15 +78,36 @@ export default class coinbase extends coinbaseRest {
78
78
  }
79
79
  const url = this.urls['api']['ws'];
80
80
  const timestamp = this.numberToString(this.seconds());
81
+ const isCloudAPiKey = (this.apiKey.indexOf('organizations/') >= 0) || (this.secret.startsWith('-----BEGIN'));
81
82
  const auth = timestamp + name + productIds.join(',');
82
83
  const subscribe = {
83
84
  'type': 'subscribe',
84
85
  'product_ids': productIds,
85
86
  'channel': name,
86
- 'api_key': this.apiKey,
87
- 'timestamp': timestamp,
88
- 'signature': this.hmac(this.encode(auth), this.encode(this.secret), sha256),
87
+ // 'api_key': this.apiKey,
88
+ // 'timestamp': timestamp,
89
+ // 'signature': this.hmac (this.encode (auth), this.encode (this.secret), sha256),
89
90
  };
91
+ if (!isCloudAPiKey) {
92
+ subscribe['api_key'] = this.apiKey;
93
+ subscribe['timestamp'] = timestamp;
94
+ subscribe['signature'] = this.hmac(this.encode(auth), this.encode(this.secret), sha256);
95
+ }
96
+ else {
97
+ if (this.apiKey.startsWith('-----BEGIN')) {
98
+ throw new ArgumentsRequired(this.id + ' apiKey should contain the name (eg: organizations/3b910e93....) and not the public key');
99
+ }
100
+ const currentToken = this.safeString(this.options, 'wsToken');
101
+ const tokenTimestamp = this.safeInteger(this.options, 'wsTokenTimestamp', 0);
102
+ const seconds = this.seconds();
103
+ if (currentToken === undefined || tokenTimestamp + 120 < seconds) {
104
+ // we should generate new token
105
+ const token = this.createAuthToken(seconds);
106
+ this.options['wsToken'] = token;
107
+ this.options['wsTokenTimestamp'] = seconds;
108
+ }
109
+ subscribe['jwt'] = this.safeString(this.options, 'wsToken');
110
+ }
90
111
  return await this.watch(url, messageHash, subscribe, messageHash);
91
112
  }
92
113
  async watchTicker(symbol, params = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.2.98",
3
+ "version": "4.2.100",
4
4
  "description": "A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges",
5
5
  "unpkg": "dist/ccxt.browser.js",
6
6
  "type": "module",