Skip to content

feat: use Hyperliquid Fast L2 order book subscriptions (OK-57953, OK-57833)#12477

Open
Minnzen wants to merge 28 commits into
release/v6.5.0from
codex/fix-hyperliquid-fast-l2-v6.5.0
Open

feat: use Hyperliquid Fast L2 order book subscriptions (OK-57953, OK-57833)#12477
Minnzen wants to merge 28 commits into
release/v6.5.0from
codex/fix-hyperliquid-fast-l2-v6.5.0

Conversation

@Minnzen

@Minnzen Minnzen commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

OK-57953 OK-57833


Summary

  • Make Hyperliquid Fast L2 the primary order-book transport for perp and spot markets while preserving target-scoped l2Book fallback.
  • Reconstruct snapshots and deltas safely, and carry coin and precision identity through background cache and main rendering.
  • Serialize subscription reconciliation and prevent transient precision state from poisoning subscriptions or cache entries.

Intent & Context

Hyperliquid reduced the update frequency of the existing l2Book feed. This change uses the higher-frequency Fast L2 feed without upgrading the SDK, while keeping the existing UI order-book contract and providing safe recovery on all app platforms. Related requirements: OK-57953 and OK-57833.

Root Cause

The existing order-book pipeline assumed full l2Book snapshots. Fast L2 sends a snapshot followed by incremental frames, which may be compressed. During mobile coin or depth switches, the main and background runtimes update independently; stale reconciles and placeholder tick options could temporarily subscribe to or render the wrong target or precision.

Design Decisions

  • Keep the current SDK and add the Fast L2 wire subscription at the existing WebSocket boundary.
  • Decode and validate compressed frames with bounded cross-platform decompression, then expose the existing IBook shape.
  • Use Fast L2 first; retry the current target, reconnect once, and only then fall back to l2Book for that target.
  • Serialize and coalesce subscription reconciles so only the latest coin and precision target wins.
  • Treat coin + nSigFigs + mantissa as the order-book identity across the background cache and main UI.
  • Do not persist placeholder tick options while a new precision snapshot is pending.
  • Remove temporary diagnostic instrumentation before release.

Changes Detail

  • Added Fast L2 subscription parameters, decoder, validation, delta merging, and recovery state.
  • Added target-scoped subscription reconciliation and fallback behavior.
  • Added precision-aware cache, read, and render guards while preserving source precision.
  • Prevented transitional fallback precision from being written back into subscription state.
  • Added a Fast L2 recovery generation guard so delayed recovery cannot tear down a subscription that has already received a healthy delta.
  • Removed hidden iOS and Android Open Orders native view trees while preserving React list state, preventing filtered rows from resurfacing.
  • Added focused unit tests for decoding, recovery invalidation, reconciliation, cache identity, freshness, precision transitions, and mobile hidden-view behavior.

Risk Assessment

  • Risk Level: Medium
  • Affected Platforms: Extension / Mobile / Desktop / Web
  • Risk Areas: Fast L2 frame decoding, rapid coin and precision switching, WebSocket recovery, and cached order-book identity.

Test plan

  • Run focused Jest coverage for Fast L2 decoding and recovery, subscription planning and reconciliation, cache freshness, tick precision, and mobile hidden-view behavior.
  • Run yarn agent:check --profile commit.
  • Verify perp and spot order books on Web, Desktop, Extension, iOS, and Android.
  • Rapidly switch coins and order-book depths; verify no stale book, blank lock-up, or 1200 -> 1400 -> 1200 precision flash.
  • On iOS and Android, enable Hide Other Trading Pairs and switch panels/coins; verify filtered Open Orders rows never reappear.
  • Verify foreground and background transitions, disconnect and reconnect, invalid-frame recovery, and target-scoped l2Book fallback.
  • Build and validate the v6.5.0 hot-update bundle in GitHub Actions.

Apply the validated Fast L2 order-book path to the v6.5.0 bundle baseline while preserving target-scoped fallback, precision identity, and serialized subscription reconciliation.\n\nConstraint: the hot-update bundle must remain compatible with the v6.5.0 shell baseline and exclude temporary diagnostic logging.\nRejected: cherry-picking only the initial feature commit | later switching and precision fixes are required for stable mobile behavior.\nConfidence: high\nScope-risk: moderate\nDirective: keep order-book source precision attached across bg cache and main rendering boundaries.\nTested: 44 targeted Jest tests and yarn agent:check --profile commit.\nNot-tested: GitHub Actions bundle build and native hot-update smoke.
@socket-security

socket-security Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedfflate@​0.8.210010010081100

View full report

Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidCache.ts Outdated
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Constraint: Fast L2 recovery must keep l2Book fallback safe across asynchronous coin and precision changes.
Rejected: Label fallback frames from desired UI state | old wire subscriptions can still emit while teardown is in progress.
Confidence: high
Scope-risk: narrow
Directive: Keep actual wire subscription identity separate from desired subscription state.
Tested: 49 targeted Jest tests; lint-worktree-ts; lint-staged.
Not-tested: Full tsc-staged remains blocked by the existing AutoSizeInput.native.tsx mostRecentEventCount type error on the release baseline.
Comment thread packages/kit/src/views/Perp/hooks/usePerpMarketData.ts
Minnzen added 6 commits July 14, 2026 15:00
Constraint: Identical order book levels may be emitted for different precision targets during a subscription transition.
Rejected: Rely on timestamp freshness to replace the book | the new target can arrive inside the dedupe interval.
Confidence: high
Scope-risk: narrow
Directive: Treat coin and source precision as part of order book identity before content deduplication.
Tested: 64 targeted Jest tests; lint-worktree-ts; lint-staged.
Not-tested: Full tsc-staged remains blocked by the existing AutoSizeInput.native.tsx mostRecentEventCount type error on the release baseline.
Guard the async order-book option read before publishing so an older iOS spot switch cannot overwrite the latest coin target.

Constraint: Native main and bg runtimes synchronize global atoms asynchronously during rapid spot switching.
Rejected: Retry subscriptions in bg | the stale main-runtime option write is the source of the target mismatch.
Confidence: high
Scope-risk: narrow
Directive: Revalidate the active instrument after awaited work before publishing subscription targets.
Tested: 8 targeted Jest suites, 66 tests; lint-worktree-ts; lint-staged; git diff --check.
Not-tested: iOS device QA; tsc-staged is blocked by the existing AutoSizeInput.native.tsx mostRecentEventCount type error.
Load persisted precision before publishing a spot subscription target, keep existing selections authoritative, and hide provisional first frames until the final precision is initialized. Add scoped main/bg diagnostics for bundle verification.

Constraint: iOS main and background runtimes initialize independently during rapid spot switching.

Rejected: render a mismatched provisional snapshot | it recreates the incorrect-price flash.

Confidence: high

Scope-risk: moderate

Directive: remove orderBookSwitchDiagnostic after bundle logs confirm stable switching.

Tested: 8 targeted Jest suites (56 tests), lint-worktree-ts, lint-staged, git diff --check.

Not-tested: iOS bundle; tsc-staged is blocked only by the pre-existing AutoSizeInput.native.tsx mostRecentEventCount error.
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Comment thread packages/kit/src/states/jotai/contexts/hyperliquid/utils/instrumentSwitch.ts Outdated
Retain same-coin tick option data while a Fast L2 precision resubscription temporarily removes the renderable book, without carrying precision across coin switches.

Constraint: strict precision filtering intentionally creates a short empty-book window in main JS.

Rejected: show the generic fallback precision during reload | it causes the selector to flash an incorrect value.

Confidence: high

Scope-risk: narrow

Directive: keep cache reuse scoped to the active coin.

Tested: 8 targeted Jest suites (58 tests), lint-worktree-ts, lint-staged, git diff --check.

Not-tested: iOS bundle; tsc-staged is blocked only by the pre-existing AutoSizeInput.native.tsx mostRecentEventCount error.
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Comment thread packages/kit/src/states/jotai/contexts/hyperliquid/utils/instrumentSwitch.ts Outdated
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Extend the existing local Fast L2 diagnostic with selector source, value, option count, initialization, and explicit selection events for bundle verification.

Constraint: exported production bundle logs require LogToLocal rather than development-only console output.

Rejected: log full order book payloads | scalar state is sufficient and safer.

Confidence: high

Scope-risk: narrow

Directive: remove temporary orderBookSwitchDiagnostic instrumentation after verification.

Tested: tickSizeUtils Jest suite (13 tests), lint-worktree-ts, lint-staged, git diff --check.

Not-tested: iOS bundle; tsc-staged is blocked only by the pre-existing AutoSizeInput.native.tsx mostRecentEventCount error.
@Minnzen
Minnzen force-pushed the codex/fix-hyperliquid-fast-l2-v6.5.0 branch from 592ba3d to 7af92cb Compare July 15, 2026 13:31
Minnzen added 2 commits July 15, 2026 21:43
Add temporary local diagnostics around the mobile filter checkbox, committed list snapshots, next-frame state, and row lifecycle to distinguish main-state fallback from an iOS native-view residue.

Constraint: production-shaped bundle exports require LogToLocal diagnostics.

Rejected: log account addresses or order identifiers | coin and bounded counts are sufficient for this single-row reproduction.

Confidence: high

Scope-risk: narrow

Directive: remove openOrdersFilterDiagnostic and its call sites after OK-57833 verification.

Tested: lint-worktree-ts, lint-staged, git diff --check.

Not-tested: iOS bundle; tsc-staged is blocked only by the pre-existing AutoSizeInput.native.tsx mostRecentEventCount error.
Keep the mobile funding header mounted while only the order book body switches between loading and ready states.

Constraint: Funding data is independent from Fast L2 snapshot readiness.
Rejected: Continue forcing a funding placeholder during order book reloads | it couples unrelated data and resets the countdown through remounts.
Confidence: high
Scope-risk: narrow
Directive: Keep the mobile funding header outside order book loading and ready branches.
Tested: 39 targeted Perp order book tests passed; commit-profile lint checks passed.
Not-tested: iOS bundle/device verification; staged typecheck remains blocked by the pre-existing AutoSizeInput.native.tsx mostRecentEventCount error.
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Comment thread packages/kit/src/states/jotai/contexts/hyperliquid/utils/instrumentSwitch.ts Outdated
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Comment thread packages/shared/src/logger/scopes/perp/scenes/hyperliquid.ts Outdated
Minnzen added 3 commits July 15, 2026 23:30
Derive the full-precision tick from the coin reference price and Hyperliquid size-decimal rules so loading and live frames use the same selector value.

Constraint: Default precision must be available before the first L2 snapshot.\nRejected: Generic buildTickOptions(1, 0) fallback | It exposes a false transient precision.\nConfidence: high\nScope-risk: narrow\nDirective: Keep default precision coin-keyed and derived from current-instrument szDecimals.\nTested: 42 targeted order book tests; changed-file lint; staged TypeScript has no changed-file errors.\nNot-tested: iOS bundle/device; repository baseline TypeScript error remains in AutoSizeInput.native.tsx:103.
Keep Fast L2 recovery budgets across snapshots, serialize cross-runtime option writes, and reconnect instead of creating a replacement feed after teardown failure.

Constraint: Fast L2 frames do not identify their originating precision subscription and main/bg writes complete asynchronously.\nRejected: Continue after an order-book unsubscribe failure | It can leave overlapping server streams.\nConfidence: high\nScope-risk: moderate\nDirective: Reset Fast L2 recovery only after an applied delta and preserve latest-write ordering across runtimes.\nTested: 92 targeted Fast L2, subscription, cache, switch, and order-book tests; changed-file lint; git diff --check.\nNot-tested: iOS bundle/device; repository baseline TypeScript error remains in AutoSizeInput.native.tsx:103.
Add rate-limited diagnostics across bg Fast L2 processing and main-runtime order book and mark-price rendering so the final iOS bundle can isolate a stalled layer without logging full payloads.

Constraint: The next iOS bundle is the penultimate diagnostic round and must distinguish bg data flow from main rendering.
Rejected: Log every Fast L2 frame or full order books | Excessive production log volume and unnecessary market payload retention.
Confidence: high
Scope-risk: narrow
Directive: Remove these temporary diagnostics after the next device-log verification.
Tested: 12 related Jest suites (87 tests), worktree and staged lint, git diff check.
Not-tested: iOS bundle/device; repository baseline TypeScript error remains in AutoSizeInput.native.tsx:103.
Comment thread packages/kit/src/views/Perp/components/PerpOrderBook.tsx Outdated
Remove the completed Fast L2, order-book transition, mark-price, and open-orders diagnostics while preserving the validated switching and recovery behavior.

Constraint: Device verification is complete and production-shaped bundles must no longer persist troubleshooting-only market or list state.
Rejected: Keep the rate-limited heartbeat for future debugging | It still adds production log volume and review surface after the issue is verified.
Confidence: high
Scope-risk: narrow
Directive: Add new temporary diagnostics only for a new reproducible investigation and remove them after verification.
Tested: 11 related Jest suites (84 tests), worktree and staged lint, git diff check, diagnostic symbol search.
Not-tested: iOS device after log removal; repository baseline TypeScript error remains in AutoSizeInput.native.tsx:103.
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Constraint: Preserve PerpOpenOrdersList React state while removing hidden native views on iOS and Android.
Rejected: Unmount the entire list component | resets local tab and pagination state.
Rejected: Limit the fix to iOS | Android shares the React Native native-view lifecycle risk.
Confidence: high
Scope-risk: narrow
Directive: Keep Web and desktop hidden-panel behavior unchanged unless separately reproduced.
Tested: 33 Perp Jest suites with 241 tests; staged and worktree lint.
Not-tested: Physical iOS and Android devices; full typecheck remains blocked by the pre-existing AutoSizeInput.native.tsx:103 error.
@Minnzen Minnzen changed the title feat: use Hyperliquid Fast L2 order book subscriptions(OK-57953) feat: use Hyperliquid Fast L2 order book subscriptions (OK-57953, OK-57833) Jul 15, 2026
Comment thread packages/kit-bg/src/services/ServiceHyperLiquid/ServiceHyperliquidSubscription.ts Outdated
Minnzen added 4 commits July 16, 2026 03:06
Invalidate delayed recovery work after a healthy delta or subscription lifecycle change, and recheck its generation immediately before subscription teardown.

Constraint: Fast L2 recovery waits may overlap healthy bg-runtime frames for the same target.

Rejected: Clear only retry counters | the delayed promise would still destroy a recovered subscription.

Confidence: high

Scope-risk: narrow

Directive: Keep delayed recovery side effects guarded by target and generation at execution time.

Tested: FastL2Book Jest suite (9 tests); lint-worktree-ts; lint-staged; git diff --check.

Not-tested: Full tsc-staged remains blocked by the release baseline AutoSizeInput.native.tsx:103 type error.
Constrain generated aggregation ticks to Hyperliquid's asset-specific decimal floor and keep small labels in fixed decimal form.

Constraint: Spot price decimals cannot exceed 8 minus szDecimals.
Rejected: UI-only formatting workaround | it would leave an invalid subscription option available.
Confidence: high
Scope-risk: narrow
Directive: Keep future tick options bounded by both significant figures and asset decimal limits.
Tested: yarn jest packages/kit/src/views/Perp/components/OrderBook/tickSizeUtils.test.ts --runInBand; lint-worktree-ts; lint-staged
Not-tested: tsc-staged is blocked by the existing AutoSizeInput.native.tsx mostRecentEventCount baseline error.
Constraint: Preserve exact coin and precision guards across native and desktop runtimes.
Rejected: One-shot HTTP l2Book bootstrap | connection and cache fixes cover the measured bottlenecks.
Confidence: high
Scope-risk: moderate
Directive: Keep cached order books visual-only until the first live frame.
Tested: 58 targeted tests; lint-worktree-ts; lint-staged
Not-tested: Physical iOS, Android, and desktop runtime latency
Minnzen added 2 commits July 16, 2026 20:54
Constraint: Keep cached books exact-target scoped and visual-only until live data arrives.
Rejected: Global cache write throttling | it drops alternate targets during rapid switches.
Confidence: high
Scope-risk: narrow
Directive: Preserve per-target throttling and merge semantics for order book cold-cache writes.
Tested: 60 targeted Fast L2 tests; lint-worktree-ts; lint-staged
Not-tested: Interactive browser latency after a fresh runtime restart
Constraint: Reject cached snapshots only after a live book is already active.
Rejected: Blanket cache-to-live source ordering | it blocks valid cold-start hydration when no current book exists.
Confidence: high
Scope-risk: narrow
Directive: Keep the empty, cached-to-live, and live-to-cached transitions covered together.
Tested: 61 targeted Fast L2 tests; lint-worktree-ts; lint-staged
Not-tested: Interactive cold start on physical native devices
Invalidate delayed recovery when transport lifecycle changes, and compare target identity before applying live-over-cache source ordering.

Constraint: Preserve recovery retry budgets across transport replacement and live-over-cache ordering within one target.

Rejected: Reset all Fast L2 recovery state on close | would erase failure progression before fallback.

Confidence: high

Scope-risk: narrow

Directive: Treat transport epoch and coin/precision identity as independent freshness boundaries.

Tested: 12 targeted Jest suites (106 tests); lint-worktree-ts; lint-staged

Not-tested: Physical iOS reconnect timing; full tsc-staged is blocked by existing AutoSizeInput.native.tsx:103 baseline error
Comment thread packages/kit/src/views/Perp/components/OrderBook/useTickOptions.ts
Constraint: Keep Fast L2 subscriptions and mobile order book paths unchanged.
Rejected: Separate fixed-row loading skeleton | It diverges from the measured desktop layout.
Confidence: high
Scope-risk: narrow
Directive: Keep the desktop empty state on the measured OrderBook layout.
Tested: 3 targeted Jest suites (5 tests), worktree/staged lint, and diff checks.
Not-tested: Full TypeScript check is blocked by the pre-existing AutoSizeInput.native.tsx TS2322 error.
Comment thread packages/kit/src/views/Perp/components/OrderBook/useTickOptions.ts
Minnzen added 3 commits July 17, 2026 10:26
Persist the fully resolved tick option once option data is ready so the UI selection and background subscription use the same wire precision.

Constraint: Preserve the previous selection while tick options are still transitioning.

Rejected: Derive subscription parameters directly in PerpOrderBook | would duplicate the persisted preference owner and leave stale state behind.

Confidence: high

Scope-risk: narrow

Directive: Compare value, nSigFigs, and mantissa together when synchronizing tick options.

Tested: targeted OrderBook Jest suites (25 tests); targeted Oxlint; agent:check commit profile

Not-tested: physical iOS price-magnitude transition
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.

3 participants