ddx-python 1.0.4__cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

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 (106) hide show
  1. ddx/.gitignore +1 -0
  2. ddx/__init__.py +58 -0
  3. ddx/_rust/__init__.pyi +2685 -0
  4. ddx/_rust/common/__init__.pyi +17 -0
  5. ddx/_rust/common/accounting.pyi +6 -0
  6. ddx/_rust/common/enums.pyi +3 -0
  7. ddx/_rust/common/requests/__init__.pyi +23 -0
  8. ddx/_rust/common/requests/intents.pyi +19 -0
  9. ddx/_rust/common/specs.pyi +17 -0
  10. ddx/_rust/common/state/__init__.pyi +41 -0
  11. ddx/_rust/common/state/keys.pyi +29 -0
  12. ddx/_rust/common/transactions.pyi +7 -0
  13. ddx/_rust/decimal.pyi +3 -0
  14. ddx/_rust/h256.pyi +3 -0
  15. ddx/_rust.abi3.so +0 -0
  16. ddx/app_config/ethereum/addresses.json +526 -0
  17. ddx/auditor/README.md +32 -0
  18. ddx/auditor/__init__.py +0 -0
  19. ddx/auditor/auditor_driver.py +1043 -0
  20. ddx/auditor/websocket_message.py +54 -0
  21. ddx/common/__init__.py +0 -0
  22. ddx/common/epoch_params.py +28 -0
  23. ddx/common/fill_context.py +141 -0
  24. ddx/common/logging.py +184 -0
  25. ddx/common/market_aware_account.py +259 -0
  26. ddx/common/market_specs.py +64 -0
  27. ddx/common/trade_mining_params.py +19 -0
  28. ddx/common/transaction_utils.py +85 -0
  29. ddx/common/transactions/__init__.py +0 -0
  30. ddx/common/transactions/advance_epoch.py +91 -0
  31. ddx/common/transactions/advance_settlement_epoch.py +63 -0
  32. ddx/common/transactions/all_price_checkpoints.py +84 -0
  33. ddx/common/transactions/cancel.py +76 -0
  34. ddx/common/transactions/cancel_all.py +88 -0
  35. ddx/common/transactions/complete_fill.py +103 -0
  36. ddx/common/transactions/disaster_recovery.py +96 -0
  37. ddx/common/transactions/event.py +48 -0
  38. ddx/common/transactions/fee_distribution.py +119 -0
  39. ddx/common/transactions/funding.py +292 -0
  40. ddx/common/transactions/futures_expiry.py +123 -0
  41. ddx/common/transactions/genesis.py +108 -0
  42. ddx/common/transactions/inner/__init__.py +0 -0
  43. ddx/common/transactions/inner/adl_outcome.py +25 -0
  44. ddx/common/transactions/inner/fill.py +232 -0
  45. ddx/common/transactions/inner/liquidated_position.py +41 -0
  46. ddx/common/transactions/inner/liquidation_entry.py +41 -0
  47. ddx/common/transactions/inner/liquidation_fill.py +118 -0
  48. ddx/common/transactions/inner/outcome.py +32 -0
  49. ddx/common/transactions/inner/trade_fill.py +292 -0
  50. ddx/common/transactions/insurance_fund_update.py +138 -0
  51. ddx/common/transactions/insurance_fund_withdraw.py +100 -0
  52. ddx/common/transactions/liquidation.py +353 -0
  53. ddx/common/transactions/partial_fill.py +125 -0
  54. ddx/common/transactions/pnl_realization.py +120 -0
  55. ddx/common/transactions/post.py +72 -0
  56. ddx/common/transactions/post_order.py +95 -0
  57. ddx/common/transactions/price_checkpoint.py +97 -0
  58. ddx/common/transactions/signer_registered.py +62 -0
  59. ddx/common/transactions/specs_update.py +61 -0
  60. ddx/common/transactions/strategy_update.py +158 -0
  61. ddx/common/transactions/tradable_product_update.py +98 -0
  62. ddx/common/transactions/trade_mining.py +147 -0
  63. ddx/common/transactions/trader_update.py +131 -0
  64. ddx/common/transactions/withdraw.py +90 -0
  65. ddx/common/transactions/withdraw_ddx.py +74 -0
  66. ddx/common/utils.py +176 -0
  67. ddx/config.py +17 -0
  68. ddx/derivadex_client.py +270 -0
  69. ddx/models/__init__.py +0 -0
  70. ddx/models/base.py +132 -0
  71. ddx/py.typed +0 -0
  72. ddx/realtime_client/__init__.py +2 -0
  73. ddx/realtime_client/config.py +2 -0
  74. ddx/realtime_client/models/__init__.py +611 -0
  75. ddx/realtime_client/realtime_client.py +646 -0
  76. ddx/rest_client/__init__.py +0 -0
  77. ddx/rest_client/clients/__init__.py +0 -0
  78. ddx/rest_client/clients/base_client.py +60 -0
  79. ddx/rest_client/clients/market_client.py +1243 -0
  80. ddx/rest_client/clients/on_chain_client.py +439 -0
  81. ddx/rest_client/clients/signed_client.py +292 -0
  82. ddx/rest_client/clients/system_client.py +843 -0
  83. ddx/rest_client/clients/trade_client.py +357 -0
  84. ddx/rest_client/constants/__init__.py +0 -0
  85. ddx/rest_client/constants/endpoints.py +66 -0
  86. ddx/rest_client/contracts/__init__.py +0 -0
  87. ddx/rest_client/contracts/checkpoint/__init__.py +560 -0
  88. ddx/rest_client/contracts/ddx/__init__.py +1949 -0
  89. ddx/rest_client/contracts/dummy_token/__init__.py +1014 -0
  90. ddx/rest_client/contracts/i_collateral/__init__.py +1414 -0
  91. ddx/rest_client/contracts/i_stake/__init__.py +696 -0
  92. ddx/rest_client/exceptions/__init__.py +0 -0
  93. ddx/rest_client/exceptions/exceptions.py +32 -0
  94. ddx/rest_client/http/__init__.py +0 -0
  95. ddx/rest_client/http/http_client.py +336 -0
  96. ddx/rest_client/models/__init__.py +0 -0
  97. ddx/rest_client/models/market.py +693 -0
  98. ddx/rest_client/models/signed.py +61 -0
  99. ddx/rest_client/models/system.py +311 -0
  100. ddx/rest_client/models/trade.py +185 -0
  101. ddx/rest_client/utils/__init__.py +0 -0
  102. ddx/rest_client/utils/encryption_utils.py +26 -0
  103. ddx/utils/__init__.py +0 -0
  104. ddx_python-1.0.4.dist-info/METADATA +63 -0
  105. ddx_python-1.0.4.dist-info/RECORD +106 -0
  106. ddx_python-1.0.4.dist-info/WHEEL +5 -0
@@ -0,0 +1,270 @@
1
+ """
2
+ DerivaDEX Client
3
+ """
4
+
5
+ from typing import Optional
6
+ from web3 import Web3
7
+ from web3.middleware import geth_poa_middleware
8
+
9
+ from ddx.realtime_client import RealtimeClient
10
+ from ddx.rest_client.clients.market_client import MarketClient
11
+ from ddx.rest_client.clients.on_chain_client import OnChainClient
12
+ from ddx.rest_client.clients.signed_client import SignedClient
13
+ from ddx.rest_client.clients.system_client import SystemClient
14
+ from ddx.rest_client.clients.trade_client import TradeClient
15
+ from ddx.rest_client.http.http_client import HTTPClient
16
+
17
+
18
+ class DerivaDEXClient:
19
+ """
20
+ Main client for interacting with the DerivaDEX API.
21
+
22
+ This client provides access to all DerivaDEX API endpoints through
23
+ various client objects and supports both REST and WebSocket APIs.
24
+ It can be used as an async context manager to ensure proper client cleanup.
25
+
26
+ Attributes
27
+ ----------
28
+ market : MarketClient
29
+ Access to market operations
30
+ on_chain : OnChainClient
31
+ Access to on-chain operations
32
+ signed : SignedClient
33
+ Access to signed operations
34
+ system : SystemClient
35
+ Access to system operations
36
+ trade : TradeClient
37
+ Access to trade operations
38
+ web3_account : Account
39
+ The Web3 account used for signing transactions
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ base_url: str,
45
+ ws_url: str,
46
+ rpc_url: str,
47
+ contract_deployment: str,
48
+ private_key: Optional[str] = None,
49
+ mnemonic: Optional[str] = None,
50
+ timeout: int = 30,
51
+ http_max_connections: int = 100,
52
+ http_max_keepalive: int = 20,
53
+ keepalive_expiry: int = 5,
54
+ ) -> None:
55
+ """
56
+ Initialize the client.
57
+
58
+ Parameters
59
+ ----------
60
+ base_url : str
61
+ Base URL for webserver
62
+ ws_url : str
63
+ WebSocket URL for real-time updates
64
+ rpc_url : str
65
+ RPC URL for webserver
66
+ contract_deployment : str
67
+ Type of contract deployment (e.g. "mainnet")
68
+ private_key : Optional[str]
69
+ Ethereum private key for user
70
+ mnemonic : Optional[str]
71
+ Ethereum mnemonic for user
72
+ timeout : int, default=30
73
+ Timeout in seconds for HTTP requests
74
+ http_max_connections : int, default=100
75
+ Max concurrent connections allowed for the HTTP client
76
+ http_max_keepalive : int, default=20
77
+ Max allowable keep-alive connections, None means always allow
78
+ keepalive_expiry: int, default=5
79
+ Time in seconds to keep HTTP connection alive. None means connection never expires
80
+
81
+ Raises
82
+ ------
83
+ ValueError
84
+ If neither private_key nor mnemonic is provided
85
+ """
86
+
87
+ if not private_key and not mnemonic:
88
+ raise ValueError("Either private_key or mnemonic must be provided")
89
+
90
+ self._base_url = base_url
91
+ self._ws_url = ws_url
92
+
93
+ # Initialize HTTP client
94
+ self._http = HTTPClient(timeout, max_connections=http_max_connections, max_keepalive=http_max_keepalive, keepalive_expiry=keepalive_expiry)
95
+
96
+ self._contract_deployment = contract_deployment
97
+
98
+ # These will be initialized when needed
99
+ self._chain_id: Optional[int] = None
100
+ self._verifying_contract: Optional[str] = None
101
+
102
+ # Initialize web3 service
103
+ self.w3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 60}))
104
+
105
+ if contract_deployment == "geth":
106
+ self.w3.middleware_onion.inject(geth_poa_middleware, layer=0)
107
+
108
+ # Initialize web3 account from private key or mnemonic
109
+ if private_key is not None:
110
+ self.web3_account = self.w3.eth.account.from_key(private_key)
111
+ else:
112
+ self.w3.eth.account.enable_unaudited_hdwallet_features()
113
+ self.web3_account = self.w3.eth.account.from_mnemonic(mnemonic)
114
+
115
+ # Set default account for send transactions
116
+ self.w3.eth.defaultAccount = self.web3_account.address
117
+
118
+ # Initialize clients (lazy loading)
119
+ self._market: Optional[MarketClient] = None
120
+ self._on_chain: Optional[OnChainClient] = None
121
+ self._signed: Optional[SignedClient] = None
122
+ self._system: Optional[SystemClient] = None
123
+ self._trade: Optional[TradeClient] = None
124
+
125
+ async def __aenter__(self) -> "DerivaDEXClient":
126
+ await self._http.__aenter__()
127
+
128
+ # Get deployment configuration
129
+ deployment_info = await self.system.get_deployment_info(
130
+ self._contract_deployment
131
+ )
132
+ self._chain_id = deployment_info.chain_id
133
+ self._verifying_contract = deployment_info.addresses.derivadex_address
134
+
135
+ # Propagate chain and verifying contract to already-initialized sub-clients (if any)
136
+ if self._on_chain is not None:
137
+ self._on_chain._verifying_contract = self._verifying_contract # type: ignore[attr-defined]
138
+ if self._signed is not None:
139
+ self._signed._chain_id = self._chain_id # type: ignore[attr-defined]
140
+ self._signed._verifying_contract = self._verifying_contract # type: ignore[attr-defined]
141
+
142
+ # Initialize and start WebSocket client
143
+ # We do this here rather than lazy loading because we want
144
+ # to ensure the connection is established when using the context manager
145
+ self._ws = RealtimeClient(self._ws_url)
146
+ await self._ws.connect()
147
+
148
+ return self
149
+
150
+ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
151
+ # Stop WebSocket client if it was started
152
+ if self._ws is not None:
153
+ await self._ws.disconnect()
154
+ await self._http.__aexit__(exc_type, exc_val, exc_tb)
155
+
156
+ @property
157
+ def ws(self) -> RealtimeClient:
158
+ """
159
+ Access WebSocket functionality.
160
+
161
+ Returns
162
+ -------
163
+ RealtimeClient
164
+ The WebSocket Realtime API client instance
165
+
166
+ Raises
167
+ ------
168
+ RuntimeError
169
+ If accessed outside of context manager
170
+ """
171
+
172
+ if not hasattr(self, "_ws"):
173
+ raise RuntimeError("WebSocket client must be used within context manager")
174
+
175
+ return self._ws
176
+
177
+ @property
178
+ def market(self) -> MarketClient:
179
+ """
180
+ Access to market operations.
181
+
182
+ Returns
183
+ -------
184
+ MarketClient
185
+ The market client instance, initialized on first access
186
+ """
187
+
188
+ if self._market is None:
189
+ self._market = MarketClient(self._http, self._base_url)
190
+
191
+ return self._market
192
+
193
+ @property
194
+ def on_chain(self) -> OnChainClient:
195
+ """
196
+ Access on-chain operations.
197
+
198
+ Returns
199
+ -------
200
+ OnChainClient
201
+ The on-chain client instance, initialized on first access
202
+ """
203
+
204
+ if self._on_chain is None:
205
+ self._on_chain = OnChainClient(
206
+ self._http,
207
+ self._base_url,
208
+ self.web3_account,
209
+ self.w3,
210
+ self._verifying_contract,
211
+ )
212
+
213
+ return self._on_chain
214
+
215
+ @property
216
+ def signed(self) -> SignedClient:
217
+ """
218
+ Access to signed operations
219
+
220
+ Returns
221
+ -------
222
+ SignedClient
223
+ The signed client instance, initialized on first access
224
+ """
225
+
226
+ if self._signed is None:
227
+ self._signed = SignedClient(
228
+ self._http,
229
+ self._base_url,
230
+ self.web3_account,
231
+ self._chain_id,
232
+ self._verifying_contract,
233
+ )
234
+
235
+ return self._signed
236
+
237
+ @property
238
+ def system(self) -> SystemClient:
239
+ """
240
+ Access to system operations.
241
+
242
+ Returns
243
+ -------
244
+ SystemClient
245
+ The system client instance, initialized on first access
246
+ """
247
+
248
+ if self._system is None:
249
+ self._system = SystemClient(self._http, self._base_url)
250
+
251
+ return self._system
252
+
253
+ @property
254
+ def trade(self) -> TradeClient:
255
+ """
256
+ Access to trade operations
257
+
258
+ Returns
259
+ -------
260
+ TradeClient
261
+ The trade client instance, initialized on first access
262
+ """
263
+
264
+ if self._trade is None:
265
+ self._trade = TradeClient(
266
+ self._http,
267
+ self._base_url,
268
+ )
269
+
270
+ return self._trade
ddx/models/__init__.py ADDED
File without changes
ddx/models/base.py ADDED
@@ -0,0 +1,132 @@
1
+ """
2
+ Shared base Pydantic model enabling unified camel-case behaviour for
3
+ all realtime- and rest-client models.
4
+
5
+ Import `CamelModel` and inherit from it instead of `pydantic.BaseModel`.
6
+ """
7
+
8
+ from pydantic import BaseModel, ConfigDict
9
+ from pydantic.alias_generators import to_camel
10
+
11
+ from enum import Enum
12
+ from pydantic.types import StringConstraints
13
+ from typing import Annotated
14
+
15
+ from ddx._rust.common.enums import (
16
+ PositionSide as RustPositionSide,
17
+ OrderSide as RustOrderSide,
18
+ )
19
+ from ddx._rust.decimal import Decimal
20
+
21
+
22
+ class CamelModel(BaseModel):
23
+ model_config = ConfigDict(
24
+ alias_generator=to_camel,
25
+ validate_by_alias=True,
26
+ validate_by_name=True,
27
+ serialize_by_alias=True,
28
+ extra="forbid",
29
+ )
30
+
31
+
32
+ def validate_decimal_str(value: str, field_name: str, nonnegative: bool = True) -> str:
33
+ try:
34
+ d = Decimal(value)
35
+ except Exception:
36
+ raise ValueError(f"Invalid decimal value for {field_name}: {value}")
37
+ if nonnegative and d < 0:
38
+ raise ValueError(f"Value for {field_name} must be non-negative: {value}")
39
+ return value
40
+
41
+
42
+ HexStr = Annotated[str, StringConstraints(pattern=r"^0x[0-9A-Fa-f]+$")]
43
+
44
+
45
+ class TradeSide(int, Enum):
46
+ BID = 0
47
+ ASK = 1
48
+
49
+ def raw_order_side(self) -> RustOrderSide:
50
+ if self == TradeSide.BID:
51
+ return RustOrderSide.Bid
52
+ else:
53
+ return RustOrderSide.Ask
54
+
55
+
56
+ class OrderType(int, Enum):
57
+ LIMIT = 0
58
+ MARKET = 1
59
+ STOP = 2
60
+ LIMIT_POST_ONLY = 3
61
+
62
+
63
+ class OrderRejection(int, Enum):
64
+ SELF_MATCH = 0
65
+ SOLVENCY_GUARD = 1
66
+ MAX_TAKER_PRICE_DEVIATION = 2
67
+ NO_LIQUIDITY = 3
68
+ INVALID_STRATEGY = 4
69
+ POST_ONLY_VIOLATION = 5
70
+
71
+
72
+ class CancelRejection(int, Enum):
73
+ INVALID_ORDER = 0
74
+
75
+
76
+ class OrderUpdateReason(int, Enum):
77
+ POST = 0
78
+ TRADE = 1
79
+ LIQUIDATION = 2
80
+ CANCELLATION = 3
81
+ ORDER_REJECTION = 4
82
+ CANCEL_REJECTION = 5
83
+
84
+
85
+ class WithdrawRejection(int, Enum):
86
+ INVALID_STRATEGY = 0
87
+ INVALID_INSURANCE_FUND_CONTRIBUTION = 1
88
+ MAX_WITHDRAWAL_AMOUNT = 2
89
+ INSUFFICIENT_INSURANCE_FUND_CONTRIBUTION = 3
90
+ INSUFFICIENT_REMAINING_INSURANCE_FUND = 4
91
+
92
+
93
+ class StrategyUpdateReason(int, Enum):
94
+ DEPOSIT = 0
95
+ WITHDRAW = 1
96
+ WITHDRAW_INTENT = 2
97
+ FUNDING_PAYMENT = 3
98
+ PNL_SETTLEMENT = 4
99
+ TRADE = 5
100
+ FEE = 6
101
+ LIQUIDATION = 7
102
+ ADL = 8
103
+ WITHDRAW_REJECTION = 9
104
+
105
+
106
+ class WithdrawDDXRejection(int, Enum):
107
+ INVALID_TRADER = 0
108
+ INSUFFICIENT_DDX_BALANCE = 1
109
+
110
+
111
+ class TraderUpdateReason(int, Enum):
112
+ DEPOSIT_DDX = 0
113
+ WITHDRAW_DDX = 1
114
+ WITHDRAW_DDX_INTENT = 2
115
+ TRADE_MINING_REWARD = 3
116
+ PROFILE_UPDATE = 4
117
+ FEE_DISTRIBUTION = 5
118
+ ADMISSION = 6
119
+ DENIAL = 7
120
+ FEE = 8
121
+ WITHDRAW_DDX_REJECTION = 9
122
+
123
+
124
+ class PositionSide(int, Enum):
125
+ LONG = 1
126
+ SHORT = 2
127
+
128
+ def raw_position_side(self) -> RustPositionSide:
129
+ if self == PositionSide.LONG:
130
+ return RustPositionSide.Long
131
+ else:
132
+ return RustPositionSide.Short
ddx/py.typed ADDED
File without changes
@@ -0,0 +1,2 @@
1
+ from .realtime_client import RealtimeClient
2
+ from .models import *
@@ -0,0 +1,2 @@
1
+ DEFAULT_RETRY_DELAY = 1
2
+ MAX_RETRY_DELAY = 60