Skip to content

Commit 402ea72

Browse files
authored
Merge branch 'master' into feat/add-missing-info-methods
2 parents 9be6ff9 + c2de06b commit 402ea72

File tree

3 files changed

+158
-3
lines changed

3 files changed

+158
-3
lines changed

hyperliquid/exchange.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,24 @@ def __init__(
6161
spot_meta: Optional[SpotMeta] = None,
6262
perp_dexs: Optional[List[str]] = None,
6363
timeout: Optional[float] = None,
64+
info_base_url: Optional[str] = None,
65+
exchange_base_url: Optional[str] = None,
66+
ws_base_url: Optional[str] = None,
6467
):
65-
super().__init__(base_url, timeout)
68+
# Use exchange_base_url for exchange endpoints, fallback to base_url
69+
exchange_url = exchange_base_url or base_url
70+
super().__init__(exchange_url, timeout)
6671
self.wallet = wallet
6772
self.vault_address = vault_address
6873
self.account_address = account_address
69-
self.info = Info(base_url, True, meta, spot_meta, perp_dexs, timeout)
74+
75+
# Use info_base_url for info endpoints, fallback to base_url
76+
info_url = info_base_url or base_url
77+
78+
# Use ws_base_url for websocket connections, fallback to info_base_url, then base_url
79+
ws_url = ws_base_url or info_url
80+
81+
self.info = Info(info_url, True, meta, spot_meta, perp_dexs, timeout, ws_url)
7082
self.expires_after: Optional[int] = None
7183

7284
def _post_action(self, action, signature, nonce):

hyperliquid/info.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ def __init__(
2525
# the original dex.
2626
perp_dexs: Optional[List[str]] = None,
2727
timeout: Optional[float] = None,
28+
ws_base_url: Optional[str] = None,
2829
): # pylint: disable=too-many-locals
2930
super().__init__(base_url, timeout)
3031
self.ws_manager: Optional[WebsocketManager] = None
3132
if not skip_ws:
32-
self.ws_manager = WebsocketManager(self.base_url)
33+
# Use ws_base_url if provided, otherwise fallback to base_url
34+
ws_url = ws_base_url or self.base_url
35+
self.ws_manager = WebsocketManager(ws_url)
3336
self.ws_manager.start()
3437

3538
if spot_meta is None:
@@ -747,6 +750,9 @@ def delegator_history(self, user: str) -> Any:
747750
"""
748751
return self.post("/info", {"type": "delegatorHistory", "user": user})
749752

753+
def query_spot_deploy_auction_status(self, user: str) -> Any:
754+
return self.post("/info", {"type": "spotDeployState", "user": user})
755+
750756
def _remap_coin_subscription(self, subscription: Subscription) -> None:
751757
if (
752758
subscription["type"] == "l2Book"

tests/exchange_test.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import pytest
2+
import eth_account
3+
4+
from hyperliquid.exchange import Exchange
5+
from hyperliquid.utils.types import Meta, SpotMeta
6+
7+
TEST_META: Meta = {"universe": []}
8+
TEST_SPOT_META: SpotMeta = {"universe": [], "tokens": []}
9+
10+
# Create a test wallet using a deterministic private key
11+
TEST_PRIVATE_KEY = "0x0123456789012345678901234567890123456789012345678901234567890123"
12+
TEST_WALLET = eth_account.Account.from_key(TEST_PRIVATE_KEY)
13+
14+
15+
def test_exchange_default_base_url():
16+
"""Test Exchange with default base URL behavior (backward compatibility)"""
17+
exchange = Exchange(
18+
wallet=TEST_WALLET,
19+
base_url="https://api.hyperliquid.xyz",
20+
meta=TEST_META,
21+
spot_meta=TEST_SPOT_META
22+
)
23+
24+
# All components should use the same base URL
25+
assert exchange.base_url == "https://api.hyperliquid.xyz"
26+
assert exchange.info.base_url == "https://api.hyperliquid.xyz"
27+
# WebSocket URL is constructed by replacing http with ws
28+
if exchange.info.ws_manager:
29+
assert "wss://api.hyperliquid.xyz/ws" in exchange.info.ws_manager.ws.url
30+
31+
32+
def test_exchange_separate_base_urls():
33+
"""Test Exchange with separate base URLs for each endpoint"""
34+
exchange = Exchange(
35+
wallet=TEST_WALLET,
36+
base_url="https://api.hyperliquid.xyz", # Fallback default
37+
info_base_url="https://info-provider.com", # For /info
38+
exchange_base_url="https://exchange-provider.com", # For /exchange
39+
ws_base_url="wss://ws-provider.com", # For /ws
40+
meta=TEST_META,
41+
spot_meta=TEST_SPOT_META
42+
)
43+
44+
# Each component should use its specific URL
45+
assert exchange.base_url == "https://exchange-provider.com"
46+
assert exchange.info.base_url == "https://info-provider.com"
47+
if exchange.info.ws_manager:
48+
assert "wss://ws-provider.com/ws" in exchange.info.ws_manager.ws.url
49+
50+
51+
def test_exchange_partial_url_specification():
52+
"""Test Exchange with partial URL specification (fallback behavior)"""
53+
exchange = Exchange(
54+
wallet=TEST_WALLET,
55+
base_url="https://api.hyperliquid.xyz",
56+
info_base_url="https://info-provider.com",
57+
# exchange_base_url not specified - should use base_url
58+
# ws_base_url not specified - should use info_base_url
59+
meta=TEST_META,
60+
spot_meta=TEST_SPOT_META
61+
)
62+
63+
# Exchange should use base_url (fallback)
64+
assert exchange.base_url == "https://api.hyperliquid.xyz"
65+
# Info should use info_base_url
66+
assert exchange.info.base_url == "https://info-provider.com"
67+
# WebSocket should use info_base_url (fallback)
68+
if exchange.info.ws_manager:
69+
assert "wss://info-provider.com/ws" in exchange.info.ws_manager.ws.url
70+
71+
72+
def test_exchange_only_exchange_url_specified():
73+
"""Test Exchange with only exchange_base_url specified"""
74+
exchange = Exchange(
75+
wallet=TEST_WALLET,
76+
base_url="https://api.hyperliquid.xyz",
77+
exchange_base_url="https://exchange-provider.com",
78+
# info_base_url not specified - should use base_url
79+
# ws_base_url not specified - should use info_base_url (which is base_url)
80+
meta=TEST_META,
81+
spot_meta=TEST_SPOT_META
82+
)
83+
84+
# Exchange should use exchange_base_url
85+
assert exchange.base_url == "https://exchange-provider.com"
86+
# Info should use base_url (fallback)
87+
assert exchange.info.base_url == "https://api.hyperliquid.xyz"
88+
# WebSocket should use base_url (fallback chain)
89+
if exchange.info.ws_manager:
90+
assert "wss://api.hyperliquid.xyz/ws" in exchange.info.ws_manager.ws.url
91+
92+
93+
def test_exchange_only_ws_url_specified():
94+
"""Test Exchange with only ws_base_url specified"""
95+
exchange = Exchange(
96+
wallet=TEST_WALLET,
97+
base_url="https://api.hyperliquid.xyz",
98+
ws_base_url="wss://ws-provider.com",
99+
# info_base_url not specified - should use base_url
100+
# exchange_base_url not specified - should use base_url
101+
meta=TEST_META,
102+
spot_meta=TEST_SPOT_META
103+
)
104+
105+
# Exchange should use base_url (fallback)
106+
assert exchange.base_url == "https://api.hyperliquid.xyz"
107+
# Info should use base_url (fallback)
108+
assert exchange.info.base_url == "https://api.hyperliquid.xyz"
109+
# WebSocket should use ws_base_url
110+
if exchange.info.ws_manager:
111+
assert "wss://ws-provider.com/ws" in exchange.info.ws_manager.ws.url
112+
113+
114+
def test_exchange_skip_websocket():
115+
"""Test Exchange creation with WebSocket disabled"""
116+
exchange = Exchange(
117+
wallet=TEST_WALLET,
118+
base_url="https://api.hyperliquid.xyz",
119+
info_base_url="https://info-provider.com",
120+
exchange_base_url="https://exchange-provider.com",
121+
ws_base_url="wss://ws-provider.com",
122+
meta=TEST_META,
123+
spot_meta=TEST_SPOT_META
124+
)
125+
126+
# Manually create info with skip_ws=True to test the parameter passing
127+
from hyperliquid.info import Info
128+
info_no_ws = Info(
129+
base_url="https://info-provider.com",
130+
skip_ws=True,
131+
meta=TEST_META,
132+
spot_meta=TEST_SPOT_META,
133+
ws_base_url="wss://ws-provider.com"
134+
)
135+
136+
assert info_no_ws.base_url == "https://info-provider.com"
137+
assert info_no_ws.ws_manager is None

0 commit comments

Comments
 (0)