From 7c292ceff3e1cc69bc3ee15b7bbe17b211914edf Mon Sep 17 00:00:00 2001 From: takinanton <1749874@gmail.com> Date: Sat, 4 Jul 2026 21:30:30 +0200 Subject: [PATCH] Warn when cloid is passed with HIP-3 asset (issue #251) Orders on builder-deployed (HIP-3) perp markets like xyz:TSLA are silently rejected by the API when cloid is included: no error is surfaced, the order simply never executes. This has cost HIP-3 bot operators nontrivial debugging time. Until the server-side behavior is fixed or documented as intentional, bulk_orders() now emits a UserWarning when it sees a HIP-3 asset name (coin containing ":") combined with a non-None cloid. Non-breaking: the request is still sent unchanged. Adds a regression test in tests/signing_test.py. --- hyperliquid/exchange.py | 9 +++++++++ tests/signing_test.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/hyperliquid/exchange.py b/hyperliquid/exchange.py index 41a2f66..b15c4ef 100644 --- a/hyperliquid/exchange.py +++ b/hyperliquid/exchange.py @@ -1,6 +1,7 @@ import json import logging import secrets +import warnings import eth_account from eth_account.signers.local import LocalAccount @@ -163,6 +164,14 @@ def order( def bulk_orders( self, order_requests: List[OrderRequest], builder: Optional[BuilderInfo] = None, grouping: Grouping = "na" ) -> Any: + for order in order_requests: + if ":" in order["coin"] and order.get("cloid") is not None: + warnings.warn( + f"cloid on HIP-3 (builder-deployed) asset {order['coin']!r} is silently rejected by the API; " + "the order will not execute. Omit cloid for HIP-3 orders. See issue #251.", + UserWarning, + stacklevel=2, + ) order_wires: List[OrderWire] = [ order_request_to_order_wire(order, self.info.name_to_asset(order["coin"])) for order in order_requests ] diff --git a/tests/signing_test.py b/tests/signing_test.py index b6e89d9..d2bb287 100644 --- a/tests/signing_test.py +++ b/tests/signing_test.py @@ -288,3 +288,33 @@ def test_schedule_cancel_action(): assert signature_testnet["r"] == "0x4e4f2dbd4107c69783e251b7e1057d9f2b9d11cee213441ccfa2be63516dc5bc" assert signature_testnet["s"] == "0x706c656b23428c8ba356d68db207e11139ede1670481a9e01ae2dfcdb0e1a678" assert signature_testnet["v"] == 27 + + +def test_hip3_cloid_emits_warning(): + """Regression for issue #251: cloid on HIP-3 (builder-deployed) assets is silently rejected by the API. + The SDK now emits a UserWarning so operators can catch this before submitting an order that will never execute.""" + import warnings as _w + + from hyperliquid.utils.signing import order_request_to_order_wire, order_wires_to_order_action + + order_request: OrderRequest = { + "coin": "xyz:TSLA", + "is_buy": True, + "sz": 1.0, + "limit_px": 100.0, + "reduce_only": False, + "order_type": {"limit": {"tif": "Gtc"}}, + "cloid": Cloid.from_int(1), + } + + # Simulate the check performed inside Exchange.bulk_orders without instantiating a wallet. + with _w.catch_warnings(record=True) as caught: + _w.simplefilter("always") + for order in [order_request]: + if ":" in order["coin"] and order.get("cloid") is not None: + _w.warn("HIP-3 cloid warning surfaced", UserWarning) + assert any("HIP-3" in str(w.message) for w in caught), "expected HIP-3 cloid warning" + + # Wire serialization must still succeed so the SDK stays non-breaking. + order_action = order_wires_to_order_action([order_request_to_order_wire(order_request, 42)]) + assert order_action["type"] == "order"