Skip to content

Commit 46522b3

Browse files
committed
Fix market order price rounding for builder-deployed perp dexs
_slippage_price classifies an asset as spot with `asset >= 10_000`, but builder-deployed (HIP-3) perp dex assets start at 110000, so they are also caught by that check. Those perps are then rounded to 8 - szDecimals decimals instead of 6 - szDecimals, and market_open/market_close can produce a price with too many decimal places, which the exchange rejects. Spot asset ids live in [10000, 110000), so bound the check on both sides.
1 parent 2fdb18f commit 46522b3

2 files changed

Lines changed: 59 additions & 2 deletions

File tree

hyperliquid/exchange.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@ def _slippage_price(
123123
px = float(self.info.all_mids(dex)[coin])
124124

125125
asset = self.info.coin_to_asset[coin]
126-
# spot assets start at 10000
127-
is_spot = asset >= 10_000
126+
# spot assets start at 10000 and builder-deployed perp dex assets start at 110000
127+
is_spot = 10_000 <= asset < 110_000
128128

129129
# Calculate Slippage
130130
px *= (1 + slippage) if is_buy else (1 - slippage)

tests/exchange_test.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import eth_account
2+
3+
from hyperliquid.exchange import Exchange
4+
from hyperliquid.utils.types import Meta, SpotMeta
5+
6+
TEST_META: Meta = {"universe": [{"name": "ABC", "szDecimals": 0}]}
7+
TEST_SPOT_META: SpotMeta = {
8+
"universe": [{"name": "@1", "tokens": [1, 0], "index": 1, "isCanonical": False}],
9+
"tokens": [
10+
{
11+
"name": "USDC",
12+
"szDecimals": 8,
13+
"weiDecimals": 8,
14+
"index": 0,
15+
"tokenId": "0x6d1e7cde53ba9467b783cb7c530ce054",
16+
"isCanonical": True,
17+
"evmContract": None,
18+
"fullName": None,
19+
},
20+
{
21+
"name": "PURR",
22+
"szDecimals": 0,
23+
"weiDecimals": 5,
24+
"index": 1,
25+
"tokenId": "0xc1fb593aeffbeb02f85e0308e9956a90",
26+
"isCanonical": True,
27+
"evmContract": None,
28+
"fullName": None,
29+
},
30+
],
31+
}
32+
33+
34+
def make_exchange() -> Exchange:
35+
wallet = eth_account.Account.from_key("0x0123456789012345678901234567890123456789012345678901234567890123")
36+
return Exchange(wallet, meta=TEST_META, spot_meta=TEST_SPOT_META)
37+
38+
39+
def test_slippage_price_perp():
40+
exchange = make_exchange()
41+
# 5 significant figures, then at most 6 - szDecimals decimals
42+
assert exchange._slippage_price("ABC", True, 0.05, 0.0012345678) == 0.001296
43+
44+
45+
def test_slippage_price_spot():
46+
exchange = make_exchange()
47+
# spot allows 8 - szDecimals decimals
48+
assert exchange._slippage_price("@1", True, 0.05, 0.0012345678) == 0.0012963
49+
50+
51+
def test_slippage_price_builder_deployed_perp():
52+
exchange = make_exchange()
53+
# builder-deployed perp dex assets start at 110000, above the spot range, but are still perps
54+
exchange.info.name_to_coin["test:ABC"] = "test:ABC"
55+
exchange.info.coin_to_asset["test:ABC"] = 110000
56+
exchange.info.asset_to_sz_decimals[110000] = 0
57+
assert exchange._slippage_price("test:ABC", True, 0.05, 0.0012345678) == 0.001296

0 commit comments

Comments
 (0)