Skip to content

Commit 894e9d3

Browse files
committed
Version 0.14.0
1 parent 583a96d commit 894e9d3

File tree

7 files changed

+261
-23
lines changed

7 files changed

+261
-23
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# This example shows how to place and query orders for a builder-deployed perp dex
2+
import json
3+
4+
import example_utils
5+
6+
from hyperliquid.utils import constants
7+
8+
DUMMY_DEX = "test"
9+
COIN = f"{DUMMY_DEX}:ABC"
10+
11+
12+
def main():
13+
# Supply the builder-deployed perps dex as an argument
14+
address, info, exchange = example_utils.setup(
15+
base_url=constants.TESTNET_API_URL, skip_ws=True, perp_dexs=[DUMMY_DEX]
16+
)
17+
18+
# Get the user state and print out position information
19+
user_state = info.user_state(address)
20+
positions = []
21+
for position in user_state["assetPositions"]:
22+
positions.append(position["position"])
23+
if len(positions) > 0:
24+
print("positions:")
25+
for position in positions:
26+
print(json.dumps(position, indent=2))
27+
else:
28+
print("no open positions")
29+
30+
# Print the meta for DUMMY_DEX
31+
print("dummy dex meta:", info.meta(dex=DUMMY_DEX))
32+
33+
# Place an order that should rest by setting the price very low
34+
order_result = exchange.order(COIN, True, 20, 1, {"limit": {"tif": "Gtc"}})
35+
print(order_result)
36+
37+
# Query the order status by oid
38+
if order_result["status"] == "ok":
39+
status = order_result["response"]["data"]["statuses"][0]
40+
if "resting" in status:
41+
order_status = info.query_order_by_oid(address, status["resting"]["oid"])
42+
print("Order status by oid:", order_status)
43+
44+
# Cancel the order
45+
if order_result["status"] == "ok":
46+
status = order_result["response"]["data"]["statuses"][0]
47+
if "resting" in status:
48+
cancel_result = exchange.cancel(COIN, status["resting"]["oid"])
49+
print(cancel_result)
50+
51+
52+
if __name__ == "__main__":
53+
main()

examples/example_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from hyperliquid.info import Info
99

1010

11-
def setup(base_url=None, skip_ws=False):
11+
def setup(base_url=None, skip_ws=False, perp_dexs=None):
1212
config_path = os.path.join(os.path.dirname(__file__), "config.json")
1313
with open(config_path) as f:
1414
config = json.load(f)
@@ -19,7 +19,7 @@ def setup(base_url=None, skip_ws=False):
1919
print("Running with account address:", address)
2020
if address != account.address:
2121
print("Running with agent address:", account.address)
22-
info = Info(base_url, skip_ws)
22+
info = Info(base_url, skip_ws, perp_dexs=perp_dexs)
2323
user_state = info.user_state(address)
2424
spot_user_state = info.spot_user_state(address)
2525
margin_summary = user_state["marginSummary"]
@@ -28,7 +28,7 @@ def setup(base_url=None, skip_ws=False):
2828
url = info.base_url.split(".", 1)[1]
2929
error_string = f"No accountValue:\nIf you think this is a mistake, make sure that {address} has a balance on {url}.\nIf address shown is your API wallet address, update the config to specify the address of your account, not the address of the API wallet."
3030
raise Exception(error_string)
31-
exchange = Exchange(account, base_url, account_address=address)
31+
exchange = Exchange(account, base_url, account_address=address, perp_dexs=perp_dexs)
3232
return address, info, exchange
3333

3434

examples/perp_deploy.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Example script to for deploying a perp dex
2+
#
3+
# IMPORTANT: Replace any arguments for the exchange calls below to match your deployment requirements.
4+
5+
import example_utils
6+
7+
from hyperliquid.utils import constants
8+
9+
# Set to True to register a new perp dex.
10+
REGISTER_PERP_DEX = False
11+
12+
DUMMY_DEX = "test"
13+
14+
15+
def main():
16+
address, info, exchange = example_utils.setup(constants.TESTNET_API_URL, skip_ws=True)
17+
18+
# Step 1: Registering a Perp Dex and Assets
19+
#
20+
# Takes part in the perp deploy auction and if successful, registers asset "TEST0".
21+
# The max gas is $1M USDC and represents the max amount to be paid for the perp deploy auction.
22+
# Registering an asset can be done multiple times.
23+
perp_dex_schema_input = None
24+
if REGISTER_PERP_DEX:
25+
perp_dex_schema_input = {
26+
"fullName": "test dex",
27+
"collateralToken": 0,
28+
"oracleUpdater": address,
29+
}
30+
register_asset_result = exchange.perp_deploy_register_asset(
31+
dex=DUMMY_DEX,
32+
max_gas=1000000000000,
33+
coin="TEST0",
34+
sz_decimals=2,
35+
oracle_px="10.0",
36+
margin_table_id=10,
37+
only_isolated=False,
38+
schema=perp_dex_schema_input,
39+
)
40+
print("register asset result:", register_asset_result)
41+
# If registration is successful, the "dex" that was used can serve as the index into this clearinghouse for later asset
42+
# registrations and oracle updates.
43+
44+
# Step 2: Set the Oracle Prices
45+
#
46+
# Oracle updates can be sent multiple times
47+
set_oracle_result = exchange.perp_deploy_set_oracle(
48+
DUMMY_DEX,
49+
{
50+
"TEST0": "12.0",
51+
"TEST1": "1.0",
52+
},
53+
{
54+
"TEST1": "3.0",
55+
"TEST0": "14.0",
56+
},
57+
)
58+
print("set oracle result:", set_oracle_result)
59+
60+
# get DUMMY_DEX meta
61+
print("dummy dex meta:", info.meta(dex=DUMMY_DEX))
62+
63+
64+
if __name__ == "__main__":
65+
main()

hyperliquid/exchange.py

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,18 @@
3232
sign_usd_transfer_action,
3333
sign_withdraw_from_bridge_action,
3434
)
35-
from hyperliquid.utils.types import Any, BuilderInfo, Cloid, List, Meta, Optional, SpotMeta, Tuple
35+
from hyperliquid.utils.types import (
36+
Any,
37+
BuilderInfo,
38+
Cloid,
39+
Dict,
40+
List,
41+
Meta,
42+
Optional,
43+
PerpDexSchemaInput,
44+
SpotMeta,
45+
Tuple,
46+
)
3647

3748

3849
class Exchange(API):
@@ -47,12 +58,13 @@ def __init__(
4758
vault_address: Optional[str] = None,
4859
account_address: Optional[str] = None,
4960
spot_meta: Optional[SpotMeta] = None,
61+
perp_dexs: Optional[List[str]] = None,
5062
):
5163
super().__init__(base_url)
5264
self.wallet = wallet
5365
self.vault_address = vault_address
5466
self.account_address = account_address
55-
self.info = Info(base_url, True, meta, spot_meta)
67+
self.info = Info(base_url, True, meta, spot_meta, perp_dexs)
5668
self.expires_after: Optional[int] = None
5769

5870
def _post_action(self, action, signature, nonce):
@@ -831,6 +843,87 @@ def spot_deploy_set_deployer_trading_fee_share(self, token: int, share: str) ->
831843
timestamp,
832844
)
833845

846+
def perp_deploy_register_asset(
847+
self,
848+
dex: str,
849+
max_gas: Optional[int],
850+
coin: str,
851+
sz_decimals: int,
852+
oracle_px: str,
853+
margin_table_id: int,
854+
only_isolated: bool,
855+
schema: Optional[PerpDexSchemaInput],
856+
) -> Any:
857+
timestamp = get_timestamp_ms()
858+
schema_wire = None
859+
if schema is not None:
860+
schema_wire = {
861+
"fullName": schema["fullName"],
862+
"collateralToken": schema["collateralToken"],
863+
"oracleUpdater": schema["oracleUpdater"].lower() if schema["oracleUpdater"] is not None else None,
864+
}
865+
action = {
866+
"type": "perpDeploy",
867+
"registerAsset": {
868+
"maxGas": max_gas,
869+
"assetRequest": {
870+
"coin": coin,
871+
"szDecimals": sz_decimals,
872+
"oraclePx": oracle_px,
873+
"marginTableId": margin_table_id,
874+
"onlyIsolated": only_isolated,
875+
},
876+
"dex": dex,
877+
"schema": schema_wire,
878+
},
879+
}
880+
signature = sign_l1_action(
881+
self.wallet,
882+
action,
883+
None,
884+
timestamp,
885+
self.expires_after,
886+
self.base_url == MAINNET_API_URL,
887+
)
888+
return self._post_action(
889+
action,
890+
signature,
891+
timestamp,
892+
)
893+
894+
def perp_deploy_set_oracle(
895+
self,
896+
dex: str,
897+
oracle_pxs: Dict[str, str],
898+
mark_pxs: Optional[Dict[str, str]],
899+
) -> Any:
900+
timestamp = get_timestamp_ms()
901+
oracle_pxs_wire = sorted(list(oracle_pxs.items()))
902+
mark_pxs_wire = None
903+
if mark_pxs is not None:
904+
mark_pxs_wire = sorted(list(mark_pxs.items()))
905+
action = {
906+
"type": "perpDeploy",
907+
"setOracle": {
908+
"dex": dex,
909+
"oraclePxs": oracle_pxs_wire,
910+
"markPxs": mark_pxs_wire,
911+
},
912+
}
913+
signature = sign_l1_action(
914+
self.wallet,
915+
action,
916+
None,
917+
timestamp,
918+
self.expires_after,
919+
self.base_url == MAINNET_API_URL,
920+
)
921+
return self._post_action(
922+
action,
923+
signature,
924+
timestamp,
925+
)
926+
834927
def c_signer_unjail_self(self) -> Any:
835928
return self.c_signer_inner("unjailSelf")
836929

0 commit comments

Comments
 (0)