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,120 @@
1
+ """Account exchange method types."""
2
+ from typing import Optional
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
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
+ # Add Agent Method
31
+ class AddAgentParams(BaseModel):
32
+ """Parameters for adding an agent."""
33
+ agent_name: str = Field(..., alias="agentName", description="Agent name")
34
+ agent: str = Field(..., description="Agent address")
35
+ for_account: str = Field(..., alias="forAccount", description="Account to add agent for")
36
+ signature: Optional[str] = Field(None, description="Agent signature")
37
+ valid_until: int = Field(..., alias="validUntil", description="Validity expiration timestamp")
38
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
39
+ agent_private_key: Optional[str] = Field(None, alias="agentPrivateKey", description="Agent private key")
40
+ signer: Optional[str] = Field(None, description="Signer address")
41
+
42
+ model_config = ConfigDict(populate_by_name=True)
43
+
44
+ @field_validator('agent', 'signer', mode='before')
45
+ @classmethod
46
+ def validate_addresses(cls, v: Optional[str]) -> Optional[str]:
47
+ """Validate and checksum Ethereum addresses."""
48
+ if v is None or v == "":
49
+ return v
50
+ return validate_ethereum_address(v)
51
+
52
+
53
+ # Revoke Agent Method
54
+ class RevokeAgentParams(BaseModel):
55
+ """Parameters for revoking an agent."""
56
+ agent: str = Field(..., description="Agent address")
57
+ for_account: Optional[str] = Field(None, alias="forAccount", description="Account to revoke agent for")
58
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
59
+
60
+ model_config = ConfigDict(populate_by_name=True)
61
+
62
+ @field_validator('agent', mode='before')
63
+ @classmethod
64
+ def validate_agent_address(cls, v: str) -> str:
65
+ """Validate and checksum the agent address."""
66
+ return validate_ethereum_address(v)
67
+
68
+
69
+ # Update Perp Instrument Leverage Method
70
+ class UpdatePerpInstrumentLeverageParams(BaseModel):
71
+ """Parameters for updating perp instrument leverage."""
72
+ instrument_id: int = Field(..., alias="instrumentId", description="Instrument ID")
73
+ leverage: int = Field(..., description="Leverage value")
74
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
75
+
76
+ model_config = ConfigDict(populate_by_name=True)
77
+
78
+
79
+ # Approve Broker Fee Method
80
+ class ApproveBrokerFeeParams(BaseModel):
81
+ """Parameters for approving broker fee."""
82
+ broker: str = Field(..., description="Broker address")
83
+ max_fee_rate: str = Field(..., alias="maxFeeRate", description="Maximum fee rate")
84
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
85
+
86
+ model_config = ConfigDict(populate_by_name=True)
87
+
88
+ @field_validator('broker', mode='before')
89
+ @classmethod
90
+ def validate_broker_address(cls, v: str) -> str:
91
+ """Validate and checksum the broker address."""
92
+ return validate_ethereum_address(v)
93
+
94
+
95
+ # Create Referral Code Method
96
+ class CreateReferralCodeParams(BaseModel):
97
+ """Parameters for creating a referral code."""
98
+ code: str = Field(..., description="Referral code")
99
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
100
+
101
+ model_config = ConfigDict(populate_by_name=True)
102
+
103
+
104
+ # Set Referrer Method
105
+ class SetReferrerParams(BaseModel):
106
+ """Parameters for setting a referrer."""
107
+ code: str = Field(..., description="Referral code")
108
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
109
+
110
+ model_config = ConfigDict(populate_by_name=True)
111
+
112
+
113
+ # Claim Referral Rewards Method
114
+ class ClaimReferralRewardsParams(BaseModel):
115
+ """Parameters for claiming referral rewards."""
116
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
117
+ spot: bool = Field(..., description="Whether to claim from spot account")
118
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
119
+
120
+ model_config = ConfigDict(populate_by_name=True)
@@ -0,0 +1,94 @@
1
+ """Collateral exchange method types."""
2
+ from typing import Optional
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
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
+ # Account Spot Withdraw Request Method
31
+ class AccountSpotWithdrawRequestParams(BaseModel):
32
+ """Parameters for account spot withdraw request."""
33
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
34
+ amount: str = Field(..., description="Withdrawal amount")
35
+ chain_id: int = Field(..., alias="chainId", description="Chain ID")
36
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
37
+
38
+ model_config = ConfigDict(populate_by_name=True)
39
+
40
+
41
+ # Account Derivative Withdraw Request Method
42
+ class AccountDerivativeWithdrawRequestParams(BaseModel):
43
+ """Parameters for account derivative withdraw request."""
44
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
45
+ amount: str = Field(..., description="Withdrawal amount")
46
+ chain_id: int = Field(..., alias="chainId", description="Chain ID")
47
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
48
+
49
+ model_config = ConfigDict(populate_by_name=True)
50
+
51
+
52
+ # Account Spot Balance Transfer Request Method
53
+ class AccountSpotBalanceTransferRequestParams(BaseModel):
54
+ """Parameters for account spot balance transfer request."""
55
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
56
+ amount: str = Field(..., description="Transfer amount")
57
+ destination: str = Field(..., description="Destination address")
58
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
59
+
60
+ model_config = ConfigDict(populate_by_name=True)
61
+
62
+ @field_validator('destination', mode='before')
63
+ @classmethod
64
+ def validate_destination_address(cls, v: str) -> str:
65
+ """Validate and checksum the destination address."""
66
+ return validate_ethereum_address(v)
67
+
68
+
69
+ # Account Derivative Balance Transfer Request Method
70
+ class AccountDerivativeBalanceTransferRequestParams(BaseModel):
71
+ """Parameters for account derivative balance transfer request."""
72
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
73
+ amount: str = Field(..., description="Transfer amount")
74
+ destination: str = Field(..., description="Destination address")
75
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
76
+
77
+ model_config = ConfigDict(populate_by_name=True)
78
+
79
+ @field_validator('destination', mode='before')
80
+ @classmethod
81
+ def validate_destination_address(cls, v: str) -> str:
82
+ """Validate and checksum the destination address."""
83
+ return validate_ethereum_address(v)
84
+
85
+
86
+ # Account Internal Balance Transfer Request Method
87
+ class AccountInternalBalanceTransferRequestParams(BaseModel):
88
+ """Parameters for account internal balance transfer request."""
89
+ collateral_id: int = Field(..., alias="collateralId", description="Collateral ID")
90
+ amount: str = Field(..., description="Transfer amount")
91
+ to_derivatives_account: bool = Field(..., alias="toDerivativesAccount", description="Transfer to derivatives account flag")
92
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
93
+
94
+ model_config = ConfigDict(populate_by_name=True)
@@ -0,0 +1,28 @@
1
+ """Exchange operation codes."""
2
+ EXCHANGE_OP_CODES = {
3
+ # Account Actions
4
+ "addAgent": 1201,
5
+ "revokeAgent": 1211,
6
+ "updatePerpInstrumentLeverage": 1203,
7
+ "approveBrokerFee": 1207,
8
+ "createReferralCode": 1208,
9
+ "setReferrer": 1209,
10
+ "claimReferralRewards": 1210,
11
+
12
+ # Trading Actions
13
+ "placeOrder": 1301,
14
+ "cancelByOid": 1302,
15
+ "cancelAll": 1311,
16
+ "cancelByCloid": 1312,
17
+
18
+ # Collateral Actions
19
+ "accountSpotWithdrawRequest": 1002,
20
+ "accountDerivativeWithdrawRequest": 1003,
21
+ "accountSpotBalanceTransferRequest": 1051,
22
+ "accountDerivativeBalanceTransferRequest": 1052,
23
+ "accountInternalBalanceTransferRequest": 1053,
24
+
25
+ # Vault Actions
26
+ "depositToVault": 1401,
27
+ "redeemFromVault": 1402,
28
+ }
@@ -0,0 +1,117 @@
1
+ """Trading exchange method types."""
2
+ from typing import List, Literal, Optional, Any
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator, field_serializer
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
+ # Place Order Method
31
+ class UnitOrder(BaseModel):
32
+ """Single order unit."""
33
+ instrument_id: int = Field(..., gt=0, alias="instrumentId", description="Instrument ID")
34
+ side: Literal["b", "s"] = Field(..., description="Order side: 'b' for buy, 's' for sell")
35
+ position_side: Literal["LONG", "SHORT", "BOTH"] = Field(..., alias="positionSide", description="Position side")
36
+ price: str = Field(..., description="Order price")
37
+ size: str = Field(..., description="Order size")
38
+ tif: Literal["GTC", "IOC", "FOK"] = Field(..., description="Time in force")
39
+ ro: bool = Field(..., description="Reduce-only flag")
40
+ po: bool = Field(..., description="Post-only flag")
41
+ cloid: str = Field(..., description="Client order ID")
42
+ trigger_px: Optional[str] = Field(None, alias="triggerPx", description="Trigger price")
43
+ is_market: Optional[bool] = Field(None, alias="isMarket", description="Market order flag")
44
+ tpsl: Optional[Literal["tp", "sl", ""]] = Field(None, description="Take profit/stop loss")
45
+ grouping: Optional[Literal["position", "normal", ""]] = Field(None, description="Order grouping")
46
+
47
+ model_config = ConfigDict(populate_by_name=True)
48
+
49
+ @field_serializer('trigger_px', 'tpsl', 'grouping')
50
+ def serialize_optional_strings(self, value: Optional[str], _info) -> str:
51
+ """Convert None to empty string for optional string fields to match original SDK."""
52
+ return "" if value is None else value
53
+
54
+
55
+ class BrokerConfig(BaseModel):
56
+ """Broker configuration."""
57
+ broker: str = Field(..., description="Broker address")
58
+ fee: str = Field(..., description="Broker fee")
59
+
60
+ @field_validator('broker', mode='before')
61
+ @classmethod
62
+ def validate_broker_address(cls, v: str) -> str:
63
+ """Validate and checksum the broker address."""
64
+ if v == "":
65
+ return v # Allow empty string for no broker
66
+ return validate_ethereum_address(v)
67
+
68
+
69
+ class PlaceOrderParams(BaseModel):
70
+ """Parameters for placing an order."""
71
+ orders: List[UnitOrder] = Field(..., description="List of orders to place")
72
+ expires_after: int = Field(..., alias="expiresAfter", description="Expiration timestamp")
73
+ broker_config: Optional[BrokerConfig] = Field(None, alias="brokerConfig", description="Broker configuration")
74
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
75
+
76
+ model_config = ConfigDict(populate_by_name=True)
77
+
78
+
79
+ # Cancel By Oid Method
80
+ class UnitCancelByOrderId(BaseModel):
81
+ """Cancel by order ID unit."""
82
+ oid: int = Field(..., description="Order ID")
83
+ instrument_id: int = Field(..., gt=0, description="Instrument ID")
84
+
85
+
86
+ class CancelByOidParams(BaseModel):
87
+ """Parameters for cancelling by order ID."""
88
+ cancels: List[UnitCancelByOrderId] = Field(..., description="List of orders to cancel")
89
+ expires_after: int = Field(..., alias="expiresAfter", description="Expiration timestamp")
90
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
91
+
92
+ model_config = ConfigDict(populate_by_name=True)
93
+
94
+
95
+ # Cancel By Cloid Method
96
+ class UnitCancelByClOrderId(BaseModel):
97
+ """Cancel by client order ID unit."""
98
+ cloid: str = Field(..., description="Client order ID")
99
+ instrument_id: int = Field(..., gt=0, description="Instrument ID")
100
+
101
+
102
+ class CancelByCloidParams(BaseModel):
103
+ """Parameters for cancelling by client order ID."""
104
+ cancels: List[UnitCancelByClOrderId] = Field(..., description="List of orders to cancel")
105
+ expires_after: int = Field(..., alias="expiresAfter", description="Expiration timestamp")
106
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
107
+
108
+ model_config = ConfigDict(populate_by_name=True)
109
+
110
+
111
+ # Cancel All Method
112
+ class CancelAllParams(BaseModel):
113
+ """Parameters for cancelling all orders."""
114
+ expires_after: int = Field(..., alias="expiresAfter", description="Expiration timestamp")
115
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
116
+
117
+ model_config = ConfigDict(populate_by_name=True)
@@ -0,0 +1,59 @@
1
+ """Vault exchange method types."""
2
+ from typing import Optional
3
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
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
+ # Deposit To Vault Method
31
+ class DepositToVaultParams(BaseModel):
32
+ """Parameters for depositing to a vault."""
33
+ vault_address: str = Field(..., alias="vaultAddress", description="Vault address")
34
+ amount: str = Field(..., description="Deposit amount")
35
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
36
+
37
+ model_config = ConfigDict(populate_by_name=True)
38
+
39
+ @field_validator('vault_address', mode='before')
40
+ @classmethod
41
+ def validate_vault_address(cls, v: str) -> str:
42
+ """Validate and checksum the vault address."""
43
+ return validate_ethereum_address(v)
44
+
45
+
46
+ # Redeem From Vault Method
47
+ class RedeemFromVaultParams(BaseModel):
48
+ """Parameters for redeeming from a vault."""
49
+ vault_address: str = Field(..., alias="vaultAddress", description="Vault address")
50
+ shares: str = Field(..., description="Number of shares to redeem")
51
+ nonce: Optional[int] = Field(None, description="Transaction nonce")
52
+
53
+ model_config = ConfigDict(populate_by_name=True)
54
+
55
+ @field_validator('vault_address', mode='before')
56
+ @classmethod
57
+ def validate_vault_address(cls, v: str) -> str:
58
+ """Validate and checksum the vault address."""
59
+ return validate_ethereum_address(v)
@@ -0,0 +1,14 @@
1
+ """Info method types organized by category."""
2
+ import importlib
3
+
4
+ GlobalInfoMethods = importlib.import_module("hotstuff.methods.info.global")
5
+ AccountInfoMethods = importlib.import_module("hotstuff.methods.info.account")
6
+ VaultInfoMethods = importlib.import_module("hotstuff.methods.info.vault")
7
+ ExplorerInfoMethods = importlib.import_module("hotstuff.methods.info.explorer")
8
+
9
+ __all__ = [
10
+ "GlobalInfoMethods",
11
+ "AccountInfoMethods",
12
+ "VaultInfoMethods",
13
+ "ExplorerInfoMethods",
14
+ ]