hyperliquid-python-sdk-async 0.24.6__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.
- hyperliquid/__init__.py +0 -0
- hyperliquid/api.py +69 -0
- hyperliquid/exchange.py +888 -0
- hyperliquid/info.py +288 -0
- hyperliquid/utils/__init__.py +0 -0
- hyperliquid/utils/constants.py +3 -0
- hyperliquid/utils/error.py +17 -0
- hyperliquid/utils/signing.py +527 -0
- hyperliquid/utils/types.py +220 -0
- hyperliquid/websocket_manager.py +197 -0
- hyperliquid_python_sdk_async-0.24.6.dist-info/LICENSE.md +21 -0
- hyperliquid_python_sdk_async-0.24.6.dist-info/METADATA +162 -0
- hyperliquid_python_sdk_async-0.24.6.dist-info/RECORD +15 -0
- hyperliquid_python_sdk_async-0.24.6.dist-info/WHEEL +4 -0
- hyperliquid_python_sdk_async-0.24.6.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
|
|
6
|
+
import msgpack
|
|
7
|
+
from eth_account import Account
|
|
8
|
+
from eth_account.messages import encode_typed_data
|
|
9
|
+
from eth_utils import keccak, to_hex
|
|
10
|
+
|
|
11
|
+
from hyperliquid.utils.types import Cloid, Literal, NotRequired, Optional, TypedDict, Union
|
|
12
|
+
|
|
13
|
+
Tif = Union[Literal["Alo"], Literal["Ioc"], Literal["Gtc"]]
|
|
14
|
+
Tpsl = Union[Literal["tp"], Literal["sl"]]
|
|
15
|
+
LimitOrderType = TypedDict("LimitOrderType", {"tif": Tif})
|
|
16
|
+
TriggerOrderType = TypedDict("TriggerOrderType", {"triggerPx": float, "isMarket": bool, "tpsl": Tpsl})
|
|
17
|
+
TriggerOrderTypeWire = TypedDict("TriggerOrderTypeWire", {"triggerPx": str, "isMarket": bool, "tpsl": Tpsl})
|
|
18
|
+
OrderType = TypedDict("OrderType", {"limit": LimitOrderType, "trigger": TriggerOrderType}, total=False)
|
|
19
|
+
OrderTypeWire = TypedDict("OrderTypeWire", {"limit": LimitOrderType, "trigger": TriggerOrderTypeWire}, total=False)
|
|
20
|
+
OrderRequest = TypedDict(
|
|
21
|
+
"OrderRequest",
|
|
22
|
+
{
|
|
23
|
+
"coin": str,
|
|
24
|
+
"is_buy": bool,
|
|
25
|
+
"sz": float,
|
|
26
|
+
"limit_px": float,
|
|
27
|
+
"order_type": OrderType,
|
|
28
|
+
"reduce_only": bool,
|
|
29
|
+
"cloid": NotRequired[Optional[Cloid]],
|
|
30
|
+
},
|
|
31
|
+
total=False,
|
|
32
|
+
)
|
|
33
|
+
OidOrCloid = Union[int, Cloid]
|
|
34
|
+
ModifyRequest = TypedDict(
|
|
35
|
+
"ModifyRequest",
|
|
36
|
+
{
|
|
37
|
+
"oid": OidOrCloid,
|
|
38
|
+
"order": OrderRequest,
|
|
39
|
+
},
|
|
40
|
+
total=False,
|
|
41
|
+
)
|
|
42
|
+
CancelRequest = TypedDict("CancelRequest", {"coin": str, "oid": int})
|
|
43
|
+
CancelByCloidRequest = TypedDict("CancelByCloidRequest", {"coin": str, "cloid": Cloid})
|
|
44
|
+
|
|
45
|
+
PriorityGrouping = TypedDict("PriorityGrouping", {"p": int})
|
|
46
|
+
Grouping = Union[Literal["na"], Literal["normalTpsl"], Literal["positionTpsl"], PriorityGrouping]
|
|
47
|
+
Order = TypedDict(
|
|
48
|
+
"Order", {"asset": int, "isBuy": bool, "limitPx": float, "sz": float, "reduceOnly": bool, "cloid": Optional[Cloid]}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
OrderWire = TypedDict(
|
|
53
|
+
"OrderWire",
|
|
54
|
+
{
|
|
55
|
+
"a": int,
|
|
56
|
+
"b": bool,
|
|
57
|
+
"p": str,
|
|
58
|
+
"s": str,
|
|
59
|
+
"r": bool,
|
|
60
|
+
"t": OrderTypeWire,
|
|
61
|
+
"c": NotRequired[Optional[str]],
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
ModifyWire = TypedDict(
|
|
66
|
+
"ModifyWire",
|
|
67
|
+
{
|
|
68
|
+
"oid": int,
|
|
69
|
+
"order": OrderWire,
|
|
70
|
+
},
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
ScheduleCancelAction = TypedDict(
|
|
74
|
+
"ScheduleCancelAction",
|
|
75
|
+
{
|
|
76
|
+
"type": Literal["scheduleCancel"],
|
|
77
|
+
"time": NotRequired[Optional[int]],
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
USD_SEND_SIGN_TYPES = [
|
|
82
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
83
|
+
{"name": "destination", "type": "string"},
|
|
84
|
+
{"name": "amount", "type": "string"},
|
|
85
|
+
{"name": "time", "type": "uint64"},
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
SPOT_TRANSFER_SIGN_TYPES = [
|
|
89
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
90
|
+
{"name": "destination", "type": "string"},
|
|
91
|
+
{"name": "token", "type": "string"},
|
|
92
|
+
{"name": "amount", "type": "string"},
|
|
93
|
+
{"name": "time", "type": "uint64"},
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
WITHDRAW_SIGN_TYPES = [
|
|
97
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
98
|
+
{"name": "destination", "type": "string"},
|
|
99
|
+
{"name": "amount", "type": "string"},
|
|
100
|
+
{"name": "time", "type": "uint64"},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
USD_CLASS_TRANSFER_SIGN_TYPES = [
|
|
104
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
105
|
+
{"name": "amount", "type": "string"},
|
|
106
|
+
{"name": "toPerp", "type": "bool"},
|
|
107
|
+
{"name": "nonce", "type": "uint64"},
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
SEND_ASSET_SIGN_TYPES = [
|
|
111
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
112
|
+
{"name": "destination", "type": "string"},
|
|
113
|
+
{"name": "sourceDex", "type": "string"},
|
|
114
|
+
{"name": "destinationDex", "type": "string"},
|
|
115
|
+
{"name": "token", "type": "string"},
|
|
116
|
+
{"name": "amount", "type": "string"},
|
|
117
|
+
{"name": "fromSubAccount", "type": "string"},
|
|
118
|
+
{"name": "nonce", "type": "uint64"},
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
USER_DEX_ABSTRACTION_SIGN_TYPES = [
|
|
122
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
123
|
+
{"name": "user", "type": "address"},
|
|
124
|
+
{"name": "enabled", "type": "bool"},
|
|
125
|
+
{"name": "nonce", "type": "uint64"},
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
USER_SET_ABSTRACTION_SIGN_TYPES = [
|
|
129
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
130
|
+
{"name": "user", "type": "address"},
|
|
131
|
+
{"name": "abstraction", "type": "string"},
|
|
132
|
+
{"name": "nonce", "type": "uint64"},
|
|
133
|
+
]
|
|
134
|
+
|
|
135
|
+
TOKEN_DELEGATE_TYPES = [
|
|
136
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
137
|
+
{"name": "validator", "type": "address"},
|
|
138
|
+
{"name": "wei", "type": "uint64"},
|
|
139
|
+
{"name": "isUndelegate", "type": "bool"},
|
|
140
|
+
{"name": "nonce", "type": "uint64"},
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
CONVERT_TO_MULTI_SIG_USER_SIGN_TYPES = [
|
|
144
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
145
|
+
{"name": "signers", "type": "string"},
|
|
146
|
+
{"name": "nonce", "type": "uint64"},
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
MULTI_SIG_ENVELOPE_SIGN_TYPES = [
|
|
150
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
151
|
+
{"name": "multiSigActionHash", "type": "bytes32"},
|
|
152
|
+
{"name": "nonce", "type": "uint64"},
|
|
153
|
+
]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def order_type_to_wire(order_type: OrderType) -> OrderTypeWire:
|
|
157
|
+
if "limit" in order_type:
|
|
158
|
+
return {"limit": order_type["limit"]}
|
|
159
|
+
elif "trigger" in order_type:
|
|
160
|
+
return {
|
|
161
|
+
"trigger": {
|
|
162
|
+
"isMarket": order_type["trigger"]["isMarket"],
|
|
163
|
+
"triggerPx": float_to_wire(order_type["trigger"]["triggerPx"]),
|
|
164
|
+
"tpsl": order_type["trigger"]["tpsl"],
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
raise ValueError("Invalid order type", order_type)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def address_to_bytes(address):
|
|
171
|
+
return bytes.fromhex(address[2:] if address.startswith("0x") else address)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def action_hash(action, vault_address, nonce, expires_after):
|
|
175
|
+
data = msgpack.packb(action)
|
|
176
|
+
data += nonce.to_bytes(8, "big")
|
|
177
|
+
if vault_address is None:
|
|
178
|
+
data += b"\x00"
|
|
179
|
+
else:
|
|
180
|
+
data += b"\x01"
|
|
181
|
+
data += address_to_bytes(vault_address)
|
|
182
|
+
if expires_after is not None:
|
|
183
|
+
data += b"\x00"
|
|
184
|
+
data += expires_after.to_bytes(8, "big")
|
|
185
|
+
return keccak(data)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def construct_phantom_agent(hash, is_mainnet):
|
|
189
|
+
return {"source": "a" if is_mainnet else "b", "connectionId": hash}
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def l1_payload(phantom_agent):
|
|
193
|
+
return {
|
|
194
|
+
"domain": {
|
|
195
|
+
"chainId": 1337,
|
|
196
|
+
"name": "Exchange",
|
|
197
|
+
"verifyingContract": "0x0000000000000000000000000000000000000000",
|
|
198
|
+
"version": "1",
|
|
199
|
+
},
|
|
200
|
+
"types": {
|
|
201
|
+
"Agent": [
|
|
202
|
+
{"name": "source", "type": "string"},
|
|
203
|
+
{"name": "connectionId", "type": "bytes32"},
|
|
204
|
+
],
|
|
205
|
+
"EIP712Domain": [
|
|
206
|
+
{"name": "name", "type": "string"},
|
|
207
|
+
{"name": "version", "type": "string"},
|
|
208
|
+
{"name": "chainId", "type": "uint256"},
|
|
209
|
+
{"name": "verifyingContract", "type": "address"},
|
|
210
|
+
],
|
|
211
|
+
},
|
|
212
|
+
"primaryType": "Agent",
|
|
213
|
+
"message": phantom_agent,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def user_signed_payload(primary_type, payload_types, action):
|
|
218
|
+
chain_id = int(action["signatureChainId"], 16)
|
|
219
|
+
return {
|
|
220
|
+
"domain": {
|
|
221
|
+
"name": "HyperliquidSignTransaction",
|
|
222
|
+
"version": "1",
|
|
223
|
+
"chainId": chain_id,
|
|
224
|
+
"verifyingContract": "0x0000000000000000000000000000000000000000",
|
|
225
|
+
},
|
|
226
|
+
"types": {
|
|
227
|
+
primary_type: payload_types,
|
|
228
|
+
"EIP712Domain": [
|
|
229
|
+
{"name": "name", "type": "string"},
|
|
230
|
+
{"name": "version", "type": "string"},
|
|
231
|
+
{"name": "chainId", "type": "uint256"},
|
|
232
|
+
{"name": "verifyingContract", "type": "address"},
|
|
233
|
+
],
|
|
234
|
+
},
|
|
235
|
+
"primaryType": primary_type,
|
|
236
|
+
"message": action,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def sign_l1_action(wallet, action, active_pool, nonce, expires_after, is_mainnet):
|
|
241
|
+
hash = action_hash(action, active_pool, nonce, expires_after)
|
|
242
|
+
phantom_agent = construct_phantom_agent(hash, is_mainnet)
|
|
243
|
+
data = l1_payload(phantom_agent)
|
|
244
|
+
return sign_inner(wallet, data)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def sign_user_signed_action(wallet, action, payload_types, primary_type, is_mainnet):
|
|
248
|
+
# signatureChainId is the chain used by the wallet to sign and can be any chain.
|
|
249
|
+
# hyperliquidChain determines the environment and prevents replaying an action on a different chain.
|
|
250
|
+
action["signatureChainId"] = "0x66eee"
|
|
251
|
+
action["hyperliquidChain"] = "Mainnet" if is_mainnet else "Testnet"
|
|
252
|
+
data = user_signed_payload(primary_type, payload_types, action)
|
|
253
|
+
return sign_inner(wallet, data)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def add_multi_sig_types(sign_types):
|
|
257
|
+
enriched_sign_types = []
|
|
258
|
+
enriched = False
|
|
259
|
+
for sign_type in sign_types:
|
|
260
|
+
enriched_sign_types.append(sign_type)
|
|
261
|
+
if sign_type["name"] == "hyperliquidChain":
|
|
262
|
+
enriched = True
|
|
263
|
+
enriched_sign_types.append(
|
|
264
|
+
{
|
|
265
|
+
"name": "payloadMultiSigUser",
|
|
266
|
+
"type": "address",
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
enriched_sign_types.append(
|
|
270
|
+
{
|
|
271
|
+
"name": "outerSigner",
|
|
272
|
+
"type": "address",
|
|
273
|
+
}
|
|
274
|
+
)
|
|
275
|
+
if not enriched:
|
|
276
|
+
print('"hyperliquidChain" missing from sign_types. sign_types was not enriched with multi-sig signing types')
|
|
277
|
+
return enriched_sign_types
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def add_multi_sig_fields(action, payload_multi_sig_user, outer_signer):
|
|
281
|
+
action = action.copy()
|
|
282
|
+
action["payloadMultiSigUser"] = payload_multi_sig_user.lower()
|
|
283
|
+
action["outerSigner"] = outer_signer.lower()
|
|
284
|
+
return action
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def sign_multi_sig_user_signed_action_payload(
|
|
288
|
+
wallet, action, is_mainnet, sign_types, tx_type, payload_multi_sig_user, outer_signer
|
|
289
|
+
):
|
|
290
|
+
envelope = add_multi_sig_fields(action, payload_multi_sig_user, outer_signer)
|
|
291
|
+
sign_types = add_multi_sig_types(sign_types)
|
|
292
|
+
return sign_user_signed_action(
|
|
293
|
+
wallet,
|
|
294
|
+
envelope,
|
|
295
|
+
sign_types,
|
|
296
|
+
tx_type,
|
|
297
|
+
is_mainnet,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def sign_multi_sig_l1_action_payload(
|
|
302
|
+
wallet, action, is_mainnet, vault_address, timestamp, expires_after, payload_multi_sig_user, outer_signer
|
|
303
|
+
):
|
|
304
|
+
envelope = [payload_multi_sig_user.lower(), outer_signer.lower(), action]
|
|
305
|
+
return sign_l1_action(
|
|
306
|
+
wallet,
|
|
307
|
+
envelope,
|
|
308
|
+
vault_address,
|
|
309
|
+
timestamp,
|
|
310
|
+
expires_after,
|
|
311
|
+
is_mainnet,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def sign_multi_sig_action(wallet, action, is_mainnet, vault_address, nonce, expires_after):
|
|
316
|
+
action_without_tag = action.copy()
|
|
317
|
+
del action_without_tag["type"]
|
|
318
|
+
multi_sig_action_hash = action_hash(action_without_tag, vault_address, nonce, expires_after)
|
|
319
|
+
envelope = {
|
|
320
|
+
"multiSigActionHash": multi_sig_action_hash,
|
|
321
|
+
"nonce": nonce,
|
|
322
|
+
}
|
|
323
|
+
return sign_user_signed_action(
|
|
324
|
+
wallet,
|
|
325
|
+
envelope,
|
|
326
|
+
MULTI_SIG_ENVELOPE_SIGN_TYPES,
|
|
327
|
+
"HyperliquidTransaction:SendMultiSig",
|
|
328
|
+
is_mainnet,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def sign_usd_transfer_action(wallet, action, is_mainnet):
|
|
333
|
+
return sign_user_signed_action(
|
|
334
|
+
wallet,
|
|
335
|
+
action,
|
|
336
|
+
USD_SEND_SIGN_TYPES,
|
|
337
|
+
"HyperliquidTransaction:UsdSend",
|
|
338
|
+
is_mainnet,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def sign_spot_transfer_action(wallet, action, is_mainnet):
|
|
343
|
+
return sign_user_signed_action(
|
|
344
|
+
wallet,
|
|
345
|
+
action,
|
|
346
|
+
SPOT_TRANSFER_SIGN_TYPES,
|
|
347
|
+
"HyperliquidTransaction:SpotSend",
|
|
348
|
+
is_mainnet,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def sign_withdraw_from_bridge_action(wallet, action, is_mainnet):
|
|
353
|
+
return sign_user_signed_action(
|
|
354
|
+
wallet,
|
|
355
|
+
action,
|
|
356
|
+
WITHDRAW_SIGN_TYPES,
|
|
357
|
+
"HyperliquidTransaction:Withdraw",
|
|
358
|
+
is_mainnet,
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def sign_usd_class_transfer_action(wallet, action, is_mainnet):
|
|
363
|
+
return sign_user_signed_action(
|
|
364
|
+
wallet,
|
|
365
|
+
action,
|
|
366
|
+
USD_CLASS_TRANSFER_SIGN_TYPES,
|
|
367
|
+
"HyperliquidTransaction:UsdClassTransfer",
|
|
368
|
+
is_mainnet,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def sign_send_asset_action(wallet, action, is_mainnet):
|
|
373
|
+
return sign_user_signed_action(
|
|
374
|
+
wallet,
|
|
375
|
+
action,
|
|
376
|
+
SEND_ASSET_SIGN_TYPES,
|
|
377
|
+
"HyperliquidTransaction:SendAsset",
|
|
378
|
+
is_mainnet,
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
def sign_user_dex_abstraction_action(wallet, action, is_mainnet):
|
|
383
|
+
return sign_user_signed_action(
|
|
384
|
+
wallet,
|
|
385
|
+
action,
|
|
386
|
+
USER_DEX_ABSTRACTION_SIGN_TYPES,
|
|
387
|
+
"HyperliquidTransaction:UserDexAbstraction",
|
|
388
|
+
is_mainnet,
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def sign_user_set_abstraction_action(wallet, action, is_mainnet):
|
|
393
|
+
return sign_user_signed_action(
|
|
394
|
+
wallet,
|
|
395
|
+
action,
|
|
396
|
+
USER_SET_ABSTRACTION_SIGN_TYPES,
|
|
397
|
+
"HyperliquidTransaction:UserSetAbstraction",
|
|
398
|
+
is_mainnet,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def sign_convert_to_multi_sig_user_action(wallet, action, is_mainnet):
|
|
403
|
+
return sign_user_signed_action(
|
|
404
|
+
wallet,
|
|
405
|
+
action,
|
|
406
|
+
CONVERT_TO_MULTI_SIG_USER_SIGN_TYPES,
|
|
407
|
+
"HyperliquidTransaction:ConvertToMultiSigUser",
|
|
408
|
+
is_mainnet,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def sign_agent(wallet, action, is_mainnet):
|
|
413
|
+
return sign_user_signed_action(
|
|
414
|
+
wallet,
|
|
415
|
+
action,
|
|
416
|
+
[
|
|
417
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
418
|
+
{"name": "agentAddress", "type": "address"},
|
|
419
|
+
{"name": "agentName", "type": "string"},
|
|
420
|
+
{"name": "nonce", "type": "uint64"},
|
|
421
|
+
],
|
|
422
|
+
"HyperliquidTransaction:ApproveAgent",
|
|
423
|
+
is_mainnet,
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def sign_approve_builder_fee(wallet, action, is_mainnet):
|
|
428
|
+
return sign_user_signed_action(
|
|
429
|
+
wallet,
|
|
430
|
+
action,
|
|
431
|
+
[
|
|
432
|
+
{"name": "hyperliquidChain", "type": "string"},
|
|
433
|
+
{"name": "maxFeeRate", "type": "string"},
|
|
434
|
+
{"name": "builder", "type": "address"},
|
|
435
|
+
{"name": "nonce", "type": "uint64"},
|
|
436
|
+
],
|
|
437
|
+
"HyperliquidTransaction:ApproveBuilderFee",
|
|
438
|
+
is_mainnet,
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def sign_token_delegate_action(wallet, action, is_mainnet):
|
|
443
|
+
return sign_user_signed_action(
|
|
444
|
+
wallet,
|
|
445
|
+
action,
|
|
446
|
+
TOKEN_DELEGATE_TYPES,
|
|
447
|
+
"HyperliquidTransaction:TokenDelegate",
|
|
448
|
+
is_mainnet,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def sign_inner(wallet, data):
|
|
453
|
+
structured_data = encode_typed_data(full_message=data)
|
|
454
|
+
signed = wallet.sign_message(structured_data)
|
|
455
|
+
return {"r": to_hex(signed["r"]), "s": to_hex(signed["s"]), "v": signed["v"]}
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
def recover_agent_or_user_from_l1_action(action, signature, active_pool, nonce, expires_after, is_mainnet):
|
|
459
|
+
hash = action_hash(action, active_pool, nonce, expires_after)
|
|
460
|
+
phantom_agent = construct_phantom_agent(hash, is_mainnet)
|
|
461
|
+
data = l1_payload(phantom_agent)
|
|
462
|
+
structured_data = encode_typed_data(full_message=data)
|
|
463
|
+
address = Account.recover_message(structured_data, vrs=[signature["v"], signature["r"], signature["s"]])
|
|
464
|
+
return address
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def recover_user_from_user_signed_action(action, signature, payload_types, primary_type, is_mainnet):
|
|
468
|
+
action["hyperliquidChain"] = "Mainnet" if is_mainnet else "Testnet"
|
|
469
|
+
data = user_signed_payload(primary_type, payload_types, action)
|
|
470
|
+
structured_data = encode_typed_data(full_message=data)
|
|
471
|
+
address = Account.recover_message(structured_data, vrs=[signature["v"], signature["r"], signature["s"]])
|
|
472
|
+
return address
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def float_to_wire(x: float) -> str:
|
|
476
|
+
rounded = f"{x:.8f}"
|
|
477
|
+
if abs(float(rounded) - x) >= 1e-12:
|
|
478
|
+
raise ValueError("float_to_wire causes rounding", x)
|
|
479
|
+
if rounded == "-0":
|
|
480
|
+
rounded = "0"
|
|
481
|
+
normalized = Decimal(rounded).normalize()
|
|
482
|
+
return f"{normalized:f}"
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def float_to_int_for_hashing(x: float) -> int:
|
|
486
|
+
return float_to_int(x, 8)
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def float_to_usd_int(x: float) -> int:
|
|
490
|
+
return float_to_int(x, 6)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
def float_to_int(x: float, power: int) -> int:
|
|
494
|
+
with_decimals = x * 10**power
|
|
495
|
+
if abs(round(with_decimals) - with_decimals) >= 1e-3:
|
|
496
|
+
raise ValueError("float_to_int causes rounding", x)
|
|
497
|
+
res: int = round(with_decimals)
|
|
498
|
+
return res
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def get_timestamp_ms() -> int:
|
|
502
|
+
return int(time.time() * 1000)
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def order_request_to_order_wire(order: OrderRequest, asset: int) -> OrderWire:
|
|
506
|
+
order_wire: OrderWire = {
|
|
507
|
+
"a": asset,
|
|
508
|
+
"b": order["is_buy"],
|
|
509
|
+
"p": float_to_wire(order["limit_px"]),
|
|
510
|
+
"s": float_to_wire(order["sz"]),
|
|
511
|
+
"r": order["reduce_only"],
|
|
512
|
+
"t": order_type_to_wire(order["order_type"]),
|
|
513
|
+
}
|
|
514
|
+
if "cloid" in order and order["cloid"] is not None:
|
|
515
|
+
order_wire["c"] = order["cloid"].to_raw()
|
|
516
|
+
return order_wire
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def order_wires_to_order_action(order_wires: list[OrderWire], builder: Any = None, grouping: Grouping = "na") -> Any:
|
|
520
|
+
action = {
|
|
521
|
+
"type": "order",
|
|
522
|
+
"orders": order_wires,
|
|
523
|
+
"grouping": grouping,
|
|
524
|
+
}
|
|
525
|
+
if builder:
|
|
526
|
+
action["builder"] = builder
|
|
527
|
+
return action
|