ccxt 4.5.18 → 4.5.20

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 (152) hide show
  1. package/README.md +7 -6
  2. package/dist/ccxt.browser.min.js +40 -16
  3. package/dist/cjs/_virtual/index.cjs.js +1459 -9
  4. package/dist/cjs/ccxt.js +8 -2
  5. package/dist/cjs/src/abstract/dydx.js +11 -0
  6. package/dist/cjs/src/base/Exchange.js +164 -10
  7. package/dist/cjs/src/base/ws/Client.js +3 -1
  8. package/dist/cjs/src/binance.js +8 -1
  9. package/dist/cjs/src/bingx.js +20 -0
  10. package/dist/cjs/src/bitget.js +43 -41
  11. package/dist/cjs/src/bybit.js +21 -23
  12. package/dist/cjs/src/deribit.js +6 -0
  13. package/dist/cjs/src/dydx.js +2454 -0
  14. package/dist/cjs/src/gate.js +4 -4
  15. package/dist/cjs/src/hibachi.js +1 -1
  16. package/dist/cjs/src/hyperliquid.js +207 -9
  17. package/dist/cjs/src/kucoin.js +711 -109
  18. package/dist/cjs/src/mexc.js +2 -3
  19. package/dist/cjs/src/pro/binance.js +59 -144
  20. package/dist/cjs/src/pro/dydx.js +418 -0
  21. package/dist/cjs/src/pro/kraken.js +4 -3
  22. package/dist/cjs/src/pro/xt.js +218 -4
  23. package/dist/cjs/src/protobuf/mexc/compiled.cjs.js +1 -0
  24. package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.js +56 -0
  25. package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.js +56 -0
  26. package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.js +48 -0
  27. package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.js +343 -0
  28. package/dist/cjs/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.js +717 -0
  29. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.js +60 -0
  30. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.js +45 -0
  31. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.js +380 -0
  32. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.js +72 -0
  33. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.js +211 -0
  34. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.js +195 -0
  35. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.js +49 -0
  36. package/dist/cjs/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.js +57 -0
  37. package/dist/cjs/src/static_dependencies/dydx-v4-client/google/protobuf/any.js +56 -0
  38. package/dist/cjs/src/static_dependencies/dydx-v4-client/helpers.js +79 -0
  39. package/dist/cjs/src/static_dependencies/dydx-v4-client/long/index.cjs.js +9 -0
  40. package/dist/cjs/src/static_dependencies/dydx-v4-client/onboarding.js +59 -0
  41. package/dist/cjs/src/static_dependencies/dydx-v4-client/registry.js +39 -0
  42. package/dist/cjs/src/static_dependencies/noble-hashes/pbkdf2.js +69 -0
  43. package/dist/cjs/src/static_dependencies/noble-hashes/ripemd160.js +108 -0
  44. package/dist/cjs/src/static_dependencies/noble-hashes/utils.js +50 -1
  45. package/dist/cjs/src/static_dependencies/scure-base/index.js +29 -0
  46. package/dist/cjs/src/static_dependencies/scure-bip32/index.js +278 -0
  47. package/dist/cjs/src/static_dependencies/scure-bip39/index.js +97 -0
  48. package/dist/cjs/src/static_dependencies/scure-bip39/wordlists/english.js +2060 -0
  49. package/dist/cjs/src/static_dependencies/zklink/zklink-sdk-web.js +2 -0
  50. package/dist/cjs/src/toobit.js +2 -1
  51. package/js/ccxt.d.ts +8 -2
  52. package/js/ccxt.js +6 -2
  53. package/js/src/abstract/binance.d.ts +7 -0
  54. package/js/src/abstract/binancecoinm.d.ts +7 -0
  55. package/js/src/abstract/binanceus.d.ts +7 -0
  56. package/js/src/abstract/binanceusdm.d.ts +7 -0
  57. package/js/src/abstract/bitget.d.ts +1 -0
  58. package/js/src/abstract/dydx.d.ts +61 -0
  59. package/js/src/abstract/dydx.js +11 -0
  60. package/js/src/abstract/kucoin.d.ts +1 -1
  61. package/js/src/abstract/kucoinfutures.d.ts +1 -1
  62. package/js/src/base/Exchange.d.ts +7 -0
  63. package/js/src/base/Exchange.js +163 -10
  64. package/js/src/base/ws/Client.js +3 -1
  65. package/js/src/binance.js +8 -1
  66. package/js/src/bingx.js +20 -0
  67. package/js/src/bitget.d.ts +3 -3
  68. package/js/src/bitget.js +43 -41
  69. package/js/src/bybit.d.ts +3 -3
  70. package/js/src/bybit.js +21 -23
  71. package/js/src/deribit.js +6 -0
  72. package/js/src/dydx.d.ts +364 -0
  73. package/js/src/dydx.js +2453 -0
  74. package/js/src/gate.d.ts +2 -2
  75. package/js/src/gate.js +4 -4
  76. package/js/src/hibachi.js +1 -1
  77. package/js/src/hyperliquid.d.ts +17 -0
  78. package/js/src/hyperliquid.js +207 -9
  79. package/js/src/kucoin.d.ts +48 -1
  80. package/js/src/kucoin.js +711 -109
  81. package/js/src/mexc.js +2 -3
  82. package/js/src/pro/binance.d.ts +2 -2
  83. package/js/src/pro/binance.js +59 -144
  84. package/js/src/pro/dydx.d.ts +81 -0
  85. package/js/src/pro/dydx.js +417 -0
  86. package/js/src/pro/kraken.js +4 -3
  87. package/js/src/pro/xt.d.ts +85 -2
  88. package/js/src/pro/xt.js +218 -4
  89. package/js/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.d.ts +90 -0
  90. package/js/src/static_dependencies/dydx-v4-client/cosmos/base/v1beta1/coin.js +163 -0
  91. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/keys.d.ts +26 -0
  92. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/keys.js +51 -0
  93. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.d.ts +48 -0
  94. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/multisig/v1beta1/multisig.js +85 -0
  95. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.d.ts +40 -0
  96. package/js/src/static_dependencies/dydx-v4-client/cosmos/crypto/secp256k1/keys.js +77 -0
  97. package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.d.ts +162 -0
  98. package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/signing/v1beta1/signing.js +329 -0
  99. package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.d.ts +460 -0
  100. package/js/src/static_dependencies/dydx-v4-client/cosmos/tx/v1beta1/tx.js +698 -0
  101. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.d.ts +127 -0
  102. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/accountplus/tx.js +286 -0
  103. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/block_rate_limit_config.d.ts +66 -0
  104. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/block_rate_limit_config.js +109 -0
  105. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.d.ts +127 -0
  106. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/clob_pair.js +257 -0
  107. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/equity_tier_limit_config.d.ts +48 -0
  108. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/equity_tier_limit_config.js +93 -0
  109. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/finalize_block.d.ts +23 -0
  110. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/finalize_block.js +43 -0
  111. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations.d.ts +92 -0
  112. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations.js +164 -0
  113. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations_config.d.ts +124 -0
  114. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/liquidations_config.js +196 -0
  115. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/matches.d.ts +159 -0
  116. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/matches.js +324 -0
  117. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.d.ts +546 -0
  118. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order.js +872 -0
  119. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.d.ts +84 -0
  120. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/order_removals.js +181 -0
  121. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.d.ts +397 -0
  122. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/clob/tx.js +757 -0
  123. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.d.ts +120 -0
  124. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/transfer.js +246 -0
  125. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.d.ts +79 -0
  126. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/sending/tx.js +147 -0
  127. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/asset_position.d.ts +32 -0
  128. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/asset_position.js +59 -0
  129. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/perpetual_position.d.ts +34 -0
  130. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/perpetual_position.js +66 -0
  131. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.d.ts +62 -0
  132. package/js/src/static_dependencies/dydx-v4-client/dydxprotocol/subaccounts/subaccount.js +111 -0
  133. package/js/src/static_dependencies/dydx-v4-client/google/protobuf/any.d.ts +207 -0
  134. package/js/src/static_dependencies/dydx-v4-client/google/protobuf/any.js +50 -0
  135. package/js/src/static_dependencies/dydx-v4-client/helpers.d.ts +82 -0
  136. package/js/src/static_dependencies/dydx-v4-client/helpers.js +172 -0
  137. package/js/src/static_dependencies/dydx-v4-client/long/index.cjs +1473 -0
  138. package/js/src/static_dependencies/dydx-v4-client/long/index.d.cts +2 -0
  139. package/js/src/static_dependencies/dydx-v4-client/onboarding.d.ts +35 -0
  140. package/js/src/static_dependencies/dydx-v4-client/onboarding.js +56 -0
  141. package/js/src/static_dependencies/dydx-v4-client/registry.d.ts +7 -0
  142. package/js/src/static_dependencies/dydx-v4-client/registry.js +36 -0
  143. package/js/src/static_dependencies/noble-hashes/utils.d.ts +1 -0
  144. package/js/src/static_dependencies/noble-hashes/utils.js +4 -0
  145. package/js/src/static_dependencies/scure-bip32/index.d.ts +49 -0
  146. package/js/src/static_dependencies/scure-bip32/index.js +295 -0
  147. package/js/src/static_dependencies/scure-bip39/index.d.ts +54 -0
  148. package/js/src/static_dependencies/scure-bip39/index.js +140 -0
  149. package/js/src/static_dependencies/scure-bip39/wordlists/english.d.ts +1 -0
  150. package/js/src/static_dependencies/scure-bip39/wordlists/english.js +2054 -0
  151. package/js/src/toobit.js +2 -1
  152. package/package.json +9 -3
package/js/src/dydx.js ADDED
@@ -0,0 +1,2453 @@
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 Exchange from './abstract/dydx.js';
9
+ import { ArgumentsRequired, NotSupported, ExchangeError, InsufficientFunds, InvalidOrder, BadRequest } from './base/errors.js';
10
+ import { TICK_SIZE } from './base/functions/number.js';
11
+ import Precise from './base/Precise.js';
12
+ import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
13
+ import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
14
+ import { ecdsa } from './base/functions/crypto.js';
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * @class dydx
18
+ * @augments Exchange
19
+ */
20
+ export default class dydx extends Exchange {
21
+ describe() {
22
+ return this.deepExtend(super.describe(), {
23
+ 'id': 'dydx',
24
+ 'name': 'dYdX',
25
+ 'countries': ['US'],
26
+ 'rateLimit': 100,
27
+ 'version': 'v4',
28
+ 'certified': false,
29
+ 'dex': true,
30
+ 'pro': 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
+ 'cancelAllOrders': false,
40
+ 'cancelAllOrdersAfter': false,
41
+ 'cancelOrder': true,
42
+ 'cancelOrders': true,
43
+ 'cancelWithdraw': false,
44
+ 'closeAllPositions': false,
45
+ 'closePosition': false,
46
+ 'createConvertTrade': false,
47
+ 'createDepositAddress': false,
48
+ 'createMarketBuyOrderWithCost': false,
49
+ 'createMarketOrder': false,
50
+ 'createMarketOrderWithCost': false,
51
+ 'createMarketSellOrderWithCost': false,
52
+ 'createOrder': true,
53
+ 'createOrderWithTakeProfitAndStopLoss': false,
54
+ 'createReduceOnlyOrder': false,
55
+ 'createStopLimitOrder': false,
56
+ 'createStopLossOrder': false,
57
+ 'createStopMarketOrder': false,
58
+ 'createStopOrder': false,
59
+ 'createTakeProfitOrder': false,
60
+ 'createTrailingAmountOrder': false,
61
+ 'createTrailingPercentOrder': false,
62
+ 'createTriggerOrder': false,
63
+ 'fetchAccounts': true,
64
+ 'fetchBalance': true,
65
+ 'fetchCanceledOrders': false,
66
+ 'fetchClosedOrder': false,
67
+ 'fetchClosedOrders': true,
68
+ 'fetchConvertCurrencies': false,
69
+ 'fetchConvertQuote': false,
70
+ 'fetchConvertTrade': false,
71
+ 'fetchConvertTradeHistory': false,
72
+ 'fetchCurrencies': false,
73
+ 'fetchDepositAddress': false,
74
+ 'fetchDepositAddresses': false,
75
+ 'fetchDepositAddressesByNetwork': false,
76
+ 'fetchDeposits': true,
77
+ 'fetchDepositsWithdrawals': true,
78
+ 'fetchFundingHistory': false,
79
+ 'fetchFundingInterval': false,
80
+ 'fetchFundingIntervals': false,
81
+ 'fetchFundingRate': false,
82
+ 'fetchFundingRateHistory': true,
83
+ 'fetchFundingRates': false,
84
+ 'fetchIndexOHLCV': false,
85
+ 'fetchLedger': true,
86
+ 'fetchLeverage': false,
87
+ 'fetchMarginAdjustmentHistory': false,
88
+ 'fetchMarginMode': false,
89
+ 'fetchMarkets': true,
90
+ 'fetchMarkOHLCV': false,
91
+ 'fetchMyTrades': false,
92
+ 'fetchOHLCV': true,
93
+ 'fetchOpenInterestHistory': false,
94
+ 'fetchOpenOrder': false,
95
+ 'fetchOpenOrders': true,
96
+ 'fetchOrder': true,
97
+ 'fetchOrderBook': true,
98
+ 'fetchOrders': true,
99
+ 'fetchOrderTrades': false,
100
+ 'fetchPosition': true,
101
+ 'fetchPositionHistory': false,
102
+ 'fetchPositionMode': false,
103
+ 'fetchPositions': true,
104
+ 'fetchPositionsHistory': false,
105
+ 'fetchPremiumIndexOHLCV': false,
106
+ 'fetchStatus': false,
107
+ 'fetchTicker': false,
108
+ 'fetchTickers': false,
109
+ 'fetchTime': true,
110
+ 'fetchTrades': true,
111
+ 'fetchTradingFee': false,
112
+ 'fetchTradingFees': false,
113
+ 'fetchTransactions': false,
114
+ 'fetchTransfers': true,
115
+ 'fetchWithdrawals': true,
116
+ 'reduceMargin': false,
117
+ 'sandbox': false,
118
+ 'setLeverage': false,
119
+ 'setMargin': false,
120
+ 'setPositionMode': false,
121
+ 'transfer': true,
122
+ 'withdraw': true,
123
+ },
124
+ 'timeframes': {
125
+ '1m': '1MIN',
126
+ '5m': '5MINS',
127
+ '15m': '15MINS',
128
+ '30m': '30MINS',
129
+ '1h': '1HOUR',
130
+ '4h': '4HOURS',
131
+ '1d': '1DAY',
132
+ },
133
+ 'urls': {
134
+ 'logo': 'https://github.com/user-attachments/assets/617ea0c1-f05a-4d26-9fcb-a0d1d4091ae1',
135
+ 'api': {
136
+ 'indexer': 'https://indexer.dydx.trade/v4',
137
+ 'nodeRpc': 'https://dydx-ops-rpc.kingnodes.com',
138
+ 'nodeRest': 'https://dydx-rest.publicnode.com',
139
+ },
140
+ 'test': {
141
+ 'indexer': 'https://indexer.v4testnet.dydx.exchange/v4',
142
+ 'nodeRpc': 'https://test-dydx-rpc.kingnodes.com',
143
+ 'nodeRest': 'https://test-dydx-rest.kingnodes.com',
144
+ },
145
+ 'www': 'https://www.dydx.xyz',
146
+ 'doc': [
147
+ 'https://docs.dydx.xyz',
148
+ ],
149
+ 'fees': [
150
+ 'https://docs.dydx.exchange/introduction-trading_fees',
151
+ ],
152
+ 'referral': 'dydx.trade?ref=ccxt',
153
+ },
154
+ 'api': {
155
+ 'indexer': {
156
+ 'get': {
157
+ 'addresses/{address}': 1,
158
+ 'addresses/{address}/parentSubaccountNumber/{number}': 1,
159
+ 'addresses/{address}/subaccountNumber/{subaccountNumber}': 1,
160
+ 'assetPositions': 1,
161
+ 'assetPositions/parentSubaccountNumber': 1,
162
+ 'candles/perpetualMarkets/{market}': 1,
163
+ 'compliance/screen/{address}': 1,
164
+ 'fills': 1,
165
+ 'fills/parentSubaccountNumber': 1,
166
+ 'fundingPayments': 1,
167
+ 'fundingPayments/parentSubaccount': 1,
168
+ 'height': 0.1,
169
+ 'historical-pnl': 1,
170
+ 'historical-pnl/parentSubaccountNumber': 1,
171
+ 'historicalBlockTradingRewards/{address}': 1,
172
+ 'historicalFunding/{market}': 1,
173
+ 'historicalTradingRewardAggregations/{address}': 1,
174
+ 'orderbooks/perpetualMarket/{market}': 1,
175
+ 'orders': 1,
176
+ 'orders/parentSubaccountNumber': 1,
177
+ 'orders/{orderId}': 1,
178
+ 'perpetualMarkets': 1,
179
+ 'perpetualPositions': 1,
180
+ 'perpetualPositions/parentSubaccountNumber': 1,
181
+ 'screen': 1,
182
+ 'sparklines': 1,
183
+ 'time': 1,
184
+ 'trades/perpetualMarket/{market}': 1,
185
+ 'transfers': 1,
186
+ 'transfers/between': 1,
187
+ 'transfers/parentSubaccountNumber': 1,
188
+ 'vault/v1/megavault/historicalPnl': 1,
189
+ 'vault/v1/megavault/positions': 1,
190
+ 'vault/v1/vaults/historicalPnl': 1,
191
+ //
192
+ 'perpetualMarketSparklines': 1,
193
+ 'perpetualMarkets/{ticker}': 1,
194
+ 'perpetualMarkets/{ticker}/orderbook': 1,
195
+ 'trades/perpetualMarket/{ticker}': 1,
196
+ 'historicalFunding/{ticker}': 1,
197
+ 'candles/{ticker}/{resolution}': 1,
198
+ 'addresses/{address}/subaccounts': 1,
199
+ 'addresses/{address}/subaccountNumber/{subaccountNumber}/assetPositions': 1,
200
+ 'addresses/{address}/subaccountNumber/{subaccountNumber}/perpetualPositions': 1,
201
+ 'addresses/{address}/subaccountNumber/{subaccountNumber}/orders': 1,
202
+ 'fills/parentSubaccount': 1,
203
+ 'historical-pnl/parentSubaccount': 1,
204
+ },
205
+ },
206
+ 'nodeRpc': {
207
+ 'get': {
208
+ 'abci_info': 1,
209
+ 'block': 1,
210
+ 'broadcast_tx_async': 1,
211
+ 'broadcast_tx_sync': 1,
212
+ 'tx': 1,
213
+ },
214
+ },
215
+ 'nodeRest': {
216
+ 'get': {
217
+ 'cosmos/auth/v1beta1/account_info/{dydxAddress}': 1,
218
+ },
219
+ 'post': {
220
+ 'cosmos/tx/v1beta1/encode': 1,
221
+ 'cosmos/tx/v1beta1/simulate': 1,
222
+ },
223
+ },
224
+ },
225
+ 'fees': {
226
+ 'trading': {
227
+ 'tierBased': true,
228
+ 'percentage': true,
229
+ 'maker': this.parseNumber('0.0001'),
230
+ 'taker': this.parseNumber('0.0005'),
231
+ },
232
+ },
233
+ 'requiredCredentials': {
234
+ 'apiKey': false,
235
+ 'secret': false,
236
+ 'privateKey': false,
237
+ },
238
+ 'options': {
239
+ 'mnemonic': undefined,
240
+ 'chainName': 'dydx-mainnet-1',
241
+ 'chainId': 1,
242
+ 'sandboxMode': false,
243
+ 'defaultFeeDenom': 'uusdc',
244
+ 'defaultFeeMultiplier': '1.6',
245
+ 'feeDenom': {
246
+ 'USDC_DENOM': 'ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5',
247
+ 'USDC_GAS_DENOM': 'uusdc',
248
+ 'USDC_DECIMALS': 6,
249
+ 'USDC_GAS_PRICE': '0.025',
250
+ 'CHAINTOKEN_DENOM': 'adydx',
251
+ 'CHAINTOKEN_DECIMALS': 18,
252
+ 'CHAINTOKEN_GAS_PRICE': '25000000000',
253
+ },
254
+ },
255
+ 'features': {
256
+ 'default': {
257
+ 'sandbox': true,
258
+ 'createOrder': {
259
+ 'marginMode': false,
260
+ 'triggerPrice': true,
261
+ 'triggerPriceType': {
262
+ 'last': true,
263
+ 'mark': true,
264
+ 'index': false,
265
+ },
266
+ 'triggerDirection': false,
267
+ 'stopLossPrice': false,
268
+ 'takeProfitPrice': false,
269
+ 'attachedStopLossTakeProfit': undefined,
270
+ 'timeInForce': {
271
+ 'IOC': true,
272
+ 'FOK': true,
273
+ 'PO': true,
274
+ 'GTD': true,
275
+ },
276
+ 'hedged': false,
277
+ 'trailing': false,
278
+ 'leverage': false,
279
+ 'marketBuyByCost': false,
280
+ 'marketBuyRequiresPrice': false,
281
+ 'selfTradePrevention': false,
282
+ 'iceberg': false,
283
+ },
284
+ 'createOrders': undefined,
285
+ 'fetchMyTrades': {
286
+ 'marginMode': false,
287
+ 'limit': 500,
288
+ 'daysBack': 90,
289
+ 'untilDays': 10000,
290
+ 'symbolRequired': false,
291
+ },
292
+ 'fetchOrder': {
293
+ 'marginMode': false,
294
+ 'trigger': true,
295
+ 'trailing': false,
296
+ 'symbolRequired': false,
297
+ },
298
+ 'fetchOpenOrders': {
299
+ 'marginMode': false,
300
+ 'limit': 500,
301
+ 'trigger': true,
302
+ 'trailing': true,
303
+ 'symbolRequired': false,
304
+ },
305
+ 'fetchOrders': {
306
+ 'marginMode': false,
307
+ 'limit': 500,
308
+ 'daysBack': undefined,
309
+ 'untilDays': 100000,
310
+ 'trigger': true,
311
+ 'trailing': true,
312
+ 'symbolRequired': false,
313
+ },
314
+ 'fetchClosedOrders': {
315
+ 'marginMode': false,
316
+ 'limit': 500,
317
+ 'daysBack': undefined,
318
+ 'daysBackCanceled': undefined,
319
+ 'untilDays': 100000,
320
+ 'trigger': true,
321
+ 'trailing': true,
322
+ 'symbolRequired': false,
323
+ },
324
+ 'fetchOHLCV': {
325
+ 'limit': 1000,
326
+ },
327
+ },
328
+ 'forSwap': {
329
+ 'extends': 'default',
330
+ 'createOrder': {
331
+ 'hedged': true,
332
+ },
333
+ },
334
+ 'swap': {
335
+ 'linear': {
336
+ 'extends': 'forSwap',
337
+ },
338
+ 'inverse': undefined,
339
+ },
340
+ 'future': {
341
+ 'linear': undefined,
342
+ 'inverse': undefined,
343
+ },
344
+ },
345
+ 'commonCurrencies': {},
346
+ 'exceptions': {
347
+ 'exact': {
348
+ // error collision for clob and sending modules from 2 - 8
349
+ // https://github.com/dydxprotocol/v4-chain/blob/5f9f6c9b95cc87d732e23de764909703b81a6e8b/protocol/x/clob/types/errors.go#L320
350
+ // https://github.com/dydxprotocol/v4-chain/blob/5f9f6c9b95cc87d732e23de764909703b81a6e8b/protocol/x/sending/types/errors.go
351
+ '9': InvalidOrder,
352
+ '10': InvalidOrder,
353
+ '11': InvalidOrder,
354
+ '12': InvalidOrder,
355
+ '13': InvalidOrder,
356
+ '14': InvalidOrder,
357
+ '15': InvalidOrder,
358
+ '16': InvalidOrder,
359
+ '17': InvalidOrder,
360
+ '18': InvalidOrder,
361
+ '19': InvalidOrder,
362
+ '20': InvalidOrder,
363
+ '21': InvalidOrder,
364
+ '22': InvalidOrder,
365
+ '23': InvalidOrder,
366
+ '24': InvalidOrder,
367
+ '25': InvalidOrder,
368
+ '26': InvalidOrder,
369
+ '27': InvalidOrder,
370
+ '28': InvalidOrder,
371
+ '29': InvalidOrder,
372
+ '30': InvalidOrder,
373
+ '31': InvalidOrder,
374
+ '32': InvalidOrder,
375
+ '33': InvalidOrder,
376
+ '34': InvalidOrder,
377
+ '35': InvalidOrder,
378
+ '36': InvalidOrder,
379
+ '37': InvalidOrder,
380
+ '39': InvalidOrder,
381
+ '40': InvalidOrder,
382
+ '41': InvalidOrder,
383
+ '42': InvalidOrder,
384
+ '43': InvalidOrder,
385
+ '44': InvalidOrder,
386
+ '45': InvalidOrder,
387
+ '46': InvalidOrder,
388
+ '47': InvalidOrder,
389
+ '48': InvalidOrder,
390
+ '49': InvalidOrder,
391
+ '50': InvalidOrder,
392
+ '1000': BadRequest,
393
+ '1001': BadRequest,
394
+ '1002': BadRequest,
395
+ '1003': InvalidOrder,
396
+ '1004': InvalidOrder,
397
+ '1005': InvalidOrder,
398
+ '1006': InvalidOrder,
399
+ '1007': InvalidOrder,
400
+ '1008': InvalidOrder,
401
+ '1009': InvalidOrder,
402
+ '1010': InvalidOrder,
403
+ '1011': InvalidOrder,
404
+ '1012': InvalidOrder,
405
+ '1013': InvalidOrder,
406
+ '1014': InvalidOrder,
407
+ '1015': InvalidOrder,
408
+ '1017': InvalidOrder,
409
+ '1018': InvalidOrder,
410
+ '1019': InvalidOrder,
411
+ '1020': InvalidOrder,
412
+ '1021': InvalidOrder,
413
+ '1022': InvalidOrder,
414
+ '2000': InvalidOrder,
415
+ '2001': InvalidOrder,
416
+ '2002': InvalidOrder,
417
+ '2003': InvalidOrder,
418
+ '2004': InvalidOrder,
419
+ '2005': InvalidOrder,
420
+ '3000': InvalidOrder,
421
+ '3001': InvalidOrder,
422
+ '3002': InvalidOrder,
423
+ '3003': InvalidOrder,
424
+ '3004': InvalidOrder,
425
+ '3005': InvalidOrder,
426
+ '3006': InvalidOrder,
427
+ '3007': InvalidOrder,
428
+ '3008': InvalidOrder,
429
+ '3009': InvalidOrder,
430
+ '3010': InvalidOrder,
431
+ '4000': InvalidOrder,
432
+ '4001': InvalidOrder,
433
+ '4002': InvalidOrder,
434
+ '4003': InvalidOrder,
435
+ '4004': InvalidOrder,
436
+ '4005': InvalidOrder,
437
+ '4006': InvalidOrder,
438
+ '4007': InvalidOrder,
439
+ '4008': InvalidOrder,
440
+ '5000': InvalidOrder,
441
+ '5001': InvalidOrder,
442
+ '6000': InvalidOrder,
443
+ '6001': InvalidOrder,
444
+ '6002': InvalidOrder,
445
+ '9000': InvalidOrder,
446
+ '9001': InvalidOrder,
447
+ '9002': InvalidOrder,
448
+ '9003': InvalidOrder,
449
+ '10000': InvalidOrder,
450
+ '10001': InvalidOrder,
451
+ '11000': InvalidOrder, // Invalid order router address
452
+ },
453
+ 'broad': {
454
+ 'insufficient funds': InsufficientFunds,
455
+ },
456
+ },
457
+ 'precisionMode': TICK_SIZE,
458
+ });
459
+ }
460
+ /**
461
+ * @method
462
+ * @name dydx#fetchTime
463
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
464
+ * @see https://docs.dydx.xyz/indexer-client/http#get-time
465
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
466
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
467
+ */
468
+ async fetchTime(params = {}) {
469
+ const response = await this.indexerGetTime(params);
470
+ //
471
+ // {
472
+ // "iso": "2025-07-20T15:12:13.466Z",
473
+ // "epoch": 1753024333.466
474
+ // }
475
+ //
476
+ return this.safeInteger(response, 'epoch');
477
+ }
478
+ parseMarket(market) {
479
+ //
480
+ // {
481
+ // "clobPairId": "0",
482
+ // "ticker": "BTC-USD",
483
+ // "status": "ACTIVE",
484
+ // "oraclePrice": "118976.5376",
485
+ // "priceChange24H": "659.9736",
486
+ // "volume24H": "1292729.3605",
487
+ // "trades24H": 9387,
488
+ // "nextFundingRate": "0",
489
+ // "initialMarginFraction": "0.02",
490
+ // "maintenanceMarginFraction": "0.012",
491
+ // "openInterest": "52.0691",
492
+ // "atomicResolution": -10,
493
+ // "quantumConversionExponent": -9,
494
+ // "tickSize": "1",
495
+ // "stepSize": "0.0001",
496
+ // "stepBaseQuantums": 1000000,
497
+ // "subticksPerTick": 100000,
498
+ // "marketType": "CROSS",
499
+ // "openInterestLowerCap": "0",
500
+ // "openInterestUpperCap": "0",
501
+ // "baseOpenInterest": "50.3776",
502
+ // "defaultFundingRate1H": "0"
503
+ // }
504
+ //
505
+ const quoteId = 'USDC';
506
+ const marketId = this.safeString(market, 'ticker');
507
+ const parts = marketId.split('-');
508
+ const baseName = this.safeString(parts, 0);
509
+ const base = this.safeCurrencyCode(baseName);
510
+ const quote = this.safeCurrencyCode(quoteId);
511
+ const baseId = this.safeString(market, 'baseId');
512
+ const settleId = 'USDC';
513
+ const settle = this.safeCurrencyCode(settleId);
514
+ const symbol = base + '/' + quote + ':' + settle;
515
+ const contract = true;
516
+ const swap = true;
517
+ const amountPrecisionStr = this.safeString(market, 'stepSize');
518
+ const pricePrecisionStr = this.safeString(market, 'tickSize');
519
+ const status = this.safeString(market, 'status');
520
+ let active = true;
521
+ if (status !== 'ACTIVE') {
522
+ active = false;
523
+ }
524
+ return this.safeMarketStructure({
525
+ 'id': this.safeString(market, 'ticker'),
526
+ 'symbol': symbol,
527
+ 'base': base,
528
+ 'quote': quote,
529
+ 'settle': settle,
530
+ 'baseId': baseId,
531
+ 'baseName': baseName,
532
+ 'quoteId': quoteId,
533
+ 'settleId': settleId,
534
+ 'type': 'swap',
535
+ 'spot': false,
536
+ 'margin': undefined,
537
+ 'swap': swap,
538
+ 'future': false,
539
+ 'option': false,
540
+ 'active': active,
541
+ 'contract': contract,
542
+ 'linear': true,
543
+ 'inverse': false,
544
+ 'taker': undefined,
545
+ 'maker': undefined,
546
+ 'contractSize': undefined,
547
+ 'expiry': undefined,
548
+ 'expiryDatetime': undefined,
549
+ 'strike': undefined,
550
+ 'optionType': undefined,
551
+ 'precision': {
552
+ 'amount': this.parseNumber(amountPrecisionStr),
553
+ 'price': this.parseNumber(pricePrecisionStr),
554
+ },
555
+ 'limits': {
556
+ 'leverage': {
557
+ 'min': undefined,
558
+ 'max': undefined,
559
+ },
560
+ 'amount': {
561
+ 'min': undefined,
562
+ 'max': undefined,
563
+ },
564
+ 'price': {
565
+ 'min': undefined,
566
+ 'max': undefined,
567
+ },
568
+ 'cost': {
569
+ 'min': undefined,
570
+ 'max': undefined,
571
+ },
572
+ },
573
+ 'created': undefined,
574
+ 'info': market,
575
+ });
576
+ }
577
+ /**
578
+ * @method
579
+ * @name dydx#fetchMarkets
580
+ * @description retrieves data on all markets for hyperliquid
581
+ * @see https://docs.dydx.xyz/indexer-client/http#get-perpetual-markets
582
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
583
+ * @returns {object[]} an array of objects representing market data
584
+ */
585
+ async fetchMarkets(params = {}) {
586
+ const request = {
587
+ // 'limit': 1000,
588
+ };
589
+ const response = await this.indexerGetPerpetualMarkets(this.extend(request, params));
590
+ //
591
+ // {
592
+ // "markets": {
593
+ // "BTC-USD": {
594
+ // "clobPairId": "0",
595
+ // "ticker": "BTC-USD",
596
+ // "status": "ACTIVE",
597
+ // "oraclePrice": "118976.5376",
598
+ // "priceChange24H": "659.9736",
599
+ // "volume24H": "1292729.3605",
600
+ // "trades24H": 9387,
601
+ // "nextFundingRate": "0",
602
+ // "initialMarginFraction": "0.02",
603
+ // "maintenanceMarginFraction": "0.012",
604
+ // "openInterest": "52.0691",
605
+ // "atomicResolution": -10,
606
+ // "quantumConversionExponent": -9,
607
+ // "tickSize": "1",
608
+ // "stepSize": "0.0001",
609
+ // "stepBaseQuantums": 1000000,
610
+ // "subticksPerTick": 100000,
611
+ // "marketType": "CROSS",
612
+ // "openInterestLowerCap": "0",
613
+ // "openInterestUpperCap": "0",
614
+ // "baseOpenInterest": "50.3776",
615
+ // "defaultFundingRate1H": "0"
616
+ // }
617
+ // }
618
+ // }
619
+ //
620
+ const data = this.safeDict(response, 'markets', {});
621
+ const markets = Object.values(data);
622
+ return this.parseMarkets(markets);
623
+ }
624
+ parseTrade(trade, market = undefined) {
625
+ //
626
+ // {
627
+ // "id": "02ac5b1f0000000200000002",
628
+ // "side": "BUY",
629
+ // "size": "0.0501",
630
+ // "price": "115732",
631
+ // "type": "LIMIT",
632
+ // "createdAt": "2025-07-25T05:11:09.800Z",
633
+ // "createdAtHeight": "44849951"
634
+ // }
635
+ //
636
+ const timestamp = this.parse8601(this.safeString(trade, 'createdAt'));
637
+ const symbol = market['symbol'];
638
+ const price = this.safeString(trade, 'price');
639
+ const amount = this.safeString(trade, 'size');
640
+ const side = this.safeStringLower(trade, 'side');
641
+ const id = this.safeString(trade, 'id');
642
+ return this.safeTrade({
643
+ 'id': id,
644
+ 'timestamp': timestamp,
645
+ 'datetime': this.iso8601(timestamp),
646
+ 'symbol': symbol,
647
+ 'side': side,
648
+ 'price': price,
649
+ 'amount': amount,
650
+ 'cost': undefined,
651
+ 'order': undefined,
652
+ 'takerOrMaker': undefined,
653
+ 'type': undefined,
654
+ 'fee': undefined,
655
+ 'info': trade,
656
+ }, market);
657
+ }
658
+ /**
659
+ * @method
660
+ * @name dydx#fetchTrades
661
+ * @description get the list of most recent trades for a particular symbol
662
+ * @see https://developer.woox.io/api-reference/endpoint/public_data/marketTrades
663
+ * @param {string} symbol unified symbol of the market to fetch trades for
664
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
665
+ * @param {int} [limit] the maximum amount of trades to fetch
666
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
667
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
668
+ */
669
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
670
+ await this.loadMarkets();
671
+ const market = this.market(symbol);
672
+ const request = {
673
+ 'market': market['id'],
674
+ };
675
+ if (limit !== undefined) {
676
+ request['limit'] = limit;
677
+ }
678
+ const response = await this.indexerGetTradesPerpetualMarketMarket(this.extend(request, params));
679
+ //
680
+ // {
681
+ // "trades": [
682
+ // {
683
+ // "id": "02ac5b1f0000000200000002",
684
+ // "side": "BUY",
685
+ // "size": "0.0501",
686
+ // "price": "115732",
687
+ // "type": "LIMIT",
688
+ // "createdAt": "2025-07-25T05:11:09.800Z",
689
+ // "createdAtHeight": "44849951"
690
+ // }
691
+ // ]
692
+ // }
693
+ //
694
+ const rows = this.safeList(response, 'trades', []);
695
+ return this.parseTrades(rows, market, since, limit);
696
+ }
697
+ parseOHLCV(ohlcv, market = undefined) {
698
+ //
699
+ // {
700
+ // "startedAt": "2025-07-25T09:47:00.000Z",
701
+ // "ticker": "BTC-USD",
702
+ // "resolution": "1MIN",
703
+ // "low": "116099",
704
+ // "high": "116099",
705
+ // "open": "116099",
706
+ // "close": "116099",
707
+ // "baseTokenVolume": "0",
708
+ // "usdVolume": "0",
709
+ // "trades": 0,
710
+ // "startingOpenInterest": "54.0594",
711
+ // "orderbookMidPriceOpen": "115845.5",
712
+ // "orderbookMidPriceClose": "115845.5"
713
+ // }
714
+ //
715
+ return [
716
+ this.parse8601(this.safeString(ohlcv, 'startedAt')),
717
+ this.safeNumber(ohlcv, 'open'),
718
+ this.safeNumber(ohlcv, 'high'),
719
+ this.safeNumber(ohlcv, 'low'),
720
+ this.safeNumber(ohlcv, 'close'),
721
+ this.safeNumber(ohlcv, 'baseTokenVolume'),
722
+ ];
723
+ }
724
+ /**
725
+ * @method
726
+ * @name dydx#fetchOHLCV
727
+ * @see https://docs.dydx.xyz/indexer-client/http#get-candles
728
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
729
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
730
+ * @param {string} timeframe the length of time each candle represents
731
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
732
+ * @param {int} [limit] the maximum amount of candles to fetch
733
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
734
+ * @param {int} [params.until] the latest time in ms to fetch entries for
735
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
736
+ */
737
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
738
+ await this.loadMarkets();
739
+ const market = this.market(symbol);
740
+ const request = {
741
+ 'market': market['id'],
742
+ 'resolution': this.safeString(this.timeframes, timeframe, timeframe),
743
+ };
744
+ if (limit !== undefined) {
745
+ request['limit'] = Math.min(limit, 1000);
746
+ }
747
+ if (since !== undefined) {
748
+ request['fromIso'] = this.iso8601(since);
749
+ }
750
+ const until = this.safeInteger(params, 'until');
751
+ params = this.omit(params, 'until');
752
+ if (until !== undefined) {
753
+ request['toIso'] = this.iso8601(until);
754
+ }
755
+ const response = await this.indexerGetCandlesPerpetualMarketsMarket(this.extend(request, params));
756
+ //
757
+ // {
758
+ // "candles": [
759
+ // {
760
+ // "startedAt": "2025-07-25T09:47:00.000Z",
761
+ // "ticker": "BTC-USD",
762
+ // "resolution": "1MIN",
763
+ // "low": "116099",
764
+ // "high": "116099",
765
+ // "open": "116099",
766
+ // "close": "116099",
767
+ // "baseTokenVolume": "0",
768
+ // "usdVolume": "0",
769
+ // "trades": 0,
770
+ // "startingOpenInterest": "54.0594",
771
+ // "orderbookMidPriceOpen": "115845.5",
772
+ // "orderbookMidPriceClose": "115845.5"
773
+ // }
774
+ // ]
775
+ // }
776
+ //
777
+ const rows = this.safeList(response, 'candles', []);
778
+ return this.parseOHLCVs(rows, market, timeframe, since, limit);
779
+ }
780
+ /**
781
+ * @method
782
+ * @name dydx#fetchFundingRateHistory
783
+ * @description fetches historical funding rate prices
784
+ * @see https://docs.dydx.xyz/indexer-client/http#get-historical-funding
785
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
786
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
787
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
788
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
789
+ * @param {int} [params.until] timestamp in ms of the latest funding rate
790
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
791
+ */
792
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
793
+ if (symbol === undefined) {
794
+ throw new ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
795
+ }
796
+ await this.loadMarkets();
797
+ const market = this.market(symbol);
798
+ const request = {
799
+ 'market': market['id'],
800
+ };
801
+ if (limit !== undefined) {
802
+ request['limit'] = limit;
803
+ }
804
+ const until = this.safeInteger(params, 'until');
805
+ if (until !== undefined) {
806
+ request['effectiveBeforeOrAt'] = this.iso8601(until);
807
+ }
808
+ const response = await this.indexerGetHistoricalFundingMarket(this.extend(request, params));
809
+ //
810
+ // {
811
+ // "historicalFunding": [
812
+ // {
813
+ // "ticker": "BTC-USD",
814
+ // "rate": "0",
815
+ // "price": "116302.62419",
816
+ // "effectiveAtHeight": "44865196",
817
+ // "effectiveAt": "2025-07-25T11:00:00.013Z"
818
+ // }
819
+ // ]
820
+ // }
821
+ //
822
+ const rates = [];
823
+ const rows = this.safeList(response, 'historicalFunding', []);
824
+ for (let i = 0; i < rows.length; i++) {
825
+ const entry = rows[i];
826
+ const timestamp = this.parse8601(this.safeString(entry, 'effectiveAt'));
827
+ const marketId = this.safeString(entry, 'ticker');
828
+ rates.push({
829
+ 'info': entry,
830
+ 'symbol': this.safeSymbol(marketId, market),
831
+ 'fundingRate': this.safeNumber(entry, 'rate'),
832
+ 'timestamp': timestamp,
833
+ 'datetime': this.iso8601(timestamp),
834
+ });
835
+ }
836
+ const sorted = this.sortBy(rates, 'timestamp');
837
+ return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
838
+ }
839
+ handlePublicAddress(methodName, params) {
840
+ let userAux = undefined;
841
+ [userAux, params] = this.handleOptionAndParams(params, methodName, 'user');
842
+ let user = userAux;
843
+ [user, params] = this.handleOptionAndParams(params, methodName, 'address', userAux);
844
+ if ((user !== undefined) && (user !== '')) {
845
+ return [user, params];
846
+ }
847
+ if ((this.walletAddress !== undefined) && (this.walletAddress !== '')) {
848
+ return [this.walletAddress, params];
849
+ }
850
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the walletAddress set');
851
+ }
852
+ parseOrder(order, market = undefined) {
853
+ //
854
+ // {
855
+ // "id": "dad46410-3444-5566-a129-19a619300fb7",
856
+ // "subaccountId": "8586bcf6-1f58-5ec9-a0bc-e53db273e7b0",
857
+ // "clientId": "716238006",
858
+ // "clobPairId": "0",
859
+ // "side": "BUY",
860
+ // "size": "0.001",
861
+ // "totalFilled": "0.001",
862
+ // "price": "400000",
863
+ // "type": "LIMIT",
864
+ // "status": "FILLED",
865
+ // "timeInForce": "GTT",
866
+ // "reduceOnly": false,
867
+ // "orderFlags": "64",
868
+ // "goodTilBlockTime": "2025-07-28T12:07:33.000Z",
869
+ // "createdAtHeight": "45058325",
870
+ // "clientMetadata": "2",
871
+ // "updatedAt": "2025-07-28T12:06:35.330Z",
872
+ // "updatedAtHeight": "45058326",
873
+ // "postOnly": false,
874
+ // "ticker": "BTC-USD",
875
+ // "subaccountNumber": 0
876
+ // }
877
+ //
878
+ const status = this.parseOrderStatus(this.safeStringUpper(order, 'status'));
879
+ const marketId = this.safeString(order, 'ticker');
880
+ const symbol = this.safeSymbol(marketId, market);
881
+ const filled = this.safeString(order, 'totalFilled');
882
+ const timestamp = this.parse8601(this.safeString(order, 'updatedAt'));
883
+ const price = this.safeString(order, 'price');
884
+ const amount = this.safeString(order, 'size');
885
+ const type = this.parseOrderType(this.safeStringUpper(order, 'type'));
886
+ const side = this.safeStringLower(order, 'side');
887
+ const timeInForce = this.safeStringUpper(order, 'timeInForce');
888
+ return this.safeOrder({
889
+ 'info': order,
890
+ 'id': this.safeString(order, 'id'),
891
+ 'clientOrderId': this.safeString(order, 'clientId'),
892
+ 'timestamp': timestamp,
893
+ 'datetime': this.iso8601(timestamp),
894
+ 'lastTradeTimestamp': undefined,
895
+ 'lastUpdateTimestamp': timestamp,
896
+ 'symbol': symbol,
897
+ 'type': type,
898
+ 'timeInForce': timeInForce,
899
+ 'postOnly': this.safeBool(order, 'postOnly'),
900
+ 'reduceOnly': this.safeBool(order, 'reduceOnly'),
901
+ 'side': side,
902
+ 'price': price,
903
+ 'triggerPrice': undefined,
904
+ 'amount': amount,
905
+ 'cost': undefined,
906
+ 'average': undefined,
907
+ 'filled': filled,
908
+ 'remaining': undefined,
909
+ 'status': status,
910
+ 'fee': undefined,
911
+ 'trades': undefined,
912
+ }, market);
913
+ }
914
+ parseOrderStatus(status) {
915
+ const statuses = {
916
+ 'UNTRIGGERED': 'open',
917
+ 'OPEN': 'open',
918
+ 'FILLED': 'closed',
919
+ 'CANCELED': 'canceled',
920
+ 'BEST_EFFORT_CANCELED': 'canceling',
921
+ };
922
+ return this.safeString(statuses, status, status);
923
+ }
924
+ parseOrderType(type) {
925
+ const types = {
926
+ 'LIMIT': 'LIMIT',
927
+ 'STOP_LIMIT': 'LIMIT',
928
+ 'TAKE_PROFIT_LIMIT': 'LIMIT',
929
+ 'MARKET': 'MARKET',
930
+ 'STOP_MARKET': 'MARKET',
931
+ 'TAKE_PROFIT_MARKET': 'MARKET',
932
+ 'TRAILING_STOP': 'MARKET',
933
+ };
934
+ return this.safeStringUpper(types, type, type);
935
+ }
936
+ /**
937
+ * @method
938
+ * @name dydx#fetchOrder
939
+ * @description fetches information on an order made by the user
940
+ * @see https://docs.dydx.xyz/indexer-client/http#get-order
941
+ * @param {string} id the order id
942
+ * @param {string} symbol unified symbol of the market the order was made in
943
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
944
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
945
+ */
946
+ async fetchOrder(id, symbol = undefined, params = {}) {
947
+ await this.loadMarkets();
948
+ const request = {
949
+ 'orderId': id,
950
+ };
951
+ const order = await this.indexerGetOrdersOrderId(this.extend(request, params));
952
+ return this.parseOrder(order);
953
+ }
954
+ /**
955
+ * @method
956
+ * @name dydx#fetchOrders
957
+ * @description fetches information on multiple orders made by the user
958
+ * @see https://docs.dydx.xyz/indexer-client/http#list-orders
959
+ * @param {string} symbol unified market symbol of the market orders were made in
960
+ * @param {int} [since] the earliest time in ms to fetch orders for
961
+ * @param {int} [limit] the maximum number of order structures to retrieve
962
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
963
+ * @param {string} [params.address] wallet address that made trades
964
+ * @param {string} [params.subAccountNumber] sub account number
965
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
966
+ */
967
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
968
+ let userAddress = undefined;
969
+ let subAccountNumber = undefined;
970
+ [userAddress, params] = this.handlePublicAddress('fetchOrders', params);
971
+ [subAccountNumber, params] = this.handleOptionAndParams(params, 'fetchOrders', 'subAccountNumber', '0');
972
+ await this.loadMarkets();
973
+ const request = {
974
+ 'address': userAddress,
975
+ 'subaccountNumber': subAccountNumber,
976
+ };
977
+ let market = undefined;
978
+ if (symbol !== undefined) {
979
+ market = this.market(symbol);
980
+ request['ticker'] = market['id'];
981
+ }
982
+ if (limit !== undefined) {
983
+ request['limit'] = limit;
984
+ }
985
+ const response = await this.indexerGetOrders(this.extend(request, params));
986
+ //
987
+ // [
988
+ // {
989
+ // "id": "dad46410-3444-5566-a129-19a619300fb7",
990
+ // "subaccountId": "8586bcf6-1f58-5ec9-a0bc-e53db273e7b0",
991
+ // "clientId": "716238006",
992
+ // "clobPairId": "0",
993
+ // "side": "BUY",
994
+ // "size": "0.001",
995
+ // "totalFilled": "0.001",
996
+ // "price": "400000",
997
+ // "type": "LIMIT",
998
+ // "status": "FILLED",
999
+ // "timeInForce": "GTT",
1000
+ // "reduceOnly": false,
1001
+ // "orderFlags": "64",
1002
+ // "goodTilBlockTime": "2025-07-28T12:07:33.000Z",
1003
+ // "createdAtHeight": "45058325",
1004
+ // "clientMetadata": "2",
1005
+ // "updatedAt": "2025-07-28T12:06:35.330Z",
1006
+ // "updatedAtHeight": "45058326",
1007
+ // "postOnly": false,
1008
+ // "ticker": "BTC-USD",
1009
+ // "subaccountNumber": 0
1010
+ // }
1011
+ // ]
1012
+ //
1013
+ return this.parseOrders(response, market, since, limit);
1014
+ }
1015
+ /**
1016
+ * @method
1017
+ * @name dydx#fetchOpenOrders
1018
+ * @description fetch all unfilled currently open orders
1019
+ * @see https://docs.dydx.xyz/indexer-client/http#list-orders
1020
+ * @param {string} symbol unified market symbol of the market orders were made in
1021
+ * @param {int} [since] the earliest time in ms to fetch orders for
1022
+ * @param {int} [limit] the maximum number of order structures to retrieve
1023
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1024
+ * @param {string} [params.address] wallet address that made trades
1025
+ * @param {string} [params.subAccountNumber] sub account number
1026
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1027
+ */
1028
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1029
+ const request = {
1030
+ 'status': 'OPEN', // ['OPEN', 'FILLED', 'CANCELED', 'BEST_EFFORT_CANCELED', 'UNTRIGGERED', 'BEST_EFFORT_OPENED']
1031
+ };
1032
+ return await this.fetchOrders(symbol, since, limit, this.extend(request, params));
1033
+ }
1034
+ /**
1035
+ * @method
1036
+ * @name dydx#fetchClosedOrders
1037
+ * @description fetches information on multiple closed orders made by the user
1038
+ * @see https://docs.dydx.xyz/indexer-client/http#list-orders
1039
+ * @param {string} symbol unified market symbol of the market orders were made in
1040
+ * @param {int} [since] the earliest time in ms to fetch orders for
1041
+ * @param {int} [limit] the maximum number of order structures to retrieve
1042
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1043
+ * @param {string} [params.address] wallet address that made trades
1044
+ * @param {string} [params.subAccountNumber] sub account number
1045
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1046
+ */
1047
+ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1048
+ const request = {
1049
+ 'status': 'FILLED', // ['OPEN', 'FILLED', 'CANCELED', 'BEST_EFFORT_CANCELED', 'UNTRIGGERED', 'BEST_EFFORT_OPENED']
1050
+ };
1051
+ return await this.fetchOrders(symbol, since, limit, this.extend(request, params));
1052
+ }
1053
+ parsePosition(position, market = undefined) {
1054
+ //
1055
+ // {
1056
+ // "market": "BTC-USD",
1057
+ // "status": "OPEN",
1058
+ // "side": "SHORT",
1059
+ // "size": "-0.407",
1060
+ // "maxSize": "-0.009",
1061
+ // "entryPrice": "118692.04840909090909090909",
1062
+ // "exitPrice": "119526.565625",
1063
+ // "realizedPnl": "476.42665909090909090909088",
1064
+ // "unrealizedPnl": "-57.26681734000000000000037",
1065
+ // "createdAt": "2025-07-14T07:53:55.631Z",
1066
+ // "createdAtHeight": "44140908",
1067
+ // "closedAt": null,
1068
+ // "sumOpen": "0.44",
1069
+ // "sumClose": "0.032",
1070
+ // "netFunding": "503.13121",
1071
+ // "subaccountNumber": 0
1072
+ // }
1073
+ //
1074
+ const marketId = this.safeString(position, 'market');
1075
+ market = this.safeMarket(marketId, market);
1076
+ const symbol = market['symbol'];
1077
+ const side = this.safeStringLower(position, 'side');
1078
+ let quantity = this.safeString(position, 'size');
1079
+ if (side !== 'long') {
1080
+ quantity = Precise.stringMul('-1', quantity);
1081
+ }
1082
+ const timestamp = this.parse8601(this.safeString(position, 'createdAt'));
1083
+ return this.safePosition({
1084
+ 'info': position,
1085
+ 'id': undefined,
1086
+ 'symbol': symbol,
1087
+ 'entryPrice': this.safeNumber(position, 'entryPrice'),
1088
+ 'markPrice': undefined,
1089
+ 'notional': undefined,
1090
+ 'collateral': undefined,
1091
+ 'unrealizedPnl': this.safeNumber(position, 'unrealizedPnl'),
1092
+ 'side': side,
1093
+ 'contracts': this.parseNumber(quantity),
1094
+ 'contractSize': undefined,
1095
+ 'timestamp': timestamp,
1096
+ 'datetime': this.iso8601(timestamp),
1097
+ 'hedged': undefined,
1098
+ 'maintenanceMargin': undefined,
1099
+ 'maintenanceMarginPercentage': undefined,
1100
+ 'initialMargin': undefined,
1101
+ 'initialMarginPercentage': undefined,
1102
+ 'leverage': undefined,
1103
+ 'liquidationPrice': undefined,
1104
+ 'marginRatio': undefined,
1105
+ 'marginMode': undefined,
1106
+ 'percentage': undefined,
1107
+ });
1108
+ }
1109
+ /**
1110
+ * @method
1111
+ * @name dydx#fetchPosition
1112
+ * @description fetch data on an open position
1113
+ * @see https://docs.dydx.xyz/indexer-client/http#list-positions
1114
+ * @param {string} symbol unified market symbol of the market the position is held in
1115
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1116
+ * @param {string} [params.address] wallet address that made trades
1117
+ * @param {string} [params.subAccountNumber] sub account number
1118
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1119
+ */
1120
+ async fetchPosition(symbol, params = {}) {
1121
+ const positions = await this.fetchPositions([symbol], params);
1122
+ return this.safeDict(positions, 0, {});
1123
+ }
1124
+ /**
1125
+ * @method
1126
+ * @name dydx#fetchPositions
1127
+ * @description fetch all open positions
1128
+ * @see https://docs.dydx.xyz/indexer-client/http#list-positions
1129
+ * @param {string[]} [symbols] list of unified market symbols
1130
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1131
+ * @param {string} [params.address] wallet address that made trades
1132
+ * @param {string} [params.subAccountNumber] sub account number
1133
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1134
+ */
1135
+ async fetchPositions(symbols = undefined, params = {}) {
1136
+ let userAddress = undefined;
1137
+ let subAccountNumber = undefined;
1138
+ [userAddress, params] = this.handlePublicAddress('fetchPositions', params);
1139
+ [subAccountNumber, params] = this.handleOptionAndParams(params, 'fetchOrders', 'subAccountNumber', '0');
1140
+ await this.loadMarkets();
1141
+ const request = {
1142
+ 'address': userAddress,
1143
+ 'subaccountNumber': subAccountNumber,
1144
+ 'status': 'OPEN', // ['OPEN', 'CLOSED', 'LIQUIDATED']
1145
+ };
1146
+ const response = await this.indexerGetPerpetualPositions(this.extend(request, params));
1147
+ //
1148
+ // {
1149
+ // "positions": [
1150
+ // {
1151
+ // "market": "BTC-USD",
1152
+ // "status": "OPEN",
1153
+ // "side": "SHORT",
1154
+ // "size": "-0.407",
1155
+ // "maxSize": "-0.009",
1156
+ // "entryPrice": "118692.04840909090909090909",
1157
+ // "exitPrice": "119526.565625",
1158
+ // "realizedPnl": "476.42665909090909090909088",
1159
+ // "unrealizedPnl": "-57.26681734000000000000037",
1160
+ // "createdAt": "2025-07-14T07:53:55.631Z",
1161
+ // "createdAtHeight": "44140908",
1162
+ // "closedAt": null,
1163
+ // "sumOpen": "0.44",
1164
+ // "sumClose": "0.032",
1165
+ // "netFunding": "503.13121",
1166
+ // "subaccountNumber": 0
1167
+ // }
1168
+ // ]
1169
+ // }
1170
+ //
1171
+ const rows = this.safeList(response, 'positions', []);
1172
+ return this.parsePositions(rows, symbols);
1173
+ }
1174
+ hashMessage(message) {
1175
+ return this.hash(message, keccak, 'hex');
1176
+ }
1177
+ signHash(hash, privateKey) {
1178
+ const signature = ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1, undefined);
1179
+ const r = signature['r'];
1180
+ const s = signature['s'];
1181
+ return {
1182
+ 'r': r.padStart(64, '0'),
1183
+ 's': s.padStart(64, '0'),
1184
+ 'v': this.sum(27, signature['v']),
1185
+ };
1186
+ }
1187
+ signMessage(message, privateKey) {
1188
+ return this.signHash(this.hashMessage(message), privateKey.slice(-64));
1189
+ }
1190
+ signOnboardingAction() {
1191
+ const message = { 'action': 'dYdX Chain Onboarding' };
1192
+ const chainId = this.options['chainId'];
1193
+ const domain = {
1194
+ 'chainId': chainId,
1195
+ 'name': 'dYdX Chain',
1196
+ };
1197
+ const messageTypes = {
1198
+ 'dYdX': [
1199
+ { 'name': 'action', 'type': 'string' },
1200
+ ],
1201
+ };
1202
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, message);
1203
+ if (this.privateKey === undefined || this.privateKey === '') {
1204
+ throw new ArgumentsRequired(this.id + ' signOnboardingAction() requires a privateKey to be set.');
1205
+ }
1206
+ const signature = this.signMessage(msg, this.privateKey);
1207
+ return signature;
1208
+ }
1209
+ signDydxTx(privateKey, message, memo, chainId, account, authenticators, fee = undefined) {
1210
+ const [encodedTx, signDoc] = this.encodeDydxTxForSigning(message, memo, chainId, account, authenticators, fee);
1211
+ const signature = this.signHash(encodedTx, privateKey);
1212
+ return this.encodeDydxTxRaw(signDoc, signature['r'] + signature['s']);
1213
+ }
1214
+ retrieveCredentials() {
1215
+ let credentials = this.safeDict(this.options, 'dydxCredentials');
1216
+ if (credentials !== undefined) {
1217
+ return credentials;
1218
+ }
1219
+ let entropy = this.safeString(this.options, 'mnemonic');
1220
+ if (entropy === undefined) {
1221
+ const signature = this.signOnboardingAction();
1222
+ entropy = this.hashMessage(this.base16ToBinary(signature['r'] + signature['s']));
1223
+ }
1224
+ credentials = this.retrieveDydxCredentials(entropy);
1225
+ credentials['privateKey'] = this.binaryToBase16(credentials['privateKey']);
1226
+ credentials['publicKey'] = this.binaryToBase16(credentials['publicKey']);
1227
+ this.options['dydxCredentials'] = credentials;
1228
+ return credentials;
1229
+ }
1230
+ async fetchDydxAccount() {
1231
+ // required in js
1232
+ await this.loadDydxProtos();
1233
+ const dydxAccount = this.safeDict(this.options, 'dydxAccount');
1234
+ if (dydxAccount !== undefined) {
1235
+ return dydxAccount;
1236
+ }
1237
+ if (this.walletAddress === undefined) {
1238
+ throw new ArgumentsRequired(this.id + ' fetchDydxAccount() requires the walletAddress to be set using the dydx chain address eg: dydx1cpb4tedmwq304c2kc9pwzjwq0sc6z2a4tasxrz');
1239
+ }
1240
+ if (!this.walletAddress.startsWith('dydx')) {
1241
+ throw new ArgumentsRequired(this.id + ' fetchDydxAccount() requires a valid dydx chain address, starting with dydx, not the l1 address.');
1242
+ }
1243
+ const request = {
1244
+ 'dydxAddress': this.walletAddress,
1245
+ };
1246
+ //
1247
+ // {
1248
+ // "info": {
1249
+ // "address": "string",
1250
+ // "pub_key": {
1251
+ // "type_url": "string",
1252
+ // "key": "string"
1253
+ // },
1254
+ // "account_number": "string",
1255
+ // "sequence": "string"
1256
+ // }
1257
+ // }
1258
+ //
1259
+ const response = await this.nodeRestGetCosmosAuthV1beta1AccountInfoDydxAddress(request);
1260
+ const account = this.safeDict(response, 'info');
1261
+ account['pub_key'] = {
1262
+ // encode with binary key would fail in python
1263
+ 'key': account['pub_key']['key'],
1264
+ };
1265
+ this.options['dydxAccount'] = account;
1266
+ return account;
1267
+ }
1268
+ pow(n, m) {
1269
+ let r = Precise.stringMul(n, '1');
1270
+ const c = this.parseToInt(m);
1271
+ // TODO: cap
1272
+ for (let i = 1; i < c; i++) {
1273
+ r = Precise.stringMul(r, n);
1274
+ }
1275
+ return r;
1276
+ }
1277
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
1278
+ const reduceOnly = this.safeBool2(params, 'reduceOnly', 'reduce_only', false);
1279
+ const orderType = type.toUpperCase();
1280
+ const market = this.market(symbol);
1281
+ const orderSide = side.toUpperCase();
1282
+ let subaccountId = 0;
1283
+ [subaccountId, params] = this.handleOptionAndParams(params, 'createOrder', 'subAccountId', subaccountId);
1284
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
1285
+ const stopLossPrice = this.safeValue(params, 'stopLossPrice', triggerPrice);
1286
+ const takeProfitPrice = this.safeValue(params, 'takeProfitPrice');
1287
+ const isConditional = triggerPrice !== undefined || stopLossPrice !== undefined || takeProfitPrice !== undefined;
1288
+ const isMarket = orderType === 'MARKET';
1289
+ const timeInForce = this.safeStringUpper(params, 'timeInForce', 'GTT');
1290
+ const postOnly = this.isPostOnly(isMarket, undefined, params);
1291
+ const amountStr = this.amountToPrecision(symbol, amount);
1292
+ const priceStr = this.priceToPrecision(symbol, price);
1293
+ const marketInfo = this.safeDict(market, 'info');
1294
+ const atomicResolution = marketInfo['atomicResolution'];
1295
+ const quantumScale = this.pow('10', Precise.stringNeg(atomicResolution));
1296
+ const quantums = Precise.stringMul(amountStr, quantumScale);
1297
+ const quantumConversionExponent = marketInfo['quantumConversionExponent'];
1298
+ const priceScale = this.pow('10', Precise.stringSub(Precise.stringSub(atomicResolution, quantumConversionExponent), '-6'));
1299
+ const subticks = Precise.stringMul(priceStr, priceScale);
1300
+ let clientMetadata = 0;
1301
+ let conditionalType = 0;
1302
+ let conditionalOrderTriggerSubticks = '0';
1303
+ let orderFlag = undefined;
1304
+ let timeInForceNumber = undefined;
1305
+ if (timeInForce === 'FOK') {
1306
+ throw new InvalidOrder(this.id + ' timeInForce fok has been deprecated');
1307
+ }
1308
+ if (orderType === 'MARKET') {
1309
+ // short-term
1310
+ orderFlag = 0;
1311
+ clientMetadata = 1; // STOP_MARKET / TAKE_PROFIT_MARKET
1312
+ if (timeInForce !== undefined) {
1313
+ // default is ioc
1314
+ timeInForceNumber = 1;
1315
+ }
1316
+ }
1317
+ else if (orderType === 'LIMIT') {
1318
+ if (timeInForce === 'GTT') {
1319
+ // long-term
1320
+ orderFlag = 64;
1321
+ if (postOnly) {
1322
+ timeInForceNumber = 2;
1323
+ }
1324
+ else {
1325
+ timeInForceNumber = 0;
1326
+ }
1327
+ }
1328
+ else {
1329
+ orderFlag = 0;
1330
+ if (timeInForce === 'IOC') {
1331
+ timeInForceNumber = 1;
1332
+ }
1333
+ else {
1334
+ throw new InvalidOrder('unexpected code path: timeInForce');
1335
+ }
1336
+ }
1337
+ }
1338
+ if (isConditional) {
1339
+ // conditional
1340
+ orderFlag = 32;
1341
+ if (stopLossPrice !== undefined) {
1342
+ conditionalType = 1;
1343
+ conditionalOrderTriggerSubticks = this.priceToPrecision(symbol, stopLossPrice);
1344
+ }
1345
+ else if (takeProfitPrice !== undefined) {
1346
+ conditionalType = 2;
1347
+ conditionalOrderTriggerSubticks = this.priceToPrecision(symbol, takeProfitPrice);
1348
+ }
1349
+ conditionalOrderTriggerSubticks = Precise.stringMul(conditionalOrderTriggerSubticks, priceScale);
1350
+ }
1351
+ const latestBlockHeight = this.safeInteger(params, 'latestBlockHeight');
1352
+ let goodTillBlock = this.safeInteger(params, 'goodTillBlock');
1353
+ let goodTillBlockTime = undefined;
1354
+ let goodTillBlockTimeInSeconds = 2592000;
1355
+ [goodTillBlockTimeInSeconds, params] = this.handleOptionAndParams(params, 'createOrder', 'goodTillBlockTimeInSeconds', goodTillBlockTimeInSeconds); // default is 30 days
1356
+ if (orderFlag === 0) {
1357
+ if (goodTillBlock === undefined) {
1358
+ // short term order
1359
+ goodTillBlock = latestBlockHeight + 20;
1360
+ }
1361
+ }
1362
+ else {
1363
+ if (goodTillBlockTimeInSeconds === undefined) {
1364
+ throw new ArgumentsRequired('goodTillBlockTimeInSeconds is required.');
1365
+ }
1366
+ goodTillBlockTime = this.seconds() + goodTillBlockTimeInSeconds;
1367
+ }
1368
+ const sideNumber = (orderSide === 'BUY') ? 1 : 2;
1369
+ const defaultClientOrderId = this.randNumber(9); // 2**32 - 1 is 10 digits, but it may overflow with 10
1370
+ const clientOrderId = this.safeInteger(params, 'clientOrderId', defaultClientOrderId);
1371
+ const orderPayload = {
1372
+ 'order': {
1373
+ 'orderId': {
1374
+ 'subaccountId': {
1375
+ 'owner': this.getWalletAddress(),
1376
+ 'number': subaccountId,
1377
+ },
1378
+ 'clientId': clientOrderId,
1379
+ 'orderFlags': orderFlag,
1380
+ 'clobPairId': marketInfo['clobPairId'],
1381
+ },
1382
+ 'side': sideNumber,
1383
+ 'quantums': this.toDydxLong(quantums),
1384
+ 'subticks': this.toDydxLong(subticks),
1385
+ 'goodTilBlock': goodTillBlock,
1386
+ 'goodTilBlockTime': goodTillBlockTime,
1387
+ 'timeInForce': timeInForceNumber,
1388
+ 'reduceOnly': reduceOnly,
1389
+ 'clientMetadata': clientMetadata,
1390
+ 'conditionType': conditionalType,
1391
+ 'conditionalOrderTriggerSubticks': this.toDydxLong(conditionalOrderTriggerSubticks),
1392
+ 'orderRouterAddress': this.safeString(this.options, 'routerAddress', 'dydx165sfn2k3vucvq7gklauy2r3agyjw4c3m60ascn'),
1393
+ },
1394
+ };
1395
+ const signingPayload = {
1396
+ 'typeUrl': '/dydxprotocol.clob.MsgPlaceOrder',
1397
+ 'value': orderPayload,
1398
+ };
1399
+ params = this.omit(params, ['reduceOnly', 'reduce_only', 'clientOrderId', 'postOnly', 'timeInForce', 'stopPrice', 'triggerPrice', 'stopLoss', 'takeProfit', 'latestBlockHeight', 'goodTillBlock', 'goodTillBlockTimeInSeconds', 'subaccountId']);
1400
+ const orderId = this.createOrderIdFromParts(this.getWalletAddress(), subaccountId, clientOrderId, orderFlag, marketInfo['clobPairId']);
1401
+ return [orderId, this.extend(signingPayload, params)];
1402
+ }
1403
+ createOrderIdFromParts(address, subAccountNumber, clientOrderId, orderFlags, clobPairId) {
1404
+ const nameSp = this.safeString(this.options, 'namespace', '0f9da948-a6fb-4c45-9edc-4685c3f3317d');
1405
+ const prefixAddress = address + '-' + subAccountNumber.toString();
1406
+ const prefix = this.uuid5(nameSp, prefixAddress);
1407
+ const orderInfo = prefix + '-' + this.numberToString(clientOrderId) + '-' + this.numberToString(clobPairId) + '-' + this.numberToString(orderFlags);
1408
+ return this.uuid5(nameSp, orderInfo);
1409
+ }
1410
+ async fetchLatestBlockHeight(params = {}) {
1411
+ const response = await this.nodeRpcGetAbciInfo(params);
1412
+ //
1413
+ // {
1414
+ // "jsonrpc": "2.0",
1415
+ // "id": -1,
1416
+ // "result": {
1417
+ // "response": {
1418
+ // "data": "dydxprotocol",
1419
+ // "version": "9.1.0-rc0",
1420
+ // "last_block_height": "49157714",
1421
+ // "last_block_app_hash": "9LHAcDDI5zmWiC6bGiiGtxuWPlKJV+/fTBZk/WQ/Y4U="
1422
+ // }
1423
+ // }
1424
+ // }
1425
+ //
1426
+ const result = this.safeDict(response, 'result');
1427
+ const info = this.safeDict(result, 'response');
1428
+ return this.safeInteger(info, 'last_block_height');
1429
+ }
1430
+ /**
1431
+ * @method
1432
+ * @name dydx#createOrder
1433
+ * @see https://docs.dydx.xyz/interaction/trading#place-an-order
1434
+ * @description create a trade order
1435
+ * @param {string} symbol unified symbol of the market to create an order in
1436
+ * @param {string} type 'market' or 'limit'
1437
+ * @param {string} side 'buy' or 'sell'
1438
+ * @param {float} amount how much of currency you want to trade in units of base currency
1439
+ * @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1440
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1441
+ * @param {string} [params.timeInForce] "GTT", "IOC", or "PO"
1442
+ * @param {float} [params.triggerPrice] The price a trigger order is triggered at
1443
+ * @param {float} [params.stopLossPrice] price for a stoploss order
1444
+ * @param {float} [params.takeProfitPrice] price for a takeprofit order
1445
+ * @param {string} [params.clientOrderId] a unique id for the order
1446
+ * @param {bool} [params.postOnly] true or false whether the order is post-only
1447
+ * @param {bool} [params.reduceOnly] true or false whether the order is reduce-only
1448
+ * @param {float} [params.goodTillBlock] expired block number for the order, required for market order and non limit GTT order, default value is latestBlockHeight + 20
1449
+ * @param {float} [params.goodTillBlockTimeInSeconds] expired time elapsed for the order, required for limit GTT order and conditional, default value is 30 days
1450
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1451
+ */
1452
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
1453
+ await this.loadMarkets();
1454
+ const credentials = this.retrieveCredentials();
1455
+ const account = await this.fetchDydxAccount();
1456
+ const lastBlockHeight = await this.fetchLatestBlockHeight();
1457
+ // params['latestBlockHeight'] = lastBlockHeight;
1458
+ const newParams = this.extend(params, { 'latestBlockHeight': lastBlockHeight });
1459
+ const orderRequestRes = this.createOrderRequest(symbol, type, side, amount, price, newParams);
1460
+ const orderId = orderRequestRes[0];
1461
+ const orderRequest = orderRequestRes[1];
1462
+ const chainName = this.options['chainName'];
1463
+ const signedTx = this.signDydxTx(credentials['privateKey'], orderRequest, '', chainName, account, undefined);
1464
+ const request = {
1465
+ 'tx': signedTx,
1466
+ };
1467
+ // nodeRpcGetBroadcastTxAsync
1468
+ const response = await this.nodeRpcGetBroadcastTxSync(request);
1469
+ //
1470
+ // {
1471
+ // "jsonrpc": "2.0",
1472
+ // "id": -1,
1473
+ // "result": {
1474
+ // "code": 0,
1475
+ // "data": "",
1476
+ // "log": "[]",
1477
+ // "codespace": "",
1478
+ // "hash": "CBEDB0603E57E5CE21FA6954770A9403D2A81BED02E608C860356152D0AA1A81"
1479
+ // }
1480
+ // }
1481
+ //
1482
+ const result = this.safeDict(response, 'result');
1483
+ return this.safeOrder({
1484
+ 'info': result,
1485
+ 'id': orderId,
1486
+ 'clientOrderId': orderRequest['value']['order']['orderId']['clientId'],
1487
+ });
1488
+ }
1489
+ /**
1490
+ * @method
1491
+ * @name dydx#cancelOrder
1492
+ * @description cancels an open order
1493
+ * @see https://docs.dydx.xyz/interaction/trading/#cancel-an-order
1494
+ * @param {string} id it should be the clientOrderId in this case
1495
+ * @param {string} symbol unified symbol of the market the order was made in
1496
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1497
+ * @param {string} [params.clientOrderId] client order id used when creating the order
1498
+ * @param {boolean} [params.trigger] whether the order is a trigger/algo order
1499
+ * @param {float} [params.orderFlags] default is 64, orderFlags for the order, market order and non limit GTT order is 0, limit GTT order is 64 and conditional order is 32
1500
+ * @param {float} [params.goodTillBlock] expired block number for the order, required for market order and non limit GTT order (orderFlags = 0), default value is latestBlockHeight + 20
1501
+ * @param {float} [params.goodTillBlockTimeInSeconds] expired time elapsed for the order, required for limit GTT order and conditional (orderFlagss > 0), default value is 30 days
1502
+ * @param {int} [params.subAccountId] sub account id, default is 0
1503
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1504
+ */
1505
+ async cancelOrder(id, symbol = undefined, params = {}) {
1506
+ const isTrigger = this.safeBool2(params, 'trigger', 'stop', false);
1507
+ params = this.omit(params, ['trigger', 'stop']);
1508
+ if (!isTrigger && (symbol === undefined)) {
1509
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
1510
+ }
1511
+ await this.loadMarkets();
1512
+ const market = this.market(symbol);
1513
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'clientId', id);
1514
+ if (clientOrderId === undefined) {
1515
+ throw new ArgumentsRequired(this.id + ' cancelOrder() requires a clientOrderId parameter, cancelling using id is not currently supported.');
1516
+ }
1517
+ const idString = id.toString();
1518
+ if (id !== undefined && idString.indexOf('-') > -1) {
1519
+ throw new NotSupported(this.id + ' cancelOrder() cancelling using id is not currently supported, please use provide the clientOrderId parameter.');
1520
+ }
1521
+ let goodTillBlock = this.safeInteger(params, 'goodTillBlock');
1522
+ let goodTillBlockTimeInSeconds = 2592000;
1523
+ [goodTillBlockTimeInSeconds, params] = this.handleOptionAndParams(params, 'cancelOrder', 'goodTillBlockTimeInSeconds', goodTillBlockTimeInSeconds); // default is 30 days
1524
+ let goodTillBlockTime = undefined;
1525
+ const defaultOrderFlags = (isTrigger) ? 32 : 64;
1526
+ const orderFlags = this.safeInteger(params, 'orderFlags', defaultOrderFlags);
1527
+ let subAccountId = 0;
1528
+ [subAccountId, params] = this.handleOptionAndParams(params, 'cancelOrder', 'subAccountId', subAccountId);
1529
+ params = this.omit(params, ['clientOrderId', 'orderFlags', 'goodTillBlock', 'goodTillBlockTime', 'goodTillBlockTimeInSeconds', 'subaccountId', 'clientId']);
1530
+ if (orderFlags !== 0 && orderFlags !== 64 && orderFlags !== 32) {
1531
+ throw new InvalidOrder(this.id + ' invalid orderFlags, allowed values are (0, 64, 32).');
1532
+ }
1533
+ if (orderFlags > 0) {
1534
+ if (goodTillBlockTimeInSeconds === undefined) {
1535
+ throw new ArgumentsRequired(this.id + ' goodTillBlockTimeInSeconds is required in params for long term or conditional order.');
1536
+ }
1537
+ if (goodTillBlock !== undefined && goodTillBlock > 0) {
1538
+ throw new InvalidOrder(this.id + ' goodTillBlock should be 0 for long term or conditional order.');
1539
+ }
1540
+ goodTillBlockTime = this.seconds() + goodTillBlockTimeInSeconds;
1541
+ }
1542
+ else {
1543
+ if (goodTillBlock === undefined) {
1544
+ const latestBlockHeight = await this.fetchLatestBlockHeight();
1545
+ goodTillBlock = latestBlockHeight + 20;
1546
+ }
1547
+ }
1548
+ const credentials = this.retrieveCredentials();
1549
+ const account = await this.fetchDydxAccount();
1550
+ const cancelPayload = {
1551
+ 'orderId': {
1552
+ 'subaccountId': {
1553
+ 'owner': this.getWalletAddress(),
1554
+ 'number': subAccountId,
1555
+ },
1556
+ 'clientId': clientOrderId,
1557
+ 'orderFlags': orderFlags,
1558
+ 'clobPairId': market['info']['clobPairId'],
1559
+ },
1560
+ 'goodTilBlock': goodTillBlock,
1561
+ 'goodTilBlockTime': goodTillBlockTime,
1562
+ };
1563
+ const signingPayload = {
1564
+ 'typeUrl': '/dydxprotocol.clob.MsgCancelOrder',
1565
+ 'value': cancelPayload,
1566
+ };
1567
+ const chainName = this.options['chainName'];
1568
+ const signedTx = this.signDydxTx(credentials['privateKey'], signingPayload, '', chainName, account, undefined);
1569
+ const request = {
1570
+ 'tx': signedTx,
1571
+ };
1572
+ // nodeRpcGetBroadcastTxAsync
1573
+ const response = await this.nodeRpcGetBroadcastTxSync(request);
1574
+ //
1575
+ // {
1576
+ // "jsonrpc": "2.0",
1577
+ // "id": -1,
1578
+ // "result": {
1579
+ // "code": 0,
1580
+ // "data": "",
1581
+ // "log": "[]",
1582
+ // "codespace": "",
1583
+ // "hash": "CBEDB0603E57E5CE21FA6954770A9403D2A81BED02E608C860356152D0AA1A81"
1584
+ // }
1585
+ // }
1586
+ //
1587
+ const result = this.safeDict(response, 'result');
1588
+ return this.safeOrder({
1589
+ 'info': result,
1590
+ });
1591
+ }
1592
+ /**
1593
+ * @method
1594
+ * @name dydx#cancelOrders
1595
+ * @description cancel multiple orders
1596
+ * @param {string[]} ids order ids
1597
+ * @param {string} [symbol] unified market symbol
1598
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1599
+ * @param {string[]} [params.clientOrderIds] max length 10 e.g. ["my_id_1","my_id_2"], encode the double quotes. No space after comma
1600
+ * @param {int} [params.subAccountId] sub account id, default is 0
1601
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
1602
+ */
1603
+ async cancelOrders(ids, symbol = undefined, params = {}) {
1604
+ await this.loadMarkets();
1605
+ const market = this.market(symbol);
1606
+ const clientOrderIds = this.safeList(params, 'clientOrderIds');
1607
+ if (!clientOrderIds) {
1608
+ throw new NotSupported(this.id + ' cancelOrders only support clientOrderIds.');
1609
+ }
1610
+ let subAccountId = 0;
1611
+ [subAccountId, params] = this.handleOptionAndParams(params, 'cancelOrders', 'subAccountId', subAccountId);
1612
+ let goodTillBlock = this.safeInteger(params, 'goodTillBlock');
1613
+ if (goodTillBlock === undefined) {
1614
+ const latestBlockHeight = await this.fetchLatestBlockHeight();
1615
+ goodTillBlock = latestBlockHeight + 20;
1616
+ }
1617
+ params = this.omit(params, ['clientOrderIds', 'goodTillBlock', 'subaccountId']);
1618
+ const credentials = this.retrieveCredentials();
1619
+ const account = await this.fetchDydxAccount();
1620
+ const cancelOrders = {
1621
+ 'clientIds': clientOrderIds,
1622
+ 'clobPairId': market['info']['clobPairId'],
1623
+ };
1624
+ const cancelPayload = {
1625
+ 'subaccountId': {
1626
+ 'owner': this.getWalletAddress(),
1627
+ 'number': subAccountId,
1628
+ },
1629
+ 'shortTermCancels': [cancelOrders],
1630
+ 'goodTilBlock': goodTillBlock,
1631
+ };
1632
+ const signingPayload = {
1633
+ 'typeUrl': '/dydxprotocol.clob.MsgBatchCancel',
1634
+ 'value': cancelPayload,
1635
+ };
1636
+ const chainName = this.options['chainName'];
1637
+ const signedTx = this.signDydxTx(credentials['privateKey'], signingPayload, '', chainName, account, undefined);
1638
+ const request = {
1639
+ 'tx': signedTx,
1640
+ };
1641
+ // nodeRpcGetBroadcastTxAsync
1642
+ const response = await this.nodeRpcGetBroadcastTxSync(request);
1643
+ //
1644
+ // {
1645
+ // "jsonrpc": "2.0",
1646
+ // "id": -1,
1647
+ // "result": {
1648
+ // "code": 0,
1649
+ // "data": "",
1650
+ // "log": "[]",
1651
+ // "codespace": "",
1652
+ // "hash": "CBEDB0603E57E5CE21FA6954770A9403D2A81BED02E608C860356152D0AA1A81"
1653
+ // }
1654
+ // }
1655
+ //
1656
+ const result = this.safeDict(response, 'result');
1657
+ return [this.safeOrder({
1658
+ 'info': result,
1659
+ })];
1660
+ }
1661
+ /**
1662
+ * @method
1663
+ * @name dydx#fetchOrderBook
1664
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1665
+ * @see https://docs.dydx.xyz/indexer-client/http#get-perpetual-market-orderbook
1666
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1667
+ * @param {int} [limit] the maximum amount of order book entries to return
1668
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1669
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1670
+ */
1671
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
1672
+ await this.loadMarkets();
1673
+ const market = this.market(symbol);
1674
+ const request = {
1675
+ 'market': market['id'],
1676
+ };
1677
+ const response = await this.indexerGetOrderbooksPerpetualMarketMarket(this.extend(request, params));
1678
+ //
1679
+ // {
1680
+ // "bids": [
1681
+ // {
1682
+ // "price": "118267",
1683
+ // "size": "0.3182"
1684
+ // }
1685
+ // ],
1686
+ // "asks": [
1687
+ // {
1688
+ // "price": "118485",
1689
+ // "size": "0.0001"
1690
+ // }
1691
+ // ]
1692
+ // }
1693
+ //
1694
+ return this.parseOrderBook(response, market['symbol'], undefined, 'bids', 'asks', 'price', 'size');
1695
+ }
1696
+ parseLedgerEntry(item, currency = undefined) {
1697
+ //
1698
+ // {
1699
+ // "id": "6a6075bc-7183-5fd9-bc9d-894e238aa527",
1700
+ // "sender": {
1701
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
1702
+ // "subaccountNumber": 0
1703
+ // },
1704
+ // "recipient": {
1705
+ // "address": "dydx1slanxj8x9ntk9knwa6cvfv2tzlsq5gk3dshml0",
1706
+ // "subaccountNumber": 1
1707
+ // },
1708
+ // "size": "0.000001",
1709
+ // "createdAt": "2025-07-29T09:43:02.105Z",
1710
+ // "createdAtHeight": "45116125",
1711
+ // "symbol": "USDC",
1712
+ // "type": "TRANSFER_OUT",
1713
+ // "transactionHash": "92B4744BA1B783CF37C79A50BEBC47FFD59C8D5197D62A8485D3DCCE9AF220AF"
1714
+ // }
1715
+ //
1716
+ const currencyId = this.safeString(item, 'symbol');
1717
+ const code = this.safeCurrencyCode(currencyId, currency);
1718
+ currency = this.safeCurrency(currencyId, currency);
1719
+ const type = this.safeStringUpper(item, 'type');
1720
+ let direction = undefined;
1721
+ if (type !== undefined) {
1722
+ if (type === 'TRANSFER_IN' || type === 'DEPOSIT') {
1723
+ direction = 'in';
1724
+ }
1725
+ else if (type === 'TRANSFER_OUT' || type === 'WITHDRAWAL') {
1726
+ direction = 'out';
1727
+ }
1728
+ }
1729
+ const amount = this.safeString(item, 'size');
1730
+ const timestamp = this.parse8601(this.safeString(item, 'createdAt'));
1731
+ const sender = this.safeDict(item, 'sender');
1732
+ const recipient = this.safeDict(item, 'recipient');
1733
+ return this.safeLedgerEntry({
1734
+ 'info': item,
1735
+ 'id': this.safeString(item, 'id'),
1736
+ 'direction': direction,
1737
+ 'account': this.safeString(sender, 'address'),
1738
+ 'referenceAccount': this.safeString(recipient, 'address'),
1739
+ 'referenceId': this.safeString(item, 'transactionHash'),
1740
+ 'type': this.parseLedgerEntryType(type),
1741
+ 'currency': code,
1742
+ 'amount': this.parseNumber(amount),
1743
+ 'timestamp': timestamp,
1744
+ 'datetime': this.iso8601(timestamp),
1745
+ 'before': undefined,
1746
+ 'after': undefined,
1747
+ 'status': undefined,
1748
+ 'fee': undefined,
1749
+ }, currency);
1750
+ }
1751
+ parseLedgerEntryType(type) {
1752
+ const ledgerType = {
1753
+ 'TRANSFER_IN': 'transfer',
1754
+ 'TRANSFER_OUT': 'transfer',
1755
+ 'DEPOSIT': 'deposit',
1756
+ 'WITHDRAWAL': 'withdrawal',
1757
+ };
1758
+ return this.safeString(ledgerType, type, type);
1759
+ }
1760
+ /**
1761
+ * @method
1762
+ * @name dydx#fetchLedger
1763
+ * @description fetch the history of changes, actions done by the user or operations that altered balance of the user
1764
+ * @see https://docs.dydx.xyz/indexer-client/http#get-transfers
1765
+ * @param {string} [code] unified currency code, default is undefined
1766
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
1767
+ * @param {int} [limit] max number of ledger entries to return, default is undefined
1768
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1769
+ * @param {string} [params.address] wallet address that made trades
1770
+ * @param {string} [params.subAccountNumber] sub account number
1771
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
1772
+ */
1773
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
1774
+ await this.loadMarkets();
1775
+ let currency = undefined;
1776
+ if (code !== undefined) {
1777
+ currency = this.currency(code);
1778
+ }
1779
+ const response = await this.fetchTransactionsHelper(code, since, limit, this.extend(params, { 'methodName': 'fetchLedger' }));
1780
+ return this.parseLedger(response, currency, since, limit);
1781
+ }
1782
+ async estimateTxFee(message, memo, account) {
1783
+ const txBytes = this.encodeDydxTxForSimulation(message, memo, account['sequence'], account['pub_key']);
1784
+ const request = {
1785
+ 'txBytes': txBytes,
1786
+ };
1787
+ const response = await this.nodeRestPostCosmosTxV1beta1Simulate(request);
1788
+ //
1789
+ // {
1790
+ // gas_info: { gas_wanted: '18446744073709551615', gas_used: '86055' },
1791
+ // result: {
1792
+ // ...
1793
+ // }
1794
+ // }
1795
+ //
1796
+ const gasInfo = this.safeDict(response, 'gas_info');
1797
+ if (gasInfo === undefined) {
1798
+ throw new ExchangeError(this.id + ' failed to simulate transaction.');
1799
+ }
1800
+ const gasUsed = this.safeString(gasInfo, 'gas_used');
1801
+ if (gasUsed === undefined) {
1802
+ throw new ExchangeError(this.id + ' failed to simulate transaction.');
1803
+ }
1804
+ const defaultFeeDenom = this.safeString(this.options, 'defaultFeeDenom');
1805
+ const defaultFeeMultiplier = this.safeString(this.options, 'defaultFeeMultiplier');
1806
+ const feeDenom = this.safeDict(this.options, 'feeDenom');
1807
+ let gasPrice = undefined;
1808
+ let denom = undefined;
1809
+ if (defaultFeeDenom === 'uusdc') {
1810
+ gasPrice = feeDenom['USDC_GAS_PRICE'];
1811
+ denom = feeDenom['USDC_DENOM'];
1812
+ }
1813
+ else {
1814
+ gasPrice = feeDenom['CHAINTOKEN_GAS_PRICE'];
1815
+ denom = feeDenom['CHAINTOKEN_DENOM'];
1816
+ }
1817
+ const gasLimit = Math.ceil(this.parseToNumeric(Precise.stringMul(gasUsed, defaultFeeMultiplier)));
1818
+ let feeAmount = Precise.stringMul(this.numberToString(gasLimit), gasPrice);
1819
+ if (feeAmount.indexOf('.') >= 0) {
1820
+ feeAmount = this.numberToString(Math.ceil(this.parseToNumeric(feeAmount)));
1821
+ }
1822
+ const feeObj = {
1823
+ 'amount': feeAmount,
1824
+ 'denom': denom,
1825
+ };
1826
+ return {
1827
+ 'amount': [feeObj],
1828
+ 'gasLimit': gasLimit,
1829
+ };
1830
+ }
1831
+ /**
1832
+ * @method
1833
+ * @name dydx#transfer
1834
+ * @description transfer currency internally between wallets on the same account
1835
+ * @param {string} code unified currency code
1836
+ * @param {float} amount amount to transfer
1837
+ * @param {string} fromAccount account to transfer from *main, subaccount*
1838
+ * @param {string} toAccount account to transfer to *subaccount, address*
1839
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1840
+ * @param {string} [params.vaultAddress] the vault address for order
1841
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
1842
+ */
1843
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
1844
+ if (code !== 'USDC') {
1845
+ throw new NotSupported(this.id + ' transfer() only support USDC');
1846
+ }
1847
+ await this.loadMarkets();
1848
+ const fromSubaccountId = this.safeInteger(params, 'fromSubaccountId');
1849
+ const toSubaccountId = this.safeInteger(params, 'toSubaccountId');
1850
+ if (fromAccount !== 'main') {
1851
+ // throw error if from subaccount id is undefind
1852
+ if (fromAccount === undefined) {
1853
+ throw new NotSupported(this.id + ' transfer only support main > subaccount and subaccount <> subaccount.');
1854
+ }
1855
+ if (fromSubaccountId === undefined || toSubaccountId === undefined) {
1856
+ throw new ArgumentsRequired(this.id + ' transfer requires fromSubaccountId and toSubaccountId.');
1857
+ }
1858
+ }
1859
+ params = this.omit(params, ['fromSubaccountId', 'toSubaccountId']);
1860
+ const credentials = this.retrieveCredentials();
1861
+ const account = await this.fetchDydxAccount();
1862
+ const usd = this.parseToInt(Precise.stringMul(this.numberToString(amount), '1000000'));
1863
+ let payload = undefined;
1864
+ let signingPayload = undefined;
1865
+ if (fromAccount === 'main') {
1866
+ // deposit to subaccount
1867
+ if (toSubaccountId === undefined) {
1868
+ throw new ArgumentsRequired(this.id + ' transfer() requeire toSubaccoutnId.');
1869
+ }
1870
+ payload = {
1871
+ 'sender': this.getWalletAddress(),
1872
+ 'recipient': {
1873
+ 'owner': this.getWalletAddress(),
1874
+ 'number': toSubaccountId,
1875
+ },
1876
+ 'assetId': 0,
1877
+ 'quantums': usd,
1878
+ };
1879
+ signingPayload = {
1880
+ 'typeUrl': '/dydxprotocol.sending.MsgDepositToSubaccount',
1881
+ 'value': payload,
1882
+ };
1883
+ }
1884
+ else {
1885
+ payload = {
1886
+ 'transfer': {
1887
+ 'sender': {
1888
+ 'owner': fromAccount,
1889
+ 'number': fromSubaccountId,
1890
+ },
1891
+ 'recipient': {
1892
+ 'owner': toAccount,
1893
+ 'number': toSubaccountId,
1894
+ },
1895
+ 'assetId': 0,
1896
+ 'amount': usd,
1897
+ },
1898
+ };
1899
+ signingPayload = {
1900
+ 'typeUrl': '/dydxprotocol.sending.MsgCreateTransfer',
1901
+ 'value': payload,
1902
+ };
1903
+ }
1904
+ const txFee = await this.estimateTxFee(signingPayload, '', account);
1905
+ const chainName = this.options['chainName'];
1906
+ const signedTx = this.signDydxTx(credentials['privateKey'], signingPayload, '', chainName, account, undefined, txFee);
1907
+ const request = {
1908
+ 'tx': signedTx,
1909
+ };
1910
+ // nodeRpcGetBroadcastTxAsync
1911
+ const response = await this.nodeRpcGetBroadcastTxSync(request);
1912
+ //
1913
+ // {
1914
+ // "jsonrpc": "2.0",
1915
+ // "id": -1,
1916
+ // "result": {
1917
+ // "code": 0,
1918
+ // "data": "",
1919
+ // "log": "[]",
1920
+ // "codespace": "",
1921
+ // "hash": "CBEDB0603E57E5CE21FA6954770A9403D2A81BED02E608C860356152D0AA1A81"
1922
+ // }
1923
+ // }
1924
+ //
1925
+ return this.parseTransfer(response);
1926
+ }
1927
+ parseTransfer(transfer, currency = undefined) {
1928
+ //
1929
+ // {
1930
+ // "id": "6a6075bc-7183-5fd9-bc9d-894e238aa527",
1931
+ // "sender": {
1932
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
1933
+ // "subaccountNumber": 0
1934
+ // },
1935
+ // "recipient": {
1936
+ // "address": "dydx1slanxj8x9ntk9knwa6cvfv2tzlsq5gk3dshml0",
1937
+ // "subaccountNumber": 1
1938
+ // },
1939
+ // "size": "0.000001",
1940
+ // "createdAt": "2025-07-29T09:43:02.105Z",
1941
+ // "createdAtHeight": "45116125",
1942
+ // "symbol": "USDC",
1943
+ // "type": "TRANSFER_OUT",
1944
+ // "transactionHash": "92B4744BA1B783CF37C79A50BEBC47FFD59C8D5197D62A8485D3DCCE9AF220AF"
1945
+ // }
1946
+ //
1947
+ const id = this.safeString(transfer, 'id');
1948
+ const currencyId = this.safeString(transfer, 'symbol');
1949
+ const code = this.safeCurrencyCode(currencyId, currency);
1950
+ const amount = this.safeNumber(transfer, 'size');
1951
+ const sender = this.safeDict(transfer, 'sender');
1952
+ const recipient = this.safeDict(transfer, 'recipient');
1953
+ const fromAccount = this.safeString(sender, 'address');
1954
+ const toAccount = this.safeString(recipient, 'address');
1955
+ const timestamp = this.parse8601(this.safeString(transfer, 'createdAt'));
1956
+ return {
1957
+ 'info': transfer,
1958
+ 'id': id,
1959
+ 'timestamp': timestamp,
1960
+ 'datetime': this.iso8601(timestamp),
1961
+ 'currency': code,
1962
+ 'amount': amount,
1963
+ 'fromAccount': fromAccount,
1964
+ 'toAccount': toAccount,
1965
+ 'status': undefined,
1966
+ };
1967
+ }
1968
+ /**
1969
+ * @method
1970
+ * @name dydx#fetchTransfers
1971
+ * @description fetch a history of internal transfers made on an account
1972
+ * @see https://docs.dydx.xyz/indexer-client/http#get-transfers
1973
+ * @param {string} code unified currency code of the currency transferred
1974
+ * @param {int} [since] the earliest time in ms to fetch transfers for
1975
+ * @param {int} [limit] the maximum number of transfers structures to retrieve
1976
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1977
+ * @param {string} [params.address] wallet address that made trades
1978
+ * @param {string} [params.subAccountNumber] sub account number
1979
+ * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
1980
+ */
1981
+ async fetchTransfers(code = undefined, since = undefined, limit = undefined, params = {}) {
1982
+ await this.loadMarkets();
1983
+ let currency = undefined;
1984
+ if (code !== undefined) {
1985
+ currency = this.currency(code);
1986
+ }
1987
+ const response = await this.fetchTransactionsHelper(code, since, limit, this.extend(params, { 'methodName': 'fetchTransfers' }));
1988
+ const transferIn = this.filterBy(response, 'type', 'TRANSFER_IN');
1989
+ const transferOut = this.filterBy(response, 'type', 'TRANSFER_OUT');
1990
+ const rows = this.arrayConcat(transferIn, transferOut);
1991
+ return this.parseTransfers(rows, currency, since, limit);
1992
+ }
1993
+ parseTransaction(transaction, currency = undefined) {
1994
+ //
1995
+ // {
1996
+ // "id": "6a6075bc-7183-5fd9-bc9d-894e238aa527",
1997
+ // "sender": {
1998
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
1999
+ // "subaccountNumber": 0
2000
+ // },
2001
+ // "recipient": {
2002
+ // "address": "dydx1slanxj8x9ntk9knwa6cvfv2tzlsq5gk3dshml0",
2003
+ // "subaccountNumber": 1
2004
+ // },
2005
+ // "size": "0.000001",
2006
+ // "createdAt": "2025-07-29T09:43:02.105Z",
2007
+ // "createdAtHeight": "45116125",
2008
+ // "symbol": "USDC",
2009
+ // "type": "TRANSFER_OUT",
2010
+ // "transactionHash": "92B4744BA1B783CF37C79A50BEBC47FFD59C8D5197D62A8485D3DCCE9AF220AF"
2011
+ // }
2012
+ //
2013
+ const id = this.safeString(transaction, 'id');
2014
+ const sender = this.safeDict(transaction, 'sender');
2015
+ const recipient = this.safeDict(transaction, 'recipient');
2016
+ const addressTo = this.safeString(recipient, 'address');
2017
+ const addressFrom = this.safeString(sender, 'address');
2018
+ const txid = this.safeString(transaction, 'transactionHash');
2019
+ const currencyId = this.safeString(transaction, 'symbol');
2020
+ const code = this.safeCurrencyCode(currencyId, currency);
2021
+ const timestamp = this.parse8601(this.safeString(transaction, 'createdAt'));
2022
+ const amount = this.safeNumber(transaction, 'size');
2023
+ return {
2024
+ 'info': transaction,
2025
+ 'id': id,
2026
+ 'txid': txid,
2027
+ 'timestamp': timestamp,
2028
+ 'datetime': this.iso8601(timestamp),
2029
+ 'network': undefined,
2030
+ 'address': addressTo,
2031
+ 'addressTo': addressTo,
2032
+ 'addressFrom': addressFrom,
2033
+ 'tag': undefined,
2034
+ 'tagTo': undefined,
2035
+ 'tagFrom': undefined,
2036
+ 'type': this.safeStringLower(transaction, 'type'),
2037
+ 'amount': amount,
2038
+ 'currency': code,
2039
+ 'status': undefined,
2040
+ 'updated': undefined,
2041
+ 'internal': undefined,
2042
+ 'comment': undefined,
2043
+ 'fee': undefined,
2044
+ };
2045
+ }
2046
+ /**
2047
+ * @method
2048
+ * @name dydx#withdraw
2049
+ * @description make a withdrawal
2050
+ * @param {string} code unified currency code
2051
+ * @param {float} amount the amount to withdraw
2052
+ * @param {string} address the address to withdraw to
2053
+ * @param {string} tag
2054
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2055
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2056
+ */
2057
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
2058
+ if (code !== 'USDC') {
2059
+ throw new NotSupported(this.id + ' withdraw() only support USDC');
2060
+ }
2061
+ await this.loadMarkets();
2062
+ this.checkAddress(address);
2063
+ const subaccountId = this.safeInteger(params, 'subaccountId');
2064
+ if (subaccountId === undefined) {
2065
+ throw new ArgumentsRequired(this.id + ' withdraw requires subaccountId.');
2066
+ }
2067
+ params = this.omit(params, ['subaccountId']);
2068
+ const currency = this.currency(code);
2069
+ const credentials = this.retrieveCredentials();
2070
+ const account = await this.fetchDydxAccount();
2071
+ const usd = this.parseToInt(Precise.stringMul(this.numberToString(amount), '1000000'));
2072
+ const payload = {
2073
+ 'sender': {
2074
+ 'owner': this.getWalletAddress(),
2075
+ 'number': subaccountId,
2076
+ },
2077
+ 'recipient': address,
2078
+ 'assetId': 0,
2079
+ 'quantums': usd,
2080
+ };
2081
+ const signingPayload = {
2082
+ 'typeUrl': '/dydxprotocol.sending.MsgWithdrawFromSubaccount',
2083
+ 'value': payload,
2084
+ };
2085
+ const txFee = await this.estimateTxFee(signingPayload, tag, account);
2086
+ const chainName = this.options['chainName'];
2087
+ const signedTx = this.signDydxTx(credentials['privateKey'], signingPayload, tag, chainName, account, undefined, txFee);
2088
+ const request = {
2089
+ 'tx': signedTx,
2090
+ };
2091
+ // nodeRpcGetBroadcastTxAsync
2092
+ const response = await this.nodeRpcGetBroadcastTxSync(request);
2093
+ //
2094
+ // {
2095
+ // "jsonrpc": "2.0",
2096
+ // "id": -1,
2097
+ // "result": {
2098
+ // "code": 0,
2099
+ // "data": "",
2100
+ // "log": "[]",
2101
+ // "codespace": "",
2102
+ // "hash": "CBEDB0603E57E5CE21FA6954770A9403D2A81BED02E608C860356152D0AA1A81"
2103
+ // }
2104
+ // }
2105
+ //
2106
+ const data = this.safeDict(response, 'result', {});
2107
+ return this.parseTransaction(data, currency);
2108
+ }
2109
+ /**
2110
+ * @method
2111
+ * @name dydx#fetchWithdrawals
2112
+ * @description fetch all withdrawals made from an account
2113
+ * @see https://docs.dydx.xyz/indexer-client/http#get-transfers
2114
+ * @param {string} code unified currency code
2115
+ * @param {int} [since] the earliest time in ms to fetch withdrawals for
2116
+ * @param {int} [limit] the maximum number of withdrawals structures to retrieve
2117
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2118
+ * @param {string} [params.address] wallet address that made trades
2119
+ * @param {string} [params.subAccountNumber] sub account number
2120
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2121
+ */
2122
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2123
+ await this.loadMarkets();
2124
+ let currency = undefined;
2125
+ if (code !== undefined) {
2126
+ currency = this.currency(code);
2127
+ }
2128
+ const response = await this.fetchTransactionsHelper(code, since, limit, this.extend(params, { 'methodName': 'fetchWithdrawals' }));
2129
+ const rows = this.filterBy(response, 'type', 'WITHDRAWAL');
2130
+ return this.parseTransactions(rows, currency, since, limit);
2131
+ }
2132
+ /**
2133
+ * @method
2134
+ * @name dydx#fetchDeposits
2135
+ * @description fetch all deposits made to an account
2136
+ * @see https://docs.dydx.xyz/indexer-client/http#get-transfers
2137
+ * @param {string} code unified currency code
2138
+ * @param {int} [since] the earliest time in ms to fetch deposits for
2139
+ * @param {int} [limit] the maximum number of deposits structures to retrieve
2140
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2141
+ * @param {string} [params.address] wallet address that made trades
2142
+ * @param {string} [params.subAccountNumber] sub account number
2143
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2144
+ */
2145
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
2146
+ await this.loadMarkets();
2147
+ let currency = undefined;
2148
+ if (code !== undefined) {
2149
+ currency = this.currency(code);
2150
+ }
2151
+ const response = await this.fetchTransactionsHelper(code, since, limit, this.extend(params, { 'methodName': 'fetchDeposits' }));
2152
+ const rows = this.filterBy(response, 'type', 'DEPOSIT');
2153
+ return this.parseTransactions(rows, currency, since, limit);
2154
+ }
2155
+ /**
2156
+ * @method
2157
+ * @name dydx#fetchDepositsWithdrawals
2158
+ * @description fetch history of deposits and withdrawals
2159
+ * @see https://docs.dydx.xyz/indexer-client/http#get-transfers
2160
+ * @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
2161
+ * @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
2162
+ * @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
2163
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2164
+ * @param {string} [params.address] wallet address that made trades
2165
+ * @param {string} [params.subAccountNumber] sub account number
2166
+ * @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
2167
+ */
2168
+ async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
2169
+ await this.loadMarkets();
2170
+ let currency = undefined;
2171
+ if (code !== undefined) {
2172
+ currency = this.currency(code);
2173
+ }
2174
+ const response = await this.fetchTransactionsHelper(code, since, limit, this.extend(params, { 'methodName': 'fetchDepositsWithdrawals' }));
2175
+ const withdrawals = this.filterBy(response, 'type', 'WITHDRAWAL');
2176
+ const deposits = this.filterBy(response, 'type', 'DEPOSIT');
2177
+ const rows = this.arrayConcat(withdrawals, deposits);
2178
+ return this.parseTransactions(rows, currency, since, limit);
2179
+ }
2180
+ async fetchTransactionsHelper(code = undefined, since = undefined, limit = undefined, params = {}) {
2181
+ const methodName = this.safeString(params, 'methodName');
2182
+ params = this.omit(params, 'methodName');
2183
+ let userAddress = undefined;
2184
+ let subAccountNumber = undefined;
2185
+ [userAddress, params] = this.handlePublicAddress(methodName, params);
2186
+ [subAccountNumber, params] = this.handleOptionAndParams(params, methodName, 'subAccountNumber', '0');
2187
+ const request = {
2188
+ 'address': userAddress,
2189
+ 'subaccountNumber': subAccountNumber,
2190
+ };
2191
+ const response = await this.indexerGetTransfers(this.extend(request, params));
2192
+ //
2193
+ // {
2194
+ // "transfers": [
2195
+ // {
2196
+ // "id": "6a6075bc-7183-5fd9-bc9d-894e238aa527",
2197
+ // "sender": {
2198
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
2199
+ // "subaccountNumber": 0
2200
+ // },
2201
+ // "recipient": {
2202
+ // "address": "dydx1slanxj8x9ntk9knwa6cvfv2tzlsq5gk3dshml0",
2203
+ // "subaccountNumber": 1
2204
+ // },
2205
+ // "size": "0.000001",
2206
+ // "createdAt": "2025-07-29T09:43:02.105Z",
2207
+ // "createdAtHeight": "45116125",
2208
+ // "symbol": "USDC",
2209
+ // "type": "TRANSFER_OUT",
2210
+ // "transactionHash": "92B4744BA1B783CF37C79A50BEBC47FFD59C8D5197D62A8485D3DCCE9AF220AF"
2211
+ // }
2212
+ // ]
2213
+ // }
2214
+ //
2215
+ return this.safeList(response, 'transfers', []);
2216
+ }
2217
+ /**
2218
+ * @method
2219
+ * @name dydx#fetchAccounts
2220
+ * @description fetch all the accounts associated with a profile
2221
+ * @see https://docs.dydx.xyz/indexer-client/http#get-subaccounts
2222
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2223
+ * @param {string} [params.address] wallet address that made trades
2224
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
2225
+ */
2226
+ async fetchAccounts(params = {}) {
2227
+ let userAddress = undefined;
2228
+ [userAddress, params] = this.handlePublicAddress('fetchAccounts', params);
2229
+ const request = {
2230
+ 'address': userAddress,
2231
+ };
2232
+ const response = await this.indexerGetAddressesAddress(this.extend(request, params));
2233
+ //
2234
+ // {
2235
+ // "subaccounts": [
2236
+ // {
2237
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
2238
+ // "subaccountNumber": 0,
2239
+ // "equity": "25346.73993597",
2240
+ // "freeCollateral": "24207.8530595294",
2241
+ // "openPerpetualPositions": {
2242
+ // "BTC-USD": {
2243
+ // "market": "BTC-USD",
2244
+ // "status": "OPEN",
2245
+ // "side": "SHORT",
2246
+ // "size": "-0.491",
2247
+ // "maxSize": "-0.009",
2248
+ // "entryPrice": "118703.60811320754716981132",
2249
+ // "exitPrice": "119655.95",
2250
+ // "realizedPnl": "3075.17994830188679245283016",
2251
+ // "unrealizedPnl": "1339.12776155490566037735812",
2252
+ // "createdAt": "2025-07-14T07:53:55.631Z",
2253
+ // "createdAtHeight": "44140908",
2254
+ // "closedAt": null,
2255
+ // "sumOpen": "0.53",
2256
+ // "sumClose": "0.038",
2257
+ // "netFunding": "3111.36894",
2258
+ // "subaccountNumber": 0
2259
+ // }
2260
+ // },
2261
+ // "assetPositions": {
2262
+ // "USDC": {
2263
+ // "size": "82291.083758",
2264
+ // "symbol": "USDC",
2265
+ // "side": "LONG",
2266
+ // "assetId": "0",
2267
+ // "subaccountNumber": 0
2268
+ // }
2269
+ // },
2270
+ // "marginEnabled": true,
2271
+ // "updatedAtHeight": "45234659",
2272
+ // "latestProcessedBlockHeight": "45293477"
2273
+ // }
2274
+ // ]
2275
+ // }
2276
+ //
2277
+ const rows = this.safeList(response, 'subaccounts', []);
2278
+ const result = [];
2279
+ for (let i = 0; i < rows.length; i++) {
2280
+ const account = rows[i];
2281
+ const accountId = this.safeString(account, 'subaccountNumber');
2282
+ result.push({
2283
+ 'id': accountId,
2284
+ 'type': undefined,
2285
+ 'currency': undefined,
2286
+ 'info': account,
2287
+ 'code': undefined,
2288
+ });
2289
+ }
2290
+ return result;
2291
+ }
2292
+ /**
2293
+ * @method
2294
+ * @name dydx#fetchBalance
2295
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
2296
+ * @see https://docs.dydx.xyz/indexer-client/http#get-subaccount
2297
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2298
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
2299
+ */
2300
+ async fetchBalance(params = {}) {
2301
+ await this.loadMarkets();
2302
+ let userAddress = undefined;
2303
+ [userAddress, params] = this.handlePublicAddress('fetchAccounts', params);
2304
+ let subaccountNumber = undefined;
2305
+ [subaccountNumber, params] = this.handleOptionAndParams(params, 'fetchAccounts', 'subaccountNumber', 0);
2306
+ const request = {
2307
+ 'address': userAddress,
2308
+ 'subaccountNumber': subaccountNumber,
2309
+ };
2310
+ const response = await this.indexerGetAddressesAddressSubaccountNumberSubaccountNumber(this.extend(request, params));
2311
+ //
2312
+ // {
2313
+ // "subaccount": {
2314
+ // "address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art",
2315
+ // "subaccountNumber": 0,
2316
+ // "equity": "161451.040416029",
2317
+ // "freeCollateral": "152508.28819133578",
2318
+ // "openPerpetualPositions": {
2319
+ // "ETH-USD": {
2320
+ // "market": "ETH-USD",
2321
+ // "status": "OPEN",
2322
+ // "side": "LONG",
2323
+ // "size": "0.001",
2324
+ // "maxSize": "0.002",
2325
+ // "entryPrice": "3894.7",
2326
+ // "exitPrice": "3864.5",
2327
+ // "realizedPnl": "-0.034847",
2328
+ // "unrealizedPnl": "-0.044675155",
2329
+ // "createdAt": "2025-10-22T08:34:05.883Z",
2330
+ // "createdAtHeight": "52228825",
2331
+ // "closedAt": null,
2332
+ // "sumOpen": "0.002",
2333
+ // "sumClose": "0.001",
2334
+ // "netFunding": "-0.004647",
2335
+ // "subaccountNumber": 0
2336
+ // },
2337
+ // "BTC-USD": {
2338
+ // "market": "BTC-USD",
2339
+ // "status": "OPEN",
2340
+ // "side": "SHORT",
2341
+ // "size": "-4.1368",
2342
+ // "maxSize": "-0.009",
2343
+ // "entryPrice": "112196.87848803433219017636",
2344
+ // "exitPrice": "113885.21872652924977050823",
2345
+ // "realizedPnl": "-15180.426770788459736511679821",
2346
+ // "unrealizedPnl": "17002.285719484425404321566048",
2347
+ // "createdAt": "2025-07-14T07:53:55.631Z",
2348
+ // "createdAtHeight": "44140908",
2349
+ // "closedAt": null,
2350
+ // "sumOpen": "5.3361",
2351
+ // "sumClose": "1.1983",
2352
+ // "netFunding": "-13157.288663",
2353
+ // "subaccountNumber": 0
2354
+ // }
2355
+ // },
2356
+ // "assetPositions": {
2357
+ // "USDC": {
2358
+ // "size": "608580.951601",
2359
+ // "symbol": "USDC",
2360
+ // "side": "LONG",
2361
+ // "assetId": "0",
2362
+ // "subaccountNumber": 0
2363
+ // }
2364
+ // },
2365
+ // "marginEnabled": true,
2366
+ // "updatedAtHeight": "52228833",
2367
+ // "latestProcessedBlockHeight": "52246761"
2368
+ // }
2369
+ // }
2370
+ //
2371
+ const data = this.safeDict(response, 'subaccount');
2372
+ return this.parseBalance(data);
2373
+ }
2374
+ parseBalance(response) {
2375
+ const account = this.account();
2376
+ account['free'] = this.safeString(response, 'freeCollateral');
2377
+ const result = {
2378
+ 'info': response,
2379
+ 'USDC': account,
2380
+ };
2381
+ return this.safeBalance(result);
2382
+ }
2383
+ nonce() {
2384
+ return this.milliseconds() - this.options['timeDifference'];
2385
+ }
2386
+ getWalletAddress() {
2387
+ if (this.walletAddress !== undefined && this.walletAddress !== '') {
2388
+ return this.walletAddress;
2389
+ }
2390
+ const dydxAccount = this.safeDict(this.options, 'dydxAccount');
2391
+ if (dydxAccount !== undefined) {
2392
+ // return dydxAccount;
2393
+ const wallet = this.safeString(dydxAccount, 'address');
2394
+ if (wallet !== undefined) {
2395
+ return wallet;
2396
+ }
2397
+ }
2398
+ throw new ArgumentsRequired(this.id + ' getWalletAddress() requires a wallet address. Set `walletAddress` or `dydxAccount` in exchange options.');
2399
+ }
2400
+ sign(path, section = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
2401
+ const pathWithParams = this.implodeParams(path, params);
2402
+ let url = this.implodeHostname(this.urls['api'][section]);
2403
+ params = this.omit(params, this.extractParams(path));
2404
+ params = this.keysort(params);
2405
+ url += '/' + pathWithParams;
2406
+ if (method === 'GET') {
2407
+ if (Object.keys(params).length) {
2408
+ url += '?' + this.urlencode(params);
2409
+ }
2410
+ }
2411
+ else {
2412
+ body = this.json(params);
2413
+ headers = {
2414
+ 'Content-type': 'application/json',
2415
+ };
2416
+ }
2417
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
2418
+ }
2419
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
2420
+ if (!response) {
2421
+ return undefined; // fallback to default error handler
2422
+ }
2423
+ //
2424
+ // abci response
2425
+ // { "result": { "code": 0 } }
2426
+ //
2427
+ // rest response
2428
+ // { "code": 123 }
2429
+ //
2430
+ const result = this.safeDict(response, 'result');
2431
+ let errorCode = this.safeString(result, 'code');
2432
+ if (!errorCode) {
2433
+ errorCode = this.safeString(response, 'code');
2434
+ }
2435
+ if (errorCode) {
2436
+ const errorCodeNum = this.parseToNumeric(errorCode);
2437
+ if (errorCodeNum > 0) {
2438
+ const feedback = this.id + ' ' + this.json(response);
2439
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
2440
+ this.throwBroadlyMatchedException(this.exceptions['broad'], body, feedback);
2441
+ throw new ExchangeError(feedback);
2442
+ }
2443
+ }
2444
+ return undefined;
2445
+ }
2446
+ setSandboxMode(enable) {
2447
+ super.setSandboxMode(enable);
2448
+ // rewrite testnet parameters
2449
+ this.options['chainName'] = 'dydx-testnet-4';
2450
+ this.options['chainId'] = 11155111;
2451
+ this.options['feeDenom']['CHAINTOKEN_DENOM'] = 'adv4tnt';
2452
+ }
2453
+ }