silhouette-python-sdk 0.2.0__tar.gz → 0.3.0__tar.gz

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 (143) hide show
  1. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/PKG-INFO +42 -15
  2. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/README.md +39 -12
  3. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/pyproject.toml +18 -10
  4. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/api/__init__.py +6 -1
  5. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/api/auth.py +43 -45
  6. silhouette_python_sdk-0.3.0/silhouette/api/base_model.py +11 -0
  7. silhouette_python_sdk-0.3.0/silhouette/api/client.py +1330 -0
  8. silhouette_python_sdk-0.3.0/silhouette/api/generated/__init__.py +2268 -0
  9. silhouette_python_sdk-0.3.0/silhouette/api/rfq_types.py +15 -0
  10. silhouette_python_sdk-0.3.0/silhouette/api/v1/__init__.py +1 -0
  11. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/__init__.py +1 -1
  12. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/exchange.py +5 -13
  13. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/twap/USAGE_GUIDE.md +4 -8
  14. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/twap/__init__.py +1 -6
  15. silhouette_python_sdk-0.3.0/silhouette/twap/authenticated_client.py +114 -0
  16. silhouette_python_sdk-0.3.0/silhouette/twap/base_model.py +11 -0
  17. silhouette_python_sdk-0.3.0/silhouette/twap/client.py +171 -0
  18. silhouette_python_sdk-0.3.0/silhouette/twap/generated/__init__.py +56 -0
  19. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/twap/interfaces.py +8 -27
  20. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/utils/constants.py +1 -1
  21. silhouette_python_sdk-0.2.0/generated/.gitkeep +0 -3
  22. silhouette_python_sdk-0.2.0/generated/__init__.py +0 -1
  23. silhouette_python_sdk-0.2.0/generated/twap_client/.gitignore +0 -23
  24. silhouette_python_sdk-0.2.0/generated/twap_client/README.md +0 -124
  25. silhouette_python_sdk-0.2.0/generated/twap_client/pyproject.toml +0 -26
  26. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/__init__.py +0 -8
  27. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/__init__.py +0 -1
  28. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/auth/__init__.py +0 -1
  29. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/auth/auth_controller_register_v_0.py +0 -156
  30. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/auth/auth_controller_verify_v_0.py +0 -123
  31. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/hyperliquid/__init__.py +0 -1
  32. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/hyperliquid/hyperliquid_controller_get_exchange_status_v_0.py +0 -125
  33. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/hyperliquid/hyperliquid_controller_l_2_book_v_0.py +0 -123
  34. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/__init__.py +0 -1
  35. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_cancel_order_v_0.py +0 -147
  36. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_create_twap_order_v_0.py +0 -156
  37. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_get_orders_by_user_v_0.py +0 -130
  38. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_get_task_status_v_0.py +0 -147
  39. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_get_twap_order_v_0.py +0 -147
  40. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_pause_order_v_0.py +0 -141
  41. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/orders/orders_controller_resume_order_v_0.py +0 -141
  42. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/system/__init__.py +0 -1
  43. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/api/system/system_controller_get_health_check_v_0.py +0 -123
  44. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/client.py +0 -268
  45. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/errors.py +0 -16
  46. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/__init__.py +0 -37
  47. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/auth_controller_register_v0_response_200.py +0 -44
  48. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/auth_controller_verify_v0_response_200.py +0 -77
  49. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/create_twap_order_dto.py +0 -175
  50. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/create_twap_order_dto_market_type.py +0 -9
  51. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/create_twap_order_dto_order_intent.py +0 -9
  52. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/create_twap_order_dto_order_side.py +0 -9
  53. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/hyperliquid_controller_get_exchange_status_v0_response_200.py +0 -44
  54. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/hyperliquid_controller_l2_book_v0_response_200.py +0 -44
  55. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/orders_controller_cancel_order_v0_response_200.py +0 -44
  56. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/orders_controller_create_twap_order_v0_response_201.py +0 -44
  57. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/orders_controller_get_orders_by_user_v0_response_200_item.py +0 -44
  58. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/orders_controller_get_task_status_v0_response_200.py +0 -44
  59. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/orders_controller_get_twap_order_v0_response_200.py +0 -44
  60. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/register_api_key_dto.py +0 -67
  61. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/models/system_controller_get_health_check_v0_response_200.py +0 -44
  62. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/py.typed +0 -1
  63. silhouette_python_sdk-0.2.0/generated/twap_client/silhouette_scheduler_api_reference_client/types.py +0 -54
  64. silhouette_python_sdk-0.2.0/silhouette/abi/silhouette.json +0 -1
  65. silhouette_python_sdk-0.2.0/silhouette/api/client.py +0 -695
  66. silhouette_python_sdk-0.2.0/silhouette/api/generated/__init__.py +0 -118
  67. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/__init__.py +0 -122
  68. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/api_error.py +0 -97
  69. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/auth_required_event.py +0 -87
  70. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/balance_event.py +0 -99
  71. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/batch_get_delegated_orders_request.py +0 -93
  72. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/batch_get_delegated_orders_response.py +0 -102
  73. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/cancel_order_request.py +0 -94
  74. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/cancel_order_response.py +0 -102
  75. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/create_order_request.py +0 -152
  76. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/create_order_response.py +0 -102
  77. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/events_get401_response.py +0 -85
  78. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/events_get429_response.py +0 -85
  79. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/events_get503_response.py +0 -85
  80. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_balances_request.py +0 -92
  81. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_balances_response.py +0 -108
  82. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_balances_response_balances_inner.py +0 -97
  83. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_delegated_order_request.py +0 -93
  84. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_delegated_order_response.py +0 -100
  85. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_features_request.py +0 -92
  86. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_features_response.py +0 -98
  87. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_info_request.py +0 -92
  88. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_info_response.py +0 -98
  89. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_ready_request.py +0 -92
  90. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_ready_response.py +0 -98
  91. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_request.py +0 -92
  92. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_health_response.py +0 -100
  93. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_history_request.py +0 -97
  94. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_history_response.py +0 -98
  95. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_hypercore_trading_info_request.py +0 -92
  96. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_hypercore_trading_info_response.py +0 -98
  97. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_l1_balances_request.py +0 -92
  98. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_l1_balances_response.py +0 -98
  99. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_stats_request.py +0 -92
  100. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_stats_response.py +0 -98
  101. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_user_orders_request.py +0 -104
  102. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_user_orders_response.py +0 -108
  103. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_user_orders_response_orders_inner.py +0 -153
  104. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_user_withdrawals_request.py +0 -92
  105. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_user_withdrawals_response.py +0 -108
  106. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_withdrawal_status_request.py +0 -94
  107. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_withdrawal_status_response.py +0 -104
  108. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/get_withdrawal_status_response_withdrawal.py +0 -118
  109. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/heartbeat_event.py +0 -85
  110. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/initiate_withdrawal_request.py +0 -111
  111. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/initiate_withdrawal_response.py +0 -102
  112. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/list_delegated_orders_request.py +0 -97
  113. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/list_delegated_orders_response.py +0 -102
  114. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/login_request.py +0 -96
  115. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/login_response.py +0 -100
  116. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/match_event.py +0 -107
  117. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/order_event.py +0 -138
  118. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/ping_get200_response.py +0 -97
  119. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/refund_event.py +0 -102
  120. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/response_metadata.py +0 -98
  121. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/v0_get200_response.py +0 -91
  122. silhouette_python_sdk-0.2.0/silhouette/api/generated/models/withdrawal_event.py +0 -112
  123. silhouette_python_sdk-0.2.0/silhouette/twap/auth/__init__.py +0 -41
  124. silhouette_python_sdk-0.2.0/silhouette/twap/auth/exceptions.py +0 -160
  125. silhouette_python_sdk-0.2.0/silhouette/twap/auth/jwt_service.py +0 -330
  126. silhouette_python_sdk-0.2.0/silhouette/twap/auth/jwt_signer.py +0 -215
  127. silhouette_python_sdk-0.2.0/silhouette/twap/auth/utils.py +0 -125
  128. silhouette_python_sdk-0.2.0/silhouette/twap/authenticated_client.py +0 -320
  129. silhouette_python_sdk-0.2.0/silhouette/twap/client.py +0 -1024
  130. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/LICENSE.md +0 -0
  131. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/__init__.py +0 -0
  132. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/api.py +0 -0
  133. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/info.py +0 -0
  134. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/utils/__init__.py +0 -0
  135. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/utils/constants.py +0 -0
  136. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/utils/error.py +0 -0
  137. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/utils/signing.py +0 -0
  138. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/utils/types.py +0 -0
  139. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/hyperliquid/websocket_manager.py +0 -0
  140. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/py.typed +0 -0
  141. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/utils/__init__.py +0 -0
  142. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/utils/conversions.py +0 -0
  143. {silhouette_python_sdk-0.2.0 → silhouette_python_sdk-0.3.0}/silhouette/utils/types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: silhouette-python-sdk
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Python SDK for trading on Silhouette - the shield exchange on Hyperliquid
5
5
  License: MIT
6
6
  Keywords: silhouette,trading,privacy,exchange,hyperliquid,defi,crypto,sdk
@@ -17,15 +17,15 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
- Requires-Dist: attrs (>=22.2)
21
20
  Requires-Dist: cryptography (>=46,<47)
22
21
  Requires-Dist: httpx (>=0.23,<0.29)
23
22
  Requires-Dist: hyperliquid-python-sdk (>=0.21,<1)
23
+ Requires-Dist: pydantic (>=2.0,<3)
24
24
  Requires-Dist: pyjwt (>=2.10,<3)
25
- Requires-Dist: python-dateutil (>=2.8,<3)
26
25
  Requires-Dist: requests (>=2.32,<3)
27
26
  Requires-Dist: siwe (>=4.4,<5)
28
27
  Requires-Dist: typing_extensions (>=4.9) ; python_version < "3.11"
28
+ Requires-Dist: websockets (>=15,<16)
29
29
  Project-URL: Homepage, https://github.com/silhouette-exchange/silhouette-python-sdk
30
30
  Project-URL: Repository, https://github.com/silhouette-exchange/silhouette-python-sdk
31
31
  Description-Content-Type: text/markdown
@@ -105,9 +105,9 @@ print(f"Balances: {balances_response['balances']}")
105
105
  # Place an order (returns dict, no need to import models)
106
106
  order = client.order.create_order(
107
107
  side="buy",
108
- orderType="limit",
109
- baseToken="HYPE",
110
- quoteToken="USDC",
108
+ order_type="limit",
109
+ base_token="HYPE",
110
+ quote_token="USDC",
111
111
  amount="1.0",
112
112
  price="0.001",
113
113
  )
@@ -129,7 +129,7 @@ The enhanced Hyperliquid SDK includes these convenience methods:
129
129
  - `await_withdrawal_completion(wallet_address: str, pre_withdrawal_balance: float, token_symbol: str, timeout: int) -> bool` - Poll balance until withdrawal completes
130
130
 
131
131
  **Exchange class:**
132
- - `deposit_to_silhouette(contract_address: str, token_symbol: str, amount: str, converter: TokenConverter) -> dict` - Deposit tokens from Hyperliquid to Silhouette contract
132
+ - `deposit_to_silhouette(silhouette_address: str, token_symbol: str, amount: str, converter: TokenConverter) -> dict` - Deposit tokens from Hyperliquid to Silhouette contract
133
133
 
134
134
  All other Hyperliquid SDK methods work exactly as documented in the [official Hyperliquid SDK](https://github.com/hyperliquid-dex/hyperliquid-python-sdk).
135
135
 
@@ -141,6 +141,7 @@ The `SilhouetteApiClient` provides access to the Silhouette shielded exchange:
141
141
  - **No model imports needed**: Pydantic models are used internally for validation, but you work with simple dicts
142
142
  - **User operations**: Balances, withdrawal initiation
143
143
  - **Order management**: Create, cancel, query orders
144
+ - **Delegated orders**: List, get, and batch retrieve delegated orders
144
145
  - **Trade execution**: Privacy-preserving order execution
145
146
  - **Automatic authentication**: SIWE-based session management with automatic token refresh
146
147
 
@@ -154,6 +155,29 @@ response = client.user.get_balances()
154
155
  # }
155
156
  ```
156
157
 
158
+ ### Delegated orders
159
+
160
+ Delegated orders are orders placed on Hyperliquid by Silhouette on behalf of a trader. Query them using the `delegated_order` operations:
161
+
162
+ ```python
163
+ # List delegated orders with optional filters
164
+ orders = client.delegated_order.list_delegated_orders(
165
+ status="open",
166
+ limit=50,
167
+ )
168
+ print(f"Found {len(orders['orders'])} orders")
169
+
170
+ # Get a single order by ID
171
+ order = client.delegated_order.get_delegated_order("order-id-here")
172
+ print(f"Order status: {order['order']['status']}")
173
+
174
+ # Batch retrieve multiple orders
175
+ batch = client.delegated_order.batch_get_delegated_orders(
176
+ ["order-1", "order-2", "order-3"]
177
+ )
178
+ print(f"Found: {len(batch['orders'])}, Not found: {batch['notFound']}")
179
+ ```
180
+
157
181
  ## API Design
158
182
 
159
183
  ### Why Dicts Instead of Models?
@@ -173,21 +197,24 @@ The SDK uses a hybrid approach for optimal developer experience:
173
197
 
174
198
  ### Regenerating models
175
199
 
176
- Models are generated from the OpenAPI specification. When the Silhouette API changes, regenerate the models to stay in sync:
200
+ Models are generated from the OpenAPI specifications using `datamodel-code-generator`. When the Silhouette API changes, regenerate the models to stay in sync:
177
201
 
178
202
  ```bash
179
- # Fetch spec from local Heimdall and regenerate models
180
- ./scripts/regenerate-models.sh
203
+ # Generate from committed specs
204
+ make generate
181
205
 
182
- # Or specify a custom URL
183
- ./scripts/regenerate-models.sh https://api.silhouette.exchange
206
+ # Or fetch fresh specs and regenerate in one step
207
+ make regenerate
184
208
 
185
- # Then run tests to catch any breaking changes
209
+ # Fetch from a specific URL
210
+ make fetch-heimdall-v0-spec URL=https://api-staging.silhouette.exchange
211
+ make fetch-heimdall-v1-spec URL=https://api-staging.silhouette.exchange
212
+ make generate
213
+
214
+ # Run tests to catch any breaking changes
186
215
  make test
187
216
  ```
188
217
 
189
- Requires `curl`, `jq`, and `openapi-generator-cli` to be installed.
190
-
191
218
  ## Configuration
192
219
 
193
220
  Create `examples/config.json` from the example template:
@@ -73,9 +73,9 @@ print(f"Balances: {balances_response['balances']}")
73
73
  # Place an order (returns dict, no need to import models)
74
74
  order = client.order.create_order(
75
75
  side="buy",
76
- orderType="limit",
77
- baseToken="HYPE",
78
- quoteToken="USDC",
76
+ order_type="limit",
77
+ base_token="HYPE",
78
+ quote_token="USDC",
79
79
  amount="1.0",
80
80
  price="0.001",
81
81
  )
@@ -97,7 +97,7 @@ The enhanced Hyperliquid SDK includes these convenience methods:
97
97
  - `await_withdrawal_completion(wallet_address: str, pre_withdrawal_balance: float, token_symbol: str, timeout: int) -> bool` - Poll balance until withdrawal completes
98
98
 
99
99
  **Exchange class:**
100
- - `deposit_to_silhouette(contract_address: str, token_symbol: str, amount: str, converter: TokenConverter) -> dict` - Deposit tokens from Hyperliquid to Silhouette contract
100
+ - `deposit_to_silhouette(silhouette_address: str, token_symbol: str, amount: str, converter: TokenConverter) -> dict` - Deposit tokens from Hyperliquid to Silhouette contract
101
101
 
102
102
  All other Hyperliquid SDK methods work exactly as documented in the [official Hyperliquid SDK](https://github.com/hyperliquid-dex/hyperliquid-python-sdk).
103
103
 
@@ -109,6 +109,7 @@ The `SilhouetteApiClient` provides access to the Silhouette shielded exchange:
109
109
  - **No model imports needed**: Pydantic models are used internally for validation, but you work with simple dicts
110
110
  - **User operations**: Balances, withdrawal initiation
111
111
  - **Order management**: Create, cancel, query orders
112
+ - **Delegated orders**: List, get, and batch retrieve delegated orders
112
113
  - **Trade execution**: Privacy-preserving order execution
113
114
  - **Automatic authentication**: SIWE-based session management with automatic token refresh
114
115
 
@@ -122,6 +123,29 @@ response = client.user.get_balances()
122
123
  # }
123
124
  ```
124
125
 
126
+ ### Delegated orders
127
+
128
+ Delegated orders are orders placed on Hyperliquid by Silhouette on behalf of a trader. Query them using the `delegated_order` operations:
129
+
130
+ ```python
131
+ # List delegated orders with optional filters
132
+ orders = client.delegated_order.list_delegated_orders(
133
+ status="open",
134
+ limit=50,
135
+ )
136
+ print(f"Found {len(orders['orders'])} orders")
137
+
138
+ # Get a single order by ID
139
+ order = client.delegated_order.get_delegated_order("order-id-here")
140
+ print(f"Order status: {order['order']['status']}")
141
+
142
+ # Batch retrieve multiple orders
143
+ batch = client.delegated_order.batch_get_delegated_orders(
144
+ ["order-1", "order-2", "order-3"]
145
+ )
146
+ print(f"Found: {len(batch['orders'])}, Not found: {batch['notFound']}")
147
+ ```
148
+
125
149
  ## API Design
126
150
 
127
151
  ### Why Dicts Instead of Models?
@@ -141,21 +165,24 @@ The SDK uses a hybrid approach for optimal developer experience:
141
165
 
142
166
  ### Regenerating models
143
167
 
144
- Models are generated from the OpenAPI specification. When the Silhouette API changes, regenerate the models to stay in sync:
168
+ Models are generated from the OpenAPI specifications using `datamodel-code-generator`. When the Silhouette API changes, regenerate the models to stay in sync:
145
169
 
146
170
  ```bash
147
- # Fetch spec from local Heimdall and regenerate models
148
- ./scripts/regenerate-models.sh
171
+ # Generate from committed specs
172
+ make generate
149
173
 
150
- # Or specify a custom URL
151
- ./scripts/regenerate-models.sh https://api.silhouette.exchange
174
+ # Or fetch fresh specs and regenerate in one step
175
+ make regenerate
152
176
 
153
- # Then run tests to catch any breaking changes
177
+ # Fetch from a specific URL
178
+ make fetch-heimdall-v0-spec URL=https://api-staging.silhouette.exchange
179
+ make fetch-heimdall-v1-spec URL=https://api-staging.silhouette.exchange
180
+ make generate
181
+
182
+ # Run tests to catch any breaking changes
154
183
  make test
155
184
  ```
156
185
 
157
- Requires `curl`, `jq`, and `openapi-generator-cli` to be installed.
158
-
159
186
  ## Configuration
160
187
 
161
188
  Create `examples/config.json` from the example template:
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "silhouette-python-sdk"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Python SDK for trading on Silhouette - the shield exchange on Hyperliquid"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -31,8 +31,8 @@ dependencies = [
31
31
  "pyjwt>=2.10,<3",
32
32
  "cryptography>=46,<47",
33
33
  "httpx>=0.23,<0.29",
34
- "attrs>=22.2",
35
- "python-dateutil>=2.8,<3",
34
+ "websockets>=15,<16",
35
+ "pydantic>=2.0,<3",
36
36
  ]
37
37
 
38
38
  [project.urls]
@@ -42,9 +42,13 @@ Repository = "https://github.com/silhouette-exchange/silhouette-python-sdk"
42
42
  [tool.poetry]
43
43
  packages = [
44
44
  { include = "silhouette" },
45
- { include = "generated" },
46
45
  ]
47
- include = ["silhouette/py.typed"]
46
+ include = [
47
+ "silhouette/py.typed",
48
+ { path = "silhouette/api/generated/__init__.py", format = ["sdist", "wheel"] },
49
+ { path = "silhouette/api/v1/generated/__init__.py", format = ["sdist", "wheel"] },
50
+ { path = "silhouette/twap/generated/__init__.py", format = ["sdist", "wheel"] },
51
+ ]
48
52
 
49
53
  [tool.poetry.group.dev.dependencies]
50
54
  pytest = "^8.4"
@@ -54,15 +58,14 @@ pre-commit = "^4.3"
54
58
  safety = "^3.6"
55
59
  coverage = "^7.10"
56
60
  pytest-cov = "^7"
57
- pytest-socket = "^0.7"
61
+ pytest-socket = "^0.7.0"
58
62
  types-requests = "^2.31"
59
- types-python-dateutil = "^2.8"
60
- openapi-python-client = "^0.26"
63
+ datamodel-code-generator = {version = "^0.29", extras = ["http"]}
61
64
 
62
65
  [tool.ruff]
63
66
  target-version = "py310"
64
67
  line-length = 120
65
- exclude = [".git", ".mypy_cache", ".ruff_cache", "__pycache__", "dist", "build", "silhouette/api/generated"]
68
+ exclude = [".git", ".mypy_cache", ".ruff_cache", "__pycache__", "dist", "build", "silhouette/api/generated", "silhouette/api/v1/generated", "silhouette/twap/generated"]
66
69
 
67
70
  [tool.ruff.lint]
68
71
  select = ["E", "W", "F", "I", "B", "C4", "UP", "S"]
@@ -94,7 +97,7 @@ python_version = "3.10"
94
97
  pretty = true
95
98
  show_traceback = true
96
99
  color_output = true
97
- exclude = ["examples/", "silhouette/api/generated/"]
100
+ exclude = ["examples/", "silhouette/api/generated/", "silhouette/api/v1/generated/", "silhouette/twap/generated/"]
98
101
 
99
102
  allow_redefinition = false
100
103
  check_untyped_defs = true
@@ -162,7 +165,10 @@ norecursedirs = [
162
165
  ".tox",
163
166
  ".git",
164
167
  "__pycache__",
168
+ "examples",
165
169
  "silhouette/api/generated",
170
+ "silhouette/api/v1/generated",
171
+ "silhouette/twap/generated",
166
172
  ]
167
173
  doctest_optionflags = [
168
174
  "NUMBER",
@@ -186,6 +192,8 @@ addopts = [
186
192
  branch = true
187
193
  omit = [
188
194
  "silhouette/api/generated/*",
195
+ "silhouette/api/v1/generated/*",
196
+ "silhouette/twap/generated/*",
189
197
  ]
190
198
 
191
199
  [tool.coverage.report]
@@ -1,5 +1,10 @@
1
1
  """Silhouette API client for enclave integration."""
2
2
 
3
3
  from silhouette.api.client import SilhouetteApiClient, SilhouetteApiError
4
+ from silhouette.api.rfq_types import RfqEvent
4
5
 
5
- __all__ = ["SilhouetteApiClient", "SilhouetteApiError"]
6
+ __all__ = [
7
+ "RfqEvent",
8
+ "SilhouetteApiClient",
9
+ "SilhouetteApiError",
10
+ ]
@@ -40,6 +40,44 @@ class AuthConfig:
40
40
  """Chain ID for SIWE message signing (1 for mainnet, 421614 for Arbitrum Sepolia testnet)."""
41
41
 
42
42
 
43
+ def sign_siwe_message(
44
+ wallet: LocalAccount,
45
+ base_url: str,
46
+ chain_id: int = 1,
47
+ ) -> tuple[str, str]:
48
+ """Create and sign a SIWE message for authentication.
49
+
50
+ Args:
51
+ wallet: The wallet to sign with
52
+ base_url: The API base URL (used for domain and URI)
53
+ chain_id: Chain ID for SIWE message (1 for mainnet)
54
+
55
+ Returns:
56
+ Tuple of (prepared_message_str, signature_hex)
57
+ """
58
+ from urllib.parse import urlparse
59
+
60
+ parsed = urlparse(base_url)
61
+ domain = parsed.netloc or "localhost"
62
+
63
+ message = SiweMessage(
64
+ domain=domain,
65
+ address=wallet.address,
66
+ statement="Sign in with Ethereum to the app.",
67
+ uri=f"{base_url}/login",
68
+ version="1",
69
+ chain_id=chain_id,
70
+ nonce=secrets.token_hex(12),
71
+ issued_at=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
72
+ )
73
+ prepared_message_str = message.prepare_message()
74
+
75
+ message_to_sign = encode_defunct(text=prepared_message_str)
76
+ signed_message = wallet.sign_message(message_to_sign)
77
+ signature_hex = "0x" + signed_message.signature.hex()
78
+ return prepared_message_str, signature_hex
79
+
80
+
43
81
  class AuthManager:
44
82
  """Manages authentication state and automatic login for the API client."""
45
83
 
@@ -191,26 +229,6 @@ class AuthManager:
191
229
 
192
230
  raise RuntimeError(f"Login failed after {self.config.max_login_retries} attempts: {last_error}") from last_error
193
231
 
194
- def _extract_domain_from_url(self, url: str) -> str:
195
- """
196
- Extract domain (host:port) from a URL for SIWE message.
197
-
198
- Args:
199
- url: Full URL like "https://api.silhouette.exchange/v0"
200
-
201
- Returns:
202
- Domain string like "api.silhouette.exchange""
203
- """
204
- from urllib.parse import urlparse
205
-
206
- parsed = urlparse(url)
207
- # netloc includes host and port (e.g., "localhost:8081" or "api.silhouette.exchange")
208
- domain = parsed.netloc
209
- if not domain:
210
- # Fallback if URL parsing fails
211
- domain = "localhost"
212
- return domain
213
-
214
232
  def _perform_login(self) -> None:
215
233
  """
216
234
  Perform the SIWE login flow.
@@ -221,32 +239,12 @@ class AuthManager:
221
239
  if self._wallet is None:
222
240
  raise ValueError("No wallet configured for login")
223
241
 
224
- # Extract domain from base_url for SIWE message
225
- domain = self._extract_domain_from_url(self.client.base_url)
226
-
227
- # Generate SIWE message
228
- message = SiweMessage(
229
- domain=domain,
230
- address=self._wallet.address,
231
- statement="Sign in with Ethereum to the app.",
232
- uri=f"{self.client.base_url}/login",
233
- version="1",
234
- chain_id=self.config.chain_id,
235
- nonce=secrets.token_hex(12),
236
- issued_at=datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
242
+ message, signature = sign_siwe_message(
243
+ self._wallet,
244
+ self.client.base_url,
245
+ self.config.chain_id,
237
246
  )
238
- prepared_message_str = message.prepare_message()
239
-
240
- # Sign the message
241
- message_to_sign = encode_defunct(text=prepared_message_str)
242
- signed_message = self._wallet.sign_message(message_to_sign)
243
-
244
- # Verify signature client-side
245
- message.verify(signed_message.signature)
246
-
247
- # Call login API
248
- signature_hex = "0x" + signed_message.signature.hex()
249
- token = self.client._raw_login(prepared_message_str, signature_hex)
247
+ token = self.client._raw_login(message, signature)
250
248
  self.set_token(token)
251
249
 
252
250
  def handle_auth_error(self, response_status: int) -> bool:
@@ -0,0 +1,11 @@
1
+ """Base model for generated Pydantic models.
2
+
3
+ Configures `populate_by_name=True` so that models accept both snake_case
4
+ field names and their camelCase aliases when constructing instances.
5
+ """
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+
9
+
10
+ class ApiBaseModel(BaseModel):
11
+ model_config = ConfigDict(populate_by_name=True)