Skip to main content

Module dispatch

Module dispatch 

Source
Expand description

WebSocket execution dispatch for the Hyperliquid execution client.

Implements the two-tier execution dispatch contract from docs/developer_guide/adapters.md (lines 1232-1296):

  1. The execution client registers an OrderIdentity in WsDispatchState when it submits an order, and refreshes the cached venue order id when a modify is sent so the WebSocket consumer can detect cancel-replace.
  2. Incoming [OrderStatusReport] and [FillReport] messages are routed through dispatch_order_event and dispatch_order_fill. For tracked orders these build typed [OrderEventAny] events and emit them via [ExecutionEventEmitter::send_order_event]. For untracked / external orders the dispatch falls back to forwarding the raw report.

The dispatch state lives in an Arc<WsDispatchState> shared between the main client task (which registers identities at submission time) and the spawned WebSocket consumer task.

§GH-3827 cancel-replace handling

Hyperliquid implements modify as a cancel-and-replace: the venue emits an ACCEPTED(new_voi) together with a CANCELED(old_voi) under the same client_order_id. The dispatch detects the replacement leg by comparing report.venue_order_id to the last cached value, promotes it to an OrderUpdated event, and suppresses the stale cancel so strategies never observe a spurious termination.

The pending-modify marker (keyed on client_order_id) is set by modify_order before the HTTP call and cleared on either the matching ACCEPTED(new_voi) or any modify failure. It lets dispatch skip an early CANCELED(old_voi) that arrives before the replacement ACCEPTED(new_voi) on the WebSocket, regardless of whether the WS message races ahead of the HTTP response.

A fill carrying the replacement venue_order_id during an in-flight modify promotes the binding directly (the same OrderUpdated path as the replacement ACCEPTED), so a dropped ACCEPTED does not strand the fill. A fill is buffered into WsDispatchState::buffered_fills only when the identity has no price to promote with; handle_accepted drains the buffer on the replacement ACCEPTED. A delayed earlier-leg fill during a chained modify is a known limitation. See GH-3972.

When neither the replacement ACCEPTED nor a fill arrives, a query that resolves the replacement by cloid promotes the binding the same way via promote_replacement_from_query, so a dropped ACCEPTED with no fill cannot leave the order bound to the canceled leg.

Structs§

BoundedDedup
Bounded FIFO deduplication set.
OrderIdentity
Identity metadata captured when an order is submitted through this client.
WsDispatchState
Per-client dispatch state shared between order submission and the WebSocket consumer task.

Enums§

DispatchOutcome
Outcome of a single dispatch call.

Constants§

DEDUP_CAPACITY

Functions§

dispatch_order_event
Dispatches an [OrderStatusReport] using the two-tier routing contract.
dispatch_order_fill
Dispatches a [FillReport] using the two-tier routing contract.
promote_replacement_from_query
Promotes a cancel-replace replacement surfaced by a query during an in-flight modify.