ccxt 4.3.70 → 4.3.71

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 (151) hide show
  1. package/README.md +6 -5
  2. package/dist/ccxt.browser.min.js +13 -10
  3. package/dist/cjs/ccxt.js +6 -1
  4. package/dist/cjs/src/abstract/paradex.js +9 -0
  5. package/dist/cjs/src/base/Exchange.js +49 -0
  6. package/dist/cjs/src/paradex.js +2075 -0
  7. package/dist/cjs/src/pro/bequant.js +4 -0
  8. package/dist/cjs/src/pro/paradex.js +365 -0
  9. package/dist/cjs/src/static_dependencies/noble-curves/abstract/poseidon.js +100 -0
  10. package/dist/cjs/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -0
  11. package/dist/cjs/src/static_dependencies/scure-starknet/index.js +284 -0
  12. package/dist/cjs/src/static_dependencies/starknet/constants.js +60 -0
  13. package/dist/cjs/src/static_dependencies/starknet/types/calldata.js +26 -0
  14. package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/abi.js +8 -0
  15. package/dist/cjs/src/static_dependencies/starknet/types/lib/contract/index.js +13 -0
  16. package/dist/cjs/src/static_dependencies/starknet/types/lib/index.js +56 -0
  17. package/dist/cjs/src/static_dependencies/starknet/types/typedData.js +19 -0
  18. package/dist/cjs/src/static_dependencies/starknet/utils/assert.js +15 -0
  19. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +44 -0
  20. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +122 -0
  21. package/dist/cjs/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +137 -0
  22. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/byteArray.js +61 -0
  23. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/cairo.js +218 -0
  24. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
  25. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
  26. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
  27. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/formatter.js +66 -0
  28. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/index.js +281 -0
  29. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/index.js +33 -0
  30. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +37 -0
  31. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
  32. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +156 -0
  33. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/requestParser.js +250 -0
  34. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/responseParser.js +215 -0
  35. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/tuple.js +112 -0
  36. package/dist/cjs/src/static_dependencies/starknet/utils/calldata/validate.js +206 -0
  37. package/dist/cjs/src/static_dependencies/starknet/utils/encode.js +58 -0
  38. package/dist/cjs/src/static_dependencies/starknet/utils/hash/classHash.js +57 -0
  39. package/dist/cjs/src/static_dependencies/starknet/utils/merkle.js +76 -0
  40. package/dist/cjs/src/static_dependencies/starknet/utils/num.js +92 -0
  41. package/dist/cjs/src/static_dependencies/starknet/utils/selector.js +48 -0
  42. package/dist/cjs/src/static_dependencies/starknet/utils/shortString.js +101 -0
  43. package/dist/cjs/src/static_dependencies/starknet/utils/typedData.js +334 -0
  44. package/dist/cjs/src/woo.js +4 -2
  45. package/js/ccxt.d.ts +8 -2
  46. package/js/ccxt.js +6 -2
  47. package/js/src/abstract/paradex.d.ts +43 -0
  48. package/js/src/abstract/paradex.js +11 -0
  49. package/js/src/base/Exchange.d.ts +7 -0
  50. package/js/src/base/Exchange.js +45 -0
  51. package/js/src/paradex.d.ts +76 -0
  52. package/js/src/paradex.js +2075 -0
  53. package/js/src/pro/bequant.js +4 -0
  54. package/js/src/pro/paradex.d.ts +15 -0
  55. package/js/src/pro/paradex.js +366 -0
  56. package/js/src/static_dependencies/noble-curves/abstract/weierstrass.d.ts +24 -0
  57. package/js/src/static_dependencies/noble-curves/abstract/weierstrass.js +1 -1
  58. package/js/src/static_dependencies/scure-starknet/index.d.ts +79 -0
  59. package/js/src/static_dependencies/scure-starknet/index.js +323 -0
  60. package/js/src/static_dependencies/starknet/constants.d.ts +61 -0
  61. package/js/src/static_dependencies/starknet/constants.js +67 -0
  62. package/js/src/static_dependencies/starknet/index.d.ts +7 -0
  63. package/js/src/static_dependencies/starknet/index.js +50 -0
  64. package/js/src/static_dependencies/starknet/types/cairoEnum.d.ts +2 -0
  65. package/js/src/static_dependencies/starknet/types/cairoEnum.js +7 -0
  66. package/js/src/static_dependencies/starknet/types/calldata.d.ts +19 -0
  67. package/js/src/static_dependencies/starknet/types/calldata.js +28 -0
  68. package/js/src/static_dependencies/starknet/types/index.d.ts +13 -0
  69. package/js/src/static_dependencies/starknet/types/index.js +16 -0
  70. package/js/src/static_dependencies/starknet/types/lib/contract/abi.d.ts +71 -0
  71. package/js/src/static_dependencies/starknet/types/lib/contract/abi.js +13 -0
  72. package/js/src/static_dependencies/starknet/types/lib/contract/index.d.ts +24 -0
  73. package/js/src/static_dependencies/starknet/types/lib/contract/index.js +16 -0
  74. package/js/src/static_dependencies/starknet/types/lib/contract/legacy.d.ts +33 -0
  75. package/js/src/static_dependencies/starknet/types/lib/contract/legacy.js +7 -0
  76. package/js/src/static_dependencies/starknet/types/lib/contract/sierra.d.ts +52 -0
  77. package/js/src/static_dependencies/starknet/types/lib/contract/sierra.js +7 -0
  78. package/js/src/static_dependencies/starknet/types/lib/index.d.ts +248 -0
  79. package/js/src/static_dependencies/starknet/types/lib/index.js +52 -0
  80. package/js/src/static_dependencies/starknet/types/typedData.d.ts +44 -0
  81. package/js/src/static_dependencies/starknet/types/typedData.js +19 -0
  82. package/js/src/static_dependencies/starknet/utils/address.d.ts +53 -0
  83. package/js/src/static_dependencies/starknet/utils/address.js +89 -0
  84. package/js/src/static_dependencies/starknet/utils/assert.d.ts +7 -0
  85. package/js/src/static_dependencies/starknet/utils/assert.js +17 -0
  86. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.d.ts +6 -0
  87. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/felt.js +43 -0
  88. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.d.ts +72 -0
  89. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint256.js +117 -0
  90. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.d.ts +76 -0
  91. package/js/src/static_dependencies/starknet/utils/cairoDataTypes/uint512.js +136 -0
  92. package/js/src/static_dependencies/starknet/utils/calldata/byteArray.d.ts +32 -0
  93. package/js/src/static_dependencies/starknet/utils/calldata/byteArray.js +59 -0
  94. package/js/src/static_dependencies/starknet/utils/calldata/cairo.d.ts +183 -0
  95. package/js/src/static_dependencies/starknet/utils/calldata/cairo.js +229 -0
  96. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.d.ts +38 -0
  97. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoCustomEnum.js +57 -0
  98. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.d.ts +35 -0
  99. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoOption.js +64 -0
  100. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.d.ts +34 -0
  101. package/js/src/static_dependencies/starknet/utils/calldata/enum/CairoResult.js +63 -0
  102. package/js/src/static_dependencies/starknet/utils/calldata/enum/index.d.ts +3 -0
  103. package/js/src/static_dependencies/starknet/utils/calldata/enum/index.js +9 -0
  104. package/js/src/static_dependencies/starknet/utils/calldata/formatter.d.ts +9 -0
  105. package/js/src/static_dependencies/starknet/utils/calldata/formatter.js +67 -0
  106. package/js/src/static_dependencies/starknet/utils/calldata/index.d.ts +89 -0
  107. package/js/src/static_dependencies/starknet/utils/calldata/index.js +280 -0
  108. package/js/src/static_dependencies/starknet/utils/calldata/parser/index.d.ts +5 -0
  109. package/js/src/static_dependencies/starknet/utils/calldata/parser/index.js +30 -0
  110. package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.d.ts +20 -0
  111. package/js/src/static_dependencies/starknet/utils/calldata/parser/interface.js +8 -0
  112. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.d.ts +24 -0
  113. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-0-1.1.0.js +36 -0
  114. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.d.ts +23 -0
  115. package/js/src/static_dependencies/starknet/utils/calldata/parser/parser-2.0.0.js +40 -0
  116. package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.d.ts +2 -0
  117. package/js/src/static_dependencies/starknet/utils/calldata/propertyOrder.js +155 -0
  118. package/js/src/static_dependencies/starknet/utils/calldata/requestParser.d.ts +11 -0
  119. package/js/src/static_dependencies/starknet/utils/calldata/requestParser.js +248 -0
  120. package/js/src/static_dependencies/starknet/utils/calldata/responseParser.d.ts +11 -0
  121. package/js/src/static_dependencies/starknet/utils/calldata/responseParser.js +214 -0
  122. package/js/src/static_dependencies/starknet/utils/calldata/tuple.d.ts +6 -0
  123. package/js/src/static_dependencies/starknet/utils/calldata/tuple.js +113 -0
  124. package/js/src/static_dependencies/starknet/utils/calldata/validate.d.ts +6 -0
  125. package/js/src/static_dependencies/starknet/utils/calldata/validate.js +208 -0
  126. package/js/src/static_dependencies/starknet/utils/encode.d.ts +207 -0
  127. package/js/src/static_dependencies/starknet/utils/encode.js +282 -0
  128. package/js/src/static_dependencies/starknet/utils/hash/classHash.d.ts +57 -0
  129. package/js/src/static_dependencies/starknet/utils/hash/classHash.js +224 -0
  130. package/js/src/static_dependencies/starknet/utils/hash/index.d.ts +6 -0
  131. package/js/src/static_dependencies/starknet/utils/hash/index.js +13 -0
  132. package/js/src/static_dependencies/starknet/utils/json.d.ts +24 -0
  133. package/js/src/static_dependencies/starknet/utils/json.js +43 -0
  134. package/js/src/static_dependencies/starknet/utils/merkle.d.ts +35 -0
  135. package/js/src/static_dependencies/starknet/utils/merkle.js +84 -0
  136. package/js/src/static_dependencies/starknet/utils/num.d.ts +182 -0
  137. package/js/src/static_dependencies/starknet/utils/num.js +244 -0
  138. package/js/src/static_dependencies/starknet/utils/selector.d.ts +48 -0
  139. package/js/src/static_dependencies/starknet/utils/selector.js +85 -0
  140. package/js/src/static_dependencies/starknet/utils/shortString.d.ts +57 -0
  141. package/js/src/static_dependencies/starknet/utils/shortString.js +96 -0
  142. package/js/src/static_dependencies/starknet/utils/starknetId.d.ts +113 -0
  143. package/js/src/static_dependencies/starknet/utils/starknetId.js +265 -0
  144. package/js/src/static_dependencies/starknet/utils/typedData.d.ts +54 -0
  145. package/js/src/static_dependencies/starknet/utils/typedData.js +321 -0
  146. package/js/src/static_dependencies/starknet/utils/uint256.d.ts +21 -0
  147. package/js/src/static_dependencies/starknet/utils/uint256.js +32 -0
  148. package/js/src/static_dependencies/starknet/utils/url.d.ts +29 -0
  149. package/js/src/static_dependencies/starknet/utils/url.js +70 -0
  150. package/js/src/woo.js +4 -2
  151. package/package.json +1 -1
@@ -0,0 +1,2075 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ // ---------------------------------------------------------------------------
8
+ import { Precise } from '../ccxt.js';
9
+ import Exchange from './abstract/paradex.js';
10
+ import { ExchangeError, PermissionDenied, AuthenticationError, BadRequest, ArgumentsRequired, OperationRejected, InvalidOrder } from './base/errors.js';
11
+ import { TICK_SIZE } from './base/functions/number.js';
12
+ import { ecdsa } from './base/functions/crypto.js';
13
+ import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
14
+ import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * @class paradex
18
+ * @augments Exchange
19
+ */
20
+ export default class paradex extends Exchange {
21
+ describe() {
22
+ return this.deepExtend(super.describe(), {
23
+ 'id': 'paradex',
24
+ 'name': 'Paradex',
25
+ 'countries': [],
26
+ 'version': 'v1',
27
+ 'rateLimit': 50,
28
+ 'certified': false,
29
+ 'pro': true,
30
+ 'dex': true,
31
+ 'has': {
32
+ 'CORS': undefined,
33
+ 'spot': false,
34
+ 'margin': false,
35
+ 'swap': true,
36
+ 'future': false,
37
+ 'option': false,
38
+ 'addMargin': false,
39
+ 'borrowCrossMargin': false,
40
+ 'borrowIsolatedMargin': false,
41
+ 'cancelAllOrders': true,
42
+ 'cancelAllOrdersAfter': false,
43
+ 'cancelOrder': false,
44
+ 'cancelOrders': false,
45
+ 'cancelOrdersForSymbols': false,
46
+ 'closeAllPositions': false,
47
+ 'closePosition': false,
48
+ 'createMarketBuyOrderWithCost': false,
49
+ 'createMarketOrderWithCost': false,
50
+ 'createMarketSellOrderWithCost': false,
51
+ 'createOrder': true,
52
+ 'createOrders': false,
53
+ 'createReduceOnlyOrder': false,
54
+ 'editOrder': false,
55
+ 'fetchAccounts': false,
56
+ 'fetchBalance': true,
57
+ 'fetchBorrowInterest': false,
58
+ 'fetchBorrowRateHistories': false,
59
+ 'fetchBorrowRateHistory': false,
60
+ 'fetchCanceledOrders': false,
61
+ 'fetchClosedOrders': false,
62
+ 'fetchCrossBorrowRate': false,
63
+ 'fetchCrossBorrowRates': false,
64
+ 'fetchCurrencies': false,
65
+ 'fetchDepositAddress': false,
66
+ 'fetchDepositAddresses': false,
67
+ 'fetchDeposits': true,
68
+ 'fetchDepositWithdrawFee': false,
69
+ 'fetchDepositWithdrawFees': false,
70
+ 'fetchFundingHistory': false,
71
+ 'fetchFundingRate': false,
72
+ 'fetchFundingRateHistory': false,
73
+ 'fetchFundingRates': false,
74
+ 'fetchIndexOHLCV': false,
75
+ 'fetchIsolatedBorrowRate': false,
76
+ 'fetchIsolatedBorrowRates': false,
77
+ 'fetchLedger': false,
78
+ 'fetchLeverage': false,
79
+ 'fetchLeverageTiers': false,
80
+ 'fetchLiquidations': true,
81
+ 'fetchMarginMode': undefined,
82
+ 'fetchMarketLeverageTiers': false,
83
+ 'fetchMarkets': true,
84
+ 'fetchMarkOHLCV': false,
85
+ 'fetchMyLiquidations': false,
86
+ 'fetchMyTrades': true,
87
+ 'fetchOHLCV': true,
88
+ 'fetchOpenInterest': true,
89
+ 'fetchOpenInterestHistory': false,
90
+ 'fetchOpenOrders': true,
91
+ 'fetchOrder': true,
92
+ 'fetchOrderBook': true,
93
+ 'fetchOrders': true,
94
+ 'fetchOrderTrades': false,
95
+ 'fetchPosition': true,
96
+ 'fetchPositionMode': false,
97
+ 'fetchPositions': true,
98
+ 'fetchPositionsRisk': false,
99
+ 'fetchPremiumIndexOHLCV': false,
100
+ 'fetchStatus': true,
101
+ 'fetchTicker': true,
102
+ 'fetchTickers': true,
103
+ 'fetchTime': true,
104
+ 'fetchTrades': true,
105
+ 'fetchTradingFee': false,
106
+ 'fetchTradingFees': false,
107
+ 'fetchTransfer': false,
108
+ 'fetchTransfers': false,
109
+ 'fetchWithdrawal': false,
110
+ 'fetchWithdrawals': true,
111
+ 'reduceMargin': false,
112
+ 'repayCrossMargin': false,
113
+ 'repayIsolatedMargin': false,
114
+ 'sandbox': true,
115
+ 'setLeverage': false,
116
+ 'setMarginMode': false,
117
+ 'setPositionMode': false,
118
+ 'transfer': false,
119
+ 'withdraw': false,
120
+ },
121
+ 'timeframes': {
122
+ '1m': 1,
123
+ '3m': 3,
124
+ '5m': 5,
125
+ '15m': 15,
126
+ '30m': 30,
127
+ '1h': 60,
128
+ },
129
+ 'hostname': 'paradex.trade',
130
+ 'urls': {
131
+ 'logo': 'https://github.com/user-attachments/assets/5dadc09a-74ba-466a-a8f2-3f55c7e4654a',
132
+ 'api': {
133
+ 'v1': 'https://api.prod.{hostname}/v1',
134
+ },
135
+ 'test': {
136
+ 'v1': 'https://api.testnet.{hostname}/v1',
137
+ },
138
+ 'www': 'https://www.paradex.trade/',
139
+ 'doc': 'https://docs.api.testnet.paradex.trade/',
140
+ 'fees': 'https://docs.paradex.trade/getting-started/trading-fees',
141
+ 'referral': 'https://app.paradex.trade/r/ccxt24',
142
+ },
143
+ 'api': {
144
+ 'public': {
145
+ 'get': {
146
+ 'bbo/{market}': 1,
147
+ 'funding/data': 1,
148
+ 'markets': 1,
149
+ 'markets/klines': 1,
150
+ 'markets/summary': 1,
151
+ 'orderbook/{market}': 1,
152
+ 'insurance': 1,
153
+ 'referrals/config': 1,
154
+ 'system/config': 1,
155
+ 'system/state': 1,
156
+ 'system/time': 1,
157
+ 'trades': 1,
158
+ },
159
+ },
160
+ 'private': {
161
+ 'get': {
162
+ 'account': 1,
163
+ 'account/profile': 1,
164
+ 'balance': 1,
165
+ 'fills': 1,
166
+ 'funding/payments': 1,
167
+ 'positions': 1,
168
+ 'tradebusts': 1,
169
+ 'transactions': 1,
170
+ 'liquidations': 1,
171
+ 'orders': 1,
172
+ 'orders-history': 1,
173
+ 'orders/by_client_id/{client_id}': 1,
174
+ 'orders/{order_id}': 1,
175
+ 'points_data/{market}/{program}': 1,
176
+ 'referrals/summary': 1,
177
+ 'transfers': 1,
178
+ },
179
+ 'post': {
180
+ 'account/profile/referral_code': 1,
181
+ 'account/profile/username': 1,
182
+ 'auth': 1,
183
+ 'onboarding': 1,
184
+ 'orders': 1,
185
+ },
186
+ 'delete': {
187
+ 'orders': 1,
188
+ 'orders/by_client_id/{client_id}': 1,
189
+ 'orders/{order_id}': 1,
190
+ },
191
+ },
192
+ },
193
+ 'fees': {
194
+ 'swap': {
195
+ 'taker': this.parseNumber('0.0002'),
196
+ 'maker': this.parseNumber('0.0002'),
197
+ },
198
+ 'spot': {
199
+ 'taker': this.parseNumber('0.0002'),
200
+ 'maker': this.parseNumber('0.0002'),
201
+ },
202
+ },
203
+ 'requiredCredentials': {
204
+ 'apiKey': false,
205
+ 'secret': false,
206
+ 'walletAddress': true,
207
+ 'privateKey': true,
208
+ },
209
+ 'exceptions': {
210
+ 'exact': {
211
+ 'VALIDATION_ERROR': AuthenticationError,
212
+ 'BINDING_ERROR': OperationRejected,
213
+ 'INTERNAL_ERROR': ExchangeError,
214
+ 'NOT_FOUND': BadRequest,
215
+ 'SERVICE_UNAVAILABLE': ExchangeError,
216
+ 'INVALID_REQUEST_PARAMETER': BadRequest,
217
+ 'ORDER_ID_NOT_FOUND': InvalidOrder,
218
+ 'ORDER_IS_CLOSED': InvalidOrder,
219
+ 'ORDER_IS_NOT_OPEN_YET': InvalidOrder,
220
+ 'CLIENT_ORDER_ID_NOT_FOUND': InvalidOrder,
221
+ 'DUPLICATED_CLIENT_ID': InvalidOrder,
222
+ 'INVALID_PRICE_PRECISION': OperationRejected,
223
+ 'INVALID_SYMBOL': OperationRejected,
224
+ 'INVALID_TOKEN': OperationRejected,
225
+ 'INVALID_ETHEREUM_ADDRESS': OperationRejected,
226
+ 'INVALID_ETHEREUM_SIGNATURE': OperationRejected,
227
+ 'INVALID_STARKNET_ADDRESS': OperationRejected,
228
+ 'INVALID_STARKNET_SIGNATURE': OperationRejected,
229
+ 'STARKNET_SIGNATURE_VERIFICATION_FAILED': AuthenticationError,
230
+ 'BAD_STARKNET_REQUEST': BadRequest,
231
+ 'ETHEREUM_SIGNER_MISMATCH': BadRequest,
232
+ 'ETHEREUM_HASH_MISMATCH': BadRequest,
233
+ 'NOT_ONBOARDED': BadRequest,
234
+ 'INVALID_TIMESTAMP': BadRequest,
235
+ 'INVALID_SIGNATURE_EXPIRATION': AuthenticationError,
236
+ 'ACCOUNT_NOT_FOUND': AuthenticationError,
237
+ 'INVALID_ORDER_SIGNATURE': AuthenticationError,
238
+ 'PUBLIC_KEY_INVALID': BadRequest,
239
+ 'UNAUTHORIZED_ETHEREUM_ADDRESS': BadRequest,
240
+ 'ETHEREUM_ADDRESS_ALREADY_ONBOARDED': BadRequest,
241
+ 'MARKET_NOT_FOUND': BadRequest,
242
+ 'ALLOWLIST_ENTRY_NOT_FOUND': BadRequest,
243
+ 'USERNAME_IN_USE': AuthenticationError,
244
+ 'GEO_IP_BLOCK': PermissionDenied,
245
+ 'ETHEREUM_ADDRESS_BLOCKED': PermissionDenied,
246
+ 'PROGRAM_NOT_FOUND': BadRequest,
247
+ 'INVALID_DASHBOARD': OperationRejected,
248
+ 'MARKET_NOT_OPEN': BadRequest,
249
+ 'INVALID_REFERRAL_CODE': OperationRejected,
250
+ 'PARENT_ADDRESS_ALREADY_ONBOARDED': BadRequest,
251
+ 'INVALID_PARENT_ACCOUNT': OperationRejected,
252
+ 'INVALID_VAULT_OPERATOR_CHAIN': OperationRejected,
253
+ 'VAULT_OPERATOR_ALREADY_ONBOARDED': OperationRejected,
254
+ 'VAULT_NAME_IN_USE': OperationRejected,
255
+ 'BATCH_SIZE_OUT_OF_RANGE': OperationRejected,
256
+ 'ISOLATED_MARKET_ACCOUNT_MISMATCH': OperationRejected,
257
+ 'POINTS_SUMMARY_NOT_FOUND': OperationRejected,
258
+ '-32700': BadRequest,
259
+ '-32600': BadRequest,
260
+ '-32601': BadRequest,
261
+ '-32602': BadRequest,
262
+ '-32603': ExchangeError,
263
+ '100': BadRequest,
264
+ '40110': AuthenticationError,
265
+ '40111': AuthenticationError,
266
+ '40112': PermissionDenied, // Geo IP blocked
267
+ },
268
+ 'broad': {},
269
+ },
270
+ 'precisionMode': TICK_SIZE,
271
+ 'commonCurrencies': {},
272
+ 'options': {
273
+ 'broker': 'CCXT',
274
+ },
275
+ });
276
+ }
277
+ async fetchTime(params = {}) {
278
+ /**
279
+ * @method
280
+ * @name paradex#fetchTime
281
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
282
+ * @see https://docs.api.testnet.paradex.trade/#get-system-time-unix-milliseconds
283
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
284
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
285
+ */
286
+ const response = await this.publicGetSystemTime(params);
287
+ //
288
+ // {
289
+ // "server_time": "1681493415023"
290
+ // }
291
+ //
292
+ return this.safeInteger(response, 'server_time');
293
+ }
294
+ async fetchStatus(params = {}) {
295
+ /**
296
+ * @method
297
+ * @name paradex#fetchStatus
298
+ * @description the latest known information on the availability of the exchange API
299
+ * @see https://docs.api.testnet.paradex.trade/#get-system-state
300
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
301
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
302
+ */
303
+ const response = await this.publicGetSystemState(params);
304
+ //
305
+ // {
306
+ // "status": "ok"
307
+ // }
308
+ //
309
+ const status = this.safeString(response, 'status');
310
+ return {
311
+ 'status': (status === 'ok') ? 'ok' : 'maintenance',
312
+ 'updated': undefined,
313
+ 'eta': undefined,
314
+ 'url': undefined,
315
+ 'info': response,
316
+ };
317
+ }
318
+ async fetchMarkets(params = {}) {
319
+ /**
320
+ * @method
321
+ * @name paradex#fetchMarkets
322
+ * @description retrieves data on all markets for bitget
323
+ * @see https://docs.api.testnet.paradex.trade/#list-available-markets
324
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
325
+ * @returns {object[]} an array of objects representing market data
326
+ */
327
+ const response = await this.publicGetMarkets(params);
328
+ //
329
+ // {
330
+ // "results": [
331
+ // {
332
+ // "symbol": "BODEN-USD-PERP",
333
+ // "base_currency": "BODEN",
334
+ // "quote_currency": "USD",
335
+ // "settlement_currency": "USDC",
336
+ // "order_size_increment": "1",
337
+ // "price_tick_size": "0.00001",
338
+ // "min_notional": "200",
339
+ // "open_at": 1717065600000,
340
+ // "expiry_at": 0,
341
+ // "asset_kind": "PERP",
342
+ // "position_limit": "2000000",
343
+ // "price_bands_width": "0.2",
344
+ // "max_open_orders": 50,
345
+ // "max_funding_rate": "0.05",
346
+ // "delta1_cross_margin_params": {
347
+ // "imf_base": "0.2",
348
+ // "imf_shift": "180000",
349
+ // "imf_factor": "0.00071",
350
+ // "mmf_factor": "0.5"
351
+ // },
352
+ // "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5",
353
+ // "oracle_ewma_factor": "0.14999987905913592",
354
+ // "max_order_size": "520000",
355
+ // "max_funding_rate_change": "0.0005",
356
+ // "max_tob_spread": "0.2"
357
+ // }
358
+ // ]
359
+ // }
360
+ //
361
+ const data = this.safeList(response, 'results');
362
+ return this.parseMarkets(data);
363
+ }
364
+ parseMarket(market) {
365
+ //
366
+ // {
367
+ // "symbol": "BODEN-USD-PERP",
368
+ // "base_currency": "BODEN",
369
+ // "quote_currency": "USD",
370
+ // "settlement_currency": "USDC",
371
+ // "order_size_increment": "1",
372
+ // "price_tick_size": "0.00001",
373
+ // "min_notional": "200",
374
+ // "open_at": 1717065600000,
375
+ // "expiry_at": 0,
376
+ // "asset_kind": "PERP",
377
+ // "position_limit": "2000000",
378
+ // "price_bands_width": "0.2",
379
+ // "max_open_orders": 50,
380
+ // "max_funding_rate": "0.05",
381
+ // "delta1_cross_margin_params": {
382
+ // "imf_base": "0.2",
383
+ // "imf_shift": "180000",
384
+ // "imf_factor": "0.00071",
385
+ // "mmf_factor": "0.5"
386
+ // },
387
+ // "price_feed_id": "9LScEHse1ioZt2rUuhwiN6bmYnqpMqvZkQJDNUpxVHN5",
388
+ // "oracle_ewma_factor": "0.14999987905913592",
389
+ // "max_order_size": "520000",
390
+ // "max_funding_rate_change": "0.0005",
391
+ // "max_tob_spread": "0.2"
392
+ // }
393
+ //
394
+ const marketId = this.safeString(market, 'symbol');
395
+ const quoteId = this.safeString(market, 'quote_currency');
396
+ const baseId = this.safeString(market, 'base_currency');
397
+ const quote = this.safeCurrencyCode(quoteId);
398
+ const base = this.safeCurrencyCode(baseId);
399
+ const settleId = this.safeString(market, 'settlement_currency');
400
+ const settle = this.safeCurrencyCode(settleId);
401
+ const symbol = base + '/' + quote + ':' + settle;
402
+ const expiry = this.safeInteger(market, 'expiry_at');
403
+ const takerFee = this.parseNumber('0.0003');
404
+ const makerFee = this.parseNumber('-0.00005');
405
+ return this.safeMarketStructure({
406
+ 'id': marketId,
407
+ 'symbol': symbol,
408
+ 'base': base,
409
+ 'quote': quote,
410
+ 'settle': settle,
411
+ 'baseId': baseId,
412
+ 'quoteId': quoteId,
413
+ 'settleId': settleId,
414
+ 'type': 'swap',
415
+ 'spot': false,
416
+ 'margin': undefined,
417
+ 'swap': true,
418
+ 'future': false,
419
+ 'option': false,
420
+ 'active': this.safeBool(market, 'enableTrading'),
421
+ 'contract': true,
422
+ 'linear': true,
423
+ 'inverse': undefined,
424
+ 'taker': takerFee,
425
+ 'maker': makerFee,
426
+ 'contractSize': this.parseNumber('1'),
427
+ 'expiry': (expiry === 0) ? undefined : expiry,
428
+ 'expiryDatetime': (expiry === 0) ? undefined : this.iso8601(expiry),
429
+ 'strike': undefined,
430
+ 'optionType': undefined,
431
+ 'precision': {
432
+ 'amount': this.safeNumber(market, 'order_size_increment'),
433
+ 'price': this.safeNumber(market, 'price_tick_size'),
434
+ },
435
+ 'limits': {
436
+ 'leverage': {
437
+ 'min': undefined,
438
+ 'max': undefined,
439
+ },
440
+ 'amount': {
441
+ 'min': undefined,
442
+ 'max': this.safeNumber(market, 'max_order_size'),
443
+ },
444
+ 'price': {
445
+ 'min': undefined,
446
+ 'max': undefined,
447
+ },
448
+ 'cost': {
449
+ 'min': this.safeNumber(market, 'min_notional'),
450
+ 'max': undefined,
451
+ },
452
+ },
453
+ 'created': undefined,
454
+ 'info': market,
455
+ });
456
+ }
457
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
458
+ /**
459
+ * @method
460
+ * @name paradex#fetchOHLCV
461
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
462
+ * @see https://docs.api.testnet.paradex.trade/#ohlcv-for-a-symbol
463
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
464
+ * @param {string} timeframe the length of time each candle represents
465
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
466
+ * @param {int} [limit] the maximum amount of candles to fetch
467
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
468
+ * @param {int} [params.until] timestamp in ms of the latest candle to fetch
469
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
470
+ */
471
+ await this.loadMarkets();
472
+ const market = this.market(symbol);
473
+ const request = {
474
+ 'resolution': this.safeString(this.timeframes, timeframe, timeframe),
475
+ 'symbol': market['id'],
476
+ };
477
+ const now = this.milliseconds();
478
+ const duration = this.parseTimeframe(timeframe);
479
+ const until = this.safeInteger2(params, 'until', 'till', now);
480
+ params = this.omit(params, ['until', 'till']);
481
+ if (since !== undefined) {
482
+ request['start_at'] = since;
483
+ if (limit !== undefined) {
484
+ request['end_at'] = this.sum(since, duration * (limit + 1) * 1000) - 1;
485
+ }
486
+ else {
487
+ request['end_at'] = until;
488
+ }
489
+ }
490
+ else {
491
+ request['end_at'] = until;
492
+ if (limit !== undefined) {
493
+ request['start_at'] = until - duration * (limit + 1) * 1000 + 1;
494
+ }
495
+ else {
496
+ request['start_at'] = until - duration * 101 * 1000 + 1;
497
+ }
498
+ }
499
+ const response = await this.publicGetMarketsKlines(this.extend(request, params));
500
+ //
501
+ // {
502
+ // "results": [
503
+ // [
504
+ // 1720071900000,
505
+ // 58961.3,
506
+ // 58961.3,
507
+ // 58961.3,
508
+ // 58961.3,
509
+ // 1591
510
+ // ]
511
+ // ]
512
+ // }
513
+ //
514
+ const data = this.safeList(response, 'results', []);
515
+ return this.parseOHLCVs(data, market, timeframe, since, limit);
516
+ }
517
+ parseOHLCV(ohlcv, market = undefined) {
518
+ //
519
+ // [
520
+ // 1720071900000,
521
+ // 58961.3,
522
+ // 58961.3,
523
+ // 58961.3,
524
+ // 58961.3,
525
+ // 1591
526
+ // ]
527
+ //
528
+ return [
529
+ this.safeInteger(ohlcv, 0),
530
+ this.safeNumber(ohlcv, 1),
531
+ this.safeNumber(ohlcv, 2),
532
+ this.safeNumber(ohlcv, 3),
533
+ this.safeNumber(ohlcv, 4),
534
+ this.safeNumber(ohlcv, 5),
535
+ ];
536
+ }
537
+ async fetchTickers(symbols = undefined, params = {}) {
538
+ /**
539
+ * @method
540
+ * @name paradex#fetchTickers
541
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
542
+ * @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
543
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
544
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
545
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
546
+ */
547
+ await this.loadMarkets();
548
+ symbols = this.marketSymbols(symbols);
549
+ const request = {};
550
+ if (symbols !== undefined) {
551
+ if (Array.isArray(symbols)) {
552
+ request['market'] = this.marketId(symbols[0]);
553
+ }
554
+ else {
555
+ request['market'] = this.marketId(symbols);
556
+ }
557
+ }
558
+ else {
559
+ request['market'] = 'ALL';
560
+ }
561
+ const response = await this.publicGetMarketsSummary(this.extend(request, params));
562
+ //
563
+ // {
564
+ // "results": [
565
+ // {
566
+ // "symbol": "BTC-USD-PERP",
567
+ // "oracle_price": "68465.17449906",
568
+ // "mark_price": "68465.17449906",
569
+ // "last_traded_price": "68495.1",
570
+ // "bid": "68477.6",
571
+ // "ask": "69578.2",
572
+ // "volume_24h": "5815541.397939004",
573
+ // "total_volume": "584031465.525259686",
574
+ // "created_at": 1718170156580,
575
+ // "underlying_price": "67367.37268422",
576
+ // "open_interest": "162.272",
577
+ // "funding_rate": "0.01629574927887",
578
+ // "price_change_rate_24h": "0.009032"
579
+ // }
580
+ // ]
581
+ // }
582
+ //
583
+ const data = this.safeList(response, 'results', []);
584
+ return this.parseTickers(data, symbols);
585
+ }
586
+ async fetchTicker(symbol, params = {}) {
587
+ /**
588
+ * @method
589
+ * @name paradex#fetchTicker
590
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
591
+ * @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
592
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
593
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
594
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
595
+ */
596
+ await this.loadMarkets();
597
+ const market = this.market(symbol);
598
+ const request = {
599
+ 'market': market['id'],
600
+ };
601
+ const response = await this.publicGetMarketsSummary(this.extend(request, params));
602
+ //
603
+ // {
604
+ // "results": [
605
+ // {
606
+ // "symbol": "BTC-USD-PERP",
607
+ // "oracle_price": "68465.17449906",
608
+ // "mark_price": "68465.17449906",
609
+ // "last_traded_price": "68495.1",
610
+ // "bid": "68477.6",
611
+ // "ask": "69578.2",
612
+ // "volume_24h": "5815541.397939004",
613
+ // "total_volume": "584031465.525259686",
614
+ // "created_at": 1718170156580,
615
+ // "underlying_price": "67367.37268422",
616
+ // "open_interest": "162.272",
617
+ // "funding_rate": "0.01629574927887",
618
+ // "price_change_rate_24h": "0.009032"
619
+ // }
620
+ // ]
621
+ // }
622
+ //
623
+ const data = this.safeList(response, 'results', []);
624
+ const ticker = this.safeDict(data, 0, {});
625
+ return this.parseTicker(ticker, market);
626
+ }
627
+ parseTicker(ticker, market = undefined) {
628
+ //
629
+ // {
630
+ // "symbol": "BTC-USD-PERP",
631
+ // "oracle_price": "68465.17449906",
632
+ // "mark_price": "68465.17449906",
633
+ // "last_traded_price": "68495.1",
634
+ // "bid": "68477.6",
635
+ // "ask": "69578.2",
636
+ // "volume_24h": "5815541.397939004",
637
+ // "total_volume": "584031465.525259686",
638
+ // "created_at": 1718170156580,
639
+ // "underlying_price": "67367.37268422",
640
+ // "open_interest": "162.272",
641
+ // "funding_rate": "0.01629574927887",
642
+ // "price_change_rate_24h": "0.009032"
643
+ // }
644
+ //
645
+ let percentage = this.safeString(ticker, 'price_change_rate_24h');
646
+ if (percentage !== undefined) {
647
+ percentage = Precise.stringMul(percentage, '100');
648
+ }
649
+ const last = this.safeString(ticker, 'last_traded_price');
650
+ const marketId = this.safeString(ticker, 'symbol');
651
+ market = this.safeMarket(marketId, market);
652
+ const symbol = market['symbol'];
653
+ const timestamp = this.safeInteger(ticker, 'created_at');
654
+ return this.safeTicker({
655
+ 'symbol': symbol,
656
+ 'timestamp': timestamp,
657
+ 'datetime': this.iso8601(timestamp),
658
+ 'high': undefined,
659
+ 'low': undefined,
660
+ 'bid': this.safeString(ticker, 'bid'),
661
+ 'bidVolume': undefined,
662
+ 'ask': this.safeString(ticker, 'sdk'),
663
+ 'askVolume': undefined,
664
+ 'vwap': undefined,
665
+ 'open': undefined,
666
+ 'close': last,
667
+ 'last': last,
668
+ 'previousClose': undefined,
669
+ 'change': undefined,
670
+ 'percentage': percentage,
671
+ 'average': undefined,
672
+ 'baseVolume': undefined,
673
+ 'quoteVolume': this.safeString(ticker, 'volume_24h'),
674
+ 'info': ticker,
675
+ }, market);
676
+ }
677
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
678
+ /**
679
+ * @method
680
+ * @name paradex#fetchOrderBook
681
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
682
+ * @see https://docs.api.testnet.paradex.trade/#get-market-orderbook
683
+ * @param {string} symbol unified symbol of the market to fetch the order book for
684
+ * @param {int} [limit] the maximum amount of order book entries to return
685
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
686
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
687
+ */
688
+ await this.loadMarkets();
689
+ const market = this.market(symbol);
690
+ const request = { 'market': market['id'] };
691
+ const response = await this.publicGetOrderbookMarket(this.extend(request, params));
692
+ //
693
+ // {
694
+ // "market": "BTC-USD-PERP",
695
+ // "seq_no": 14115975,
696
+ // "last_updated_at": 1718172538340,
697
+ // "asks": [
698
+ // [
699
+ // "69578.2",
700
+ // "3.019"
701
+ // ]
702
+ // ],
703
+ // "bids": [
704
+ // [
705
+ // "68477.6",
706
+ // "0.1"
707
+ // ]
708
+ // ]
709
+ // }
710
+ //
711
+ if (limit !== undefined) {
712
+ request['depth'] = limit;
713
+ }
714
+ const timestamp = this.safeInteger(response, 'last_updated_at');
715
+ const orderbook = this.parseOrderBook(response, market['symbol'], timestamp);
716
+ orderbook['nonce'] = this.safeInteger(response, 'seq_no');
717
+ return orderbook;
718
+ }
719
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
720
+ /**
721
+ * @method
722
+ * @name paradex#fetchTrades
723
+ * @description get the list of most recent trades for a particular symbol
724
+ * @see https://docs.api.testnet.paradex.trade/#trade-tape
725
+ * @param {string} symbol unified symbol of the market to fetch trades for
726
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
727
+ * @param {int} [limit] the maximum amount of trades to fetch
728
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
729
+ * @param {int} [params.until] the latest time in ms to fetch trades for
730
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times
731
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
732
+ */
733
+ await this.loadMarkets();
734
+ let paginate = false;
735
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchTrades', 'paginate');
736
+ if (paginate) {
737
+ return await this.fetchPaginatedCallCursor('fetchTrades', symbol, since, limit, params, 'next', 'cursor', undefined, 100);
738
+ }
739
+ const market = this.market(symbol);
740
+ let request = {
741
+ 'market': market['id'],
742
+ };
743
+ if (limit !== undefined) {
744
+ request['page_size'] = limit;
745
+ }
746
+ if (since !== undefined) {
747
+ request['start_at'] = since;
748
+ }
749
+ [request, params] = this.handleUntilOption('end_at', request, params);
750
+ const response = await this.publicGetTrades(this.extend(request, params));
751
+ //
752
+ // {
753
+ // "next": "...",
754
+ // "prev": "...",
755
+ // "results": [
756
+ // {
757
+ // "id": "1718154353750201703989430001",
758
+ // "market": "BTC-USD-PERP",
759
+ // "side": "BUY",
760
+ // "size": "0.026",
761
+ // "price": "69578.2",
762
+ // "created_at": 1718154353750,
763
+ // "trade_type": "FILL"
764
+ // }
765
+ // ]
766
+ // }
767
+ //
768
+ const trades = this.safeList(response, 'results', []);
769
+ for (let i = 0; i < trades.length; i++) {
770
+ trades[i]['next'] = this.safeString(response, 'next');
771
+ }
772
+ return this.parseTrades(trades, market, since, limit);
773
+ }
774
+ parseTrade(trade, market = undefined) {
775
+ //
776
+ // fetchTrades (public)
777
+ //
778
+ // {
779
+ // "id": "1718154353750201703989430001",
780
+ // "market": "BTC-USD-PERP",
781
+ // "side": "BUY",
782
+ // "size": "0.026",
783
+ // "price": "69578.2",
784
+ // "created_at": 1718154353750,
785
+ // "trade_type": "FILL"
786
+ // }
787
+ //
788
+ // fetchMyTrades (private)
789
+ //
790
+ // {
791
+ // "id": "1718947571560201703986670001",
792
+ // "side": "BUY",
793
+ // "liquidity": "TAKER",
794
+ // "market": "BTC-USD-PERP",
795
+ // "order_id": "1718947571540201703992340000",
796
+ // "price": "64852.9",
797
+ // "size": "0.01",
798
+ // "fee": "0.1945587",
799
+ // "fee_currency": "USDC",
800
+ // "created_at": 1718947571569,
801
+ // "remaining_size": "0",
802
+ // "client_id": "",
803
+ // "fill_type": "FILL"
804
+ // }
805
+ //
806
+ const marketId = this.safeString(trade, 'market');
807
+ market = this.safeMarket(marketId, market);
808
+ const id = this.safeString(trade, 'id');
809
+ const timestamp = this.safeInteger(trade, 'created_at');
810
+ const priceString = this.safeString(trade, 'price');
811
+ const amountString = this.safeString(trade, 'size');
812
+ const side = this.safeStringLower(trade, 'side');
813
+ const liability = this.safeStringLower(trade, 'liquidity', 'taker');
814
+ const isTaker = liability === 'taker';
815
+ const takerOrMaker = (isTaker) ? 'taker' : 'maker';
816
+ const currencyId = this.safeString(trade, 'fee_currency');
817
+ const code = this.safeCurrencyCode(currencyId);
818
+ return this.safeTrade({
819
+ 'info': trade,
820
+ 'id': id,
821
+ 'order': this.safeString(trade, 'order_id'),
822
+ 'timestamp': timestamp,
823
+ 'datetime': this.iso8601(timestamp),
824
+ 'symbol': market['symbol'],
825
+ 'type': undefined,
826
+ 'takerOrMaker': takerOrMaker,
827
+ 'side': side,
828
+ 'price': priceString,
829
+ 'amount': amountString,
830
+ 'cost': undefined,
831
+ 'fee': {
832
+ 'cost': this.safeString(trade, 'fee'),
833
+ 'currency': code,
834
+ 'rate': undefined,
835
+ },
836
+ }, market);
837
+ }
838
+ async fetchOpenInterest(symbol, params = {}) {
839
+ /**
840
+ * @method
841
+ * @name paradex#fetchOpenInterest
842
+ * @description retrieves the open interest of a contract trading pair
843
+ * @see https://docs.api.testnet.paradex.trade/#list-available-markets-summary
844
+ * @param {string} symbol unified CCXT market symbol
845
+ * @param {object} [params] exchange specific parameters
846
+ * @returns {object} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure}
847
+ */
848
+ await this.loadMarkets();
849
+ const market = this.market(symbol);
850
+ if (!market['contract']) {
851
+ throw new BadRequest(this.id + ' fetchOpenInterest() supports contract markets only');
852
+ }
853
+ const request = {
854
+ 'market': market['id'],
855
+ };
856
+ const response = await this.publicGetMarketsSummary(this.extend(request, params));
857
+ //
858
+ // {
859
+ // "results": [
860
+ // {
861
+ // "symbol": "BTC-USD-PERP",
862
+ // "oracle_price": "68465.17449906",
863
+ // "mark_price": "68465.17449906",
864
+ // "last_traded_price": "68495.1",
865
+ // "bid": "68477.6",
866
+ // "ask": "69578.2",
867
+ // "volume_24h": "5815541.397939004",
868
+ // "total_volume": "584031465.525259686",
869
+ // "created_at": 1718170156580,
870
+ // "underlying_price": "67367.37268422",
871
+ // "open_interest": "162.272",
872
+ // "funding_rate": "0.01629574927887",
873
+ // "price_change_rate_24h": "0.009032"
874
+ // }
875
+ // ]
876
+ // }
877
+ //
878
+ const data = this.safeList(response, 'results', []);
879
+ const interest = this.safeDict(data, 0, {});
880
+ return this.parseOpenInterest(interest, market);
881
+ }
882
+ parseOpenInterest(interest, market = undefined) {
883
+ //
884
+ // {
885
+ // "symbol": "BTC-USD-PERP",
886
+ // "oracle_price": "68465.17449906",
887
+ // "mark_price": "68465.17449906",
888
+ // "last_traded_price": "68495.1",
889
+ // "bid": "68477.6",
890
+ // "ask": "69578.2",
891
+ // "volume_24h": "5815541.397939004",
892
+ // "total_volume": "584031465.525259686",
893
+ // "created_at": 1718170156580,
894
+ // "underlying_price": "67367.37268422",
895
+ // "open_interest": "162.272",
896
+ // "funding_rate": "0.01629574927887",
897
+ // "price_change_rate_24h": "0.009032"
898
+ // }
899
+ //
900
+ const timestamp = this.safeInteger(interest, 'created_at');
901
+ const marketId = this.safeString(interest, 'symbol');
902
+ market = this.safeMarket(marketId, market);
903
+ const symbol = market['symbol'];
904
+ return this.safeOpenInterest({
905
+ 'symbol': symbol,
906
+ 'openInterestAmount': this.safeString(interest, 'open_interest'),
907
+ 'openInterestValue': undefined,
908
+ 'timestamp': timestamp,
909
+ 'datetime': this.iso8601(timestamp),
910
+ 'info': interest,
911
+ }, market);
912
+ }
913
+ hashMessage(message) {
914
+ return '0x' + this.hash(message, keccak, 'hex');
915
+ }
916
+ signHash(hash, privateKey) {
917
+ const signature = ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1, undefined);
918
+ const r = signature['r'];
919
+ const s = signature['s'];
920
+ const v = this.intToBase16(this.sum(27, signature['v']));
921
+ return '0x' + r.padStart(64, '0') + s.padStart(64, '0') + v;
922
+ }
923
+ signMessage(message, privateKey) {
924
+ return this.signHash(this.hashMessage(message), privateKey.slice(-64));
925
+ }
926
+ async getSystemConfig() {
927
+ const cachedConfig = this.safeDict(this.options, 'systemConfig');
928
+ if (cachedConfig !== undefined) {
929
+ return cachedConfig;
930
+ }
931
+ const response = await this.publicGetSystemConfig();
932
+ //
933
+ // {
934
+ // "starknet_gateway_url": "https://potc-testnet-sepolia.starknet.io",
935
+ // "starknet_fullnode_rpc_url": "https://pathfinder.api.testnet.paradex.trade/rpc/v0_7",
936
+ // "starknet_chain_id": "PRIVATE_SN_POTC_SEPOLIA",
937
+ // "block_explorer_url": "https://voyager.testnet.paradex.trade/",
938
+ // "paraclear_address": "0x286003f7c7bfc3f94e8f0af48b48302e7aee2fb13c23b141479ba00832ef2c6",
939
+ // "paraclear_decimals": 8,
940
+ // "paraclear_account_proxy_hash": "0x3530cc4759d78042f1b543bf797f5f3d647cde0388c33734cf91b7f7b9314a9",
941
+ // "paraclear_account_hash": "0x41cb0280ebadaa75f996d8d92c6f265f6d040bb3ba442e5f86a554f1765244e",
942
+ // "oracle_address": "0x2c6a867917ef858d6b193a0ff9e62b46d0dc760366920d631715d58baeaca1f",
943
+ // "bridged_tokens": [
944
+ // {
945
+ // "name": "TEST USDC",
946
+ // "symbol": "USDC",
947
+ // "decimals": 6,
948
+ // "l1_token_address": "0x29A873159D5e14AcBd63913D4A7E2df04570c666",
949
+ // "l1_bridge_address": "0x8586e05adc0C35aa11609023d4Ae6075Cb813b4C",
950
+ // "l2_token_address": "0x6f373b346561036d98ea10fb3e60d2f459c872b1933b50b21fe6ef4fda3b75e",
951
+ // "l2_bridge_address": "0x46e9237f5408b5f899e72125dd69bd55485a287aaf24663d3ebe00d237fc7ef"
952
+ // }
953
+ // ],
954
+ // "l1_core_contract_address": "0x582CC5d9b509391232cd544cDF9da036e55833Af",
955
+ // "l1_operator_address": "0x11bACdFbBcd3Febe5e8CEAa75E0Ef6444d9B45FB",
956
+ // "l1_chain_id": "11155111",
957
+ // "liquidation_fee": "0.2"
958
+ // }
959
+ //
960
+ this.options['systemConfig'] = response;
961
+ return response;
962
+ }
963
+ async prepareParadexDomain(l1 = false) {
964
+ const systemConfig = await this.getSystemConfig();
965
+ if (l1 === true) {
966
+ return {
967
+ 'name': 'Paradex',
968
+ 'chainId': systemConfig['l1_chain_id'],
969
+ 'version': '1',
970
+ };
971
+ }
972
+ return {
973
+ 'name': 'Paradex',
974
+ 'chainId': systemConfig['starknet_chain_id'],
975
+ 'version': 1,
976
+ };
977
+ }
978
+ async retrieveAccount() {
979
+ this.checkRequiredCredentials();
980
+ const cachedAccount = this.safeDict(this.options, 'paradexAccount');
981
+ if (cachedAccount !== undefined) {
982
+ return cachedAccount;
983
+ }
984
+ const systemConfig = await this.getSystemConfig();
985
+ const domain = await this.prepareParadexDomain(true);
986
+ const messageTypes = {
987
+ 'Constant': [
988
+ { 'name': 'action', 'type': 'string' },
989
+ ],
990
+ };
991
+ const message = {
992
+ 'action': 'STARK Key',
993
+ };
994
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, message);
995
+ const signature = this.signMessage(msg, this.privateKey);
996
+ const account = this.retrieveStarkAccount(signature, systemConfig['paraclear_account_hash'], systemConfig['paraclear_account_proxy_hash']);
997
+ this.options['paradexAccount'] = account;
998
+ return account;
999
+ }
1000
+ async onboarding(params = {}) {
1001
+ const account = await this.retrieveAccount();
1002
+ const req = {
1003
+ 'action': 'Onboarding',
1004
+ };
1005
+ const domain = await this.prepareParadexDomain();
1006
+ const messageTypes = {
1007
+ 'Constant': [
1008
+ { 'name': 'action', 'type': 'felt' },
1009
+ ],
1010
+ };
1011
+ const msg = this.starknetEncodeStructuredData(domain, messageTypes, req, account['address']);
1012
+ const signature = this.starknetSign(msg, account['privateKey']);
1013
+ params['signature'] = signature;
1014
+ params['account'] = account['address'];
1015
+ params['public_key'] = account['publicKey'];
1016
+ const response = await this.privatePostOnboarding(params);
1017
+ return response;
1018
+ }
1019
+ async authenticateRest(params = {}) {
1020
+ const cachedToken = this.safeString(this.options, 'authToken');
1021
+ if (cachedToken !== undefined) {
1022
+ return cachedToken;
1023
+ }
1024
+ const account = await this.retrieveAccount();
1025
+ const now = this.nonce();
1026
+ const req = {
1027
+ 'method': 'POST',
1028
+ 'path': '/v1/auth',
1029
+ 'body': '',
1030
+ 'timestamp': now,
1031
+ 'expiration': now + 86400 * 7,
1032
+ };
1033
+ const domain = await this.prepareParadexDomain();
1034
+ const messageTypes = {
1035
+ 'Request': [
1036
+ { 'name': 'method', 'type': 'felt' },
1037
+ { 'name': 'path', 'type': 'felt' },
1038
+ { 'name': 'body', 'type': 'felt' },
1039
+ { 'name': 'timestamp', 'type': 'felt' },
1040
+ { 'name': 'expiration', 'type': 'felt' },
1041
+ ],
1042
+ };
1043
+ const msg = this.starknetEncodeStructuredData(domain, messageTypes, req, account['address']);
1044
+ const signature = this.starknetSign(msg, account['privateKey']);
1045
+ params['signature'] = signature;
1046
+ params['account'] = account['address'];
1047
+ params['timestamp'] = req['timestamp'];
1048
+ params['expiration'] = req['expiration'];
1049
+ const response = await this.privatePostAuth(params);
1050
+ //
1051
+ // {
1052
+ // jwt_token: "ooooccxtooootoooootheoooomoonooooo"
1053
+ // }
1054
+ //
1055
+ const token = this.safeString(response, 'jwt_token');
1056
+ this.options['authToken'] = token;
1057
+ return token;
1058
+ }
1059
+ parseOrder(order, market = undefined) {
1060
+ //
1061
+ // {
1062
+ // "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
1063
+ // "avg_fill_price": "26000",
1064
+ // "client_id": "x1234",
1065
+ // "cancel_reason": "NOT_ENOUGH_MARGIN",
1066
+ // "created_at": 1681493746016,
1067
+ // "flags": [
1068
+ // "REDUCE_ONLY"
1069
+ // ],
1070
+ // "id": "123456",
1071
+ // "instruction": "GTC",
1072
+ // "last_updated_at": 1681493746016,
1073
+ // "market": "BTC-USD-PERP",
1074
+ // "price": "26000",
1075
+ // "published_at": 1681493746016,
1076
+ // "received_at": 1681493746016,
1077
+ // "remaining_size": "0",
1078
+ // "seq_no": 1681471234972000000,
1079
+ // "side": "BUY",
1080
+ // "size": "0.05",
1081
+ // "status": "NEW",
1082
+ // "stp": "EXPIRE_MAKER",
1083
+ // "timestamp": 1681493746016,
1084
+ // "trigger_price": "26000",
1085
+ // "type": "MARKET"
1086
+ // }
1087
+ //
1088
+ const timestamp = this.safeInteger(order, 'created_at');
1089
+ const orderId = this.safeString(order, 'id');
1090
+ const clientOrderId = this.omitZero(this.safeString(order, 'client_id'));
1091
+ const marketId = this.safeString(order, 'market');
1092
+ market = this.safeMarket(marketId, market);
1093
+ const symbol = market['symbol'];
1094
+ const price = this.safeString(order, 'price');
1095
+ const amount = this.safeString(order, 'size');
1096
+ const orderType = this.safeString(order, 'type');
1097
+ const status = this.safeString(order, 'status');
1098
+ const side = this.safeStringLower(order, 'side');
1099
+ const average = this.omitZero(this.safeString(order, 'avg_fill_price'));
1100
+ const remaining = this.omitZero(this.safeString(order, 'remaining_size'));
1101
+ const stopPrice = this.safeString(order, 'trigger_price');
1102
+ const lastUpdateTimestamp = this.safeInteger(order, 'last_updated_at');
1103
+ return this.safeOrder({
1104
+ 'id': orderId,
1105
+ 'clientOrderId': clientOrderId,
1106
+ 'timestamp': timestamp,
1107
+ 'datetime': this.iso8601(timestamp),
1108
+ 'lastTradeTimestamp': undefined,
1109
+ 'lastUpdateTimestamp': lastUpdateTimestamp,
1110
+ 'status': this.parseOrderStatus(status),
1111
+ 'symbol': symbol,
1112
+ 'type': this.parseOrderType(orderType),
1113
+ 'timeInForce': this.parseTimeInForce(this.safeString(order, 'instrunction')),
1114
+ 'postOnly': undefined,
1115
+ 'reduceOnly': undefined,
1116
+ 'side': side,
1117
+ 'price': price,
1118
+ 'stopPrice': stopPrice,
1119
+ 'triggerPrice': stopPrice,
1120
+ 'takeProfitPrice': undefined,
1121
+ 'stopLossPrice': undefined,
1122
+ 'average': average,
1123
+ 'amount': amount,
1124
+ 'filled': undefined,
1125
+ 'remaining': remaining,
1126
+ 'cost': undefined,
1127
+ 'trades': undefined,
1128
+ 'fee': {
1129
+ 'cost': undefined,
1130
+ 'currency': undefined,
1131
+ },
1132
+ 'info': order,
1133
+ }, market);
1134
+ }
1135
+ parseTimeInForce(timeInForce) {
1136
+ const timeInForces = {
1137
+ 'IOC': 'IOC',
1138
+ 'GTC': 'GTC',
1139
+ 'POST_ONLY': 'PO',
1140
+ };
1141
+ return this.safeString(timeInForces, timeInForce, undefined);
1142
+ }
1143
+ parseOrderStatus(status) {
1144
+ if (status !== undefined) {
1145
+ const statuses = {
1146
+ 'NEW': 'open',
1147
+ 'UNTRIGGERED': 'open',
1148
+ 'OPEN': 'open',
1149
+ 'CLOSED': 'closed',
1150
+ };
1151
+ return this.safeString(statuses, status, status);
1152
+ }
1153
+ return status;
1154
+ }
1155
+ parseOrderType(type) {
1156
+ const types = {
1157
+ 'LIMIT': 'limit',
1158
+ 'MARKET': 'market',
1159
+ 'STOP_LIMIT': 'limit',
1160
+ 'STOP_MARKET': 'market',
1161
+ };
1162
+ return this.safeStringLower(types, type, type);
1163
+ }
1164
+ convertShortString(str) {
1165
+ // TODO: add stringToBase16 in exchange
1166
+ return '0x' + this.binaryToBase16(this.base64ToBinary(this.stringToBase64(str)));
1167
+ }
1168
+ scaleNumber(num) {
1169
+ return Precise.stringMul(num, '100000000');
1170
+ }
1171
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1172
+ /**
1173
+ * @method
1174
+ * @name paradex#createOrder
1175
+ * @description create a trade order
1176
+ * @see https://docs.api.prod.paradex.trade/#create-order
1177
+ * @param {string} symbol unified symbol of the market to create an order in
1178
+ * @param {string} type 'market' or 'limit'
1179
+ * @param {string} side 'buy' or 'sell'
1180
+ * @param {float} amount how much of currency you want to trade in units of base currency
1181
+ * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1182
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1183
+ * @param {float} [params.stopPrice] The price a trigger order is triggered at
1184
+ * @param {float} [params.triggerPrice] The price a trigger order is triggered at
1185
+ * @param {string} [params.timeInForce] "GTC", "IOC", or "POST_ONLY"
1186
+ * @param {bool} [params.postOnly] true or false
1187
+ * @param {bool} [params.reduceOnly] Ensures that the executed order does not flip the opened position.
1188
+ * @param {string} [params.clientOrderId] a unique id for the order
1189
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1190
+ */
1191
+ await this.authenticateRest();
1192
+ await this.loadMarkets();
1193
+ const market = this.market(symbol);
1194
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only');
1195
+ const orderType = type.toUpperCase();
1196
+ const orderSide = side.toUpperCase();
1197
+ const request = {
1198
+ 'market': market['id'],
1199
+ 'side': orderSide,
1200
+ 'type': orderType,
1201
+ 'size': this.amountToPrecision(symbol, amount),
1202
+ };
1203
+ const stopPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1204
+ const isMarket = orderType === 'MARKET';
1205
+ const timeInForce = this.safeStringUpper(params, 'timeInForce');
1206
+ const postOnly = this.isPostOnly(isMarket, undefined, params);
1207
+ if (!isMarket) {
1208
+ if (postOnly) {
1209
+ request['instruction'] = 'POST_ONLY';
1210
+ }
1211
+ else if (timeInForce === 'ioc') {
1212
+ request['instruction'] = 'IOC';
1213
+ }
1214
+ }
1215
+ if (reduceOnly) {
1216
+ request['flags'] = [
1217
+ 'REDUCE_ONLY',
1218
+ ];
1219
+ }
1220
+ if (price !== undefined) {
1221
+ request['price'] = this.priceToPrecision(symbol, price);
1222
+ }
1223
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1224
+ if (clientOrderId !== undefined) {
1225
+ request['client_id'] = clientOrderId;
1226
+ }
1227
+ if (stopPrice !== undefined) {
1228
+ if (isMarket) {
1229
+ request['type'] = 'STOP_MARKET';
1230
+ }
1231
+ else {
1232
+ request['type'] = 'STOP_LIMIT';
1233
+ }
1234
+ request['trigger_price'] = this.priceToPrecision(symbol, stopPrice);
1235
+ }
1236
+ params = this.omit(params, ['reduceOnly', 'reduce_only', 'clOrdID', 'clientOrderId', 'client_order_id', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice']);
1237
+ const account = await this.retrieveAccount();
1238
+ const now = this.nonce();
1239
+ const orderReq = {
1240
+ 'timestamp': now * 1000,
1241
+ 'market': this.convertShortString(request['market']),
1242
+ 'side': (orderSide === 'BUY') ? '1' : '2',
1243
+ 'orderType': this.convertShortString(request['type']),
1244
+ 'size': this.scaleNumber(request['size']),
1245
+ 'price': (isMarket) ? '0' : this.scaleNumber(request['price']),
1246
+ };
1247
+ const domain = await this.prepareParadexDomain();
1248
+ const messageTypes = {
1249
+ 'Order': [
1250
+ { 'name': 'timestamp', 'type': 'felt' },
1251
+ { 'name': 'market', 'type': 'felt' },
1252
+ { 'name': 'side', 'type': 'felt' },
1253
+ { 'name': 'orderType', 'type': 'felt' },
1254
+ { 'name': 'size', 'type': 'felt' },
1255
+ { 'name': 'price', 'type': 'felt' },
1256
+ ],
1257
+ };
1258
+ const msg = this.starknetEncodeStructuredData(domain, messageTypes, orderReq, account['address']);
1259
+ const signature = this.starknetSign(msg, account['privateKey']);
1260
+ request['signature'] = signature;
1261
+ request['signature_timestamp'] = orderReq['timestamp'];
1262
+ const response = await this.privatePostOrders(this.extend(request, params));
1263
+ //
1264
+ // {
1265
+ // "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
1266
+ // "avg_fill_price": "26000",
1267
+ // "cancel_reason": "NOT_ENOUGH_MARGIN",
1268
+ // "client_id": "x1234",
1269
+ // "created_at": 1681493746016,
1270
+ // "flags": [
1271
+ // "REDUCE_ONLY"
1272
+ // ],
1273
+ // "id": "123456",
1274
+ // "instruction": "GTC",
1275
+ // "last_updated_at": 1681493746016,
1276
+ // "market": "BTC-USD-PERP",
1277
+ // "price": "26000",
1278
+ // "published_at": 1681493746016,
1279
+ // "received_at": 1681493746016,
1280
+ // "remaining_size": "0",
1281
+ // "seq_no": 1681471234972000000,
1282
+ // "side": "BUY",
1283
+ // "size": "0.05",
1284
+ // "status": "NEW",
1285
+ // "stp": "EXPIRE_MAKER",
1286
+ // "timestamp": 1681493746016,
1287
+ // "trigger_price": "26000",
1288
+ // "type": "MARKET"
1289
+ // }
1290
+ //
1291
+ const order = this.parseOrder(response, market);
1292
+ return order;
1293
+ }
1294
+ async cancelOrder(id, symbol = undefined, params = {}) {
1295
+ /**
1296
+ * @method
1297
+ * @name paradex#cancelOrder
1298
+ * @description cancels an open order
1299
+ * @see https://docs.api.prod.paradex.trade/#cancel-order
1300
+ * @see https://docs.api.prod.paradex.trade/#cancel-open-order-by-client-order-id
1301
+ * @param {string} id order id
1302
+ * @param {string} symbol unified symbol of the market the order was made in
1303
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1304
+ * @param {string} [params.clientOrderId] a unique id for the order
1305
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1306
+ */
1307
+ await this.authenticateRest();
1308
+ await this.loadMarkets();
1309
+ const request = {};
1310
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1311
+ let response = undefined;
1312
+ if (clientOrderId !== undefined) {
1313
+ request['client_id'] = clientOrderId;
1314
+ response = await this.privateDeleteOrdersByClientIdClientId(this.extend(request, params));
1315
+ }
1316
+ else {
1317
+ request['order_id'] = id;
1318
+ response = await this.privateDeleteOrdersOrderId(this.extend(request, params));
1319
+ }
1320
+ //
1321
+ // if success, no response...
1322
+ //
1323
+ return this.parseOrder(response);
1324
+ }
1325
+ async cancelAllOrders(symbol = undefined, params = {}) {
1326
+ /**
1327
+ * @method
1328
+ * @name paradex#cancelAllOrders
1329
+ * @description cancel all open orders in a market
1330
+ * @see https://docs.api.prod.paradex.trade/#cancel-all-open-orders
1331
+ * @param {string} symbol unified market symbol of the market to cancel orders in
1332
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1333
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1334
+ */
1335
+ if (symbol === undefined) {
1336
+ throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
1337
+ }
1338
+ await this.authenticateRest();
1339
+ await this.loadMarkets();
1340
+ const market = this.market(symbol);
1341
+ const request = {
1342
+ 'market': market['id'],
1343
+ };
1344
+ const response = await this.privateDeleteOrders(this.extend(request, params));
1345
+ //
1346
+ // if success, no response...
1347
+ //
1348
+ return response;
1349
+ }
1350
+ async fetchOrder(id, symbol = undefined, params = {}) {
1351
+ /**
1352
+ * @method
1353
+ * @name paradex#fetchOrder
1354
+ * @description fetches information on an order made by the user
1355
+ * @see https://docs.api.prod.paradex.trade/#get-order
1356
+ * @see https://docs.api.prod.paradex.trade/#get-order-by-client-id
1357
+ * @param {string} id the order id
1358
+ * @param {string} symbol unified symbol of the market the order was made in
1359
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1360
+ * @param {string} [params.clientOrderId] a unique id for the order
1361
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1362
+ */
1363
+ await this.authenticateRest();
1364
+ await this.loadMarkets();
1365
+ const request = {};
1366
+ const clientOrderId = this.safeStringN(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1367
+ params = this.omit(params, ['clOrdID', 'clientOrderId', 'client_order_id']);
1368
+ let response = undefined;
1369
+ if (clientOrderId !== undefined) {
1370
+ request['client_id'] = clientOrderId;
1371
+ response = await this.privateGetOrdersByClientIdClientId(this.extend(request, params));
1372
+ }
1373
+ else {
1374
+ request['order_id'] = id;
1375
+ response = await this.privateGetOrdersOrderId(this.extend(request, params));
1376
+ }
1377
+ //
1378
+ // {
1379
+ // "id": "1718941725080201704028870000",
1380
+ // "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
1381
+ // "market": "BTC-USD-PERP",
1382
+ // "side": "SELL",
1383
+ // "type": "LIMIT",
1384
+ // "size": "10.153",
1385
+ // "remaining_size": "10.153",
1386
+ // "price": "70784.5",
1387
+ // "status": "CLOSED",
1388
+ // "created_at": 1718941725082,
1389
+ // "last_updated_at": 1718958002991,
1390
+ // "timestamp": 1718941724678,
1391
+ // "cancel_reason": "USER_CANCELED",
1392
+ // "client_id": "",
1393
+ // "seq_no": 1718958002991595738,
1394
+ // "instruction": "GTC",
1395
+ // "avg_fill_price": "",
1396
+ // "stp": "EXPIRE_TAKER",
1397
+ // "received_at": 1718958510959,
1398
+ // "published_at": 1718958510960,
1399
+ // "flags": [],
1400
+ // "trigger_price": "0"
1401
+ // }
1402
+ //
1403
+ return this.parseOrder(response);
1404
+ }
1405
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1406
+ /**
1407
+ * @method
1408
+ * @name paradex#fetchOrders
1409
+ * @description fetches information on multiple orders made by the user
1410
+ * @see https://docs.api.prod.paradex.trade/#get-orders
1411
+ * @param {string} symbol unified market symbol of the market orders were made in
1412
+ * @param {int} [since] the earliest time in ms to fetch orders for
1413
+ * @param {int} [limit] the maximum number of order structures to retrieve
1414
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1415
+ * @param {string} [params.side] 'buy' or 'sell'
1416
+ * @param {boolean} [params.paginate] set to true if you want to fetch orders with pagination
1417
+ * @param {int} params.until timestamp in ms of the latest order to fetch
1418
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1419
+ */
1420
+ await this.authenticateRest();
1421
+ await this.loadMarkets();
1422
+ let paginate = false;
1423
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchOrders', 'paginate');
1424
+ if (paginate) {
1425
+ return await this.fetchPaginatedCallCursor('fetchOrders', symbol, since, limit, params, 'next', 'cursor', undefined, 50);
1426
+ }
1427
+ let request = {};
1428
+ let market = undefined;
1429
+ if (symbol !== undefined) {
1430
+ market = this.market(symbol);
1431
+ request['market'] = market['id'];
1432
+ }
1433
+ if (since !== undefined) {
1434
+ request['start_at'] = since;
1435
+ }
1436
+ if (limit !== undefined) {
1437
+ request['page_size'] = limit;
1438
+ }
1439
+ [request, params] = this.handleUntilOption('end_at', request, params);
1440
+ const response = await this.privateGetOrdersHistory(this.extend(request, params));
1441
+ //
1442
+ // {
1443
+ // "next": "eyJmaWx0ZXIiMsIm1hcmtlciI6eyJtYXJrZXIiOiIxNjc1NjUwMDE3NDMxMTAxNjk5N=",
1444
+ // "prev": "eyJmaWx0ZXIiOnsiTGltaXQiOjkwfSwidGltZSI6MTY4MTY3OTgzNzk3MTMwOTk1MywibWFya2VyIjp7Im1zMjExMD==",
1445
+ // "results": [
1446
+ // {
1447
+ // "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
1448
+ // "avg_fill_price": "26000",
1449
+ // "cancel_reason": "NOT_ENOUGH_MARGIN",
1450
+ // "client_id": "x1234",
1451
+ // "created_at": 1681493746016,
1452
+ // "flags": [
1453
+ // "REDUCE_ONLY"
1454
+ // ],
1455
+ // "id": "123456",
1456
+ // "instruction": "GTC",
1457
+ // "last_updated_at": 1681493746016,
1458
+ // "market": "BTC-USD-PERP",
1459
+ // "price": "26000",
1460
+ // "published_at": 1681493746016,
1461
+ // "received_at": 1681493746016,
1462
+ // "remaining_size": "0",
1463
+ // "seq_no": 1681471234972000000,
1464
+ // "side": "BUY",
1465
+ // "size": "0.05",
1466
+ // "status": "NEW",
1467
+ // "stp": "EXPIRE_MAKER",
1468
+ // "timestamp": 1681493746016,
1469
+ // "trigger_price": "26000",
1470
+ // "type": "MARKET"
1471
+ // }
1472
+ // ]
1473
+ // }
1474
+ //
1475
+ const orders = this.safeList(response, 'results', []);
1476
+ const paginationCursor = this.safeString(response, 'next');
1477
+ const ordersLength = orders.length;
1478
+ if ((paginationCursor !== undefined) && (ordersLength > 0)) {
1479
+ const first = orders[0];
1480
+ first['next'] = paginationCursor;
1481
+ orders[0] = first;
1482
+ }
1483
+ return this.parseOrders(orders, market, since, limit);
1484
+ }
1485
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1486
+ /**
1487
+ * @method
1488
+ * @name paradex#fetchOpenOrders
1489
+ * @description fetches information on multiple orders made by the user
1490
+ * @see https://docs.api.prod.paradex.trade/#paradex-rest-api-orders
1491
+ * @param {string} symbol unified market symbol of the market orders were made in
1492
+ * @param {int} [since] the earliest time in ms to fetch orders for
1493
+ * @param {int} [limit] the maximum number of order structures to retrieve
1494
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1495
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1496
+ */
1497
+ await this.authenticateRest();
1498
+ await this.loadMarkets();
1499
+ const request = {};
1500
+ let market = undefined;
1501
+ if (symbol !== undefined) {
1502
+ market = this.market(symbol);
1503
+ request['market'] = market['id'];
1504
+ }
1505
+ const response = await this.privateGetOrders(this.extend(request, params));
1506
+ //
1507
+ // {
1508
+ // "results": [
1509
+ // {
1510
+ // "account": "0x4638e3041366aa71720be63e32e53e1223316c7f0d56f7aa617542ed1e7512x",
1511
+ // "avg_fill_price": "26000",
1512
+ // "client_id": "x1234",
1513
+ // "cancel_reason": "NOT_ENOUGH_MARGIN",
1514
+ // "created_at": 1681493746016,
1515
+ // "flags": [
1516
+ // "REDUCE_ONLY"
1517
+ // ],
1518
+ // "id": "123456",
1519
+ // "instruction": "GTC",
1520
+ // "last_updated_at": 1681493746016,
1521
+ // "market": "BTC-USD-PERP",
1522
+ // "price": "26000",
1523
+ // "published_at": 1681493746016,
1524
+ // "received_at": 1681493746016,
1525
+ // "remaining_size": "0",
1526
+ // "seq_no": 1681471234972000000,
1527
+ // "side": "BUY",
1528
+ // "size": "0.05",
1529
+ // "status": "NEW",
1530
+ // "stp": "EXPIRE_MAKER",
1531
+ // "timestamp": 1681493746016,
1532
+ // "trigger_price": "26000",
1533
+ // "type": "MARKET"
1534
+ // }
1535
+ // ]
1536
+ // }
1537
+ //
1538
+ const orders = this.safeList(response, 'results', []);
1539
+ return this.parseOrders(orders, market, since, limit);
1540
+ }
1541
+ async fetchBalance(params = {}) {
1542
+ /**
1543
+ * @method
1544
+ * @name paradex#fetchBalance
1545
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1546
+ * @see https://docs.api.prod.paradex.trade/#list-balances
1547
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1548
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1549
+ */
1550
+ await this.authenticateRest();
1551
+ await this.loadMarkets();
1552
+ const response = await this.privateGetBalance();
1553
+ //
1554
+ // {
1555
+ // "results": [
1556
+ // {
1557
+ // "token": "USDC",
1558
+ // "size": "99980.2382266290601",
1559
+ // "last_updated_at": 1718529757240
1560
+ // }
1561
+ // ]
1562
+ // }
1563
+ //
1564
+ const data = this.safeList(response, 'results', []);
1565
+ return this.parseBalance(data);
1566
+ }
1567
+ parseBalance(response) {
1568
+ const result = { 'info': response };
1569
+ for (let i = 0; i < response.length; i++) {
1570
+ const balance = this.safeDict(response, i, {});
1571
+ const currencyId = this.safeString(balance, 'token');
1572
+ const code = this.safeCurrencyCode(currencyId);
1573
+ const account = this.account();
1574
+ account['total'] = this.safeString(balance, 'size');
1575
+ result[code] = account;
1576
+ }
1577
+ return this.safeBalance(result);
1578
+ }
1579
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1580
+ /**
1581
+ * @method
1582
+ * @name paradex#fetchMyTrades
1583
+ * @description fetch all trades made by the user
1584
+ * @see https://docs.api.prod.paradex.trade/#list-fills
1585
+ * @param {string} symbol unified market symbol
1586
+ * @param {int} [since] the earliest time in ms to fetch trades for
1587
+ * @param {int} [limit] the maximum number of trades structures to retrieve
1588
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1589
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1590
+ * @param {int} [params.until] the latest time in ms to fetch entries for
1591
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
1592
+ */
1593
+ await this.authenticateRest();
1594
+ await this.loadMarkets();
1595
+ let paginate = false;
1596
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchMyTrades', 'paginate');
1597
+ if (paginate) {
1598
+ return await this.fetchPaginatedCallCursor('fetchMyTrades', symbol, since, limit, params, 'next', 'cursor', undefined, 100);
1599
+ }
1600
+ let request = {};
1601
+ let market = undefined;
1602
+ if (symbol !== undefined) {
1603
+ market = this.market(symbol);
1604
+ request['market'] = market['id'];
1605
+ }
1606
+ if (limit !== undefined) {
1607
+ request['page_size'] = limit;
1608
+ }
1609
+ if (since !== undefined) {
1610
+ request['start_at'] = since;
1611
+ }
1612
+ [request, params] = this.handleUntilOption('end_at', request, params);
1613
+ const response = await this.privateGetFills(this.extend(request, params));
1614
+ //
1615
+ // {
1616
+ // "next": null,
1617
+ // "prev": null,
1618
+ // "results": [
1619
+ // {
1620
+ // "id": "1718947571560201703986670001",
1621
+ // "side": "BUY",
1622
+ // "liquidity": "TAKER",
1623
+ // "market": "BTC-USD-PERP",
1624
+ // "order_id": "1718947571540201703992340000",
1625
+ // "price": "64852.9",
1626
+ // "size": "0.01",
1627
+ // "fee": "0.1945587",
1628
+ // "fee_currency": "USDC",
1629
+ // "created_at": 1718947571569,
1630
+ // "remaining_size": "0",
1631
+ // "client_id": "",
1632
+ // "fill_type": "FILL"
1633
+ // }
1634
+ // ]
1635
+ // }
1636
+ //
1637
+ const trades = this.safeList(response, 'results', []);
1638
+ for (let i = 0; i < trades.length; i++) {
1639
+ trades[i]['next'] = this.safeString(response, 'next');
1640
+ }
1641
+ return this.parseTrades(trades, market, since, limit);
1642
+ }
1643
+ async fetchPosition(symbol, params = {}) {
1644
+ /**
1645
+ * @method
1646
+ * @name paradex#fetchPositions
1647
+ * @description fetch data on an open position
1648
+ * @see https://docs.api.prod.paradex.trade/#list-open-positions
1649
+ * @param {string} symbol unified market symbol of the market the position is held in
1650
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1651
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1652
+ */
1653
+ await this.authenticateRest();
1654
+ await this.loadMarkets();
1655
+ const market = this.market(symbol);
1656
+ const positions = await this.fetchPositions([market['symbol']], params);
1657
+ return this.safeDict(positions, 0, {});
1658
+ }
1659
+ async fetchPositions(symbols = undefined, params = {}) {
1660
+ /**
1661
+ * @method
1662
+ * @name paradex#fetchPositions
1663
+ * @description fetch all open positions
1664
+ * @see https://docs.api.prod.paradex.trade/#list-open-positions
1665
+ * @param {string[]} [symbols] list of unified market symbols
1666
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1667
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1668
+ */
1669
+ await this.authenticateRest();
1670
+ await this.loadMarkets();
1671
+ symbols = this.marketSymbols(symbols);
1672
+ const response = await this.privateGetPositions();
1673
+ //
1674
+ // {
1675
+ // "results": [
1676
+ // {
1677
+ // "id": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3-BTC-USD-PERP",
1678
+ // "market": "BTC-USD-PERP",
1679
+ // "status": "OPEN",
1680
+ // "side": "LONG",
1681
+ // "size": "0.01",
1682
+ // "average_entry_price": "64839.96053748",
1683
+ // "average_entry_price_usd": "64852.9",
1684
+ // "realized_pnl": "0",
1685
+ // "unrealized_pnl": "-2.39677214",
1686
+ // "unrealized_funding_pnl": "-0.11214013",
1687
+ // "cost": "648.39960537",
1688
+ // "cost_usd": "648.529",
1689
+ // "cached_funding_index": "35202.1002351",
1690
+ // "last_updated_at": 1718950074249,
1691
+ // "last_fill_id": "1718947571560201703986670001",
1692
+ // "seq_no": 1718950074249176253,
1693
+ // "liquidation_price": ""
1694
+ // }
1695
+ // ]
1696
+ // }
1697
+ //
1698
+ const data = this.safeList(response, 'results', []);
1699
+ return this.parsePositions(data, symbols);
1700
+ }
1701
+ parsePosition(position, market = undefined) {
1702
+ //
1703
+ // {
1704
+ // "id": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3-BTC-USD-PERP",
1705
+ // "market": "BTC-USD-PERP",
1706
+ // "status": "OPEN",
1707
+ // "side": "LONG",
1708
+ // "size": "0.01",
1709
+ // "average_entry_price": "64839.96053748",
1710
+ // "average_entry_price_usd": "64852.9",
1711
+ // "realized_pnl": "0",
1712
+ // "unrealized_pnl": "-2.39677214",
1713
+ // "unrealized_funding_pnl": "-0.11214013",
1714
+ // "cost": "648.39960537",
1715
+ // "cost_usd": "648.529",
1716
+ // "cached_funding_index": "35202.1002351",
1717
+ // "last_updated_at": 1718950074249,
1718
+ // "last_fill_id": "1718947571560201703986670001",
1719
+ // "seq_no": 1718950074249176253,
1720
+ // "liquidation_price": ""
1721
+ // }
1722
+ //
1723
+ const marketId = this.safeString(position, 'market');
1724
+ market = this.safeMarket(marketId, market);
1725
+ const symbol = market['symbol'];
1726
+ const side = this.safeStringLower(position, 'side');
1727
+ let quantity = this.safeString(position, 'size');
1728
+ if (side !== 'long') {
1729
+ quantity = Precise.stringMul('-1', quantity);
1730
+ }
1731
+ const timestamp = this.safeInteger(position, 'time');
1732
+ return this.safePosition({
1733
+ 'info': position,
1734
+ 'id': this.safeString(position, 'id'),
1735
+ 'symbol': symbol,
1736
+ 'entryPrice': this.safeString(position, 'average_entry_price'),
1737
+ 'markPrice': undefined,
1738
+ 'notional': undefined,
1739
+ 'collateral': this.safeString(position, 'cost'),
1740
+ 'unrealizedPnl': this.safeString(position, 'unrealized_pnl'),
1741
+ 'side': side,
1742
+ 'contracts': this.parseNumber(quantity),
1743
+ 'contractSize': undefined,
1744
+ 'timestamp': timestamp,
1745
+ 'datetime': this.iso8601(timestamp),
1746
+ 'hedged': undefined,
1747
+ 'maintenanceMargin': undefined,
1748
+ 'maintenanceMarginPercentage': undefined,
1749
+ 'initialMargin': undefined,
1750
+ 'initialMarginPercentage': undefined,
1751
+ 'leverage': undefined,
1752
+ 'liquidationPrice': undefined,
1753
+ 'marginRatio': undefined,
1754
+ 'marginMode': undefined,
1755
+ 'percentage': undefined,
1756
+ });
1757
+ }
1758
+ async fetchLiquidations(symbol, since = undefined, limit = undefined, params = {}) {
1759
+ /**
1760
+ * @method
1761
+ * @name paradex#fetchLiquidations
1762
+ * @description retrieves the public liquidations of a trading pair
1763
+ * @see https://docs.api.prod.paradex.trade/#list-liquidations
1764
+ * @param {string} symbol unified CCXT market symbol
1765
+ * @param {int} [since] the earliest time in ms to fetch liquidations for
1766
+ * @param {int} [limit] the maximum number of liquidation structures to retrieve
1767
+ * @param {object} [params] exchange specific parameters for the huobi api endpoint
1768
+ * @param {int} [params.until] timestamp in ms of the latest liquidation
1769
+ * @returns {object} an array of [liquidation structures]{@link https://docs.ccxt.com/#/?id=liquidation-structure}
1770
+ */
1771
+ await this.authenticateRest();
1772
+ let request = {};
1773
+ if (since !== undefined) {
1774
+ request['from'] = since;
1775
+ }
1776
+ else {
1777
+ request['from'] = 1;
1778
+ }
1779
+ const market = this.market(symbol);
1780
+ [request, params] = this.handleUntilOption('to', request, params);
1781
+ const response = await this.privateGetLiquidations(this.extend(request, params));
1782
+ //
1783
+ // {
1784
+ // "results": [
1785
+ // {
1786
+ // "created_at": 1697213130097,
1787
+ // "id": "0x123456789"
1788
+ // }
1789
+ // ]
1790
+ // }
1791
+ //
1792
+ const data = this.safeList(response, 'results', []);
1793
+ return this.parseLiquidations(data, market, since, limit);
1794
+ }
1795
+ parseLiquidation(liquidation, market = undefined) {
1796
+ //
1797
+ // {
1798
+ // "created_at": 1697213130097,
1799
+ // "id": "0x123456789"
1800
+ // }
1801
+ //
1802
+ const timestamp = this.safeInteger(liquidation, 'created_at');
1803
+ return this.safeLiquidation({
1804
+ 'info': liquidation,
1805
+ 'symbol': undefined,
1806
+ 'contracts': undefined,
1807
+ 'contractSize': undefined,
1808
+ 'price': undefined,
1809
+ 'baseValue': undefined,
1810
+ 'quoteValue': undefined,
1811
+ 'timestamp': timestamp,
1812
+ 'datetime': this.iso8601(timestamp),
1813
+ });
1814
+ }
1815
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
1816
+ /**
1817
+ * @method
1818
+ * @name paradex#fetchTransfers
1819
+ * @description fetch all deposits made to an account
1820
+ * @see https://docs.api.prod.paradex.trade/#paradex-rest-api-transfers
1821
+ * @param {string} code unified currency code
1822
+ * @param {int} [since] the earliest time in ms to fetch deposits for
1823
+ * @param {int} [limit] the maximum number of deposits structures to retrieve
1824
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1825
+ * @param {int} [params.until] the latest time in ms to fetch entries for
1826
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1827
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1828
+ */
1829
+ await this.authenticateRest();
1830
+ await this.loadMarkets();
1831
+ let paginate = false;
1832
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchDeposits', 'paginate');
1833
+ if (paginate) {
1834
+ return await this.fetchPaginatedCallCursor('fetchDeposits', code, since, limit, params, 'next', 'cursor', undefined, 100);
1835
+ }
1836
+ let request = {};
1837
+ if (limit !== undefined) {
1838
+ request['page_size'] = limit;
1839
+ }
1840
+ if (since !== undefined) {
1841
+ request['start_at'] = since;
1842
+ }
1843
+ [request, params] = this.handleUntilOption('end_at', request, params);
1844
+ const response = await this.privateGetTransfers(this.extend(request, params));
1845
+ //
1846
+ // {
1847
+ // "next": null,
1848
+ // "prev": null,
1849
+ // "results": [
1850
+ // {
1851
+ // "id": "1718940471200201703989430000",
1852
+ // "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
1853
+ // "kind": "DEPOSIT",
1854
+ // "status": "COMPLETED",
1855
+ // "amount": "100000",
1856
+ // "token": "USDC",
1857
+ // "created_at": 1718940471208,
1858
+ // "last_updated_at": 1718941455546,
1859
+ // "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
1860
+ // "external_txn_hash": "",
1861
+ // "socialized_loss_factor": ""
1862
+ // }
1863
+ // ]
1864
+ // }
1865
+ //
1866
+ const rows = this.safeList(response, 'results', []);
1867
+ const deposits = [];
1868
+ for (let i = 0; i < rows.length; i++) {
1869
+ const row = rows[i];
1870
+ if (row['kind'] === 'DEPOSIT') {
1871
+ deposits.push(row);
1872
+ }
1873
+ }
1874
+ return this.parseTransactions(deposits, undefined, since, limit);
1875
+ }
1876
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
1877
+ /**
1878
+ * @method
1879
+ * @name paradex#fetchWithdrawals
1880
+ * @description fetch all withdrawals made from an account
1881
+ * @see https://docs.api.prod.paradex.trade/#paradex-rest-api-transfers
1882
+ * @param {string} code unified currency code
1883
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
1884
+ * @param {int} [limit] the maximum number of withdrawals structures to retrieve
1885
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1886
+ * @param {int} [params.until] the latest time in ms to fetch withdrawals for
1887
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1888
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1889
+ */
1890
+ await this.authenticateRest();
1891
+ await this.loadMarkets();
1892
+ let paginate = false;
1893
+ [paginate, params] = this.handleOptionAndParams(params, 'fetchWithdrawals', 'paginate');
1894
+ if (paginate) {
1895
+ return await this.fetchPaginatedCallCursor('fetchWithdrawals', code, since, limit, params, 'next', 'cursor', undefined, 100);
1896
+ }
1897
+ let request = {};
1898
+ if (limit !== undefined) {
1899
+ request['page_size'] = limit;
1900
+ }
1901
+ if (since !== undefined) {
1902
+ request['start_at'] = since;
1903
+ }
1904
+ [request, params] = this.handleUntilOption('end_at', request, params);
1905
+ const response = await this.privateGetTransfers(this.extend(request, params));
1906
+ //
1907
+ // {
1908
+ // "next": null,
1909
+ // "prev": null,
1910
+ // "results": [
1911
+ // {
1912
+ // "id": "1718940471200201703989430000",
1913
+ // "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
1914
+ // "kind": "DEPOSIT",
1915
+ // "status": "COMPLETED",
1916
+ // "amount": "100000",
1917
+ // "token": "USDC",
1918
+ // "created_at": 1718940471208,
1919
+ // "last_updated_at": 1718941455546,
1920
+ // "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
1921
+ // "external_txn_hash": "",
1922
+ // "socialized_loss_factor": ""
1923
+ // }
1924
+ // ]
1925
+ // }
1926
+ //
1927
+ const rows = this.safeList(response, 'results', []);
1928
+ const deposits = [];
1929
+ for (let i = 0; i < rows.length; i++) {
1930
+ const row = rows[i];
1931
+ if (row['kind'] === 'WITHDRAWAL') {
1932
+ deposits.push(row);
1933
+ }
1934
+ }
1935
+ return this.parseTransactions(deposits, undefined, since, limit);
1936
+ }
1937
+ parseTransaction(transaction, currency = undefined) {
1938
+ //
1939
+ // fetchDeposits & fetchWithdrawals
1940
+ //
1941
+ // {
1942
+ // "id": "1718940471200201703989430000",
1943
+ // "account": "0x49ddd7a564c978f6e4089ff8355b56a42b7e2d48ba282cb5aad60f04bea0ec3",
1944
+ // "kind": "DEPOSIT",
1945
+ // "status": "COMPLETED",
1946
+ // "amount": "100000",
1947
+ // "token": "USDC",
1948
+ // "created_at": 1718940471208,
1949
+ // "last_updated_at": 1718941455546,
1950
+ // "txn_hash": "0x73a415ca558a97bbdcd1c43e52b45f1e0486a0a84b3bb4958035ad6c59cb866",
1951
+ // "external_txn_hash": "",
1952
+ // "socialized_loss_factor": ""
1953
+ // }
1954
+ //
1955
+ const id = this.safeString(transaction, 'id');
1956
+ const address = this.safeString(transaction, 'account');
1957
+ const txid = this.safeString(transaction, 'txn_hash');
1958
+ const currencyId = this.safeString(transaction, 'token');
1959
+ const code = this.safeCurrencyCode(currencyId, currency);
1960
+ const timestamp = this.safeInteger(transaction, 'created_at');
1961
+ const updated = this.safeInteger(transaction, 'last_updated_at');
1962
+ let type = this.safeString(transaction, 'kind');
1963
+ type = (type === 'DEPOSIT') ? 'deposit' : 'withdrawal';
1964
+ const status = this.parseTransactionStatus(this.safeString(transaction, 'status'));
1965
+ const amount = this.safeNumber(transaction, 'amount');
1966
+ return {
1967
+ 'info': transaction,
1968
+ 'id': id,
1969
+ 'txid': txid,
1970
+ 'timestamp': timestamp,
1971
+ 'datetime': this.iso8601(timestamp),
1972
+ 'network': undefined,
1973
+ 'address': address,
1974
+ 'addressTo': address,
1975
+ 'addressFrom': undefined,
1976
+ 'tag': undefined,
1977
+ 'tagTo': undefined,
1978
+ 'tagFrom': undefined,
1979
+ 'type': type,
1980
+ 'amount': amount,
1981
+ 'currency': code,
1982
+ 'status': status,
1983
+ 'updated': updated,
1984
+ 'internal': undefined,
1985
+ 'comment': undefined,
1986
+ 'fee': undefined,
1987
+ };
1988
+ }
1989
+ parseTransactionStatus(status) {
1990
+ const statuses = {
1991
+ 'PENDING': 'pending',
1992
+ 'AVAILABLE': 'pending',
1993
+ 'COMPLETED': 'ok',
1994
+ 'FAILED': 'failed',
1995
+ };
1996
+ return this.safeString(statuses, status, status);
1997
+ }
1998
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
1999
+ let url = this.implodeHostname(this.urls['api'][this.version]) + '/' + this.implodeParams(path, params);
2000
+ const query = this.omit(params, this.extractParams(path));
2001
+ if (api === 'public') {
2002
+ if (Object.keys(query).length) {
2003
+ url += '?' + this.urlencode(query);
2004
+ }
2005
+ }
2006
+ else if (api === 'private') {
2007
+ this.checkRequiredCredentials();
2008
+ headers = {
2009
+ 'Accept': 'application/json',
2010
+ 'PARADEX-PARTNER': this.safeString(this.options, 'broker', 'CCXT'),
2011
+ };
2012
+ // TODO: optimize
2013
+ if (path === 'auth') {
2014
+ headers['PARADEX-STARKNET-ACCOUNT'] = query['account'];
2015
+ headers['PARADEX-STARKNET-SIGNATURE'] = query['signature'];
2016
+ headers['PARADEX-TIMESTAMP'] = query['timestamp'].toString();
2017
+ headers['PARADEX-SIGNATURE-EXPIRATION'] = query['expiration'].toString();
2018
+ }
2019
+ else if (path === 'onboarding') {
2020
+ headers['PARADEX-ETHEREUM-ACCOUNT'] = this.walletAddress;
2021
+ headers['PARADEX-STARKNET-ACCOUNT'] = query['account'];
2022
+ headers['PARADEX-STARKNET-SIGNATURE'] = query['signature'];
2023
+ headers['PARADEX-TIMESTAMP'] = this.nonce().toString();
2024
+ headers['Content-Type'] = 'application/json';
2025
+ body = this.json({
2026
+ 'public_key': query['public_key'],
2027
+ });
2028
+ }
2029
+ else {
2030
+ const token = this.options['authToken'];
2031
+ headers['Authorization'] = 'Bearer ' + token;
2032
+ if (method === 'POST') {
2033
+ headers['Content-Type'] = 'application/json';
2034
+ body = this.json(query);
2035
+ }
2036
+ else {
2037
+ url = url + '?' + this.urlencode(query);
2038
+ }
2039
+ }
2040
+ // headers = {
2041
+ // 'Accept': 'application/json',
2042
+ // 'Authorization': 'Bearer ' + this.apiKey,
2043
+ // };
2044
+ // if (method === 'POST') {
2045
+ // body = this.json (query);
2046
+ // headers['Content-Type'] = 'application/json';
2047
+ // } else {
2048
+ // if (Object.keys (query).length) {
2049
+ // url += '?' + this.urlencode (query);
2050
+ // }
2051
+ // }
2052
+ }
2053
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2054
+ }
2055
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2056
+ if (!response) {
2057
+ return undefined; // fallback to default error handler
2058
+ }
2059
+ //
2060
+ // {
2061
+ // "data": null,
2062
+ // "error": "NOT_ONBOARDED",
2063
+ // "message": "User has never called /onboarding endpoint"
2064
+ // }
2065
+ //
2066
+ const errorCode = this.safeString(response, 'error');
2067
+ if (errorCode !== undefined) {
2068
+ const feedback = this.id + ' ' + body;
2069
+ this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
2070
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
2071
+ throw new ExchangeError(feedback); // unknown message
2072
+ }
2073
+ return undefined;
2074
+ }
2075
+ }