Skip to content

Commit b4d2d1b

Browse files
authored
Version 0.22.0 (#260)
Add support for general user abstraction actions
1 parent be7523d commit b4d2d1b

8 files changed

Lines changed: 115 additions & 5 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ jobs:
3333
python-version: ${{ matrix.python-version }}
3434

3535
- name: Install poetry
36-
run: make poetry-download
36+
uses: snok/install-poetry@v1
37+
with:
38+
version: 1.8.5
39+
virtualenvs-create: true
40+
virtualenvs-in-project: true
3741

3842
- name: Set up cache
3943
uses: actions/cache@v4
@@ -42,9 +46,7 @@ jobs:
4246
key: venv-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('poetry.lock') }}
4347

4448
- name: Install dependencies
45-
run: |
46-
poetry config virtualenvs.in-project true
47-
poetry install
49+
run: poetry install
4850

4951
- name: Run tests
5052
run: |

examples/dex_abstraction.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# See https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#enable-hip-3-dex-abstraction for more details
2+
# NOTE: setting dex_abstraction is legacy. Prefer setting user_abstraction in user_abstraction.py
23
import example_utils
34

45
from hyperliquid.exchange import Exchange

examples/user_abstraction.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import example_utils
2+
3+
from hyperliquid.exchange import Exchange
4+
from hyperliquid.utils import constants
5+
6+
# set sub-account user address here
7+
SUB_ACCOUNT_USER = "0x0000000000000000000000000000000000000000"
8+
9+
10+
def main():
11+
address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True)
12+
13+
# set abstraction for user via agent
14+
# Note: the account must be in "default" mode to succeed
15+
user = exchange.account_address
16+
print("current user abstraction state:", info.query_user_abstraction_state(user))
17+
agent_set_abstraction_result = exchange.agent_set_abstraction("u")
18+
print(agent_set_abstraction_result)
19+
20+
if user == exchange.wallet.address:
21+
# set abstraction for user back to disabled
22+
user_set_abstraction_result = exchange.user_set_abstraction(user, "unifiedAccount")
23+
print(user_set_abstraction_result)
24+
print("current user abstraction state:", info.query_user_abstraction_state(user))
25+
26+
# set dex abstraction for sub-account of user
27+
print("setting abstraction for", SUB_ACCOUNT_USER)
28+
29+
# set abstraction for user via agent by setting the vault_address to SUB_ACCOUNT_USER
30+
exchange_with_sub_account = Exchange(exchange.wallet, exchange.base_url, vault_address=SUB_ACCOUNT_USER)
31+
agent_set_abstraction_result = exchange_with_sub_account.agent_set_abstraction("u")
32+
print("sub-account agent_set_abstraction result:", agent_set_abstraction_result)
33+
34+
for abstraction in ["disabled", "portfolioMargin"]:
35+
user_set_abstraction_result = exchange.user_set_abstraction(SUB_ACCOUNT_USER, abstraction)
36+
print(user_set_abstraction_result)
37+
print(
38+
"current sub-account user abstraction state:",
39+
info.query_user_abstraction_state(SUB_ACCOUNT_USER),
40+
)
41+
42+
else:
43+
print("not performing user set abstraction because not user", exchange.account_address, exchange.wallet.address)
44+
45+
46+
if __name__ == "__main__":
47+
main()

hyperliquid/exchange.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,12 @@
3333
sign_usd_class_transfer_action,
3434
sign_usd_transfer_action,
3535
sign_user_dex_abstraction_action,
36+
sign_user_set_abstraction_action,
3637
sign_withdraw_from_bridge_action,
3738
)
3839
from hyperliquid.utils.types import (
40+
Abstraction,
41+
AgentAbstraction,
3942
Any,
4043
BuilderInfo,
4144
Cloid,
@@ -1139,6 +1142,26 @@ def agent_enable_dex_abstraction(self) -> Any:
11391142
timestamp,
11401143
)
11411144

1145+
def agent_set_abstraction(self, abstraction: AgentAbstraction) -> Any:
1146+
timestamp = get_timestamp_ms()
1147+
action = {
1148+
"type": "agentSetAbstraction",
1149+
"abstraction": abstraction,
1150+
}
1151+
signature = sign_l1_action(
1152+
self.wallet,
1153+
action,
1154+
self.vault_address,
1155+
timestamp,
1156+
self.expires_after,
1157+
self.base_url == MAINNET_API_URL,
1158+
)
1159+
return self._post_action(
1160+
action,
1161+
signature,
1162+
timestamp,
1163+
)
1164+
11421165
def user_dex_abstraction(self, user: str, enabled: bool) -> Any:
11431166
timestamp = get_timestamp_ms()
11441167
action = {
@@ -1154,6 +1177,21 @@ def user_dex_abstraction(self, user: str, enabled: bool) -> Any:
11541177
timestamp,
11551178
)
11561179

1180+
def user_set_abstraction(self, user: str, abstraction: Abstraction) -> Any:
1181+
timestamp = get_timestamp_ms()
1182+
action = {
1183+
"type": "userSetAbstraction",
1184+
"user": user.lower(),
1185+
"abstraction": abstraction,
1186+
"nonce": timestamp,
1187+
}
1188+
signature = sign_user_set_abstraction_action(self.wallet, action, self.base_url == MAINNET_API_URL)
1189+
return self._post_action(
1190+
action,
1191+
signature,
1192+
timestamp,
1193+
)
1194+
11571195
def noop(self, nonce):
11581196
action = {"type": "noop"}
11591197
signature = sign_l1_action(

hyperliquid/info.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,9 @@ def query_perp_deploy_auction_status(self) -> Any:
629629
def query_user_dex_abstraction_state(self, user: str) -> Any:
630630
return self.post("/info", {"type": "userDexAbstraction", "user": user})
631631

632+
def query_user_abstraction_state(self, user: str) -> Any:
633+
return self.post("/info", {"type": "userAbstraction", "user": user})
634+
632635
def historical_orders(self, user: str) -> Any:
633636
"""Retrieve a user's historical orders.
634637

hyperliquid/utils/signing.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,13 @@
124124
{"name": "nonce", "type": "uint64"},
125125
]
126126

127+
USER_SET_ABSTRACTION_SIGN_TYPES = [
128+
{"name": "hyperliquidChain", "type": "string"},
129+
{"name": "user", "type": "address"},
130+
{"name": "abstraction", "type": "string"},
131+
{"name": "nonce", "type": "uint64"},
132+
]
133+
127134
TOKEN_DELEGATE_TYPES = [
128135
{"name": "hyperliquidChain", "type": "string"},
129136
{"name": "validator", "type": "address"},
@@ -381,6 +388,16 @@ def sign_user_dex_abstraction_action(wallet, action, is_mainnet):
381388
)
382389

383390

391+
def sign_user_set_abstraction_action(wallet, action, is_mainnet):
392+
return sign_user_signed_action(
393+
wallet,
394+
action,
395+
USER_SET_ABSTRACTION_SIGN_TYPES,
396+
"HyperliquidTransaction:UserSetAbstraction",
397+
is_mainnet,
398+
)
399+
400+
384401
def sign_convert_to_multi_sig_user_action(wallet, action, is_mainnet):
385402
return sign_user_signed_action(
386403
wallet,

hyperliquid/utils/types.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@
183183

184184
# b is the public address of the builder, f is the amount of the fee in tenths of basis points. e.g. 10 means 1 basis point
185185
BuilderInfo = TypedDict("BuilderInfo", {"b": str, "f": int})
186+
Abstraction = Literal["unifiedAccount", "portfolioMargin", "disabled"]
187+
AgentAbstraction = Literal["u", "p", "i"]
186188

187189
PerpDexSchemaInput = TypedDict(
188190
"PerpDexSchemaInput", {"fullName": str, "collateralToken": int, "oracleUpdater": Optional[str]}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
55

66
[tool.poetry]
77
name = "hyperliquid-python-sdk"
8-
version = "0.21.0"
8+
version = "0.22.0"
99
description = "SDK for Hyperliquid API trading with Python."
1010
readme = "README.md"
1111
authors = ["Hyperliquid <hello@hyperliquid.xyz>"]

0 commit comments

Comments
 (0)