feat(perps): expose market tradability for unavailable HIP-3 markets#9205
Conversation
Add PriceUpdate.isTradable, computed per provider from the market's mid-vs-oracle price deviation, so clients can warn before placing an order the protocol would reject (HyperLiquid rejects orders >95% from the reference price, which most often affects HIP-3 markets). - Export pure isMarketTradable helper; missing/non-positive prices default to tradable so transient no-data ticks never raise a banner. - Add HYPERLIQUID_CONFIG.OraclePriceDeviationLimit (0.95) HL default. - Add protocol-agnostic PerpsControllerConfig.fallbackPriceDeviationLimit client override, threaded controller -> provider -> subscription service.
Automated dev run — TAT-3039
Worker reportReport — TAT-3039: Block trading on unavailable HIP-3 marketsTicket: https://consensyssoftware.atlassian.net/browse/TAT-3039 ProblemHIP-3 (builder-deployed) markets can become temporarily untradable when their market (mid) SolutionCompute tradability in Core and stream it as a boolean on the existing price subscription:
Why a streamed flag (not just a util, not a new subscription)Clients already subscribe to the price stream and already receive both inputs ( Files changed (9 files, +244/−1)
Validation (all green)
Remaining risks / follow-ups
|
|
There are conflicts in the changelog file |
…navailable-hip3-trading # Conflicts: # packages/perps-controller/CHANGELOG.md
|
Resolved in |
Address review feedback (#9205): instead of leaving isTradable undefined when tradability is unknown, the field is now a required boolean that defaults to true. Providers report false only when they determine a market is currently untradable; MYX, which has no oracle-deviation rule, always reports true. Clients no longer need to coerce undefined.
…navailable-hip3-trading # Conflicts: # packages/perps-controller/CHANGELOG.md
## Explanation Since release **1062.0.0**, perps feature/fix PRs landed on `main` without a corresponding publish. This release bumps the root monorepo to **1063.0.0** and publishes **only** `@metamask/perps-controller@8.3.0`. **`@metamask/perps-controller@8.3.0`** (minor) - Terminal API integration for market metadata with HyperLiquid fallback (MetaMask#9137) - `isTradable` flag on `PriceUpdate` for HIP-3 oracle-deviation markets (MetaMask#9205) - Terminal API fetch timeout and display-name enrichment guard (MetaMask#9224) Validation: perps changelog validation passed. No build required (version/changelog-only changes). **Client follow-up:** Mobile / Extension should bump `@metamask/perps-controller` to `^8.3.0`. ## References - https://consensyssoftware.atlassian.net/browse/TAT-3392 - MetaMask#9137 — Terminal API integration (perps-controller) - MetaMask#9205 — Market tradability flag (perps-controller) - MetaMask#9224 — Terminal API timeout/name fixes (perps-controller) ## Checklist - [ ] I've updated the test suite for new or updated code as appropriate — N/A: release-only version/changelog bumps - [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate — N/A: no new code in this PR - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them — No breaking changes in this release <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Diff is limited to version numbers and changelog documentation; no runtime code changes in this PR. > > **Overview** > **Release 1063.0.0** — bumps the root monorepo version from `1062.0.0` to `1063.0.0` and publishes **`@metamask/perps-controller` `8.3.0`** (package version `8.2.0` → `8.3.0`). > > The changelog documents what ships in **8.3.0**: optional **Terminal API** market metadata (`useTerminalApi`, `TerminalMarketService`, enriched `PerpsMarketData` and search), **`isTradable`** on price updates with configurable oracle-deviation limits, **`@metamask/controller-utils` ^12.3.0**, and fixes (10s Terminal fetch timeout, safer display-name merge). No application source changes appear in this diff—only version and changelog updates. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit c37dac3. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Explanation
HIP-3 (builder-deployed) markets can become temporarily untradable when their market (mid) price
drifts too far from the oracle (reference) price. HyperLiquid then rejects every order with
Order price cannot be more than 95% away from the reference price(observed in Mixpanel). Todaynothing in
@metamask/perps-controllersurfaces this, so the user only finds out after an orderfails on submission.
This PR computes per-market trading availability in Core and exposes it so clients can warn the
user proactively (banner reusing the existing "OI cap" design — the banner UI itself lands in the
mobile/extension clients):
isTradableboolean toPriceUpdate, set on the existing price subscription.It is
falsewhen a market's mid price has drifted past the protocol's deviation limit;undefinedmeans tradability is unknown and the market should be treated as tradable. It iscomputed per provider from that protocol's own rules, so clients never reimplement
HyperLiquid-specific logic (important once other providers join the aggregated market list).
isMarketTradable({ midPrice, oraclePrice, deviationLimit })helper. Missing ornon-positive prices return
true, so a transient "no data" tick never produces a false banner.HYPERLIQUID_CONFIG.OraclePriceDeviationLimit(0.95) as the HyperLiquid default.fallbackPriceDeviationLimittoPerpsControllerConfigso a client cantune the threshold without a package release. It is threaded through the controller → provider →
subscription service; the controller stays protocol-agnostic (passes the optional value through,
each provider applies its own default when omitted).
Why a streamed flag rather than only a util or a new subscription: clients already subscribe to the
price stream and already receive both inputs (
price= mid,markPrice= oracle). A derived flagfully insulates clients from the rule and inputs and mirrors the OI-cap banner, which is likewise
driven by a live subscription.
All changes are additive and optional, so this is non-breaking for Mobile and Extension consumers.
Validation: new unit tests for the helper (boundary at 95%, both deviation directions, custom
limit, missing/zero/NaN guards) and service tests covering tradable / untradable (>95%) / an
injected custom limit; targeted suites for the subscription service, provider, and controller pass;
yarn eslintandchangelog:validatepass; the full monorepo build and the standaloneperps-controllerbuild both succeed.References
PriceUpdate.isTradabletorender the "trading unavailable" banner; copy/design pending @Varada Stern.
Checklist
Note
Medium Risk
Touches live price subscription data used for trading UX; the new required
PriceUpdate.isTradablefield may require consumer/test updates even though semantics default to tradable when uncertain.Overview
Adds
isTradableto streamedPriceUpdatepayloads so mobile/extension can warn before submit when HyperLiquid would reject an order (mid vs oracle deviation beyond the protocol limit, often on HIP-3 markets).HyperLiquid price updates now set
isTradablevia exportedisMarketTradableandHYPERLIQUID_CONFIG.OraclePriceDeviationLimit(0.95); missing or invalid prices stay tradable. OptionalfallbackPriceDeviationLimiton perps client config is passed controller →HyperLiquidProvider→HyperLiquidSubscriptionService. MYX tickers always emitisTradable: true. Unit/service tests cover boundaries and custom limits.Reviewed by Cursor Bugbot for commit 584542c. Bugbot is set up for automated code reviews on this repo. Configure here.