Port hip4 SDK to Python with sync + async clients#1
Merged
Conversation
Mirrors the TypeScript @perps/hip4 SDK module-for-module in snake_case. Sync uses requests + websocket-client, async uses httpx + websockets; both share the pure modules (types, signing, precision, classification, pricing, coin helpers, agent_wallet). Tooling matches the official Hyperliquid Python SDK: Poetry, pytest, mypy strict, black, isort, ruff, pre-commit. 111 tests cover the foundation (signing parity, msgpack encoding, action sorting, coin helpers, market classification, pricing, decimal precision). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 fixtures (orders, cancels, modifies, all 4 userOutcome variants, scheduleCancel, vault-attached, builder fees, triggers + cloid) generated by the TypeScript SDK's internal signing helpers via vitest. Each fixture asserts: 1. Same canonical key ordering after sort_*_action 2. Same MessagePack byte stream 3. Same Keccak-256 action hash 36 cross-implementation assertions, all passing — guarantees the Python port produces signatures that recover to the same agent address as the TS SDK on the Hyperliquid server. Generator script lives at hip4/tests/parity/dump-fixtures.test.ts in the TS repo; rerun via `pnpm vitest run tests/parity/dump-fixtures.test.ts` and copy fixtures.json into tests/fixtures/ts_signing_parity.json. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Core <-> HyperEVM bridging:
- hip4.core_evm:
- derive_core_evm_system_address(token_index) — 0x20 + 19B BE token id
- estimate_core_to_evm_fee(...) — pure fee math, picks HYPE-vs-source debit
- median_base_fee_wei(samples) — robust over single-block MEV spikes
- select_hype_spot_mark_px(ctxs, *, testnet) + find_hype_usdc_spot_pair_coin
- Constants: HYPE_CORE_EVM_SYSTEM_ADDRESS, CORE_TO_EVM_GAS_LIMIT,
HYPE_USDC_SPOT_PAIR_{MAINNET,TESTNET}, MAX_CORE_EVM_TOKEN_INDEX
- WalletAdapter / AsyncWalletAdapter:
- send_spot_token_to_evm — Core->HyperEVM (USDH and other spot tokens)
- send_to_evm_with_data — Core->EVM with hook data (CCTP for USDC)
- send_usdc_to_evm — convenience wrapper, auto-fills USDC token id
- set_referrer — L1-signed referral code
USDH on/off-ramp adapter (mainnet only):
- hip4.sync.ramp.RampAdapter / hip4.aio.ramp.AsyncRampAdapter:
- generate_deposit_address — counterfactual Arbitrum->HyperCore via Across
- get_sell_quote — HyperEVM USDH -> Arbitrum USDC swap
- check_deposit_status — track Across fills/refunds
- get_coinbase_session_token + generate_buy_url + generate_sell_url
- Mainnet guard raises RampError on testnet (Across/Coinbase don't support it)
Tests: 16 Core<->EVM + 16 ramp = 32 new tests; total now 222 passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Strict mypy now passes with zero errors. Changes:
- pyproject.toml: relax warn_return_any for hip4.{sync,aio}.client and
hip4.auth — these intentionally bridge Any (response.json(), eth_account
attribute access) to typed return values, and per-call cast() buys
nothing.
- signing.py: broaden sort_*_action input types from strict TypedDicts to
Mapping[str, Any] so callers don't need to narrow union TypedDicts
before dispatching. Wire shapes are still asserted by the parity tests.
- sync/aio client place_order/cancel_order/modify_order/batch_modify:
accept Mapping[str, Any] for the same reason.
- sync/aio market_data: cast() WS payloads at the dispatch points.
- sync/account: rename shadowed `names` variable; broaden _map_spot_balance
to take Mapping inputs.
- sync/aio trading: drop strict TypedDict annotations on hand-built dicts;
cast() through Any where mypy can't narrow HLModifyResponse's str|dict
union.
- sync/aio wallet: cast statuses[0] to Dict[str, Any] for the filled/error
branches.
- sync/aio events: add missing return annotations on fetch_settled_outcome.
- agent_wallet: cast _normalize_sig fall-through to HLSignature.
All 222 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Port of the TypeScript
@perps/hip4SDK to Python. ~9,700 LOC across 61 modules, mirroring the TS structure module-for-module in snake_case.requests+websocket-clienthttpx+websocketstypes,signing,precision,pricing,coin,market_classification,market_discovery,agent_wallet,streams.candle_utils,utils) are shared between bothWhat's deferred (follow-up PRs)
core_evm_system_address+core_to_evm_fees+ the Core→EVM wallet methods (send_to_evm_with_data,send_spot_token_to_evm,send_usdc_to_evm)hype_spot_mark_pxrampadapter (USDH on/off-ramp via Across + Coinbase) — types ported, adapter notstreams/perp_price_feedevents.subscribe_outcome_meta_updatesTest plan
poetry install --all-extras --with devmake test— should report 111 passingmake lint(mypy not yet clean — known)python -c "from hip4 import create_hip4_adapter; from hip4.aio import create_async_hip4_adapter"examples/get_all_markets.py)python examples/async_get_all_markets.py🤖 Generated with Claude Code