ccxt 4.5.14 → 4.5.16

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 (66) hide show
  1. package/README.md +20 -5
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/ascendex.js +1 -0
  5. package/dist/cjs/src/backpack.js +7 -2
  6. package/dist/cjs/src/base/Exchange.js +46 -0
  7. package/dist/cjs/src/binance.js +3 -0
  8. package/dist/cjs/src/bingx.js +73 -46
  9. package/dist/cjs/src/bitget.js +19 -6
  10. package/dist/cjs/src/blofin.js +7 -6
  11. package/dist/cjs/src/bybit.js +16 -6
  12. package/dist/cjs/src/delta.js +98 -3
  13. package/dist/cjs/src/gate.js +152 -151
  14. package/dist/cjs/src/htx.js +1 -0
  15. package/dist/cjs/src/kraken.js +99 -4
  16. package/dist/cjs/src/kucoin.js +1 -0
  17. package/dist/cjs/src/mexc.js +1 -0
  18. package/dist/cjs/src/okx.js +10 -0
  19. package/dist/cjs/src/phemex.js +6 -3
  20. package/dist/cjs/src/poloniex.js +3 -0
  21. package/dist/cjs/src/pro/binance.js +1 -1
  22. package/dist/cjs/src/pro/kraken.js +1 -1
  23. package/dist/cjs/src/pro/upbit.js +25 -1
  24. package/dist/cjs/src/woo.js +41 -20
  25. package/js/ccxt.d.ts +1 -1
  26. package/js/ccxt.js +1 -1
  27. package/js/src/abstract/bingx.d.ts +17 -0
  28. package/js/src/abstract/bybit.d.ts +1 -0
  29. package/js/src/abstract/delta.d.ts +5 -1
  30. package/js/src/abstract/woo.d.ts +0 -3
  31. package/js/src/ascendex.js +1 -0
  32. package/js/src/backpack.d.ts +1 -1
  33. package/js/src/backpack.js +7 -2
  34. package/js/src/base/Exchange.d.ts +31 -0
  35. package/js/src/base/Exchange.js +47 -1
  36. package/js/src/base/types.d.ts +2 -0
  37. package/js/src/binance.js +3 -0
  38. package/js/src/bingx.d.ts +2 -2
  39. package/js/src/bingx.js +73 -46
  40. package/js/src/bitget.js +19 -6
  41. package/js/src/blofin.js +7 -6
  42. package/js/src/bybit.d.ts +1 -1
  43. package/js/src/bybit.js +16 -6
  44. package/js/src/delta.d.ts +13 -0
  45. package/js/src/delta.js +98 -3
  46. package/js/src/derive.js +1 -1
  47. package/js/src/gate.d.ts +140 -140
  48. package/js/src/gate.js +152 -151
  49. package/js/src/htx.js +1 -0
  50. package/js/src/kraken.d.ts +11 -1
  51. package/js/src/kraken.js +99 -4
  52. package/js/src/kucoin.js +1 -0
  53. package/js/src/mexc.js +1 -0
  54. package/js/src/okx.js +10 -0
  55. package/js/src/phemex.js +6 -3
  56. package/js/src/poloniex.js +3 -0
  57. package/js/src/pro/binance.js +1 -1
  58. package/js/src/pro/gate.js +1 -1
  59. package/js/src/pro/gemini.js +1 -1
  60. package/js/src/pro/kraken.d.ts +1 -1
  61. package/js/src/pro/kraken.js +1 -1
  62. package/js/src/pro/onetrading.js +1 -1
  63. package/js/src/pro/upbit.js +25 -1
  64. package/js/src/woo.d.ts +1 -1
  65. package/js/src/woo.js +41 -20
  66. package/package.json +1 -1
package/js/src/htx.js CHANGED
@@ -6825,6 +6825,7 @@ export default class htx extends Exchange {
6825
6825
  'repealed': 'failed',
6826
6826
  'wallet-transfer': 'pending',
6827
6827
  'pre-transfer': 'pending',
6828
+ 'verifying': 'pending',
6828
6829
  };
6829
6830
  return this.safeString(statuses, status, status);
6830
6831
  }
@@ -1,5 +1,5 @@
1
1
  import Exchange from './abstract/kraken.js';
2
- import type { IndexType, Int, OrderSide, OrderType, OHLCV, Trade, Order, Balances, Str, Dict, Transaction, Ticker, OrderBook, Tickers, Strings, Currency, Market, TransferEntry, Num, TradingFeeInterface, Currencies, int, LedgerEntry, DepositAddress, Position } from './base/types.js';
2
+ import type { IndexType, Int, OrderSide, OrderType, OHLCV, Trade, Order, Balances, Str, Dict, Transaction, Ticker, OrderBook, Tickers, Strings, Currency, Market, TransferEntry, Num, TradingFeeInterface, Currencies, int, LedgerEntry, DepositAddress, Position, OrderRequest } from './base/types.js';
3
3
  /**
4
4
  * @class kraken
5
5
  * @augments Exchange
@@ -196,6 +196,16 @@ export default class kraken extends Exchange {
196
196
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
197
197
  */
198
198
  createOrder(symbol: string, type: OrderType, side: OrderSide, amount: number, price?: Num, params?: {}): Promise<Order>;
199
+ /**
200
+ * @method
201
+ * @name kraken#createOrders
202
+ * @description create a list of trade orders
203
+ * @see https://docs.kraken.com/api/docs/rest-api/add-order-batch/
204
+ * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
205
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
206
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
207
+ */
208
+ createOrders(orders: OrderRequest[], params?: {}): Promise<Order[]>;
199
209
  findMarketByAltnameOrId(id: any): any;
200
210
  getDelistedMarketById(id: any): any;
201
211
  parseOrderStatus(status: Str): string;
package/js/src/kraken.js CHANGED
@@ -41,6 +41,7 @@ export default class kraken extends Exchange {
41
41
  'createMarketOrderWithCost': false,
42
42
  'createMarketSellOrderWithCost': false,
43
43
  'createOrder': true,
44
+ 'createOrders': true,
44
45
  'createStopLimitOrder': true,
45
46
  'createStopMarketOrder': true,
46
47
  'createStopOrder': true,
@@ -468,7 +469,11 @@ export default class kraken extends Exchange {
468
469
  'selfTradePrevention': true,
469
470
  'iceberg': true, // todo implement
470
471
  },
471
- 'createOrders': undefined,
472
+ 'createOrders': {
473
+ 'min': 2,
474
+ 'max': 15,
475
+ 'sameSymbolOnly': true,
476
+ },
472
477
  'fetchMyTrades': {
473
478
  'marginMode': false,
474
479
  'limit': undefined,
@@ -1673,6 +1678,79 @@ export default class kraken extends Exchange {
1673
1678
  // this usingCost flag is used to help the parsing but omited from the order
1674
1679
  return this.parseOrder(result);
1675
1680
  }
1681
+ /**
1682
+ * @method
1683
+ * @name kraken#createOrders
1684
+ * @description create a list of trade orders
1685
+ * @see https://docs.kraken.com/api/docs/rest-api/add-order-batch/
1686
+ * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
1687
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1688
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1689
+ */
1690
+ async createOrders(orders, params = {}) {
1691
+ await this.loadMarkets();
1692
+ const ordersRequests = [];
1693
+ let orderSymbols = [];
1694
+ let symbol = undefined;
1695
+ let market = undefined;
1696
+ for (let i = 0; i < orders.length; i++) {
1697
+ const rawOrder = orders[i];
1698
+ const marketId = this.safeString(rawOrder, 'symbol');
1699
+ if (symbol === undefined) {
1700
+ symbol = marketId;
1701
+ }
1702
+ else {
1703
+ if (symbol !== marketId) {
1704
+ throw new BadRequest(this.id + ' createOrders() requires all orders to have the same symbol');
1705
+ }
1706
+ }
1707
+ market = this.market(marketId);
1708
+ orderSymbols.push(marketId);
1709
+ const type = this.safeString(rawOrder, 'type');
1710
+ const side = this.safeString(rawOrder, 'side');
1711
+ const amount = this.safeValue(rawOrder, 'amount');
1712
+ const price = this.safeValue(rawOrder, 'price');
1713
+ const orderParams = this.safeDict(rawOrder, 'params', {});
1714
+ const req = {
1715
+ 'type': side,
1716
+ 'ordertype': type,
1717
+ 'volume': this.amountToPrecision(market['symbol'], amount),
1718
+ };
1719
+ const orderRequest = this.orderRequest('createOrders', marketId, type, req, amount, price, orderParams);
1720
+ ordersRequests.push(orderRequest[0]);
1721
+ }
1722
+ orderSymbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
1723
+ let response = undefined;
1724
+ let request = {
1725
+ 'orders': ordersRequests,
1726
+ 'pair': market['id'],
1727
+ };
1728
+ request = this.extend(request, params);
1729
+ response = await this.privatePostAddOrderBatch(request);
1730
+ //
1731
+ // {
1732
+ // "error":[
1733
+ // ],
1734
+ // "result":{
1735
+ // "orders":[
1736
+ // {
1737
+ // "txid":"OEPPJX-34RMM-OROGZE",
1738
+ // "descr":{
1739
+ // "order":"sell 6.000000 ADAUSDC @ limit 0.400000"
1740
+ // }
1741
+ // },
1742
+ // {
1743
+ // "txid":"OLQY7O-OYBXW-W23PGL",
1744
+ // "descr":{
1745
+ // "order":"sell 6.000000 ADAUSDC @ limit 0.400000"
1746
+ // }
1747
+ // }
1748
+ // ]
1749
+ // }
1750
+ //
1751
+ const result = this.safeDict(response, 'result', {});
1752
+ return this.parseOrders(this.safeList(result, 'orders'));
1753
+ }
1676
1754
  findMarketByAltnameOrId(id) {
1677
1755
  const marketsByAltname = this.safeValue(this.options, 'marketsByAltname', {});
1678
1756
  if (id in marketsByAltname) {
@@ -3465,10 +3543,11 @@ export default class kraken extends Exchange {
3465
3543
  isTriggerPercent = (price.endsWith('%')) ? true : false;
3466
3544
  }
3467
3545
  const isCancelOrderBatch = (path === 'CancelOrderBatch');
3546
+ const isBatchOrder = (path === 'AddOrderBatch');
3468
3547
  this.checkRequiredCredentials();
3469
3548
  const nonce = this.nonce().toString();
3470
3549
  // urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
3471
- if (isCancelOrderBatch || isTriggerPercent) {
3550
+ if (isCancelOrderBatch || isTriggerPercent || isBatchOrder) {
3472
3551
  body = this.json(this.extend({ 'nonce': nonce }, params));
3473
3552
  }
3474
3553
  else {
@@ -3484,7 +3563,7 @@ export default class kraken extends Exchange {
3484
3563
  'API-Key': this.apiKey,
3485
3564
  'API-Sign': signature,
3486
3565
  };
3487
- if (isCancelOrderBatch || isTriggerPercent) {
3566
+ if (isCancelOrderBatch || isTriggerPercent || isBatchOrder) {
3488
3567
  headers['Content-Type'] = 'application/json';
3489
3568
  }
3490
3569
  else {
@@ -3509,10 +3588,10 @@ export default class kraken extends Exchange {
3509
3588
  }
3510
3589
  if (body[0] === '{') {
3511
3590
  if (typeof response !== 'string') {
3591
+ const message = this.id + ' ' + body;
3512
3592
  if ('error' in response) {
3513
3593
  const numErrors = response['error'].length;
3514
3594
  if (numErrors) {
3515
- const message = this.id + ' ' + body;
3516
3595
  for (let i = 0; i < response['error'].length; i++) {
3517
3596
  const error = response['error'][i];
3518
3597
  this.throwExactlyMatchedException(this.exceptions['exact'], error, message);
@@ -3521,6 +3600,22 @@ export default class kraken extends Exchange {
3521
3600
  throw new ExchangeError(message);
3522
3601
  }
3523
3602
  }
3603
+ // handleCreateOrdersErrors:
3604
+ if ('result' in response) {
3605
+ const result = this.safeDict(response, 'result', {});
3606
+ if ('orders' in result) {
3607
+ const orders = this.safeList(result, 'orders', []);
3608
+ for (let i = 0; i < orders.length; i++) {
3609
+ const order = orders[i];
3610
+ const error = this.safeString(order, 'error');
3611
+ if (error !== undefined) {
3612
+ this.throwExactlyMatchedException(this.exceptions['exact'], error, message);
3613
+ this.throwBroadlyMatchedException(this.exceptions['broad'], error, message);
3614
+ throw new ExchangeError(message);
3615
+ }
3616
+ }
3617
+ }
3618
+ }
3524
3619
  }
3525
3620
  }
3526
3621
  return undefined;
package/js/src/kucoin.js CHANGED
@@ -494,6 +494,7 @@ export default class kucoin extends Exchange {
494
494
  'order_not_exist': OrderNotFound,
495
495
  'order_not_exist_or_not_allow_to_cancel': InvalidOrder,
496
496
  'Order size below the minimum requirement.': InvalidOrder,
497
+ 'Order size increment invalid.': InvalidOrder,
497
498
  'The withdrawal amount is below the minimum requirement.': ExchangeError,
498
499
  'Unsuccessful! Exceeded the max. funds out-transfer limit': InsufficientFunds,
499
500
  'The amount increment is invalid.': BadRequest,
package/js/src/mexc.js CHANGED
@@ -926,6 +926,7 @@ export default class mexc extends Exchange {
926
926
  '30029': InvalidOrder,
927
927
  '30032': InvalidOrder,
928
928
  '30041': InvalidOrder,
929
+ '30087': InvalidOrder,
929
930
  '60005': ExchangeError,
930
931
  '700001': AuthenticationError,
931
932
  '700002': AuthenticationError,
package/js/src/okx.js CHANGED
@@ -1653,6 +1653,12 @@ export default class okx extends Exchange {
1653
1653
  // "uly": "BTC-USD"
1654
1654
  // }
1655
1655
  //
1656
+ // for swap "preopen" markets, only `instId` and `instType` are present
1657
+ //
1658
+ // instId: "ETH-USD_UM-SWAP",
1659
+ // instType: "SWAP",
1660
+ // state: "preopen",
1661
+ //
1656
1662
  const id = this.safeString(market, 'instId');
1657
1663
  let type = this.safeStringLower(market, 'instType');
1658
1664
  if (type === 'futures') {
@@ -1682,6 +1688,10 @@ export default class okx extends Exchange {
1682
1688
  const base = this.safeCurrencyCode(baseId);
1683
1689
  const quote = this.safeCurrencyCode(quoteId);
1684
1690
  let symbol = base + '/' + quote;
1691
+ // handle preopen empty markets
1692
+ if (base === '' || quote === '') {
1693
+ symbol = id;
1694
+ }
1685
1695
  let expiry = undefined;
1686
1696
  let strikePrice = undefined;
1687
1697
  let optionType = undefined;
package/js/src/phemex.js CHANGED
@@ -3386,12 +3386,14 @@ export default class phemex extends Exchange {
3386
3386
  if (symbol !== undefined) {
3387
3387
  market = this.market(symbol);
3388
3388
  }
3389
+ let type = undefined;
3390
+ [type, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
3389
3391
  const request = {};
3390
3392
  if (limit !== undefined) {
3391
3393
  limit = Math.min(200, limit);
3392
3394
  request['limit'] = limit;
3393
3395
  }
3394
- const isUSDTSettled = (symbol === undefined) || (this.safeString(market, 'settle') === 'USDT');
3396
+ const isUSDTSettled = (type !== 'spot') && ((symbol === undefined) || (this.safeString(market, 'settle') === 'USDT'));
3395
3397
  if (isUSDTSettled) {
3396
3398
  request['currency'] = 'USDT';
3397
3399
  request['offset'] = 0;
@@ -3399,7 +3401,7 @@ export default class phemex extends Exchange {
3399
3401
  request['limit'] = 200;
3400
3402
  }
3401
3403
  }
3402
- else {
3404
+ else if (symbol !== undefined) {
3403
3405
  request['symbol'] = market['id'];
3404
3406
  }
3405
3407
  if (since !== undefined) {
@@ -3409,7 +3411,8 @@ export default class phemex extends Exchange {
3409
3411
  if (isUSDTSettled) {
3410
3412
  response = await this.privateGetExchangeOrderV2TradingList(this.extend(request, params));
3411
3413
  }
3412
- else if (market['swap']) {
3414
+ else if (type === 'swap') {
3415
+ request['tradeType'] = 'Trade';
3413
3416
  response = await this.privateGetExchangeOrderTrade(this.extend(request, params));
3414
3417
  }
3415
3418
  else {
@@ -3611,6 +3611,9 @@ export default class poloniex extends Exchange {
3611
3611
  if (this.inArray(api, ['swapPublic', 'swapPrivate'])) {
3612
3612
  url = this.urls['api']['swap'];
3613
3613
  }
3614
+ if ('symbol' in params) {
3615
+ params['symbol'] = this.encodeURIComponent(params['symbol']); // handle symbols like 索拉拉/USDT'
3616
+ }
3614
3617
  const query = this.omit(params, this.extractParams(path));
3615
3618
  const implodedPath = this.implodeParams(path, params);
3616
3619
  if (api === 'public' || api === 'swapPublic') {
@@ -2330,7 +2330,7 @@ export default class binance extends binanceRest {
2330
2330
  'apiKey': this.apiKey,
2331
2331
  }, params);
2332
2332
  extendedParams = this.keysort(extendedParams);
2333
- const query = this.urlencode(extendedParams);
2333
+ const query = this.rawencode(extendedParams);
2334
2334
  let signature = undefined;
2335
2335
  if (this.secret.indexOf('PRIVATE KEY') > -1) {
2336
2336
  if (this.secret.length > 120) {
@@ -3,7 +3,7 @@ import gateRest from '../gate.js';
3
3
  import { AuthenticationError, BadRequest, ArgumentsRequired, ChecksumError, ExchangeError, NotSupported } from '../base/errors.js';
4
4
  import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
5
5
  import { sha512 } from '../static_dependencies/noble-hashes/sha512.js';
6
- import Precise from '../base/Precise.js';
6
+ import { Precise } from '../base/Precise.js';
7
7
  // ---------------------------------------------------------------------------
8
8
  export default class gate extends gateRest {
9
9
  describe() {
@@ -3,7 +3,7 @@ import geminiRest from '../gemini.js';
3
3
  import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
4
4
  import { ExchangeError, NotSupported } from '../base/errors.js';
5
5
  import { sha384 } from '../static_dependencies/noble-hashes/sha512.js';
6
- import Precise from '../base/Precise.js';
6
+ import { Precise } from '../base/Precise.js';
7
7
  // ---------------------------------------------------------------------------
8
8
  export default class gemini extends geminiRest {
9
9
  describe() {
@@ -70,7 +70,7 @@ export default class kraken extends krakenRest {
70
70
  handleCancelAllOrders(client: any, message: any): void;
71
71
  handleTicker(client: any, message: any): void;
72
72
  handleTrades(client: Client, message: any): void;
73
- handleOHLCV(client: Client, message: any, subscription: any): void;
73
+ handleOHLCV(client: Client, message: any): void;
74
74
  requestId(): any;
75
75
  /**
76
76
  * @method
@@ -583,7 +583,7 @@ export default class kraken extends krakenRest {
583
583
  }
584
584
  client.resolve(stored, messageHash);
585
585
  }
586
- handleOHLCV(client, message, subscription) {
586
+ handleOHLCV(client, message) {
587
587
  //
588
588
  // {
589
589
  // "channel": "ohlc",
@@ -2,7 +2,7 @@
2
2
  import onetradingRest from '../onetrading.js';
3
3
  import { NotSupported, ExchangeError } from '../base/errors.js';
4
4
  import { ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
5
- import Precise from '../base/Precise.js';
5
+ import { Precise } from '../base/Precise.js';
6
6
  // ---------------------------------------------------------------------------
7
7
  export default class onetrading extends onetradingRest {
8
8
  describe() {
@@ -397,12 +397,36 @@ export default class upbit extends upbitRest {
397
397
  'hostname': this.hostname,
398
398
  });
399
399
  url += '/private';
400
+ const client = this.client(url);
401
+ // Track private channel subscriptions to support multiple concurrent watches
402
+ const subscriptionsKey = 'upbitPrivateSubscriptions';
403
+ if (!(subscriptionsKey in client.subscriptions)) {
404
+ client.subscriptions[subscriptionsKey] = {};
405
+ }
406
+ let channelKey = channel;
407
+ if (symbol !== undefined) {
408
+ channelKey = channel + ':' + symbol;
409
+ }
410
+ const subscriptions = client.subscriptions[subscriptionsKey];
411
+ const isNewChannel = !(channelKey in subscriptions);
412
+ if (isNewChannel) {
413
+ subscriptions[channelKey] = request;
414
+ }
415
+ // Build subscription message with all requested private channels
416
+ // Format: [{'ticket': uuid}, {'type': 'myOrder'}, {'type': 'myAsset'}, ...]
417
+ const requests = [];
418
+ const channelKeys = Object.keys(subscriptions);
419
+ for (let i = 0; i < channelKeys.length; i++) {
420
+ requests.push(subscriptions[channelKeys[i]]);
421
+ }
400
422
  const message = [
401
423
  {
402
424
  'ticket': this.uuid(),
403
425
  },
404
- request,
405
426
  ];
427
+ for (let i = 0; i < requests.length; i++) {
428
+ message.push(requests[i]);
429
+ }
406
430
  return await this.watch(url, messageHash, message, messageHash);
407
431
  }
408
432
  /**
package/js/src/woo.d.ts CHANGED
@@ -472,7 +472,7 @@ export default class woo extends Exchange {
472
472
  * @method
473
473
  * @name woo#withdraw
474
474
  * @description make a withdrawal
475
- * @see https://docs.woox.io/#token-withdraw
475
+ * @see https://docs.woox.io/#token-withdraw-v3
476
476
  * @param {string} code unified currency code
477
477
  * @param {float} amount the amount to withdraw
478
478
  * @param {string} address the address to withdraw to
package/js/src/woo.js CHANGED
@@ -206,9 +206,7 @@ export default class woo extends Exchange {
206
206
  'post': {
207
207
  'order': 1,
208
208
  'order/cancel_all_after': 1,
209
- 'asset/main_sub_transfer': 30,
210
209
  'asset/ltv': 30,
211
- 'asset/withdraw': 30,
212
210
  'asset/internal_withdraw': 30,
213
211
  'interest/repay': 60,
214
212
  'client/account_mode': 120,
@@ -282,7 +280,6 @@ export default class woo extends Exchange {
282
280
  'spotMargin/maxMargin': 60,
283
281
  'algo/order/{oid}': 1,
284
282
  'algo/orders': 1,
285
- 'balances': 1,
286
283
  'positions': 3.33,
287
284
  'buypower': 1,
288
285
  'convert/exchangeInfo': 1,
@@ -2417,7 +2414,7 @@ export default class woo extends Exchange {
2417
2414
  */
2418
2415
  async fetchBalance(params = {}) {
2419
2416
  await this.loadMarkets();
2420
- const response = await this.v3PrivateGetBalances(params);
2417
+ const response = await this.v3PrivateGetAssetBalances(params);
2421
2418
  //
2422
2419
  // {
2423
2420
  // "success": true,
@@ -2747,14 +2744,14 @@ export default class woo extends Exchange {
2747
2744
  const networkizedCode = this.safeString(transaction, 'token');
2748
2745
  const currencyDefined = this.getCurrencyFromChaincode(networkizedCode, currency);
2749
2746
  const code = currencyDefined['code'];
2750
- let movementDirection = this.safeStringLower2(transaction, 'token_side', 'tokenSide');
2747
+ let movementDirection = this.safeStringLowerN(transaction, ['token_side', 'tokenSide', 'type']);
2751
2748
  if (movementDirection === 'withdraw') {
2752
2749
  movementDirection = 'withdrawal';
2753
2750
  }
2754
2751
  const fee = this.parseTokenAndFeeTemp(transaction, ['fee_token', 'feeToken'], ['fee_amount', 'feeAmount']);
2755
- const addressTo = this.safeString2(transaction, 'target_address', 'targetAddress');
2752
+ const addressTo = this.safeStringN(transaction, ['target_address', 'targetAddress', 'addressTo']);
2756
2753
  const addressFrom = this.safeString2(transaction, 'source_address', 'sourceAddress');
2757
- const timestamp = this.safeTimestamp2(transaction, 'created_time', 'createdTime');
2754
+ const timestamp = this.safeTimestampN(transaction, ['created_time', 'createdTime'], this.safeInteger(transaction, 'timestamp'));
2758
2755
  return {
2759
2756
  'info': transaction,
2760
2757
  'id': this.safeStringN(transaction, ['id', 'withdraw_id', 'withdrawId']),
@@ -2764,7 +2761,7 @@ export default class woo extends Exchange {
2764
2761
  'address': undefined,
2765
2762
  'addressFrom': addressFrom,
2766
2763
  'addressTo': addressTo,
2767
- 'tag': this.safeString(transaction, 'extra'),
2764
+ 'tag': this.safeString2(transaction, 'extra', 'tag'),
2768
2765
  'tagFrom': undefined,
2769
2766
  'tagTo': undefined,
2770
2767
  'type': movementDirection,
@@ -2775,7 +2772,7 @@ export default class woo extends Exchange {
2775
2772
  'comment': undefined,
2776
2773
  'internal': undefined,
2777
2774
  'fee': fee,
2778
- 'network': undefined,
2775
+ 'network': this.networkIdToCode(this.safeString(transaction, 'network')),
2779
2776
  };
2780
2777
  }
2781
2778
  parseTransactionStatus(status) {
@@ -2806,17 +2803,25 @@ export default class woo extends Exchange {
2806
2803
  const request = {
2807
2804
  'token': currency['id'],
2808
2805
  'amount': this.parseToNumeric(amount),
2809
- 'from_application_id': fromAccount,
2810
- 'to_application_id': toAccount,
2806
+ 'from': {
2807
+ 'applicationId': fromAccount,
2808
+ },
2809
+ 'to': {
2810
+ 'applicationId': toAccount,
2811
+ },
2811
2812
  };
2812
- const response = await this.v1PrivatePostAssetMainSubTransfer(this.extend(request, params));
2813
+ const response = await this.v3PrivatePostAssetTransfer(this.extend(request, params));
2813
2814
  //
2814
2815
  // {
2815
2816
  // "success": true,
2816
2817
  // "id": 200
2817
2818
  // }
2818
2819
  //
2819
- const transfer = this.parseTransfer(response, currency);
2820
+ const data = this.safeDict(response, 'data', {});
2821
+ data['timestamp'] = this.safeInteger(response, 'timestamp');
2822
+ data['token'] = currency['id'];
2823
+ data['status'] = 'ok';
2824
+ const transfer = this.parseTransfer(data, currency);
2820
2825
  const transferOptions = this.safeDict(this.options, 'transfer', {});
2821
2826
  const fillResponseFromRequest = this.safeBool(transferOptions, 'fillResponseFromRequest', true);
2822
2827
  if (fillResponseFromRequest) {
@@ -2930,7 +2935,7 @@ export default class woo extends Exchange {
2930
2935
  // }
2931
2936
  //
2932
2937
  const code = this.safeCurrencyCode(this.safeString(transfer, 'token'), currency);
2933
- const timestamp = this.safeTimestamp(transfer, 'createdTime');
2938
+ const timestamp = this.safeTimestamp2(transfer, 'createdTime', 'timestamp');
2934
2939
  const success = this.safeBool(transfer, 'success');
2935
2940
  let status = undefined;
2936
2941
  if (success !== undefined) {
@@ -2964,7 +2969,7 @@ export default class woo extends Exchange {
2964
2969
  * @method
2965
2970
  * @name woo#withdraw
2966
2971
  * @description make a withdrawal
2967
- * @see https://docs.woox.io/#token-withdraw
2972
+ * @see https://docs.woox.io/#token-withdraw-v3
2968
2973
  * @param {string} code unified currency code
2969
2974
  * @param {float} amount the amount to withdraw
2970
2975
  * @param {string} address the address to withdraw to
@@ -2984,17 +2989,33 @@ export default class woo extends Exchange {
2984
2989
  if (tag !== undefined) {
2985
2990
  request['extra'] = tag;
2986
2991
  }
2987
- let specialNetworkId = undefined;
2988
- [specialNetworkId, params] = this.getDedicatedNetworkId(currency, params);
2989
- request['token'] = specialNetworkId;
2990
- const response = await this.v1PrivatePostAssetWithdraw(this.extend(request, params));
2992
+ const network = this.safeString(params, 'network');
2993
+ if (network === undefined) {
2994
+ throw new ArgumentsRequired(this.id + ' withdraw() requires a network parameter for ' + code);
2995
+ }
2996
+ params = this.omit(params, 'network');
2997
+ request['token'] = currency['id'];
2998
+ request['network'] = this.networkCodeToId(network);
2999
+ const response = await this.v3PrivatePostAssetWalletWithdraw(this.extend(request, params));
2991
3000
  //
2992
3001
  // {
2993
3002
  // "success": true,
2994
3003
  // "withdraw_id": "20200119145703654"
2995
3004
  // }
2996
3005
  //
2997
- return this.parseTransaction(response, currency);
3006
+ const data = this.safeDict(response, 'data', {});
3007
+ const transactionData = this.extend(data, {
3008
+ 'id': this.safeString(data, 'withdrawId'),
3009
+ 'timestamp': this.safeInteger(response, 'timestamp'),
3010
+ 'currency': code,
3011
+ 'amount': amount,
3012
+ 'addressTo': address,
3013
+ 'tag': tag,
3014
+ 'network': network,
3015
+ 'type': 'withdrawal',
3016
+ 'status': 'pending',
3017
+ });
3018
+ return this.parseTransaction(transactionData, currency);
2998
3019
  }
2999
3020
  /**
3000
3021
  * @method
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccxt",
3
- "version": "4.5.14",
3
+ "version": "4.5.16",
4
4
  "description": "A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go",
5
5
  "unpkg": "dist/ccxt.browser.min.js",
6
6
  "type": "module",