hotstuff-python-sdk 0.0.1b1__py3-none-any.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.
@@ -0,0 +1,371 @@
1
+ """Account info method types."""
2
+ from typing import List, Literal, Optional, Annotated
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator, RootModel
4
+ from eth_utils import is_address, to_checksum_address
5
+
6
+
7
+ def validate_ethereum_address(value: str) -> str:
8
+ """
9
+ Validate and normalize an Ethereum address.
10
+
11
+ Args:
12
+ value: The address string to validate
13
+
14
+ Returns:
15
+ Checksummed address string
16
+
17
+ Raises:
18
+ ValueError: If the address is invalid
19
+ """
20
+ if not isinstance(value, str):
21
+ raise ValueError(f"Address must be a string, got {type(value)}")
22
+
23
+ if not is_address(value):
24
+ raise ValueError(f"Invalid Ethereum address: {value}")
25
+
26
+ # Return checksummed address (EIP-55)
27
+ return to_checksum_address(value)
28
+
29
+
30
+ # Type alias for validated Ethereum addresses (similar to viem's Address type)
31
+ EthereumAddress = Annotated[
32
+ str,
33
+ Field(
34
+ ...,
35
+ description="Ethereum address (validated and checksummed)",
36
+ examples=["0x1234567890123456789012345678901234567890"],
37
+ ),
38
+ ]
39
+
40
+
41
+ # Open Orders Method
42
+ class OpenOrdersParams(BaseModel):
43
+ """Parameters for open orders query."""
44
+ user: str = Field(..., description="User address")
45
+ page: Optional[int] = Field(None, description="Page number")
46
+ limit: Optional[int] = Field(None, description="Number of orders per page")
47
+
48
+ @field_validator('user', mode='before')
49
+ @classmethod
50
+ def validate_user_address(cls, v: str) -> str:
51
+ """Validate and checksum the user address."""
52
+ return validate_ethereum_address(v)
53
+
54
+
55
+ class OpenOrder(BaseModel):
56
+ """Open order information."""
57
+ order_id: int
58
+ user: str
59
+ instrument_id: int
60
+ instrument: str
61
+ side: Literal["s", "b"]
62
+ limit_price: str
63
+ size: str
64
+ unfilled: str
65
+ state: Literal["open", "filled", "cancelled", "triggered"]
66
+ cloid: str
67
+ tif: Literal["GTC", "IOC", "FOK"]
68
+ tpsl: Literal["tp", "sl", ""]
69
+ trigger_px: str
70
+ trigger_price: Optional[str] = None
71
+ post_only: bool
72
+ reduce_only: bool
73
+ timestamp: str
74
+
75
+
76
+ class OpenOrdersResponse(BaseModel):
77
+ """Open orders response."""
78
+ orders: List[OpenOrder] = Field(..., description="List of open orders")
79
+
80
+
81
+ # Positions Method
82
+ class PositionsParams(BaseModel):
83
+ """Parameters for positions query."""
84
+ user: str = Field(..., description="User address")
85
+ instrument: Optional[str] = Field(None, description="Filter by instrument")
86
+
87
+ @field_validator('user', mode='before')
88
+ @classmethod
89
+ def validate_user_address(cls, v: str) -> str:
90
+ """Validate and checksum the user address."""
91
+ return validate_ethereum_address(v)
92
+
93
+
94
+ class PositionsResponse(BaseModel):
95
+ """Positions response."""
96
+ pass
97
+
98
+
99
+ # Account Summary Method
100
+ class AccountSummaryParams(BaseModel):
101
+ """Parameters for account summary query."""
102
+ user: str = Field(..., description="User address")
103
+
104
+ @field_validator('user', mode='before')
105
+ @classmethod
106
+ def validate_user_address(cls, v: str) -> str:
107
+ """Validate and checksum the user address."""
108
+ return validate_ethereum_address(v)
109
+
110
+
111
+ class AccountSummaryResponse(BaseModel):
112
+ """Account summary response."""
113
+ total_balance: str
114
+ total_equity: str
115
+ total_free: str
116
+ total_margin: str
117
+ total_profit_loss: str
118
+
119
+
120
+ # Referral Summary Method
121
+ class ReferralSummaryParams(BaseModel):
122
+ """Parameters for referral summary query."""
123
+ user: str = Field(..., description="User address")
124
+
125
+ @field_validator('user', mode='before')
126
+ @classmethod
127
+ def validate_user_address(cls, v: str) -> str:
128
+ """Validate and checksum the user address."""
129
+ return validate_ethereum_address(v)
130
+
131
+
132
+ class ReferralSummaryResponse(BaseModel):
133
+ """Referral summary response."""
134
+ pass
135
+
136
+
137
+ # User Fee Info Method
138
+ class UserFeeInfoParams(BaseModel):
139
+ """Parameters for user fee info query."""
140
+ user: str = Field(..., description="User address")
141
+
142
+ @field_validator('user', mode='before')
143
+ @classmethod
144
+ def validate_user_address(cls, v: str) -> str:
145
+ """Validate and checksum the user address."""
146
+ return validate_ethereum_address(v)
147
+
148
+
149
+ class UserFeeInfoResponse(BaseModel):
150
+ """User fee info response."""
151
+ pass
152
+
153
+
154
+ # Account History Method
155
+ class AccountHistoryParams(BaseModel):
156
+ """Parameters for account history query."""
157
+ user: str = Field(..., description="User address")
158
+
159
+ @field_validator('user', mode='before')
160
+ @classmethod
161
+ def validate_user_address(cls, v: str) -> str:
162
+ """Validate and checksum the user address."""
163
+ return validate_ethereum_address(v)
164
+
165
+
166
+ class AccountHistoryResponse(BaseModel):
167
+ """Account history response."""
168
+ pass
169
+
170
+
171
+ # Order History Method
172
+ class OrderHistoryParams(BaseModel):
173
+ """Parameters for order history query."""
174
+ model_config = ConfigDict(populate_by_name=True)
175
+
176
+ user: str = Field(..., description="User address")
177
+ instrument_id: Optional[str] = Field(None, alias="instrumentId", description="Filter by instrument ID")
178
+ limit: Optional[int] = Field(None, description="Number of orders to return")
179
+
180
+ @field_validator('user', mode='before')
181
+ @classmethod
182
+ def validate_user_address(cls, v: str) -> str:
183
+ """Validate and checksum the user address."""
184
+ return validate_ethereum_address(v)
185
+
186
+
187
+ class OrderHistoryResponse(BaseModel):
188
+ """Order history response."""
189
+ pass
190
+
191
+
192
+ # Trade History Method
193
+ class TradeHistoryParams(BaseModel):
194
+ """Parameters for trade history query."""
195
+ model_config = ConfigDict(populate_by_name=True)
196
+
197
+ user: str = Field(..., description="User address")
198
+ instrument_id: Optional[str] = Field(None, alias="instrumentId", description="Filter by instrument ID")
199
+ limit: Optional[int] = Field(None, description="Number of trades to return")
200
+
201
+ @field_validator('user', mode='before')
202
+ @classmethod
203
+ def validate_user_address(cls, v: str) -> str:
204
+ """Validate and checksum the user address."""
205
+ return validate_ethereum_address(v)
206
+
207
+
208
+ class TradeHistoryResponse(BaseModel):
209
+ """Trade history response."""
210
+ pass
211
+
212
+
213
+ # Funding History Method
214
+ class FundingHistoryParams(BaseModel):
215
+ """Parameters for funding history query."""
216
+ user: str = Field(..., description="User address")
217
+
218
+ @field_validator('user', mode='before')
219
+ @classmethod
220
+ def validate_user_address(cls, v: str) -> str:
221
+ """Validate and checksum the user address."""
222
+ return validate_ethereum_address(v)
223
+
224
+
225
+ class FundingHistoryResponse(BaseModel):
226
+ """Funding history response."""
227
+ pass
228
+
229
+
230
+ # Transfer History Method
231
+ class TransferHistoryParams(BaseModel):
232
+ """Parameters for transfer history query."""
233
+ user: str = Field(..., description="User address")
234
+
235
+ @field_validator('user', mode='before')
236
+ @classmethod
237
+ def validate_user_address(cls, v: str) -> str:
238
+ """Validate and checksum the user address."""
239
+ return validate_ethereum_address(v)
240
+
241
+
242
+ class TransferHistoryResponse(BaseModel):
243
+ """Transfer history response."""
244
+ pass
245
+
246
+
247
+ # Instrument Leverage Method
248
+ class InstrumentLeverageParams(BaseModel):
249
+ """Parameters for instrument leverage query."""
250
+ user: str = Field(..., description="User address")
251
+ symbol: str = Field(..., description="Instrument symbol")
252
+
253
+ @field_validator('user', mode='before')
254
+ @classmethod
255
+ def validate_user_address(cls, v: str) -> str:
256
+ """Validate and checksum the user address."""
257
+ return validate_ethereum_address(v)
258
+
259
+
260
+ class InstrumentLeverageResponse(BaseModel):
261
+ """Instrument leverage response."""
262
+ pass
263
+
264
+
265
+ # Referral Info Method
266
+ class ReferralInfoParams(BaseModel):
267
+ """Parameters for referral info query."""
268
+ user: str = Field(..., description="User address")
269
+
270
+ @field_validator('user', mode='before')
271
+ @classmethod
272
+ def validate_user_address(cls, v: str) -> str:
273
+ """Validate and checksum the user address."""
274
+ return validate_ethereum_address(v)
275
+
276
+
277
+ class ReferralInfoResponse(BaseModel):
278
+ """Referral info response."""
279
+ pass
280
+
281
+
282
+ # Sub Accounts List Method
283
+ class SubAccountsListParams(BaseModel):
284
+ """Parameters for sub accounts list query."""
285
+ user: str = Field(..., description="User address")
286
+
287
+ @field_validator('user', mode='before')
288
+ @classmethod
289
+ def validate_user_address(cls, v: str) -> str:
290
+ """Validate and checksum the user address."""
291
+ return validate_ethereum_address(v)
292
+
293
+
294
+ class SubAccountsListResponse(BaseModel):
295
+ """Sub accounts list response."""
296
+ pass
297
+
298
+
299
+ # Agents Method
300
+ class AgentsParams(BaseModel):
301
+ """Parameters for agents query."""
302
+ user: str = Field(..., description="User address")
303
+
304
+ @field_validator('user', mode='before')
305
+ @classmethod
306
+ def validate_user_address(cls, v: str) -> str:
307
+ """Validate and checksum the user address."""
308
+ return validate_ethereum_address(v)
309
+
310
+
311
+ class Agent(BaseModel):
312
+ """Agent information."""
313
+ user: str = Field(..., description="User address")
314
+ agent_address: Optional[str] = Field(None, description="Agent address")
315
+ agent_name: Optional[str] = Field(None, description="Agent name")
316
+ created_at_block_timestamp: Optional[int] = Field(None, description="Creation timestamp")
317
+ valid_until_timestamp: Optional[int] = Field(None, description="Validity expiration timestamp")
318
+
319
+ model_config = ConfigDict(populate_by_name=True)
320
+
321
+ @field_validator('user', 'agent_address', mode='before')
322
+ @classmethod
323
+ def validate_addresses(cls, v: Optional[str]) -> Optional[str]:
324
+ """Validate and checksum Ethereum addresses."""
325
+ if v is None or v == "":
326
+ return v
327
+ return validate_ethereum_address(v)
328
+
329
+
330
+ class AgentsResponse(BaseModel):
331
+ """Agents response."""
332
+ pass
333
+
334
+
335
+ # User Balance Info Method
336
+ class UserBalanceInfoParams(BaseModel):
337
+ """Parameters for user balance info query."""
338
+ user: str = Field(..., description="User address")
339
+ type: Literal["all", "spot", "derivative"] = Field(..., description="Balance type")
340
+
341
+ @field_validator('user', mode='before')
342
+ @classmethod
343
+ def validate_user_address(cls, v: str) -> str:
344
+ """Validate and checksum the user address."""
345
+ return validate_ethereum_address(v)
346
+
347
+
348
+ class UserBalanceInfoResponse(BaseModel):
349
+ """User balance info response."""
350
+ pass
351
+
352
+
353
+ # Account Info Method
354
+ class AccountInfoParams(BaseModel):
355
+ """Parameters for account info query."""
356
+ model_config = ConfigDict(populate_by_name=True)
357
+
358
+ user: str = Field(..., description="User address")
359
+ collateral_id: Optional[int] = Field(None, alias="collateralID", description="Collateral ID")
360
+ include_history: Optional[bool] = Field(None, alias="includeHistory", description="Include history")
361
+
362
+ @field_validator('user', mode='before')
363
+ @classmethod
364
+ def validate_user_address(cls, v: str) -> str:
365
+ """Validate and checksum the user address."""
366
+ return validate_ethereum_address(v)
367
+
368
+
369
+ class AccountInfoResponse(BaseModel):
370
+ """Account info response."""
371
+ pass
@@ -0,0 +1,57 @@
1
+ """Explorer info method types."""
2
+ from typing import Optional
3
+ from pydantic import BaseModel, Field
4
+
5
+
6
+ # Blocks Method
7
+ class BlocksParams(BaseModel):
8
+ """Parameters for blocks query."""
9
+ offset: int = Field(..., description="Offset for pagination")
10
+ limit: int = Field(..., description="Number of blocks to return")
11
+
12
+
13
+ class BlocksResponse(BaseModel):
14
+ """Blocks response."""
15
+ pass
16
+
17
+
18
+ # Block Details Method
19
+ class BlockDetailsParams(BaseModel):
20
+ """Parameters for block details query."""
21
+ block_hash: Optional[str] = Field(None, description="Block hash")
22
+ block_height: Optional[int] = Field(None, description="Block height")
23
+
24
+
25
+ class BlockDetailsResponse(BaseModel):
26
+ """Block details response."""
27
+ pass
28
+
29
+
30
+ # Transactions Method
31
+ class TransactionFilter(BaseModel):
32
+ """Transaction filter."""
33
+ account: Optional[str] = Field(None, description="Filter by account")
34
+ tx_type: Optional[int] = Field(None, description="Filter by transaction type")
35
+
36
+
37
+ class TransactionsParams(BaseModel):
38
+ """Parameters for transactions query."""
39
+ offset: Optional[int] = Field(None, description="Offset for pagination")
40
+ limit: Optional[int] = Field(None, description="Number of transactions to return")
41
+ filter: Optional[TransactionFilter] = Field(None, description="Transaction filter")
42
+
43
+
44
+ class TransactionsResponse(BaseModel):
45
+ """Transactions response."""
46
+ pass
47
+
48
+
49
+ # Transaction Details Method
50
+ class TransactionDetailsParams(BaseModel):
51
+ """Parameters for transaction details query."""
52
+ tx_hash: str = Field(..., description="Transaction hash")
53
+
54
+
55
+ class TransactionDetailsResponse(BaseModel):
56
+ """Transaction details response."""
57
+ pass
@@ -0,0 +1,249 @@
1
+ """Global info method types."""
2
+ from typing import List, Literal, Optional, Union
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
4
+
5
+
6
+ # Oracle Method
7
+ class OracleParams(BaseModel):
8
+ """Parameters for oracle price query."""
9
+ symbol: str = Field(..., description="Symbol to get oracle price for")
10
+
11
+
12
+ class OracleResponse(BaseModel):
13
+ """Oracle price response."""
14
+ symbol: str
15
+ index_price: str
16
+ ext_mark_price: str
17
+ updated_at: int
18
+
19
+
20
+ # Supported Collateral Method
21
+ class SupportedCollateralParams(BaseModel):
22
+ """Parameters for supported collateral query."""
23
+ pass
24
+
25
+
26
+ class BridgeByChain(BaseModel):
27
+ """Bridge chain configuration."""
28
+ bridge_chain_type: int
29
+ bridge_chain_id: int
30
+ token_address: str
31
+ bridge_contract_address: str
32
+ enabled: bool
33
+
34
+
35
+ class WeightTier(BaseModel):
36
+ """Weight tier configuration."""
37
+ amount: int
38
+ weight: int
39
+
40
+
41
+ class CollRisk(BaseModel):
42
+ """Collateral risk configuration."""
43
+ weight_tiers: List[WeightTier]
44
+ max_margin_cap: int
45
+ stale_price_guard_weight: int
46
+
47
+
48
+ class SupportedCollateral(BaseModel):
49
+ """Supported collateral information."""
50
+ id: int
51
+ symbol: str
52
+ name: str
53
+ decimals: int
54
+ default_coll_weight: int
55
+ price_index: str
56
+ type: int
57
+ bridge_by_chain: List[BridgeByChain]
58
+ coll_risk: List[CollRisk]
59
+ withdrawal_fee: int
60
+ added_at_block: int
61
+
62
+
63
+ # Instruments Method
64
+ class InstrumentsParams(BaseModel):
65
+ """Parameters for instruments query."""
66
+ type: Literal["perps", "spot", "all"] = Field(..., description="Instrument type filter")
67
+
68
+
69
+ class MarginTier(BaseModel):
70
+ """Margin tier configuration."""
71
+ notional_usd_threshold: str
72
+ max_leverage: int
73
+ mmr: float # Can be fractional
74
+ mmd: int
75
+
76
+
77
+ class PerpInstrument(BaseModel):
78
+ """Perpetual instrument information."""
79
+ id: int
80
+ name: str
81
+ price_index: str
82
+ lot_size: float # Can be fractional (e.g., 1e-05)
83
+ tick_size: float # Can be fractional (e.g., 0.1, 1e-06)
84
+ settlement_currency: int
85
+ only_isolated: bool
86
+ max_leverage: int
87
+ delisted: bool
88
+ min_notional_usd: int
89
+ margin_tiers: List[MarginTier]
90
+ listed_at_block_timestamp: int
91
+
92
+
93
+ class SpotInstrument(BaseModel):
94
+ """Spot instrument information."""
95
+ id: int
96
+ name: str
97
+ price_index: str
98
+ lot_size: int
99
+ tick_size: float # Can be fractional (e.g., 0.0001)
100
+ base_asset: int
101
+ quote_asset: int
102
+ stable_pair: bool
103
+ min_size_in_quote_asset: int
104
+ listed_at_block_timestamp: int
105
+
106
+
107
+ class InstrumentsResponse(BaseModel):
108
+ """Instruments response."""
109
+ perps: List[PerpInstrument]
110
+ spot: List[SpotInstrument]
111
+
112
+
113
+ # Ticker Method
114
+ class TickerParams(BaseModel):
115
+ """Parameters for ticker query."""
116
+ symbol: str = Field(..., description="Trading pair symbol")
117
+
118
+
119
+ class Ticker(BaseModel):
120
+ """Ticker information."""
121
+ type: Literal["perp", "spot"]
122
+ symbol: str
123
+ mark_price: str
124
+ mid_price: str
125
+ index_price: str
126
+ best_bid_price: str
127
+ best_ask_price: str
128
+ best_bid_size: str
129
+ best_ask_size: str
130
+ funding_rate: str
131
+ open_interest: str
132
+ volume_24h: str
133
+ change_24h: str
134
+ max_trading_price: str
135
+ min_trading_price: str
136
+ last_updated: int
137
+ last_price: str
138
+
139
+
140
+ # Orderbook Method
141
+ class OrderbookParams(BaseModel):
142
+ """Parameters for orderbook query."""
143
+ symbol: str = Field(..., description="Trading pair symbol")
144
+ depth: Optional[int] = Field(None, description="Orderbook depth")
145
+
146
+
147
+ class OrderbookLevel(BaseModel):
148
+ """Orderbook level (bid/ask)."""
149
+ price: str # API may return int/float, but we store as string for precision
150
+ size: str # API may return int/float, but we store as string for precision
151
+
152
+ @field_validator('price', mode='before')
153
+ @classmethod
154
+ def convert_price_to_string(cls, v: Union[str, int, float]) -> str:
155
+ """Convert numeric price to string."""
156
+ if not isinstance(v, str):
157
+ return str(v)
158
+ return v
159
+
160
+ @field_validator('size', mode='before')
161
+ @classmethod
162
+ def convert_size_to_string(cls, v: Union[str, int, float]) -> str:
163
+ """Convert numeric size to string."""
164
+ if not isinstance(v, str):
165
+ return str(v)
166
+ return v
167
+
168
+
169
+ class OrderbookResponse(BaseModel):
170
+ """Orderbook response."""
171
+ bids: List[OrderbookLevel]
172
+ asks: List[OrderbookLevel]
173
+ instrument_name: str
174
+ timestamp: int
175
+ sequence_number: int
176
+
177
+
178
+ # Trades Method
179
+ class TradesParams(BaseModel):
180
+ """Parameters for trades query."""
181
+ symbol: str = Field(..., description="Trading pair symbol")
182
+ limit: Optional[int] = Field(None, description="Number of trades to return")
183
+
184
+
185
+ class Trade(BaseModel):
186
+ """Trade information."""
187
+ instrument_id: int
188
+ instrument: str
189
+ trade_id: int
190
+ tx_hash: str
191
+ side: Literal["b", "s"]
192
+ price: str
193
+ size: str
194
+ maker: str
195
+ taker: str
196
+ timestamp: str
197
+
198
+
199
+ # Mids Method
200
+ class MidsParams(BaseModel):
201
+ """Parameters for mids query."""
202
+ pass
203
+
204
+
205
+ class Mid(BaseModel):
206
+ """Mid price information."""
207
+ symbol: str
208
+ mid_price: str
209
+
210
+
211
+ # BBO Method
212
+ class BBOParams(BaseModel):
213
+ """Parameters for best bid/offer query."""
214
+ symbol: str = Field(..., description="Trading pair symbol")
215
+
216
+
217
+ class BBO(BaseModel):
218
+ """Best bid/offer information."""
219
+ symbol: str
220
+ best_bid_price: str
221
+ best_ask_price: str
222
+ best_bid_size: str
223
+ best_ask_size: str
224
+
225
+
226
+ # Chart Method
227
+ SupportedChartResolutions = Literal["1", "5", "15", "60", "240", "1D", "1W"]
228
+ SupportedChartTypes = Literal["mark", "ltp", "index"]
229
+
230
+
231
+ class ChartParams(BaseModel):
232
+ """Parameters for chart data query."""
233
+ model_config = ConfigDict(populate_by_name=True)
234
+
235
+ symbol: str = Field(..., description="Trading pair symbol")
236
+ resolution: SupportedChartResolutions = Field(..., description="Chart resolution")
237
+ from_: int = Field(..., alias="from", description="Start timestamp")
238
+ to: int = Field(..., description="End timestamp")
239
+ chart_type: SupportedChartTypes = Field(..., description="Chart type")
240
+
241
+
242
+ class ChartPoint(BaseModel):
243
+ """Chart data point."""
244
+ open: float
245
+ high: float
246
+ low: float
247
+ close: float
248
+ volume: float
249
+ time: int