ccxt 4.2.98 → 4.2.99

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.99';
186
186
  Exchange["default"].ccxtVersion = version;
187
187
  const exchanges = {
188
188
  'ace': ace,
@@ -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');
@@ -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.98";
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.99';
42
42
  Exchange.ccxtVersion = version;
43
43
  //-----------------------------------------------------------------------------
44
44
  import ace from './src/ace.js';
@@ -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');
@@ -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.99",
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",