Skip to content

fix(hyperliquid): submit/cancel trading-path bugs (silent error, wrong asset id, msgpack int64) - #1281

Merged
realfishsam merged 1 commit into
mainfrom
fix/hl-submit-cancel-trading-paths
Jun 22, 2026
Merged

realfishsam merged 1 commit into
mainfrom
fix/hl-submit-cancel-trading-paths

Conversation

@realfishsam

Copy link
Copy Markdown
Contributor

Summary

Three real HL bugs surfaced by live ground-truth trading verification against a funded mainnet wallet:

1. submitOrder silently swallowed HL rejections

When HL returned statuses[0].error (e.g. "Order must have minimum value of 10 USDC"), the SDK reported status='filled', id='unknown' — fake success. The order didn't exist, but the caller had no way to know.

→ Now raises a typed PmxtError carrying HL's message. Also handles the filled branch correctly (was checked but never populated price or oid in the response).

2. cancelOrder hardcoded a: 0 (asset id)

Every cancel signed an action with cancels: [{a: 0, o: <oid>}]. HL rejected with User or API Wallet 0xfaf6… does not exist because the action hash with the wrong asset recovers a different signer address.

→ Now looks up the open order to derive the real asset id via encodeAssetId. Throws typed Order not found when the supplied oid isn't open.

3. msgpack int64 vs uint64 — one byte off

msgpackr encodes positive BigInts as int64 (0xd3); HL's server (Python msgpack) encodes the same values as uint64 (0xcf). Identical bit pattern, different type byte → action hash mismatch → signature recovers to wrong address. Only manifested on cancel because order actions don't carry BigInt fields; cancel does (oid).

→ Added fixInt64ToUint64 post-processor. HL actions never carry negative ints (oids, nonces, asset ids are all ≥ 0), so flipping d3 → cf when the following byte is < 0x80 is safe and produces byte-identical encoding to Python msgpack.

Verified end-to-end against live wallet 0xcb85…

createOrder (BUY 100 @ \$0.10, hl-outcome-553)
  → id=476019713300 status=open
fetch_open_orders → contains the order
cancelOrder(id) → status=canceled
fetch_open_orders → empty
cancelOrder('999999999999') → typed PmxtError 'Order not found'

No funds were lost in verification (orders rested far below market and were cancelled within seconds).

Test plan

  • Trading on HL succeeds with typed error responses
  • Cancel of open orders works
  • Cancel of stale/fake order id raises typed PmxtError

…asset, msgpack int64→uint64

Three bugs caught by ground-truth live-trade verification:

1. submitOrder silently swallowed HL rejections. When HL returned
   statuses[0].error (e.g. 'Order must have minimum value of 10 USDC'),
   the SDK reported status='filled', id='unknown' — fake success. Now
   raises a typed PmxtError carrying the HL message. Also handles the
   filled status correctly (was checked but never populated price/oid).

2. cancelOrder hardcoded asset id 'a: 0'. HL rejected every cancel with
   'User or API Wallet does not exist' because the recovered signer
   address depended on the (wrong) asset id in the signed action. Now
   looks up the actual order from openOrders, decodes coin → assetId,
   and signs the correct cancel. Also returns a typed OrderNotFound
   when the supplied oid isn't open.

3. msgpackr encoded positive BigInts as int64 (0xd3); HL's server runs
   Python msgpack which encodes the same values as uint64 (0xcf). One
   byte mismatch produced an action hash that recovered to a different
   address — HL saw 'User or API Wallet 0xfaf6... does not exist'. Added
   fixInt64ToUint64 post-processor: HL actions never carry negative
   ints (oids, nonces, asset ids are all >= 0), so flipping d3→cf when
   the next byte is < 0x80 is safe and matches Python's encoding.

Verified end-to-end against a live wallet (0xcb85…):
  createOrder (BUY 100 @ $0.10, hl-outcome-553)
    → id=476019713300 status=open
  fetch_open_orders → contains the order
  cancelOrder(id) → status=canceled
  fetch_open_orders → empty
  cancelOrder('999999999999') → typed PmxtError 'Order not found'
@realfishsam
realfishsam merged commit 1984a2c into main Jun 22, 2026
5 of 10 checks passed
@realfishsam
realfishsam deleted the fix/hl-submit-cancel-trading-paths branch June 22, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant