Skip to content

Commit 973e987

Browse files
committed
Various small updates
Fix type errors in basic_adding Updates to multi-sig examples Updates to License Fixes to Readme and dev dependencies
1 parent 636d60e commit 973e987

File tree

12 files changed

+152
-84
lines changed

12 files changed

+152
-84
lines changed

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2023 Hyperliquid Corp.
3+
Copyright (c) 2024 Hyperliquid Labs Pte. Ltd.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ python examples/basic_order.py
4646

4747
## Getting started with contributing to this repo
4848

49-
1. Download `Poetry`: https://python-poetry.org/. Note that in the install script you might have to set `symlinks=True` in `venv.EnvBuilder`.
49+
1. Download `Poetry`: https://python-poetry.org/.
50+
- Note that in the install script you might have to set `symlinks=True` in `venv.EnvBuilder`.
51+
- Note that Poetry v2 is not supported, so you'll need to specify a specific version e.g. curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.4.1 python3 -
5052

5153
2. Point poetry to correct version of python. For development we require python 3.10 exactly. Some dependencies have issues on 3.11, while older versions don't have correct typing support.
52-
`brew install [email protected] && poetry env use /opt/homebrew/Cellar/[email protected]/3.10.10_1/bin/python3.10`
54+
`brew install [email protected] && poetry env use /opt/homebrew/Cellar/[email protected]/3.10.16/bin/python3.10`
5355

5456
3. Install dependencies:
5557

@@ -210,16 +212,13 @@ This project is licensed under the terms of the `MIT` license. See [LICENSE](LIC
210212
@misc{hyperliquid-python-sdk,
211213
author = {Hyperliquid},
212214
title = {SDK for Hyperliquid API trading with Python.},
213-
year = {2023},
215+
year = {2024},
214216
publisher = {GitHub},
215217
journal = {GitHub repository},
216218
howpublished = {\url{https://github.com/hyperliquid-dex/hyperliquid-python-sdk}}
217219
}
218220
```
219221

220-
## Terms
221-
222-
By using this package you agree to the Terms of Use. See [TERMS](TERMS.md) for more details.
223222
## Credits
224223

225224
This project was generated with [`python-package-template`](https://github.com/TezRomacH/python-package-template).

TERMS.md

Lines changed: 0 additions & 36 deletions
This file was deleted.

examples/basic_adding.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from hyperliquid.utils.types import (
1414
SIDES,
1515
Dict,
16+
L2BookData,
1617
L2BookMsg,
1718
L2BookSubscription,
1819
Literal,
@@ -113,7 +114,7 @@ def on_book_update(self, book_msg: L2BookMsg) -> None:
113114
for side in SIDES:
114115
self.handle_order_placement(side, book_data)
115116

116-
def handle_order_placement(self, side: Side, book_data: Dict) -> None:
117+
def handle_order_placement(self, side: Side, book_data: L2BookData) -> None:
117118
"""Handle the placement and cancellation of orders based on the order book update."""
118119
book_price = float(book_data["levels"][side_to_uint(side)][0]["px"])
119120
ideal_distance = book_price * DEPTH
@@ -185,19 +186,19 @@ def poll(self) -> None:
185186
# Fetch open orders
186187
open_orders = self.info.open_orders(self.exchange.wallet.address)
187188
print("open_orders", open_orders)
188-
189+
189190
# Collect valid order IDs (from recently cancelled orders and resting orders)
190191
ok_oids = set(self.recently_cancelled_oid_to_time.keys())
191192
for provide_state in self.provide_state.values():
192193
if provide_state["type"] == "resting":
193194
ok_oids.add(provide_state["oid"])
194-
195+
195196
# Cancel any unknown orders
196197
for open_order in open_orders:
197198
if open_order["coin"] == COIN and open_order["oid"] not in ok_oids:
198199
print("Cancelling unknown oid", open_order["oid"])
199200
self.exchange.cancel(open_order["coin"], open_order["oid"])
200-
201+
201202
# Clean up recently cancelled orders after a timeout
202203
current_time = get_timestamp_ms()
203204
self.recently_cancelled_oid_to_time = {
@@ -224,5 +225,6 @@ def main():
224225
address, info, exchange = example_utils.setup(constants.TESTNET_API_URL)
225226
BasicAdder(address, info, exchange)
226227

228+
227229
if __name__ == "__main__":
228230
main()

examples/multi_sig_order.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from hyperliquid.utils import constants
2+
from hyperliquid.utils.signing import get_timestamp_ms, sign_multi_sig_l1_action_payload
3+
import example_utils
4+
5+
6+
def main():
7+
address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True)
8+
multi_sig_wallets = example_utils.setup_multi_sig_wallets()
9+
10+
# The outer signer is required to be an authorized user or an agent of the authorized user of the multi-sig user.
11+
12+
# Address of the multi-sig user that the action will be executed for
13+
# Executing the action requires at least the specified threshold of signatures
14+
# required for that multi-sig user
15+
multi_sig_user = "0x0000000000000000000000000000000000000005"
16+
17+
timestamp = get_timestamp_ms()
18+
19+
# Define the multi-sig inner action
20+
action = {
21+
"type": "order",
22+
"orders": [{"a": 4, "b": True, "p": "1100", "s": "0.2", "r": False, "t": {"limit": {"tif": "Gtc"}}}],
23+
"grouping": "na",
24+
}
25+
26+
timestamp = get_timestamp_ms()
27+
signatures = []
28+
29+
# Collect signatures from each wallet in multi_sig_wallets. Each wallet must belong to a user.
30+
for wallet in multi_sig_wallets:
31+
# Sign the action with each wallet
32+
signature = sign_multi_sig_l1_action_payload(
33+
wallet,
34+
action,
35+
exchange.base_url == constants.MAINNET_API_URL,
36+
None,
37+
timestamp,
38+
multi_sig_user,
39+
address,
40+
)
41+
signatures.append(signature)
42+
43+
# Execute the multi-sig action with all collected signatures
44+
# This will only succeed if enough valid signatures are provided
45+
multi_sig_result = exchange.multi_sig(multi_sig_user, action, signatures, timestamp)
46+
print(multi_sig_result)
47+
48+
49+
if __name__ == "__main__":
50+
main()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from hyperliquid.utils import constants
2+
from hyperliquid.utils.signing import get_timestamp_ms, sign_multi_sig_l1_action_payload
3+
import example_utils
4+
5+
6+
def main():
7+
address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True)
8+
multi_sig_wallets = example_utils.setup_multi_sig_wallets()
9+
10+
# The outer signer is required to be an authorized user or an agent of the authorized user of the multi-sig user.
11+
12+
# Address of the multi-sig user that the action will be executed for
13+
# Executing the action requires at least the specified threshold of signatures
14+
# required for that multi-sig user
15+
multi_sig_user = "0x0000000000000000000000000000000000000005"
16+
17+
timestamp = get_timestamp_ms()
18+
19+
# Define the multi-sig inner action
20+
action = {
21+
"type": "spotDeploy",
22+
"registerToken2": {
23+
"spec": {"name": "TESTH", "szDecimals": 2, "weiDecimals": 8},
24+
"maxGas": 1000000000000,
25+
"fullName": "Example multi-sig spot deploy",
26+
},
27+
}
28+
29+
timestamp = get_timestamp_ms()
30+
signatures = []
31+
32+
# Collect signatures from each wallet in multi_sig_wallets. Each wallet must belong to a user.
33+
for wallet in multi_sig_wallets:
34+
# Sign the action with each wallet
35+
signature = sign_multi_sig_l1_action_payload(
36+
wallet,
37+
action,
38+
exchange.base_url == constants.MAINNET_API_URL,
39+
None,
40+
timestamp,
41+
multi_sig_user,
42+
address,
43+
)
44+
signatures.append(signature)
45+
46+
# Execute the multi-sig action with all collected signatures
47+
# This will only succeed if enough valid signatures are provided
48+
multi_sig_result = exchange.multi_sig(multi_sig_user, action, signatures, timestamp)
49+
print(multi_sig_result)
50+
51+
52+
if __name__ == "__main__":
53+
main()
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from hyperliquid.utils import constants
2-
from hyperliquid.utils.signing import get_timestamp_ms, sign_multi_sig_inner, USD_SEND_SIGN_TYPES
3-
from hyperliquid.utils.types import Any, List
2+
from hyperliquid.utils.signing import get_timestamp_ms, sign_multi_sig_user_signed_action_payload, USD_SEND_SIGN_TYPES
43
import example_utils
54

65

@@ -26,12 +25,12 @@ def main():
2625
"amount": "100.0",
2726
"time": timestamp,
2827
}
29-
signatures: List[Any] = []
28+
signatures = []
3029

3130
# Collect signatures from each wallet in multi_sig_wallets. Each wallet must belong to a user.
3231
for wallet in multi_sig_wallets:
3332
# Sign the action with each wallet
34-
signature = sign_multi_sig_inner(
33+
signature = sign_multi_sig_user_signed_action_payload(
3534
wallet,
3635
action,
3736
exchange.base_url == constants.MAINNET_API_URL,

examples/multi_sig_wallets.json.example

Lines changed: 0 additions & 12 deletions
This file was deleted.

hyperliquid/utils/signing.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,9 @@ def add_multi_sig_fields(action, payload_multi_sig_user, outer_signer):
233233
return action
234234

235235

236-
def sign_multi_sig_inner(wallet, action, is_mainnet, sign_types, tx_type, payload_multi_sig_user, outer_signer):
236+
def sign_multi_sig_user_signed_action_payload(
237+
wallet, action, is_mainnet, sign_types, tx_type, payload_multi_sig_user, outer_signer
238+
):
237239
envelope = add_multi_sig_fields(action, payload_multi_sig_user, outer_signer)
238240
sign_types = add_multi_sig_types(sign_types)
239241
return sign_user_signed_action(
@@ -245,6 +247,19 @@ def sign_multi_sig_inner(wallet, action, is_mainnet, sign_types, tx_type, payloa
245247
)
246248

247249

250+
def sign_multi_sig_l1_action_payload(
251+
wallet, action, is_mainnet, vault_address, timestamp, payload_multi_sig_user, outer_signer
252+
):
253+
envelope = [payload_multi_sig_user.lower(), outer_signer.lower(), action]
254+
return sign_l1_action(
255+
wallet,
256+
envelope,
257+
vault_address,
258+
timestamp,
259+
is_mainnet,
260+
)
261+
262+
248263
def sign_multi_sig_action(wallet, action, is_mainnet, vault_address, nonce):
249264
action_without_tag = action.copy()
250265
del action_without_tag["type"]

hyperliquid/utils/types.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,11 @@
9898
"OtherWsMsg",
9999
{
100100
"channel": Union[
101-
Literal["candle"], Literal["orderUpdates"], Literal["userFundings"], Literal["userNonFundingLedgerUpdates"], Literal["webData2"]
101+
Literal["candle"],
102+
Literal["orderUpdates"],
103+
Literal["userFundings"],
104+
Literal["userNonFundingLedgerUpdates"],
105+
Literal["webData2"],
102106
],
103107
"data": Any,
104108
},

0 commit comments

Comments
 (0)