ccxt-look 1.81.50

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 (264) hide show
  1. package/.cache/eslintcache +1 -0
  2. package/.dockerignore +6 -0
  3. package/.eslintignore +1 -0
  4. package/.gitattributes +5 -0
  5. package/.readthedocs.yaml +16 -0
  6. package/CONTRIBUTING.md +1049 -0
  7. package/LICENSE.txt +21 -0
  8. package/README.md +537 -0
  9. package/SECURITY.md +5 -0
  10. package/build/cleanup-old-tags.js +94 -0
  11. package/build/countries.js +256 -0
  12. package/build/export-exchanges.js +520 -0
  13. package/build/fs.js +51 -0
  14. package/build/transpile.js +1772 -0
  15. package/build/vss.js +78 -0
  16. package/ccxt.browser.js +7 -0
  17. package/ccxt.d.ts +692 -0
  18. package/ccxt.js +171 -0
  19. package/cleanup.sh +2 -0
  20. package/composer-install.sh +20 -0
  21. package/dist/ccxt.browser.js +208383 -0
  22. package/gource.sh +3 -0
  23. package/index.html +7 -0
  24. package/js/.eslintrc +87 -0
  25. package/js/aax.js +2686 -0
  26. package/js/ascendex.js +2584 -0
  27. package/js/base/.eslintrc.js +43 -0
  28. package/js/base/Exchange.js +2371 -0
  29. package/js/base/Precise.js +283 -0
  30. package/js/base/errorHierarchy.js +47 -0
  31. package/js/base/errors.js +55 -0
  32. package/js/base/functions/crypto.js +158 -0
  33. package/js/base/functions/encode.js +118 -0
  34. package/js/base/functions/generic.js +270 -0
  35. package/js/base/functions/misc.js +138 -0
  36. package/js/base/functions/number.js +329 -0
  37. package/js/base/functions/platform.js +38 -0
  38. package/js/base/functions/string.js +21 -0
  39. package/js/base/functions/throttle.js +79 -0
  40. package/js/base/functions/time.js +210 -0
  41. package/js/base/functions/type.js +66 -0
  42. package/js/base/functions.js +28 -0
  43. package/js/bequant.js +32 -0
  44. package/js/bibox.js +1407 -0
  45. package/js/bigone.js +1366 -0
  46. package/js/binance.js +5652 -0
  47. package/js/binancecoinm.js +46 -0
  48. package/js/binanceus.js +46 -0
  49. package/js/binanceusdm.js +49 -0
  50. package/js/bit2c.js +535 -0
  51. package/js/bitbank.js +842 -0
  52. package/js/bitbay.js +16 -0
  53. package/js/bitbns.js +1073 -0
  54. package/js/bitcoincom.js +15 -0
  55. package/js/bitfinex.js +1433 -0
  56. package/js/bitfinex2.js +2025 -0
  57. package/js/bitflyer.js +840 -0
  58. package/js/bitforex.js +614 -0
  59. package/js/bitget.js +2397 -0
  60. package/js/bithumb.js +980 -0
  61. package/js/bitmart.js +2516 -0
  62. package/js/bitmex.js +1809 -0
  63. package/js/bitopro.js +1443 -0
  64. package/js/bitpanda.js +1782 -0
  65. package/js/bitrue.js +1747 -0
  66. package/js/bitso.js +1062 -0
  67. package/js/bitstamp.js +1757 -0
  68. package/js/bitstamp1.js +343 -0
  69. package/js/bittrex.js +1876 -0
  70. package/js/bitvavo.js +1579 -0
  71. package/js/bkex.js +1233 -0
  72. package/js/bl3p.js +346 -0
  73. package/js/blockchaincom.js +969 -0
  74. package/js/btcalpha.js +680 -0
  75. package/js/btcbox.js +477 -0
  76. package/js/btcmarkets.js +1022 -0
  77. package/js/btctradeua.js +466 -0
  78. package/js/btcturk.js +734 -0
  79. package/js/buda.js +946 -0
  80. package/js/bw.js +1265 -0
  81. package/js/bybit.js +3372 -0
  82. package/js/bytetrade.js +1336 -0
  83. package/js/cdax.js +1646 -0
  84. package/js/cex.js +1410 -0
  85. package/js/coinbase.js +1342 -0
  86. package/js/coinbaseprime.js +31 -0
  87. package/js/coinbasepro.js +1466 -0
  88. package/js/coincheck.js +755 -0
  89. package/js/coinex.js +3400 -0
  90. package/js/coinfalcon.js +880 -0
  91. package/js/coinmate.js +794 -0
  92. package/js/coinone.js +816 -0
  93. package/js/coinspot.js +345 -0
  94. package/js/crex24.js +1636 -0
  95. package/js/cryptocom.js +1832 -0
  96. package/js/currencycom.js +1748 -0
  97. package/js/delta.js +1547 -0
  98. package/js/deribit.js +2148 -0
  99. package/js/digifinex.js +1585 -0
  100. package/js/eqonex.js +1660 -0
  101. package/js/exmo.js +1670 -0
  102. package/js/fairdesk.js +1231 -0
  103. package/js/flowbtc.js +35 -0
  104. package/js/fmfwio.js +34 -0
  105. package/js/ftx.js +2751 -0
  106. package/js/ftxus.js +38 -0
  107. package/js/gateio.js +4174 -0
  108. package/js/gemini.js +1397 -0
  109. package/js/hitbtc.js +1343 -0
  110. package/js/hitbtc3.js +2329 -0
  111. package/js/hollaex.js +1486 -0
  112. package/js/huobi.js +5706 -0
  113. package/js/huobijp.js +1710 -0
  114. package/js/huobipro.js +18 -0
  115. package/js/idex.js +1439 -0
  116. package/js/independentreserve.js +649 -0
  117. package/js/indodax.js +742 -0
  118. package/js/itbit.js +722 -0
  119. package/js/kraken.js +2179 -0
  120. package/js/kucoin.js +2571 -0
  121. package/js/kucoinfutures.js +1771 -0
  122. package/js/kuna.js +809 -0
  123. package/js/latoken.js +1445 -0
  124. package/js/lbank.js +760 -0
  125. package/js/liquid.js +1432 -0
  126. package/js/luno.js +873 -0
  127. package/js/lykke.js +1147 -0
  128. package/js/mercado.js +771 -0
  129. package/js/mexc.js +3151 -0
  130. package/js/ndax.js +2233 -0
  131. package/js/novadax.js +1318 -0
  132. package/js/oceanex.js +816 -0
  133. package/js/okcoin.js +3841 -0
  134. package/js/okex.js +16 -0
  135. package/js/okex5.js +16 -0
  136. package/js/okx.js +4795 -0
  137. package/js/paymium.js +498 -0
  138. package/js/phemex.js +2957 -0
  139. package/js/poloniex.js +1674 -0
  140. package/js/probit.js +1346 -0
  141. package/js/qtrade.js +1588 -0
  142. package/js/ripio.js +1061 -0
  143. package/js/static_dependencies/BN/bn.js +3526 -0
  144. package/js/static_dependencies/README.md +1 -0
  145. package/js/static_dependencies/crypto-js/crypto-js.js +5988 -0
  146. package/js/static_dependencies/elliptic/lib/elliptic/curve/base.js +375 -0
  147. package/js/static_dependencies/elliptic/lib/elliptic/curve/edwards.js +433 -0
  148. package/js/static_dependencies/elliptic/lib/elliptic/curve/index.js +8 -0
  149. package/js/static_dependencies/elliptic/lib/elliptic/curve/mont.js +180 -0
  150. package/js/static_dependencies/elliptic/lib/elliptic/curve/short.js +938 -0
  151. package/js/static_dependencies/elliptic/lib/elliptic/curves.js +204 -0
  152. package/js/static_dependencies/elliptic/lib/elliptic/ec/index.js +240 -0
  153. package/js/static_dependencies/elliptic/lib/elliptic/ec/key.js +119 -0
  154. package/js/static_dependencies/elliptic/lib/elliptic/ec/signature.js +24 -0
  155. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/index.js +145 -0
  156. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/key.js +100 -0
  157. package/js/static_dependencies/elliptic/lib/elliptic/eddsa/signature.js +65 -0
  158. package/js/static_dependencies/elliptic/lib/elliptic/precomputed/secp256k1.js +780 -0
  159. package/js/static_dependencies/elliptic/lib/elliptic/utils.js +214 -0
  160. package/js/static_dependencies/elliptic/lib/elliptic.js +22 -0
  161. package/js/static_dependencies/elliptic/lib/hmac-drbg/hmac-drbg.js +114 -0
  162. package/js/static_dependencies/fetch-ponyfill/fetch-node.js +39 -0
  163. package/js/static_dependencies/node-fetch/index.js +1564 -0
  164. package/js/static_dependencies/node-rsa/NodeRSA.js +223 -0
  165. package/js/static_dependencies/node-rsa/asn1/ber/errors.js +13 -0
  166. package/js/static_dependencies/node-rsa/asn1/ber/index.js +21 -0
  167. package/js/static_dependencies/node-rsa/asn1/ber/reader.js +262 -0
  168. package/js/static_dependencies/node-rsa/asn1/ber/types.js +36 -0
  169. package/js/static_dependencies/node-rsa/asn1/index.js +17 -0
  170. package/js/static_dependencies/node-rsa/encryptEngines/js.js +34 -0
  171. package/js/static_dependencies/node-rsa/formats/components.js +71 -0
  172. package/js/static_dependencies/node-rsa/formats/formats.js +31 -0
  173. package/js/static_dependencies/node-rsa/formats/pkcs1.js +148 -0
  174. package/js/static_dependencies/node-rsa/formats/pkcs8.js +187 -0
  175. package/js/static_dependencies/node-rsa/libs/jsbn.js +1252 -0
  176. package/js/static_dependencies/node-rsa/libs/rsa.js +147 -0
  177. package/js/static_dependencies/node-rsa/schemes/pkcs1.js +176 -0
  178. package/js/static_dependencies/node-rsa/schemes/schemes.js +21 -0
  179. package/js/static_dependencies/node-rsa/utils.js +98 -0
  180. package/js/static_dependencies/qs/formats.js +18 -0
  181. package/js/static_dependencies/qs/index.js +11 -0
  182. package/js/static_dependencies/qs/parse.js +242 -0
  183. package/js/static_dependencies/qs/stringify.js +269 -0
  184. package/js/static_dependencies/qs/utils.js +230 -0
  185. package/js/stex.js +1925 -0
  186. package/js/test/.eslintrc.js +42 -0
  187. package/js/test/Exchange/test.balance.js +61 -0
  188. package/js/test/Exchange/test.borrowRate.js +32 -0
  189. package/js/test/Exchange/test.currency.js +52 -0
  190. package/js/test/Exchange/test.fetchBalance.js +23 -0
  191. package/js/test/Exchange/test.fetchBorrowInterest.js +59 -0
  192. package/js/test/Exchange/test.fetchBorrowRate.js +32 -0
  193. package/js/test/Exchange/test.fetchBorrowRates.js +28 -0
  194. package/js/test/Exchange/test.fetchClosedOrders.js +32 -0
  195. package/js/test/Exchange/test.fetchCurrencies.js +35 -0
  196. package/js/test/Exchange/test.fetchDeposits.js +31 -0
  197. package/js/test/Exchange/test.fetchFundingFees.js +19 -0
  198. package/js/test/Exchange/test.fetchFundingRateHistory.js +40 -0
  199. package/js/test/Exchange/test.fetchL2OrderBook.js +23 -0
  200. package/js/test/Exchange/test.fetchLedger.js +42 -0
  201. package/js/test/Exchange/test.fetchLeverageTiers.js +33 -0
  202. package/js/test/Exchange/test.fetchMarketLeverageTiers.js +22 -0
  203. package/js/test/Exchange/test.fetchMarkets.js +33 -0
  204. package/js/test/Exchange/test.fetchMyTrades.js +42 -0
  205. package/js/test/Exchange/test.fetchOHLCV.js +46 -0
  206. package/js/test/Exchange/test.fetchOpenOrders.js +36 -0
  207. package/js/test/Exchange/test.fetchOrderBook.js +25 -0
  208. package/js/test/Exchange/test.fetchOrderBooks.js +35 -0
  209. package/js/test/Exchange/test.fetchOrders.js +41 -0
  210. package/js/test/Exchange/test.fetchPositions.js +47 -0
  211. package/js/test/Exchange/test.fetchStatus.js +35 -0
  212. package/js/test/Exchange/test.fetchTicker.js +38 -0
  213. package/js/test/Exchange/test.fetchTickers.js +49 -0
  214. package/js/test/Exchange/test.fetchTrades.js +39 -0
  215. package/js/test/Exchange/test.fetchTradingFee.js +18 -0
  216. package/js/test/Exchange/test.fetchTradingFees.js +22 -0
  217. package/js/test/Exchange/test.fetchTransactions.js +31 -0
  218. package/js/test/Exchange/test.fetchWithdrawals.js +31 -0
  219. package/js/test/Exchange/test.ledgerItem.js +46 -0
  220. package/js/test/Exchange/test.leverageTier.js +33 -0
  221. package/js/test/Exchange/test.loadMarkets.js +35 -0
  222. package/js/test/Exchange/test.market.js +129 -0
  223. package/js/test/Exchange/test.ohlcv.js +33 -0
  224. package/js/test/Exchange/test.order.js +62 -0
  225. package/js/test/Exchange/test.orderbook.js +61 -0
  226. package/js/test/Exchange/test.position.js +21 -0
  227. package/js/test/Exchange/test.throttle.js +94 -0
  228. package/js/test/Exchange/test.ticker.js +95 -0
  229. package/js/test/Exchange/test.trade.js +68 -0
  230. package/js/test/Exchange/test.tradingFee.js +34 -0
  231. package/js/test/Exchange/test.transaction.js +35 -0
  232. package/js/test/base/.eslintrc +38 -0
  233. package/js/test/base/functions/test.crypto.js +110 -0
  234. package/js/test/base/functions/test.datetime.js +62 -0
  235. package/js/test/base/functions/test.generic.js +152 -0
  236. package/js/test/base/functions/test.number.js +362 -0
  237. package/js/test/base/functions/test.time.js +56 -0
  238. package/js/test/base/functions/test.type.js +53 -0
  239. package/js/test/base/test.base.js +193 -0
  240. package/js/test/errors/test.InsufficientFunds.js +86 -0
  241. package/js/test/errors/test.InvalidNonce.js +64 -0
  242. package/js/test/errors/test.InvalidOrder.js +35 -0
  243. package/js/test/errors/test.OrderNotFound.js +39 -0
  244. package/js/test/test.js +426 -0
  245. package/js/test/test.timeout_hang.js +12 -0
  246. package/js/therock.js +1431 -0
  247. package/js/tidebit.js +632 -0
  248. package/js/tidex.js +939 -0
  249. package/js/timex.js +1283 -0
  250. package/js/upbit.js +1622 -0
  251. package/js/vcc.js +1353 -0
  252. package/js/wavesexchange.js +2185 -0
  253. package/js/wazirx.js +732 -0
  254. package/js/whitebit.js +1352 -0
  255. package/js/woo.js +1577 -0
  256. package/js/xena.js +1948 -0
  257. package/js/yobit.js +1129 -0
  258. package/js/zaif.js +647 -0
  259. package/js/zb.js +4088 -0
  260. package/js/zipmex.js +40 -0
  261. package/js/zonda.js +1497 -0
  262. package/multilang.sh +159 -0
  263. package/package.json +591 -0
  264. package/postinstall.js +103 -0
package/js/coinbase.js ADDED
@@ -0,0 +1,1342 @@
1
+ 'use strict';
2
+
3
+ // ----------------------------------------------------------------------------
4
+
5
+ const Exchange = require ('./base/Exchange');
6
+ const { ExchangeError, ArgumentsRequired, AuthenticationError, RateLimitExceeded, InvalidNonce } = require ('./base/errors');
7
+ const Precise = require ('./base/Precise');
8
+
9
+ // ----------------------------------------------------------------------------
10
+
11
+ module.exports = class coinbase extends Exchange {
12
+ describe () {
13
+ return this.deepExtend (super.describe (), {
14
+ 'id': 'coinbase',
15
+ 'name': 'Coinbase',
16
+ 'countries': [ 'US' ],
17
+ 'rateLimit': 400, // 10k calls per hour
18
+ 'version': 'v2',
19
+ 'userAgent': this.userAgents['chrome'],
20
+ 'headers': {
21
+ 'CB-VERSION': '2018-05-30',
22
+ },
23
+ 'has': {
24
+ 'CORS': true,
25
+ 'spot': true,
26
+ 'margin': false,
27
+ 'swap': false,
28
+ 'future': false,
29
+ 'option': false,
30
+ 'addMargin': false,
31
+ 'cancelOrder': undefined,
32
+ 'createDepositAddress': true,
33
+ 'createOrder': undefined,
34
+ 'createReduceOnlyOrder': false,
35
+ 'fetchAccounts': true,
36
+ 'fetchBalance': true,
37
+ 'fetchBidsAsks': undefined,
38
+ 'fetchBorrowRate': false,
39
+ 'fetchBorrowRateHistories': false,
40
+ 'fetchBorrowRateHistory': false,
41
+ 'fetchBorrowRates': false,
42
+ 'fetchBorrowRatesPerSymbol': false,
43
+ 'fetchClosedOrders': undefined,
44
+ 'fetchCurrencies': true,
45
+ 'fetchDepositAddress': undefined,
46
+ 'fetchDeposits': true,
47
+ 'fetchFundingHistory': false,
48
+ 'fetchFundingRate': false,
49
+ 'fetchFundingRateHistory': false,
50
+ 'fetchFundingRates': false,
51
+ 'fetchIndexOHLCV': false,
52
+ 'fetchL2OrderBook': false,
53
+ 'fetchLedger': true,
54
+ 'fetchLeverage': false,
55
+ 'fetchLeverageTiers': false,
56
+ 'fetchMarkets': true,
57
+ 'fetchMarkOHLCV': false,
58
+ 'fetchMyBuys': true,
59
+ 'fetchMySells': true,
60
+ 'fetchMyTrades': undefined,
61
+ 'fetchOHLCV': false,
62
+ 'fetchOpenOrders': undefined,
63
+ 'fetchOrder': undefined,
64
+ 'fetchOrderBook': false,
65
+ 'fetchOrders': undefined,
66
+ 'fetchPosition': false,
67
+ 'fetchPositions': false,
68
+ 'fetchPositionsRisk': false,
69
+ 'fetchPremiumIndexOHLCV': false,
70
+ 'fetchTicker': true,
71
+ 'fetchTickers': true,
72
+ 'fetchTime': true,
73
+ 'fetchTrades': undefined,
74
+ 'fetchTradingFee': false,
75
+ 'fetchTradingFees': false,
76
+ 'fetchTransactions': undefined,
77
+ 'fetchWithdrawals': true,
78
+ 'reduceMargin': false,
79
+ 'setLeverage': false,
80
+ 'setMarginMode': false,
81
+ 'setPositionMode': false,
82
+ 'withdraw': undefined,
83
+ },
84
+ 'urls': {
85
+ 'logo': 'https://user-images.githubusercontent.com/1294454/40811661-b6eceae2-653a-11e8-829e-10bfadb078cf.jpg',
86
+ 'api': 'https://api.coinbase.com',
87
+ 'www': 'https://www.coinbase.com',
88
+ 'doc': 'https://developers.coinbase.com/api/v2',
89
+ 'fees': 'https://support.coinbase.com/customer/portal/articles/2109597-buy-sell-bank-transfer-fees',
90
+ 'referral': 'https://www.coinbase.com/join/58cbe25a355148797479dbd2',
91
+ },
92
+ 'requiredCredentials': {
93
+ 'apiKey': true,
94
+ 'secret': true,
95
+ },
96
+ 'api': {
97
+ 'public': {
98
+ 'get': [
99
+ 'currencies',
100
+ 'time',
101
+ 'exchange-rates',
102
+ 'users/{user_id}',
103
+ 'prices/{symbol}/buy',
104
+ 'prices/{symbol}/sell',
105
+ 'prices/{symbol}/spot',
106
+ ],
107
+ },
108
+ 'private': {
109
+ 'get': [
110
+ 'accounts',
111
+ 'accounts/{account_id}',
112
+ 'accounts/{account_id}/addresses',
113
+ 'accounts/{account_id}/addresses/{address_id}',
114
+ 'accounts/{account_id}/addresses/{address_id}/transactions',
115
+ 'accounts/{account_id}/transactions',
116
+ 'accounts/{account_id}/transactions/{transaction_id}',
117
+ 'accounts/{account_id}/buys',
118
+ 'accounts/{account_id}/buys/{buy_id}',
119
+ 'accounts/{account_id}/sells',
120
+ 'accounts/{account_id}/sells/{sell_id}',
121
+ 'accounts/{account_id}/deposits',
122
+ 'accounts/{account_id}/deposits/{deposit_id}',
123
+ 'accounts/{account_id}/withdrawals',
124
+ 'accounts/{account_id}/withdrawals/{withdrawal_id}',
125
+ 'payment-methods',
126
+ 'payment-methods/{payment_method_id}',
127
+ 'user',
128
+ 'user/auth',
129
+ ],
130
+ 'post': [
131
+ 'accounts',
132
+ 'accounts/{account_id}/primary',
133
+ 'accounts/{account_id}/addresses',
134
+ 'accounts/{account_id}/transactions',
135
+ 'accounts/{account_id}/transactions/{transaction_id}/complete',
136
+ 'accounts/{account_id}/transactions/{transaction_id}/resend',
137
+ 'accounts/{account_id}/buys',
138
+ 'accounts/{account_id}/buys/{buy_id}/commit',
139
+ 'accounts/{account_id}/sells',
140
+ 'accounts/{account_id}/sells/{sell_id}/commit',
141
+ 'accounts/{account_id}/deposists',
142
+ 'accounts/{account_id}/deposists/{deposit_id}/commit',
143
+ 'accounts/{account_id}/withdrawals',
144
+ 'accounts/{account_id}/withdrawals/{withdrawal_id}/commit',
145
+ ],
146
+ 'put': [
147
+ 'accounts/{account_id}',
148
+ 'user',
149
+ ],
150
+ 'delete': [
151
+ 'accounts/{id}',
152
+ 'accounts/{account_id}/transactions/{transaction_id}',
153
+ ],
154
+ },
155
+ },
156
+ 'exceptions': {
157
+ 'exact': {
158
+ 'two_factor_required': AuthenticationError, // 402 When sending money over 2fa limit
159
+ 'param_required': ExchangeError, // 400 Missing parameter
160
+ 'validation_error': ExchangeError, // 400 Unable to validate POST/PUT
161
+ 'invalid_request': ExchangeError, // 400 Invalid request
162
+ 'personal_details_required': AuthenticationError, // 400 User’s personal detail required to complete this request
163
+ 'identity_verification_required': AuthenticationError, // 400 Identity verification is required to complete this request
164
+ 'jumio_verification_required': AuthenticationError, // 400 Document verification is required to complete this request
165
+ 'jumio_face_match_verification_required': AuthenticationError, // 400 Document verification including face match is required to complete this request
166
+ 'unverified_email': AuthenticationError, // 400 User has not verified their email
167
+ 'authentication_error': AuthenticationError, // 401 Invalid auth (generic)
168
+ 'invalid_authentication_method': AuthenticationError, // 401 API access is blocked for deleted users.
169
+ 'invalid_token': AuthenticationError, // 401 Invalid Oauth token
170
+ 'revoked_token': AuthenticationError, // 401 Revoked Oauth token
171
+ 'expired_token': AuthenticationError, // 401 Expired Oauth token
172
+ 'invalid_scope': AuthenticationError, // 403 User hasn’t authenticated necessary scope
173
+ 'not_found': ExchangeError, // 404 Resource not found
174
+ 'rate_limit_exceeded': RateLimitExceeded, // 429 Rate limit exceeded
175
+ 'internal_server_error': ExchangeError, // 500 Internal server error
176
+ },
177
+ 'broad': {
178
+ 'request timestamp expired': InvalidNonce, // {"errors":[{"id":"authentication_error","message":"request timestamp expired"}]}
179
+ },
180
+ },
181
+ 'commonCurrencies': {
182
+ 'CGLD': 'CELO',
183
+ },
184
+ 'options': {
185
+ 'fetchCurrencies': {
186
+ 'expires': 5000,
187
+ },
188
+ 'accounts': [
189
+ 'wallet',
190
+ 'fiat',
191
+ // 'vault',
192
+ ],
193
+ },
194
+ });
195
+ }
196
+
197
+ async fetchTime (params = {}) {
198
+ const response = await this.publicGetTime (params);
199
+ //
200
+ // {
201
+ // "data": {
202
+ // "epoch": 1589295679,
203
+ // "iso": "2020-05-12T15:01:19Z"
204
+ // }
205
+ // }
206
+ //
207
+ const data = this.safeValue (response, 'data', {});
208
+ return this.safeTimestamp (data, 'epoch');
209
+ }
210
+
211
+ async fetchAccounts (params = {}) {
212
+ await this.loadMarkets ();
213
+ const request = {
214
+ 'limit': 100,
215
+ };
216
+ const response = await this.privateGetAccounts (this.extend (request, params));
217
+ //
218
+ // {
219
+ // "id": "XLM",
220
+ // "name": "XLM Wallet",
221
+ // "primary": false,
222
+ // "type": "wallet",
223
+ // "currency": {
224
+ // "code": "XLM",
225
+ // "name": "Stellar Lumens",
226
+ // "color": "#000000",
227
+ // "sort_index": 127,
228
+ // "exponent": 7,
229
+ // "type": "crypto",
230
+ // "address_regex": "^G[A-Z2-7]{55}$",
231
+ // "asset_id": "13b83335-5ede-595b-821e-5bcdfa80560f",
232
+ // "destination_tag_name": "XLM Memo ID",
233
+ // "destination_tag_regex": "^[ -~]{1,28}$"
234
+ // },
235
+ // "balance": {
236
+ // "amount": "0.0000000",
237
+ // "currency": "XLM"
238
+ // },
239
+ // "created_at": null,
240
+ // "updated_at": null,
241
+ // "resource": "account",
242
+ // "resource_path": "/v2/accounts/XLM",
243
+ // "allow_deposits": true,
244
+ // "allow_withdrawals": true
245
+ // }
246
+ //
247
+ const data = this.safeValue (response, 'data', []);
248
+ const result = [];
249
+ for (let i = 0; i < data.length; i++) {
250
+ const account = data[i];
251
+ const currency = this.safeValue (account, 'currency', {});
252
+ const currencyId = this.safeString (currency, 'code');
253
+ const code = this.safeCurrencyCode (currencyId);
254
+ result.push ({
255
+ 'id': this.safeString (account, 'id'),
256
+ 'type': this.safeString (account, 'type'),
257
+ 'code': code,
258
+ 'info': account,
259
+ });
260
+ }
261
+ return result;
262
+ }
263
+
264
+ async createDepositAddress (code, params = {}) {
265
+ let accountId = this.safeString (params, 'account_id');
266
+ params = this.omit (params, 'account_id');
267
+ if (accountId === undefined) {
268
+ await this.loadAccounts ();
269
+ for (let i = 0; i < this.accounts.length; i++) {
270
+ const account = this.accounts[i];
271
+ if (account['code'] === code && account['type'] === 'wallet') {
272
+ accountId = account['id'];
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ if (accountId === undefined) {
278
+ throw new ExchangeError (this.id + ' createDepositAddress() could not find the account with matching currency code, specify an `account_id` extra param');
279
+ }
280
+ const request = {
281
+ 'account_id': accountId,
282
+ };
283
+ const response = await this.privatePostAccountsAccountIdAddresses (this.extend (request, params));
284
+ //
285
+ // {
286
+ // "data": {
287
+ // "id": "05b1ebbf-9438-5dd4-b297-2ddedc98d0e4",
288
+ // "address": "coinbasebase",
289
+ // "address_info": {
290
+ // "address": "coinbasebase",
291
+ // "destination_tag": "287594668"
292
+ // },
293
+ // "name": null,
294
+ // "created_at": "2019-07-01T14:39:29Z",
295
+ // "updated_at": "2019-07-01T14:39:29Z",
296
+ // "network": "eosio",
297
+ // "uri_scheme": "eosio",
298
+ // "resource": "address",
299
+ // "resource_path": "/v2/accounts/14cfc769-e852-52f3-b831-711c104d194c/addresses/05b1ebbf-9438-5dd4-b297-2ddedc98d0e4",
300
+ // "warnings": [
301
+ // {
302
+ // "title": "Only send EOS (EOS) to this address",
303
+ // "details": "Sending any other cryptocurrency will result in permanent loss.",
304
+ // "image_url": "https://dynamic-assets.coinbase.com/deaca3d47b10ed4a91a872e9618706eec34081127762d88f2476ac8e99ada4b48525a9565cf2206d18c04053f278f693434af4d4629ca084a9d01b7a286a7e26/asset_icons/1f8489bb280fb0a0fd643c1161312ba49655040e9aaaced5f9ad3eeaf868eadc.png"
305
+ // },
306
+ // {
307
+ // "title": "Both an address and EOS memo are required to receive EOS",
308
+ // "details": "If you send funds without an EOS memo or with an incorrect EOS memo, your funds cannot be credited to your account.",
309
+ // "image_url": "https://www.coinbase.com/assets/receive-warning-2f3269d83547a7748fb39d6e0c1c393aee26669bfea6b9f12718094a1abff155.png"
310
+ // }
311
+ // ],
312
+ // "warning_title": "Only send EOS (EOS) to this address",
313
+ // "warning_details": "Sending any other cryptocurrency will result in permanent loss.",
314
+ // "destination_tag": "287594668",
315
+ // "deposit_uri": "eosio:coinbasebase?dt=287594668",
316
+ // "callback_url": null
317
+ // }
318
+ // }
319
+ //
320
+ const data = this.safeValue (response, 'data', {});
321
+ const tag = this.safeString (data, 'destination_tag');
322
+ const address = this.safeString (data, 'address');
323
+ return {
324
+ 'currency': code,
325
+ 'tag': tag,
326
+ 'address': address,
327
+ 'info': response,
328
+ };
329
+ }
330
+
331
+ async fetchMySells (symbol = undefined, since = undefined, limit = undefined, params = {}) {
332
+ // they don't have an endpoint for all historical trades
333
+ const request = await this.prepareAccountRequest (limit, params);
334
+ await this.loadMarkets ();
335
+ const query = this.omit (params, [ 'account_id', 'accountId' ]);
336
+ const sells = await this.privateGetAccountsAccountIdSells (this.extend (request, query));
337
+ return this.parseTrades (sells['data'], undefined, since, limit);
338
+ }
339
+
340
+ async fetchMyBuys (symbol = undefined, since = undefined, limit = undefined, params = {}) {
341
+ // they don't have an endpoint for all historical trades
342
+ const request = await this.prepareAccountRequest (limit, params);
343
+ await this.loadMarkets ();
344
+ const query = this.omit (params, [ 'account_id', 'accountId' ]);
345
+ const buys = await this.privateGetAccountsAccountIdBuys (this.extend (request, query));
346
+ return this.parseTrades (buys['data'], undefined, since, limit);
347
+ }
348
+
349
+ async fetchTransactionsWithMethod (method, code = undefined, since = undefined, limit = undefined, params = {}) {
350
+ const request = await this.prepareAccountRequestWithCurrencyCode (code, limit, params);
351
+ await this.loadMarkets ();
352
+ const query = this.omit (params, [ 'account_id', 'accountId' ]);
353
+ const response = await this[method] (this.extend (request, query));
354
+ return this.parseTransactions (response['data'], undefined, since, limit);
355
+ }
356
+
357
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
358
+ // fiat only, for crypto transactions use fetchLedger
359
+ return await this.fetchTransactionsWithMethod ('privateGetAccountsAccountIdWithdrawals', code, since, limit, params);
360
+ }
361
+
362
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
363
+ // fiat only, for crypto transactions use fetchLedger
364
+ return await this.fetchTransactionsWithMethod ('privateGetAccountsAccountIdDeposits', code, since, limit, params);
365
+ }
366
+
367
+ parseTransactionStatus (status) {
368
+ const statuses = {
369
+ 'created': 'pending',
370
+ 'completed': 'ok',
371
+ 'canceled': 'canceled',
372
+ };
373
+ return this.safeString (statuses, status, status);
374
+ }
375
+
376
+ parseTransaction (transaction, market = undefined) {
377
+ //
378
+ // fiat deposit
379
+ //
380
+ // {
381
+ // "id": "f34c19f3-b730-5e3d-9f72",
382
+ // "status": "completed",
383
+ // "payment_method": {
384
+ // "id": "a022b31d-f9c7-5043-98f2",
385
+ // "resource": "payment_method",
386
+ // "resource_path": "/v2/payment-methods/a022b31d-f9c7-5043-98f2"
387
+ // },
388
+ // "transaction": {
389
+ // "id": "04ed4113-3732-5b0c-af86-b1d2146977d0",
390
+ // "resource": "transaction",
391
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/04ed4113-3732-5b0c-af86"
392
+ // },
393
+ // "user_reference": "2VTYTH",
394
+ // "created_at": "2017-02-09T07:01:18Z",
395
+ // "updated_at": "2017-02-09T07:01:26Z",
396
+ // "resource": "deposit",
397
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/deposits/f34c19f3-b730-5e3d-9f72",
398
+ // "committed": true,
399
+ // "payout_at": "2017-02-12T07:01:17Z",
400
+ // "instant": false,
401
+ // "fee": { "amount": "0.00", "currency": "EUR" },
402
+ // "amount": { "amount": "114.02", "currency": "EUR" },
403
+ // "subtotal": { "amount": "114.02", "currency": "EUR" },
404
+ // "hold_until": null,
405
+ // "hold_days": 0,
406
+ // "hold_business_days": 0,
407
+ // "next_step": null
408
+ // }
409
+ //
410
+ // fiat_withdrawal
411
+ //
412
+ // {
413
+ // "id": "cfcc3b4a-eeb6-5e8c-8058",
414
+ // "status": "completed",
415
+ // "payment_method": {
416
+ // "id": "8b94cfa4-f7fd-5a12-a76a",
417
+ // "resource": "payment_method",
418
+ // "resource_path": "/v2/payment-methods/8b94cfa4-f7fd-5a12-a76a"
419
+ // },
420
+ // "transaction": {
421
+ // "id": "fcc2550b-5104-5f83-a444",
422
+ // "resource": "transaction",
423
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/fcc2550b-5104-5f83-a444"
424
+ // },
425
+ // "user_reference": "MEUGK",
426
+ // "created_at": "2018-07-26T08:55:12Z",
427
+ // "updated_at": "2018-07-26T08:58:18Z",
428
+ // "resource": "withdrawal",
429
+ // "resource_path": "/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/withdrawals/cfcc3b4a-eeb6-5e8c-8058",
430
+ // "committed": true,
431
+ // "payout_at": "2018-07-31T08:55:12Z",
432
+ // "instant": false,
433
+ // "fee": { "amount": "0.15", "currency": "EUR" },
434
+ // "amount": { "amount": "13130.69", "currency": "EUR" },
435
+ // "subtotal": { "amount": "13130.84", "currency": "EUR" },
436
+ // "idem": "e549dee5-63ed-4e79-8a96",
437
+ // "next_step": null
438
+ // }
439
+ //
440
+ const subtotalObject = this.safeValue (transaction, 'subtotal', {});
441
+ const feeObject = this.safeValue (transaction, 'fee', {});
442
+ const id = this.safeString (transaction, 'id');
443
+ const timestamp = this.parse8601 (this.safeValue (transaction, 'created_at'));
444
+ const updated = this.parse8601 (this.safeValue (transaction, 'updated_at'));
445
+ const type = this.safeString (transaction, 'resource');
446
+ const amount = this.safeNumber (subtotalObject, 'amount');
447
+ const currencyId = this.safeString (subtotalObject, 'currency');
448
+ const currency = this.safeCurrencyCode (currencyId);
449
+ const feeCost = this.safeNumber (feeObject, 'amount');
450
+ const feeCurrencyId = this.safeString (feeObject, 'currency');
451
+ const feeCurrency = this.safeCurrencyCode (feeCurrencyId);
452
+ const fee = {
453
+ 'cost': feeCost,
454
+ 'currency': feeCurrency,
455
+ };
456
+ let status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
457
+ if (status === undefined) {
458
+ const committed = this.safeValue (transaction, 'committed');
459
+ status = committed ? 'ok' : 'pending';
460
+ }
461
+ return {
462
+ 'info': transaction,
463
+ 'id': id,
464
+ 'txid': id,
465
+ 'timestamp': timestamp,
466
+ 'datetime': this.iso8601 (timestamp),
467
+ 'network': undefined,
468
+ 'address': undefined,
469
+ 'addressTo': undefined,
470
+ 'addressFrom': undefined,
471
+ 'tag': undefined,
472
+ 'tagTo': undefined,
473
+ 'tagFrom': undefined,
474
+ 'type': type,
475
+ 'amount': amount,
476
+ 'currency': currency,
477
+ 'status': status,
478
+ 'updated': updated,
479
+ 'fee': fee,
480
+ };
481
+ }
482
+
483
+ parseTrade (trade, market = undefined) {
484
+ //
485
+ // {
486
+ // "id": "67e0eaec-07d7-54c4-a72c-2e92826897df",
487
+ // "status": "completed",
488
+ // "payment_method": {
489
+ // "id": "83562370-3e5c-51db-87da-752af5ab9559",
490
+ // "resource": "payment_method",
491
+ // "resource_path": "/v2/payment-methods/83562370-3e5c-51db-87da-752af5ab9559"
492
+ // },
493
+ // "transaction": {
494
+ // "id": "441b9494-b3f0-5b98-b9b0-4d82c21c252a",
495
+ // "resource": "transaction",
496
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/transactions/441b9494-b3f0-5b98-b9b0-4d82c21c252a"
497
+ // },
498
+ // "amount": { "amount": "1.00000000", "currency": "BTC" },
499
+ // "total": { "amount": "10.25", "currency": "USD" },
500
+ // "subtotal": { "amount": "10.10", "currency": "USD" },
501
+ // "created_at": "2015-01-31T20:49:02Z",
502
+ // "updated_at": "2015-02-11T16:54:02-08:00",
503
+ // "resource": "buy",
504
+ // "resource_path": "/v2/accounts/2bbf394c-193b-5b2a-9155-3b4732659ede/buys/67e0eaec-07d7-54c4-a72c-2e92826897df",
505
+ // "committed": true,
506
+ // "instant": false,
507
+ // "fee": { "amount": "0.15", "currency": "USD" },
508
+ // "payout_at": "2015-02-18T16:54:00-08:00"
509
+ // }
510
+ //
511
+ let symbol = undefined;
512
+ const totalObject = this.safeValue (trade, 'total', {});
513
+ const amountObject = this.safeValue (trade, 'amount', {});
514
+ const subtotalObject = this.safeValue (trade, 'subtotal', {});
515
+ const feeObject = this.safeValue (trade, 'fee', {});
516
+ const id = this.safeString (trade, 'id');
517
+ const timestamp = this.parse8601 (this.safeValue (trade, 'created_at'));
518
+ if (market === undefined) {
519
+ const baseId = this.safeString (amountObject, 'currency');
520
+ const quoteId = this.safeString (totalObject, 'currency');
521
+ if ((baseId !== undefined) && (quoteId !== undefined)) {
522
+ const base = this.safeCurrencyCode (baseId);
523
+ const quote = this.safeCurrencyCode (quoteId);
524
+ symbol = base + '/' + quote;
525
+ }
526
+ }
527
+ const orderId = undefined;
528
+ const side = this.safeString (trade, 'resource');
529
+ const type = undefined;
530
+ const costString = this.safeString (subtotalObject, 'amount');
531
+ const amountString = this.safeString (amountObject, 'amount');
532
+ const cost = this.parseNumber (costString);
533
+ const amount = this.parseNumber (amountString);
534
+ const price = this.parseNumber (Precise.stringDiv (costString, amountString));
535
+ const feeCost = this.safeNumber (feeObject, 'amount');
536
+ const feeCurrencyId = this.safeString (feeObject, 'currency');
537
+ const feeCurrency = this.safeCurrencyCode (feeCurrencyId);
538
+ const fee = {
539
+ 'cost': feeCost,
540
+ 'currency': feeCurrency,
541
+ };
542
+ return {
543
+ 'info': trade,
544
+ 'id': id,
545
+ 'order': orderId,
546
+ 'timestamp': timestamp,
547
+ 'datetime': this.iso8601 (timestamp),
548
+ 'symbol': symbol,
549
+ 'type': type,
550
+ 'side': side,
551
+ 'takerOrMaker': undefined,
552
+ 'price': price,
553
+ 'amount': amount,
554
+ 'cost': cost,
555
+ 'fee': fee,
556
+ };
557
+ }
558
+
559
+ async fetchMarkets (params = {}) {
560
+ const response = await this.fetchCurrenciesFromCache (params);
561
+ const currencies = this.safeValue (response, 'currencies', {});
562
+ const exchangeRates = this.safeValue (response, 'exchangeRates', {});
563
+ const data = this.safeValue (currencies, 'data', []);
564
+ const dataById = this.indexBy (data, 'id');
565
+ const rates = this.safeValue (this.safeValue (exchangeRates, 'data', {}), 'rates', {});
566
+ const baseIds = Object.keys (rates);
567
+ const result = [];
568
+ for (let i = 0; i < baseIds.length; i++) {
569
+ const baseId = baseIds[i];
570
+ const base = this.safeCurrencyCode (baseId);
571
+ const type = (baseId in dataById) ? 'fiat' : 'crypto';
572
+ // https://github.com/ccxt/ccxt/issues/6066
573
+ if (type === 'crypto') {
574
+ for (let j = 0; j < data.length; j++) {
575
+ const quoteCurrency = data[j];
576
+ const quoteId = this.safeString (quoteCurrency, 'id');
577
+ const quote = this.safeCurrencyCode (quoteId);
578
+ result.push ({
579
+ 'id': baseId + '-' + quoteId,
580
+ 'symbol': base + '/' + quote,
581
+ 'base': base,
582
+ 'quote': quote,
583
+ 'settle': undefined,
584
+ 'baseId': baseId,
585
+ 'quoteId': quoteId,
586
+ 'settleId': undefined,
587
+ 'type': 'spot',
588
+ 'spot': true,
589
+ 'margin': false,
590
+ 'swap': false,
591
+ 'future': false,
592
+ 'option': false,
593
+ 'active': undefined,
594
+ 'contract': false,
595
+ 'linear': undefined,
596
+ 'inverse': undefined,
597
+ 'contractSize': undefined,
598
+ 'expiry': undefined,
599
+ 'expiryDatetime': undefined,
600
+ 'strike': undefined,
601
+ 'optionType': undefined,
602
+ 'precision': {
603
+ 'amount': undefined,
604
+ 'price': undefined,
605
+ },
606
+ 'limits': {
607
+ 'leverage': {
608
+ 'min': undefined,
609
+ 'max': undefined,
610
+ },
611
+ 'amount': {
612
+ 'min': undefined,
613
+ 'max': undefined,
614
+ },
615
+ 'price': {
616
+ 'min': undefined,
617
+ 'max': undefined,
618
+ },
619
+ 'cost': {
620
+ 'min': this.safeNumber (quoteCurrency, 'min_size'),
621
+ 'max': undefined,
622
+ },
623
+ },
624
+ 'info': quoteCurrency,
625
+ });
626
+ }
627
+ }
628
+ }
629
+ return result;
630
+ }
631
+
632
+ async fetchCurrenciesFromCache (params = {}) {
633
+ const options = this.safeValue (this.options, 'fetchCurrencies', {});
634
+ const timestamp = this.safeInteger (options, 'timestamp');
635
+ const expires = this.safeInteger (options, 'expires', 1000);
636
+ const now = this.milliseconds ();
637
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
638
+ const currencies = await this.publicGetCurrencies (params);
639
+ const exchangeRates = await this.publicGetExchangeRates (params);
640
+ this.options['fetchCurrencies'] = this.extend (options, {
641
+ 'currencies': currencies,
642
+ 'exchangeRates': exchangeRates,
643
+ 'timestamp': now,
644
+ });
645
+ }
646
+ return this.safeValue (this.options, 'fetchCurrencies', {});
647
+ }
648
+
649
+ async fetchCurrencies (params = {}) {
650
+ const response = await this.fetchCurrenciesFromCache (params);
651
+ const currencies = this.safeValue (response, 'currencies', {});
652
+ //
653
+ // {
654
+ // "data":[
655
+ // {"id":"AED","name":"United Arab Emirates Dirham","min_size":"0.01000000"},
656
+ // {"id":"AFN","name":"Afghan Afghani","min_size":"0.01000000"},
657
+ // {"id":"ALL","name":"Albanian Lek","min_size":"0.01000000"},
658
+ // {"id":"AMD","name":"Armenian Dram","min_size":"0.01000000"},
659
+ // {"id":"ANG","name":"Netherlands Antillean Gulden","min_size":"0.01000000"},
660
+ // // ...
661
+ // ],
662
+ // }
663
+ //
664
+ const exchangeRates = this.safeValue (response, 'exchangeRates', {});
665
+ //
666
+ // {
667
+ // "data":{
668
+ // "currency":"USD",
669
+ // "rates":{
670
+ // "AED":"3.67",
671
+ // "AFN":"78.21",
672
+ // "ALL":"110.42",
673
+ // "AMD":"474.18",
674
+ // "ANG":"1.75",
675
+ // // ...
676
+ // },
677
+ // }
678
+ // }
679
+ //
680
+ const data = this.safeValue (currencies, 'data', []);
681
+ const dataById = this.indexBy (data, 'id');
682
+ const rates = this.safeValue (this.safeValue (exchangeRates, 'data', {}), 'rates', {});
683
+ const keys = Object.keys (rates);
684
+ const result = {};
685
+ for (let i = 0; i < keys.length; i++) {
686
+ const key = keys[i];
687
+ const type = (key in dataById) ? 'fiat' : 'crypto';
688
+ const currency = this.safeValue (dataById, key, {});
689
+ const id = this.safeString (currency, 'id', key);
690
+ const name = this.safeString (currency, 'name');
691
+ const code = this.safeCurrencyCode (id);
692
+ result[code] = {
693
+ 'id': id,
694
+ 'code': code,
695
+ 'info': currency, // the original payload
696
+ 'type': type,
697
+ 'name': name,
698
+ 'active': true,
699
+ 'deposit': undefined,
700
+ 'withdraw': undefined,
701
+ 'fee': undefined,
702
+ 'precision': undefined,
703
+ 'limits': {
704
+ 'amount': {
705
+ 'min': this.safeNumber (currency, 'min_size'),
706
+ 'max': undefined,
707
+ },
708
+ 'withdraw': {
709
+ 'min': undefined,
710
+ 'max': undefined,
711
+ },
712
+ },
713
+ };
714
+ }
715
+ return result;
716
+ }
717
+
718
+ async fetchTickers (symbols = undefined, params = {}) {
719
+ await this.loadMarkets ();
720
+ const request = {
721
+ // 'currency': 'USD',
722
+ };
723
+ const response = await this.publicGetExchangeRates (this.extend (request, params));
724
+ //
725
+ // {
726
+ // "data":{
727
+ // "currency":"USD",
728
+ // "rates":{
729
+ // "AED":"3.6731",
730
+ // "AFN":"103.163942",
731
+ // "ALL":"106.973038",
732
+ // }
733
+ // }
734
+ // }
735
+ //
736
+ const data = this.safeValue (response, 'data', {});
737
+ const rates = this.safeValue (data, 'rates', {});
738
+ const quoteId = this.safeString (data, 'currency');
739
+ const result = {};
740
+ const baseIds = Object.keys (rates);
741
+ const delimiter = '-';
742
+ for (let i = 0; i < baseIds.length; i++) {
743
+ const baseId = baseIds[i];
744
+ const marketId = baseId + delimiter + quoteId;
745
+ const market = this.safeMarket (marketId, undefined, delimiter);
746
+ const symbol = market['symbol'];
747
+ result[symbol] = this.parseTicker (rates[baseId], market);
748
+ }
749
+ return this.filterByArray (result, 'symbol', symbols);
750
+ }
751
+
752
+ async fetchTicker (symbol, params = {}) {
753
+ await this.loadMarkets ();
754
+ const market = this.market (symbol);
755
+ const request = this.extend ({
756
+ 'symbol': market['id'],
757
+ }, params);
758
+ const spot = await this.publicGetPricesSymbolSpot (request);
759
+ //
760
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
761
+ //
762
+ const buy = await this.publicGetPricesSymbolBuy (request);
763
+ //
764
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
765
+ //
766
+ const sell = await this.publicGetPricesSymbolSell (request);
767
+ //
768
+ // {"data":{"base":"BTC","currency":"USD","amount":"48691.23"}}
769
+ //
770
+ return this.parseTicker ([ spot, buy, sell ], market);
771
+ }
772
+
773
+ parseTicker (ticker, market = undefined) {
774
+ //
775
+ // fetchTicker
776
+ //
777
+ // [
778
+ // "48691.23", // spot
779
+ // "48691.23", // buy
780
+ // "48691.23", // sell
781
+ // ]
782
+ //
783
+ // fetchTickers
784
+ //
785
+ // "48691.23"
786
+ //
787
+ const symbol = this.safeSymbol (undefined, market);
788
+ let ask = undefined;
789
+ let bid = undefined;
790
+ let last = undefined;
791
+ const timestamp = this.milliseconds ();
792
+ if (typeof ticker !== 'string') {
793
+ const [ spot, buy, sell ] = ticker;
794
+ const spotData = this.safeValue (spot, 'data', {});
795
+ const buyData = this.safeValue (buy, 'data', {});
796
+ const sellData = this.safeValue (sell, 'data', {});
797
+ last = this.safeString (spotData, 'amount');
798
+ bid = this.safeString (buyData, 'amount');
799
+ ask = this.safeString (sellData, 'amount');
800
+ }
801
+ return this.safeTicker ({
802
+ 'symbol': symbol,
803
+ 'timestamp': timestamp,
804
+ 'datetime': this.iso8601 (timestamp),
805
+ 'bid': bid,
806
+ 'ask': ask,
807
+ 'last': last,
808
+ 'high': undefined,
809
+ 'low': undefined,
810
+ 'bidVolume': undefined,
811
+ 'askVolume': undefined,
812
+ 'vwap': undefined,
813
+ 'open': undefined,
814
+ 'close': last,
815
+ 'previousClose': undefined,
816
+ 'change': undefined,
817
+ 'percentage': undefined,
818
+ 'average': undefined,
819
+ 'baseVolume': undefined,
820
+ 'quoteVolume': undefined,
821
+ 'info': ticker,
822
+ }, market, false);
823
+ }
824
+
825
+ async fetchBalance (params = {}) {
826
+ await this.loadMarkets ();
827
+ const request = {
828
+ 'limit': 100,
829
+ };
830
+ const response = await this.privateGetAccounts (this.extend (request, params));
831
+ const balances = this.safeValue (response, 'data');
832
+ const accounts = this.safeValue (params, 'type', this.options['accounts']);
833
+ const result = { 'info': response };
834
+ for (let b = 0; b < balances.length; b++) {
835
+ const balance = balances[b];
836
+ const type = this.safeString (balance, 'type');
837
+ if (this.inArray (type, accounts)) {
838
+ const value = this.safeValue (balance, 'balance');
839
+ if (value !== undefined) {
840
+ const currencyId = this.safeString (value, 'currency');
841
+ const code = this.safeCurrencyCode (currencyId);
842
+ const total = this.safeString (value, 'amount');
843
+ const free = total;
844
+ let account = this.safeValue (result, code);
845
+ if (account === undefined) {
846
+ account = this.account ();
847
+ account['free'] = free;
848
+ account['total'] = total;
849
+ } else {
850
+ account['free'] = Precise.stringAdd (account['free'], total);
851
+ account['total'] = Precise.stringAdd (account['total'], total);
852
+ }
853
+ result[code] = account;
854
+ }
855
+ }
856
+ }
857
+ return this.safeBalance (result);
858
+ }
859
+
860
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
861
+ await this.loadMarkets ();
862
+ let currency = undefined;
863
+ if (code !== undefined) {
864
+ currency = this.currency (code);
865
+ }
866
+ const request = await this.prepareAccountRequestWithCurrencyCode (code, limit, params);
867
+ const query = this.omit (params, [ 'account_id', 'accountId' ]);
868
+ // for pagination use parameter 'starting_after'
869
+ // the value for the next page can be obtained from the result of the previous call in the 'pagination' field
870
+ // eg: instance.last_json_response.pagination.next_starting_after
871
+ const response = await this.privateGetAccountsAccountIdTransactions (this.extend (request, query));
872
+ return this.parseLedger (response['data'], currency, since, limit);
873
+ }
874
+
875
+ parseLedgerEntryStatus (status) {
876
+ const types = {
877
+ 'completed': 'ok',
878
+ };
879
+ return this.safeString (types, status, status);
880
+ }
881
+
882
+ parseLedgerEntryType (type) {
883
+ const types = {
884
+ 'buy': 'trade',
885
+ 'sell': 'trade',
886
+ 'fiat_deposit': 'transaction',
887
+ 'fiat_withdrawal': 'transaction',
888
+ 'exchange_deposit': 'transaction', // fiat withdrawal (from coinbase to coinbasepro)
889
+ 'exchange_withdrawal': 'transaction', // fiat deposit (to coinbase from coinbasepro)
890
+ 'send': 'transaction', // crypto deposit OR withdrawal
891
+ 'pro_deposit': 'transaction', // crypto withdrawal (from coinbase to coinbasepro)
892
+ 'pro_withdrawal': 'transaction', // crypto deposit (to coinbase from coinbasepro)
893
+ };
894
+ return this.safeString (types, type, type);
895
+ }
896
+
897
+ parseLedgerEntry (item, currency = undefined) {
898
+ //
899
+ // crypto deposit transaction
900
+ //
901
+ // {
902
+ // id: '34e4816b-4c8c-5323-a01c-35a9fa26e490',
903
+ // type: 'send',
904
+ // status: 'completed',
905
+ // amount: { amount: '28.31976528', currency: 'BCH' },
906
+ // native_amount: { amount: '2799.65', currency: 'GBP' },
907
+ // description: null,
908
+ // created_at: '2019-02-28T12:35:20Z',
909
+ // updated_at: '2019-02-28T12:43:24Z',
910
+ // resource: 'transaction',
911
+ // resource_path: '/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/34e4816b-4c8c-5323-a01c-35a9fa26e490',
912
+ // instant_exchange: false,
913
+ // network: {
914
+ // status: 'confirmed',
915
+ // hash: '56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701',
916
+ // transaction_url: 'https://bch.btc.com/56222d865dae83774fccb2efbd9829cf08c75c94ce135bfe4276f3fb46d49701'
917
+ // },
918
+ // from: { resource: 'bitcoin_cash_network', currency: 'BCH' },
919
+ // details: { title: 'Received Bitcoin Cash', subtitle: 'From Bitcoin Cash address' }
920
+ // }
921
+ //
922
+ // crypto withdrawal transaction
923
+ //
924
+ // {
925
+ // id: '459aad99-2c41-5698-ac71-b6b81a05196c',
926
+ // type: 'send',
927
+ // status: 'completed',
928
+ // amount: { amount: '-0.36775642', currency: 'BTC' },
929
+ // native_amount: { amount: '-1111.65', currency: 'GBP' },
930
+ // description: null,
931
+ // created_at: '2019-03-20T08:37:07Z',
932
+ // updated_at: '2019-03-20T08:49:33Z',
933
+ // resource: 'transaction',
934
+ // resource_path: '/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/459aad99-2c41-5698-ac71-b6b81a05196c',
935
+ // instant_exchange: false,
936
+ // network: {
937
+ // status: 'confirmed',
938
+ // hash: '2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b',
939
+ // transaction_url: 'https://blockchain.info/tx/2732bbcf35c69217c47b36dce64933d103895277fe25738ffb9284092701e05b',
940
+ // transaction_fee: { amount: '0.00000000', currency: 'BTC' },
941
+ // transaction_amount: { amount: '0.36775642', currency: 'BTC' },
942
+ // confirmations: 15682
943
+ // },
944
+ // to: {
945
+ // resource: 'bitcoin_address',
946
+ // address: '1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX',
947
+ // currency: 'BTC',
948
+ // address_info: { address: '1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX' }
949
+ // },
950
+ // idem: 'da0a2f14-a2af-4c5a-a37e-d4484caf582bsend',
951
+ // application: {
952
+ // id: '5756ab6e-836b-553b-8950-5e389451225d',
953
+ // resource: 'application',
954
+ // resource_path: '/v2/applications/5756ab6e-836b-553b-8950-5e389451225d'
955
+ // },
956
+ // details: { title: 'Sent Bitcoin', subtitle: 'To Bitcoin address' }
957
+ // }
958
+ //
959
+ // withdrawal transaction from coinbase to coinbasepro
960
+ //
961
+ // {
962
+ // id: '5b1b9fb8-5007-5393-b923-02903b973fdc',
963
+ // type: 'pro_deposit',
964
+ // status: 'completed',
965
+ // amount: { amount: '-0.00001111', currency: 'BCH' },
966
+ // native_amount: { amount: '0.00', currency: 'GBP' },
967
+ // description: null,
968
+ // created_at: '2019-02-28T13:31:58Z',
969
+ // updated_at: '2019-02-28T13:31:58Z',
970
+ // resource: 'transaction',
971
+ // resource_path: '/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/5b1b9fb8-5007-5393-b923-02903b973fdc',
972
+ // instant_exchange: false,
973
+ // application: {
974
+ // id: '5756ab6e-836b-553b-8950-5e389451225d',
975
+ // resource: 'application',
976
+ // resource_path: '/v2/applications/5756ab6e-836b-553b-8950-5e389451225d'
977
+ // },
978
+ // details: { title: 'Transferred Bitcoin Cash', subtitle: 'To Coinbase Pro' }
979
+ // }
980
+ //
981
+ // withdrawal transaction from coinbase to gdax
982
+ //
983
+ // {
984
+ // id: 'badb7313-a9d3-5c07-abd0-00f8b44199b1',
985
+ // type: 'exchange_deposit',
986
+ // status: 'completed',
987
+ // amount: { amount: '-0.43704149', currency: 'BCH' },
988
+ // native_amount: { amount: '-51.90', currency: 'GBP' },
989
+ // description: null,
990
+ // created_at: '2019-03-19T10:30:40Z',
991
+ // updated_at: '2019-03-19T10:30:40Z',
992
+ // resource: 'transaction',
993
+ // resource_path: '/v2/accounts/c01d7364-edd7-5f3a-bd1d-de53d4cbb25e/transactions/badb7313-a9d3-5c07-abd0-00f8b44199b1',
994
+ // instant_exchange: false,
995
+ // details: { title: 'Transferred Bitcoin Cash', subtitle: 'To GDAX' }
996
+ // }
997
+ //
998
+ // deposit transaction from gdax to coinbase
999
+ //
1000
+ // {
1001
+ // id: '9c4b642c-8688-58bf-8962-13cef64097de',
1002
+ // type: 'exchange_withdrawal',
1003
+ // status: 'completed',
1004
+ // amount: { amount: '0.57729420', currency: 'BTC' },
1005
+ // native_amount: { amount: '4418.72', currency: 'GBP' },
1006
+ // description: null,
1007
+ // created_at: '2018-02-17T11:33:33Z',
1008
+ // updated_at: '2018-02-17T11:33:33Z',
1009
+ // resource: 'transaction',
1010
+ // resource_path: '/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/9c4b642c-8688-58bf-8962-13cef64097de',
1011
+ // instant_exchange: false,
1012
+ // details: { title: 'Transferred Bitcoin', subtitle: 'From GDAX' }
1013
+ // }
1014
+ //
1015
+ // deposit transaction from coinbasepro to coinbase
1016
+ //
1017
+ // {
1018
+ // id: '8d6dd0b9-3416-568a-889d-8f112fae9e81',
1019
+ // type: 'pro_withdrawal',
1020
+ // status: 'completed',
1021
+ // amount: { amount: '0.40555386', currency: 'BTC' },
1022
+ // native_amount: { amount: '1140.27', currency: 'GBP' },
1023
+ // description: null,
1024
+ // created_at: '2019-03-04T19:41:58Z',
1025
+ // updated_at: '2019-03-04T19:41:58Z',
1026
+ // resource: 'transaction',
1027
+ // resource_path: '/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/8d6dd0b9-3416-568a-889d-8f112fae9e81',
1028
+ // instant_exchange: false,
1029
+ // application: {
1030
+ // id: '5756ab6e-836b-553b-8950-5e389451225d',
1031
+ // resource: 'application',
1032
+ // resource_path: '/v2/applications/5756ab6e-836b-553b-8950-5e389451225d'
1033
+ // },
1034
+ // details: { title: 'Transferred Bitcoin', subtitle: 'From Coinbase Pro' }
1035
+ // }
1036
+ //
1037
+ // sell trade
1038
+ //
1039
+ // {
1040
+ // id: 'a9409207-df64-585b-97ab-a50780d2149e',
1041
+ // type: 'sell',
1042
+ // status: 'completed',
1043
+ // amount: { amount: '-9.09922880', currency: 'BTC' },
1044
+ // native_amount: { amount: '-7285.73', currency: 'GBP' },
1045
+ // description: null,
1046
+ // created_at: '2017-03-27T15:38:34Z',
1047
+ // updated_at: '2017-03-27T15:38:34Z',
1048
+ // resource: 'transaction',
1049
+ // resource_path: '/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/transactions/a9409207-df64-585b-97ab-a50780d2149e',
1050
+ // instant_exchange: false,
1051
+ // sell: {
1052
+ // id: 'e3550b4d-8ae6-5de3-95fe-1fb01ba83051',
1053
+ // resource: 'sell',
1054
+ // resource_path: '/v2/accounts/c6afbd34-4bd0-501e-8616-4862c193cd84/sells/e3550b4d-8ae6-5de3-95fe-1fb01ba83051'
1055
+ // },
1056
+ // details: {
1057
+ // title: 'Sold Bitcoin',
1058
+ // subtitle: 'Using EUR Wallet',
1059
+ // payment_method_name: 'EUR Wallet'
1060
+ // }
1061
+ // }
1062
+ //
1063
+ // buy trade
1064
+ //
1065
+ // {
1066
+ // id: '63eeed67-9396-5912-86e9-73c4f10fe147',
1067
+ // type: 'buy',
1068
+ // status: 'completed',
1069
+ // amount: { amount: '2.39605772', currency: 'ETH' },
1070
+ // native_amount: { amount: '98.31', currency: 'GBP' },
1071
+ // description: null,
1072
+ // created_at: '2017-03-27T09:07:56Z',
1073
+ // updated_at: '2017-03-27T09:07:57Z',
1074
+ // resource: 'transaction',
1075
+ // resource_path: '/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/transactions/63eeed67-9396-5912-86e9-73c4f10fe147',
1076
+ // instant_exchange: false,
1077
+ // buy: {
1078
+ // id: '20b25b36-76c6-5353-aa57-b06a29a39d82',
1079
+ // resource: 'buy',
1080
+ // resource_path: '/v2/accounts/8902f85d-4a69-5d74-82fe-8e390201bda7/buys/20b25b36-76c6-5353-aa57-b06a29a39d82'
1081
+ // },
1082
+ // details: {
1083
+ // title: 'Bought Ethereum',
1084
+ // subtitle: 'Using EUR Wallet',
1085
+ // payment_method_name: 'EUR Wallet'
1086
+ // }
1087
+ // }
1088
+ //
1089
+ // fiat deposit transaction
1090
+ //
1091
+ // {
1092
+ // id: '04ed4113-3732-5b0c-af86-b1d2146977d0',
1093
+ // type: 'fiat_deposit',
1094
+ // status: 'completed',
1095
+ // amount: { amount: '114.02', currency: 'EUR' },
1096
+ // native_amount: { amount: '97.23', currency: 'GBP' },
1097
+ // description: null,
1098
+ // created_at: '2017-02-09T07:01:21Z',
1099
+ // updated_at: '2017-02-09T07:01:22Z',
1100
+ // resource: 'transaction',
1101
+ // resource_path: '/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/04ed4113-3732-5b0c-af86-b1d2146977d0',
1102
+ // instant_exchange: false,
1103
+ // fiat_deposit: {
1104
+ // id: 'f34c19f3-b730-5e3d-9f72-96520448677a',
1105
+ // resource: 'fiat_deposit',
1106
+ // resource_path: '/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/deposits/f34c19f3-b730-5e3d-9f72-96520448677a'
1107
+ // },
1108
+ // details: {
1109
+ // title: 'Deposited funds',
1110
+ // subtitle: 'From SEPA Transfer (GB47 BARC 20..., reference CBADVI)',
1111
+ // payment_method_name: 'SEPA Transfer (GB47 BARC 20..., reference CBADVI)'
1112
+ // }
1113
+ // }
1114
+ //
1115
+ // fiat withdrawal transaction
1116
+ //
1117
+ // {
1118
+ // id: '957d98e2-f80e-5e2f-a28e-02945aa93079',
1119
+ // type: 'fiat_withdrawal',
1120
+ // status: 'completed',
1121
+ // amount: { amount: '-11000.00', currency: 'EUR' },
1122
+ // native_amount: { amount: '-9698.22', currency: 'GBP' },
1123
+ // description: null,
1124
+ // created_at: '2017-12-06T13:19:19Z',
1125
+ // updated_at: '2017-12-06T13:19:19Z',
1126
+ // resource: 'transaction',
1127
+ // resource_path: '/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/transactions/957d98e2-f80e-5e2f-a28e-02945aa93079',
1128
+ // instant_exchange: false,
1129
+ // fiat_withdrawal: {
1130
+ // id: 'f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7',
1131
+ // resource: 'fiat_withdrawal',
1132
+ // resource_path: '/v2/accounts/91cd2d36-3a91-55b6-a5d4-0124cf105483/withdrawals/f4bf1fd9-ab3b-5de7-906d-ed3e23f7a4e7'
1133
+ // },
1134
+ // details: {
1135
+ // title: 'Withdrew funds',
1136
+ // subtitle: 'To HSBC BANK PLC (GB74 MIDL...)',
1137
+ // payment_method_name: 'HSBC BANK PLC (GB74 MIDL...)'
1138
+ // }
1139
+ // }
1140
+ //
1141
+ const amountInfo = this.safeValue (item, 'amount', {});
1142
+ let amount = this.safeNumber (amountInfo, 'amount');
1143
+ let direction = undefined;
1144
+ if (amount < 0) {
1145
+ direction = 'out';
1146
+ amount = -amount;
1147
+ } else {
1148
+ direction = 'in';
1149
+ }
1150
+ const currencyId = this.safeString (amountInfo, 'currency');
1151
+ const code = this.safeCurrencyCode (currencyId, currency);
1152
+ //
1153
+ // the address and txid do not belong to the unified ledger structure
1154
+ //
1155
+ // let address = undefined;
1156
+ // if (item['to']) {
1157
+ // address = this.safeString (item['to'], 'address');
1158
+ // }
1159
+ // let txid = undefined;
1160
+ //
1161
+ let fee = undefined;
1162
+ const networkInfo = this.safeValue (item, 'network', {});
1163
+ // txid = network['hash']; // txid does not belong to the unified ledger structure
1164
+ const feeInfo = this.safeValue (networkInfo, 'transaction_fee');
1165
+ if (feeInfo !== undefined) {
1166
+ const feeCurrencyId = this.safeString (feeInfo, 'currency');
1167
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId, currency);
1168
+ const feeAmount = this.safeNumber (feeInfo, 'amount');
1169
+ fee = {
1170
+ 'cost': feeAmount,
1171
+ 'currency': feeCurrencyCode,
1172
+ };
1173
+ }
1174
+ const timestamp = this.parse8601 (this.safeValue (item, 'created_at'));
1175
+ const id = this.safeString (item, 'id');
1176
+ const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
1177
+ const status = this.parseLedgerEntryStatus (this.safeString (item, 'status'));
1178
+ const path = this.safeString (item, 'resource_path');
1179
+ let accountId = undefined;
1180
+ if (path !== undefined) {
1181
+ const parts = path.split ('/');
1182
+ const numParts = parts.length;
1183
+ if (numParts > 3) {
1184
+ accountId = parts[3];
1185
+ }
1186
+ }
1187
+ return {
1188
+ 'info': item,
1189
+ 'id': id,
1190
+ 'timestamp': timestamp,
1191
+ 'datetime': this.iso8601 (timestamp),
1192
+ 'direction': direction,
1193
+ 'account': accountId,
1194
+ 'referenceId': undefined,
1195
+ 'referenceAccount': undefined,
1196
+ 'type': type,
1197
+ 'currency': code,
1198
+ 'amount': amount,
1199
+ 'before': undefined,
1200
+ 'after': undefined,
1201
+ 'status': status,
1202
+ 'fee': fee,
1203
+ };
1204
+ }
1205
+
1206
+ async findAccountId (code) {
1207
+ await this.loadMarkets ();
1208
+ await this.loadAccounts ();
1209
+ for (let i = 0; i < this.accounts.length; i++) {
1210
+ const account = this.accounts[i];
1211
+ if (account['code'] === code) {
1212
+ return account['id'];
1213
+ }
1214
+ }
1215
+ return undefined;
1216
+ }
1217
+
1218
+ prepareAccountRequest (limit = undefined, params = {}) {
1219
+ const accountId = this.safeString2 (params, 'account_id', 'accountId');
1220
+ if (accountId === undefined) {
1221
+ throw new ArgumentsRequired (this.id + ' prepareAccountRequest() method requires an account_id (or accountId) parameter');
1222
+ }
1223
+ const request = {
1224
+ 'account_id': accountId,
1225
+ };
1226
+ if (limit !== undefined) {
1227
+ request['limit'] = limit;
1228
+ }
1229
+ return request;
1230
+ }
1231
+
1232
+ async prepareAccountRequestWithCurrencyCode (code = undefined, limit = undefined, params = {}) {
1233
+ let accountId = this.safeString2 (params, 'account_id', 'accountId');
1234
+ if (accountId === undefined) {
1235
+ if (code === undefined) {
1236
+ throw new ArgumentsRequired (this.id + ' prepareAccountRequestWithCurrencyCode() method requires an account_id (or accountId) parameter OR a currency code argument');
1237
+ }
1238
+ accountId = await this.findAccountId (code);
1239
+ if (accountId === undefined) {
1240
+ throw new ExchangeError (this.id + ' prepareAccountRequestWithCurrencyCode() could not find account id for ' + code);
1241
+ }
1242
+ }
1243
+ const request = {
1244
+ 'account_id': accountId,
1245
+ };
1246
+ if (limit !== undefined) {
1247
+ request['limit'] = limit;
1248
+ }
1249
+ return request;
1250
+ }
1251
+
1252
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1253
+ let fullPath = '/' + this.version + '/' + this.implodeParams (path, params);
1254
+ const query = this.omit (params, this.extractParams (path));
1255
+ if (method === 'GET') {
1256
+ if (Object.keys (query).length) {
1257
+ fullPath += '?' + this.urlencode (query);
1258
+ }
1259
+ }
1260
+ const url = this.urls['api'] + fullPath;
1261
+ if (api === 'private') {
1262
+ const authorization = this.safeString (this.headers, 'Authorization');
1263
+ if (authorization !== undefined) {
1264
+ headers = {
1265
+ 'Authorization': authorization,
1266
+ 'Content-Type': 'application/json',
1267
+ };
1268
+ } else if (this.token) {
1269
+ headers = {
1270
+ 'Authorization': 'Bearer ' + this.token,
1271
+ 'Content-Type': 'application/json',
1272
+ };
1273
+ } else {
1274
+ this.checkRequiredCredentials ();
1275
+ const nonce = this.nonce ().toString ();
1276
+ let payload = '';
1277
+ if (method !== 'GET') {
1278
+ if (Object.keys (query).length) {
1279
+ body = this.json (query);
1280
+ payload = body;
1281
+ }
1282
+ }
1283
+ const auth = nonce + method + fullPath + payload;
1284
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
1285
+ headers = {
1286
+ 'CB-ACCESS-KEY': this.apiKey,
1287
+ 'CB-ACCESS-SIGN': signature,
1288
+ 'CB-ACCESS-TIMESTAMP': nonce,
1289
+ 'Content-Type': 'application/json',
1290
+ };
1291
+ }
1292
+ }
1293
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
1294
+ }
1295
+
1296
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1297
+ if (response === undefined) {
1298
+ return; // fallback to default error handler
1299
+ }
1300
+ const feedback = this.id + ' ' + body;
1301
+ //
1302
+ // {"error": "invalid_request", "error_description": "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
1303
+ //
1304
+ // or
1305
+ //
1306
+ // {
1307
+ // "errors": [
1308
+ // {
1309
+ // "id": "not_found",
1310
+ // "message": "Not found"
1311
+ // }
1312
+ // ]
1313
+ // }
1314
+ //
1315
+ let errorCode = this.safeString (response, 'error');
1316
+ if (errorCode !== undefined) {
1317
+ const errorMessage = this.safeString (response, 'error_description');
1318
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
1319
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
1320
+ throw new ExchangeError (feedback);
1321
+ }
1322
+ const errors = this.safeValue (response, 'errors');
1323
+ if (errors !== undefined) {
1324
+ if (Array.isArray (errors)) {
1325
+ const numErrors = errors.length;
1326
+ if (numErrors > 0) {
1327
+ errorCode = this.safeString (errors[0], 'id');
1328
+ const errorMessage = this.safeString (errors[0], 'message');
1329
+ if (errorCode !== undefined) {
1330
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
1331
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
1332
+ throw new ExchangeError (feedback);
1333
+ }
1334
+ }
1335
+ }
1336
+ }
1337
+ const data = this.safeValue (response, 'data');
1338
+ if (data === undefined) {
1339
+ throw new ExchangeError (this.id + ' failed due to a malformed response ' + this.json (response));
1340
+ }
1341
+ }
1342
+ };