Skip to content

feat(perps): Lighter venue POC — WebView WASM signer bridge and recovery surface - #34865

Draft
abretonc7s wants to merge 32 commits into
mainfrom
TAT-3766-feat-lighter-webview-signer-poc
Draft

feat(perps): Lighter venue POC — WebView WASM signer bridge and recovery surface#34865
abretonc7s wants to merge 32 commits into
mainfrom
TAT-3766-feat-lighter-webview-signer-poc

Conversation

@abretonc7s

@abretonc7s abretonc7s commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Description

Description

Mobile side of the Lighter perps venue spike (TAT-3766, core PR: MetaMask/core#9889). Draft to preserve state — depends on the @metamask/perps-controller update landing first (currently consumed via a vendored .yalc payload, to be replaced by the published package before review).

What's included

  • WebView WASM signer bridge: off-screen WebView hosting the Lighter Go/WASM signer, exposed to the provider via providerCredentials.lighter.signerBridge (postMessage protocol, key material never leaves the bridge boundary). Signer-reset detection with proactive re-setup, timeout recovery, and key redaction in logs.
  • Provider exposure: Lighter in the perps provider selector (testnet + mainnet), gated behind MM_PERPS_LIGHTER_PROVIDER_ENABLED.
  • Durable-settlement recovery surface: usePerpsRecoveryStatus hook + PerpsRecoveryStatusBanner in the Perps home view — surfaces parked manual TP/SL recoveries and recovered dispatch outcomes from the controller, with explicit per-outcome acknowledgment. Refreshes on screen focus and account/provider/network changes; generation-guarded against out-of-order async commits; read/acknowledgment errors render visibly instead of degrading to "nothing pending".
  • Perps fixes shaken out by the integration: identity-change cache invalidation, debounce cancellation on disconnect takeover, side-only fill presentation/PnL routing, direction-aware flip sizing.

Status

  • Core controller changes approved through 23 rounds of cross-review (see core PR [Bug]: STX opt-in dialog not appearing on fresh install #9889 branch TAT-3766-feat-spike-lighter-perps-integratio).
  • Hook + banner unit suites green (12/12); focused eslint clean.
  • Not ready to merge: awaits the published @metamask/perps-controller release replacing the .yalc payload.

Related issues

Spike: TAT-3766

Manual testing steps

  1. Build with MM_PERPS_LIGHTER_PROVIDER_ENABLED=true.
  2. Switch the perps provider to Lighter (testnet) in the provider selector.
  3. Market list/details render live Lighter data over WebSocket; place/cancel a test order on testnet.
  4. Recovery banner: with a pending recovered dispatch or manual TP/SL recovery on the account, open Perps home — the banner surfaces it and Acknowledge clears it after refresh.

Pre-merge author checklist

Changelog

CHANGELOG entry: null

Related issues

Fixes: TAT-3766

Manual testing steps

Feature: Lighter perps venue (POC)

  Scenario: user trades on Lighter testnet end-to-end
    Given the app is launched with the Lighter provider enabled (MM_PERPS_LIGHTER_PROVIDER_ENABLED)
    And the wallet holds a funded Lighter testnet venue account

    When user selects Lighter Testnet in the Perps venue picker
    And user opens a market, presses Long, and places the seeded market order
    And user attaches TP/SL from the position card auto-close control
    And user closes the position from the Close button
    Then every step succeeds against the live venue and the venue reads back flat

Automated equivalent (recorded, 76/76 nodes):

mm-harness run lighter.capability-suite --library lighter=recipes/lighter-lib --record-video=full-run

Screenshots/Recordings

Before

Lighter venue not available; Perps trades only on HyperLiquid.

After

On-device validation evidence (Lighter testnet, iOS simulator)

Recorded by the composable recipe suite driving the real UI (no controller shortcuts for trade flows) — latest run 76/76 nodes green, venue verified flat afterwards:

mm-harness run lighter.capability-suite --library lighter=recipes/lighter-lib --record-video=full-run

🎬 Full demo video (5 m 22 s, HUD narrates each step)

Trade lifecycle — every step through the real screens

Order form seeds venue min + real liq price Market order filled TP/SL set (RoE presets)
SL line on chart (venue OCO pair) Close flow (full size preselected) BTC limit order (−2 % preset)

Venue rules are dynamic + provider-served surfaces

Lighter ETH leverage: 50x max HyperLiquid ETH: 25x max HyperLiquid BTC: 40x max
Order book (depth chart + totals) Activity: genuine venue history

Evidence + recipes live under recipes/ as a DO-NOT-MERGE holding area (spike content, removed before merge; recipes graduate to the harness perps library).

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
  • I've tested with a power user scenario
  • I've instrumented key operations with Sentry traces for production performance metrics

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Medium Risk
Vendoring a large generated perps/trading controller changes dependency resolution and review surface until replaced by a published package; runtime trading behavior follows whatever is in the committed build.

Overview
Temporary build unblock for TAT-3766: the branch vendors a prebuilt @metamask/perps-controller (12.0.0) under .yalc/@metamask/perps-controller (full dist/ plus package metadata) so mobile can consume the Lighter-capable controller before MetaMask/core publishes a preview release.

Git hygiene for the vendored tree: .gitignore is updated so only this package path is tracked (parent .yalc stays ignored, with explicit exceptions for perps-controller and its dist/). .gitattributes marks .yalc/@metamask/perps-controller/** as generated and excludes it from diff review.

This is intended to be removed once @metamask/perps-controller is published and the app depends on the registry version again (per PR notes).

Reviewed by Cursor Bugbot for commit 8db3497. Bugbot is set up for automated code reviews on this repo. Configure here.

React Native's MessageEvent (polyfilled globally for the HyperLiquid
WebSocket SDK) omits the source getter, but
@metamask/post-message-stream's WindowPostMessageStream asserts its
existence at module load, which breaks snaps execution-service init and
prevents Engine startup in dev builds. Define a null getter — the window
stream is never used at runtime on React Native, only its load-time
assert matters.
…der exposure

Adds the Lighter signer transport (TAT-3766 POC): a hidden WebView hosting
the locally-bundled Go/WASM signer page (built from elliottech/lighter-go
web-wasm source, base64-embedded, no network access) speaking the reference
postMessage protocol, exposed to @metamask/perps-controller through a
queue-behind-readiness bridge singleton injected via platform dependencies.
Surfaces the Lighter venue in the provider selector (env-gated via
MM_PERPS_LIGHTER_PROVIDER_ENABLED, testnet only) and scopes a
babel-plugin-inline-import override for the signer HTML.

Requires the Lighter-enabled @metamask/perps-controller build (POC branch;
delivered locally via yalc — package.json intentionally not switched).
The bridge moves off PerpsPlatformDependencies onto
providerCredentials.lighter.signerBridge so the shared platform surface
stays venue-agnostic (matches the core-side change).
- Reject all pending signer calls when the WebView reloads (content
  process loss) and add a per-call 60s timeout so callers retry instead
  of hanging against a dead page
- Redact the venue private key inside the WASM wrapper before results
  cross the postMessage boundary; signing stays inside the WebView
- Update the provider selector test to the Lighter rows (MYX rows were
  removed from the selector when Lighter replaced it as second venue)
…producible dependency

- lighterSignerBridge: reset now rejects callers waiting on the old
  readiness promise (their page-side state is gone) and every call is
  bounded by a 90s timeout that covers the pre-ready wait; the WebView
  also recovers on Android render-process loss and on load errors
- The signer bridge is supplied to the controller only when the same
  env flag that mounts the WebView is set, so core's enablement gate and
  the client's signer mount can never disagree
- Commit the Lighter-enabled perps-controller build under .yalc (with
  package.json already pointing at it) so the branch builds from a clean
  checkout until the core PR merges and publishes
Queued-call execution, reject-on-reload for waiters, and the
never-mounted timeout.
…iene

- The bridge exposes onReset so the controller invalidates its cached
  signer session the moment the WebView resets, instead of learning from
  the next failed trading call
- Mark the committed .yalc payload linguist-generated/-diff so
  git diff --check passes; refresh it from core 3f0608abc0
Side-only venues (Lighter) report a closed short as a plain Buy with the
realized pnl attached; the Buy branch previously showed only the fee and
dropped the PnL. Any fill carrying nonzero PnL now renders through the
close/PnL display path. Tests cover the Lighter Buy-with-PnL fill and
the unchanged zero-PnL Buy.
…idation preview

- A side-only Buy/Sell fill carrying realized PnL is categorized as a
  position close with PnL display; generic Bought/Sold titles stay
  untouched (cross-provider contract). Lighter fills with position
  context arrive as Close Short/Close Long and render natively — tests
  cover Open Short, Close Long, buy-close fallback, and zero-PnL open
- Provider capability-gate errors (liquidation preview unavailable)
  render the explicit price fallback instead of a misleading 0.00
Flips now size the post-flip position as |trade size| - |signed
startPosition| — a short flipped by a buy previously displayed the sum
instead of the remainder. Tests cover Long > Short and Short > Long with
asymmetric values.
A zero-PnL side-only Lighter fill (break-even reduction and an add both
fit) gets a new neutral 'trade' category instead of guessing open (Buy)
or close (Sell); HyperLiquid's spot Buy/Sell semantics are unchanged.
Fills carrying realized PnL keep the close category and PnL display.
- usePerpsRecoveryStatus hook: reads pending manual TP/SL recoveries and
  recovered dispatch outcomes from PerpsController; explicit per-outcome
  acknowledge that refreshes after acknowledging; read errors surface
  instead of degrading to empty lists.
- PerpsRecoveryStatusBanner: warning banner for a recovered dispatch
  (succeeded vs unknown wording) with an Acknowledge action wired to the
  stable recovery id, and a danger banner for parked manual TP/SL
  recovery naming the affected symbol; renders nothing when idle.
- Rendered account-wide in PerpsHomeView; en locale strings added.
…sh, visible errors

- usePerpsRecoveryStatus re-reads on screen focus (useFocusEffect) and
  on selected-account / active-provider / network changes, not just
  mount, so returning from a failed trade exposes fresh quarantine and
  manual state.
- Acknowledgment failures are recorded into the hook's error state and
  rethrown; read failures keep surfacing instead of degrading to empty
  lists.
- PerpsRecoveryStatusBanner renders read/acknowledgment errors as a
  danger banner (never returns null on error) while the dispatch banner
  stays rendered and actionable.
- Tests: focus re-read, account/provider-change re-read, error banner,
  ack-failure visibility and propagation.
- Every usePerpsRecoveryStatus refresh takes a request generation and
  captures the selected-address/provider/network context; lists, error,
  and loading commit only for the latest request whose context still
  matches, so a slow stale read (or stale failure) can no longer
  overwrite a newer request's state.
- Proof: mount request hangs, focus request commits fresh data, the
  stale request resolves late with empty data — the fresh state
  survives and loading settles.
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@abretonc7s abretonc7s added the team-perps Perps team label Aug 17, 2026
@metamask-ci metamask-ci Bot added the INVALID-PR-TEMPLATE PR's body doesn't match template label Aug 17, 2026
@abretonc7s
abretonc7s marked this pull request as ready for review August 17, 2026 10:54
@metamask-ci

metamask-ci Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

PR template — items to address before "Ready for review"

Warnings — informational, address before merging:

  • Description section is empty. Describe what changed and why.
  • Pre-merge author checklist has unchecked items (e.g. "I've applied the right labels on the PR (see labeling guidelines). Not required for external contributors."). Every box must be consciously checked — see docs/readme/ready-for-review.md.

See docs/readme/ready-for-review.md for the full Definition of Ready for Review.

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

🧪 Flaky unit test detection

Run history flaky detection

View recent run history

Historical failure rate is a hint, not proof — review each suggestion in context. See the flaky-test-detection skill for the full pattern reference and manual audit workflow.

Failures / runs sampled per window:

File 7d 15d 30d
app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.test.tsx 0/171 0/214 0/418
app/components/UI/Perps/adapters/mobileInfrastructure.test.ts 0/171 0/214 0/418
app/components/UI/Perps/hooks/usePerpsOrderForm.test.ts 0/171 0/214 0/418
app/components/UI/Perps/services/PerpsConnectionManager.test.ts 0/171 0/214 0/418
app/components/UI/Perps/utils/transactionTransforms.test.ts 0/171 0/214 0/418

AI-detected flaky patterns

app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.test.tsx

  • J9 — Module-level mutable let binding not reset in beforeEach (high)
    • mockRouteParams is declared as a module-level mutable let binding and initialized once. The outer beforeEach calls jest.clearAllMocks() and resets individual mock functions, but it never resets mockRouteParams back to its default value { source: 'main_action_button' }. Any test that mutates this object (e.g., by assigning a different value or adding properties such as transactionActiveAbTests) will cause that mutation to bleed into all subsequent tests in the file. Because Jest runs tests in declaration order by default but can be randomized with --randomize, this creates an order-dependent failure: tests that rely on mockRouteParams containing only { source: 'main_action_button' } will fail when run after a test that mutated it.
    • Suggested fix in app/components/UI/Perps/Views/PerpsHomeView/PerpsHomeView.test.tsx:55:
      -let mockRouteParams: Record<string, unknown> = {
      -  source: 'main_action_button',
      -};
      +let mockRouteParams: Record<string, unknown> = {
      +  source: 'main_action_button',
      +};
      +
      +// Inside the outer describe('PerpsHomeView') beforeEach:
      +beforeEach(() => {
      +  jest.clearAllMocks();
      +  mockRouteParams = { source: 'main_action_button' }; // ← reset to default before every test
      +  mockHasCompletedPerpsModeSelection.mockResolvedValue(false);
      +  // ... rest of beforeEach
      +});

app/components/UI/Perps/adapters/mobileInfrastructure.test.ts

  • J9 — Module-level mutable let bindings not reset in beforeEach (high)
    • The module-level mockSelectVipProgramEnabled is initialized with .mockReturnValue(true) at declaration time. The beforeEach only calls jest.clearAllMocks(), which clears call counts and recorded calls but does NOT reset mock implementations set via mockReturnValue. This means if the 'returns 0 discount when vipProgramEnabled is false' test runs before any test that expects true, the mockReturnValue(false) set in that test bleeds into subsequent tests. The test suite is currently order-dependent: tests that rely on the default true value will fail if they run after a test that set it to false. The fix is to restore the default implementation in beforeEach.
    • Suggested fix in app/components/UI/Perps/adapters/mobileInfrastructure.test.ts:97:
      -const mockSelectVipProgramEnabled = jest.fn().mockReturnValue(true);
      -jest.mock('../../../../selectors/featureFlagController/vipProgram', () => ({
      -  selectVipProgramEnabled: (...args: unknown[]) =>
      -    mockSelectVipProgramEnabled(...args),
      -}));
      -
      -// ...
      -
      -describe('createMobileInfrastructure', () => {
      -  beforeEach(() => {
      -    jest.clearAllMocks();
      -  });
      -
      -  // ...
      -
      -  describe('rewards', () => {
      -    it('delegates getPerpsDiscountForAccount to RewardsController when vipProgramEnabled', async () => {
      -      mockSelectVipProgramEnabled.mockReturnValue(true);
      -      // ...
      -    });
      -
      -    it('returns 0 discount when vipProgramEnabled is false', async () => {
      -      mockSelectVipProgramEnabled.mockReturnValue(false);
      -      // ...
      -    });
      -  });
      -});
      +const mockSelectVipProgramEnabled = jest.fn().mockReturnValue(true);
      +jest.mock('../../../../selectors/featureFlagController/vipProgram', () => ({
      +  selectVipProgramEnabled: (...args: unknown[]) =>
      +    mockSelectVipProgramEnabled(...args),
      +}));
      +
      +// ...
      +
      +describe('createMobileInfrastructure', () => {
      +  beforeEach(() => {
      +    jest.clearAllMocks();
      +    mockSelectVipProgramEnabled.mockReturnValue(true); // restore default before every test
      +  });
      +
      +  // ...
      +});

app/components/UI/Perps/hooks/usePerpsOrderForm.test.ts

  • J10 — jest.spyOn without restoreAllMocks()/mockRestore() afterward (medium)
    • A jest.spyOn(DevLogger, 'log').mockImplementation() is installed inside a test body. The beforeEach only calls jest.clearAllMocks(), which clears call counts but does NOT restore the original DevLogger.log implementation. Without jest.restoreAllMocks() in an afterEach, the spy persists into all subsequent tests in the file, silencing any real DevLogger.log calls and potentially masking failures in tests that depend on the original behavior. The fix is to add afterEach(() => { jest.restoreAllMocks(); }) at the top-level describe scope.
    • Suggested fix in app/components/UI/Perps/hooks/usePerpsOrderForm.test.ts:1:
      -it('preserves setStopLossPrice DevLogger side effect and clearing behavior', () => {
      -  const devLoggerSpy = jest.spyOn(DevLogger, 'log').mockImplementation();
      -  const { result } = renderHook(() => usePerpsOrderForm(), {
      -    wrapper: createWrapper(),
      -  });
      -  act(() => {
      -    // ...
      -  });
      -  // ...
      -});
      +describe('usePerpsOrderForm', () => {
      +  // ... existing beforeEach ...
      +  beforeEach(() => {
      +    jest.clearAllMocks();
      +    // ... existing mock setup ...
      +  });
      +
      +  afterEach(() => {
      +    jest.restoreAllMocks();
      +  });
      +
      +  // ... rest of describe ...
      +});

app/components/UI/Perps/services/PerpsConnectionManager.test.ts

  • J6 — Arbitrary setTimeout/sleep used as synchronization barrier (high)
    • Two newly-added tests in the 'state monitoring' describe block use await new Promise((resolve) => setTimeout(resolve, 0)) and await new Promise((resolve) => setTimeout(resolve, 60)) as synchronization barriers to let async operations settle. Even a zero-delay setTimeout is a real timer that is non-deterministic under CI load — the microtask queue may not have fully drained by the time the timer fires, and a 60 ms wall-clock delay is especially fragile on a loaded CI runner. These should be replaced with waitFor polling on the actual observable condition (e.g. the spy call count or connection state).
    • Suggested fix in app/components/UI/Perps/services/PerpsConnectionManager.test.ts:1:
      -      await new Promise((resolve) => setTimeout(resolve, 0));
      -      // ... later in the same test:
      -      await new Promise((resolve) => setTimeout(resolve, 60));
      +      // Replace:
      +      await new Promise((resolve) => setTimeout(resolve, 0));
      +      // With:
      +      await waitFor(() => {
      +        expect(reconnectSpy).toHaveBeenCalled();
      +      });
      +
      +      // Replace:
      +      await new Promise((resolve) => setTimeout(resolve, 60));
      +      // With:
      +      await waitFor(() => {
      +        expect(reconnectSpy).toHaveBeenCalledTimes(1);
      +      });
  • J10 — jest.spyOn without restoreAllMocks() (medium)
    • Two tests in the 'state monitoring' describe block install jest.spyOn(PerpsConnectionManager, 'reconnectWithNewContext').mockImplementation(...) but there is no afterEach(() => jest.restoreAllMocks()) in that describe block or its parent. The top-level beforeEach only calls jest.clearAllMocks(), which clears call counts but does NOT restore spied-on implementations. If the spy leaks into a subsequent test, PerpsConnectionManager.reconnectWithNewContext will still be the no-op mock implementation, causing tests that expect real reconnection behavior to silently pass or fail incorrectly depending on execution order.
    • Suggested fix in app/components/UI/Perps/services/PerpsConnectionManager.test.ts:1:
      -      const reconnectSpy = jest
      -        .spyOn(PerpsConnectionManager, 'reconnectWithNewContext')
      -        .mockImplementation(async () => undefined);
      +  describe('state monitoring', () => {
      +    // Add this to restore spies after each test in this block:
      +    afterEach(() => {
      +      jest.restoreAllMocks();
      +    });
      +
      +    // ... existing tests unchanged
      +  });

app/components/UI/Perps/utils/transactionTransforms.test.ts

  • J10 — jest.spyOn without restoreAllMocks() (medium)
    • Three consecutive tests each install jest.spyOn(console, 'warn') and jest.spyOn(console, 'error') but do not restore all spies. In the 'silently skips Spot Dust Conversion' test, warnSpy.mockRestore() is called but errorSpy.mockRestore() is omitted — the console.error spy leaks into subsequent tests. In the two 'emits console.warn' tests, neither spy is restored at all. Because there is no afterEach(() => jest.restoreAllMocks()) anywhere in the file, the mocked console.error and console.warn implementations accumulate across tests. Any later test that relies on console.error or console.warn behaving normally (e.g. to detect unexpected errors) will silently swallow them, causing order-dependent failures.
    • Suggested fix in app/components/UI/Perps/utils/transactionTransforms.test.ts:1:
      -    it('silently skips Spot Dust Conversion fills without console.error', () => {
      -      const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
      -      const errorSpy = jest.spyOn(console, 'error').mockImplementation();
      -      const dustFill = {
      -        ...mockFill,
      -        direction: 'Spot Dust Conversion',
      -      };
      -      const result = transformFillsToTransactions([dustFill]);
      -      expect(result).toHaveLength(0);
      -      expect(errorSpy).not.toHaveBeenCalled();
      -      expect(warnSpy).not.toHaveBeenCalled();
      -      warnSpy.mockRestore();
      -      // errorSpy is never restored
      -    });
      +afterEach(() => {
      +  jest.restoreAllMocks();
      +});
      +
      +// Then remove the manual warnSpy.mockRestore() calls inside each test body,
      +// since afterEach handles restoration for all spies uniformly:
      +
      +    it('silently skips Spot Dust Conversion fills without console.error', () => {
      +      const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
      +      const errorSpy = jest.spyOn(console, 'error').mockImplementation();
      +      const dustFill = {
      +        ...mockFill,
      +        direction: 'Spot Dust Conversion',
      +      };
      +      const result = transformFillsToTransactions([dustFill]);
      +      expect(result).toHaveLength(0);
      +      expect(errorSpy).not.toHaveBeenCalled();
      +      expect(warnSpy).not.toHaveBeenCalled();
      +      // mockRestore() removed — afterEach handles it
      +    });

This check is informational only and does not block merging.

The committed .yalc payload and yarn.lock had drifted (immutable
install failed on CI with a resolution hash mismatch). Commit the
current controller build — carrying the reviewed durable-settlement,
recovery-surface, and mainnet-gate changes — together with the
matching lockfile. Interim until the published package replaces the
vendored payload.
…tation

- Stub PerpsRecoveryStatusBanner in the PerpsHomeView view test: this
  file's useFocusEffect mock invokes callbacks synchronously during
  render, which loops against the banner hook's focus refresh; the
  banner has its own unit suite.
- createMobileClientConfig default expectation gains the disabled
  lighter credentials block the builder has emitted since the POC
  wiring (first CI run where unit tests executed on this branch).
Comment thread app/components/UI/Perps/adapters/mobileInfrastructure.test.ts
- babel-config-paths gains the LighterSignerWebView inline-import
  override row the POC added to babel.config.js.
- The order-lifecycle provider-selection phase reflects the selector
  list where the MYX rows were replaced by Lighter: MYX stays absent
  even with its flag enabled, and the switch flow selects the
  aggregated provider instead.
…ntroller

Lighter venue-key derivation signs an EIP-191 message through the
controller messenger; only signTypedMessage (HyperLiquid's method) was
delegated, so first-trade readiness failed on device with 'A handler
for KeyringController:signPersonalMessage has not been delegated'.
Found by on-device validation; with the delegation the venue key
registers on-chain from the app.
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
61.5% Coverage on New Code (required ≥ 80%)
C Security Rating on New Code (required ≥ A)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Comment thread recipes/lighter-lib/recipes/lighter/history.recipe.json
Comment thread recipes/lighter-lib/recipes/lighter/history.recipe.json

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 4 total unresolved issues (including 3 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 585abb8. Configure here.

Comment thread app/components/UI/Perps/hooks/usePerpsOrderForm.ts
@metamask-ci metamask-ci Bot removed the INVALID-PR-TEMPLATE PR's body doesn't match template label Aug 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokePerps, SmokeWalletPlatform, SmokeConfirmations
  • Selected Performance tags: @PerformancePreps
  • Risk Level: high
  • AI Confidence: 88%
click to see 🤖 AI reasoning details

E2E Test Selection:
The PR updates the .yalc/@metamask/perps-controller package (a yalc-linked local version being tested before publishing). This is a significant update to the PerpsController - a critical controller that powers all perpetuals trading functionality in MetaMask Mobile.

Key observations:

  1. PerpsController core changes: The main PerpsController.mjs and type definitions are updated with new features including Lighter provider support, MYX provider support, aggregated provider mode, watchlist sync with AUS (Authenticated User Storage), disk persistence for market/user data, and new state fields.
  2. New constants: Updates to hyperLiquidConfig, lighterConfig, myxConfig, orderTypes, performanceMetrics, chartConfig, and eventNames - all affecting perps trading behavior.
  3. Method action types: New/updated action types for the controller messenger pattern.
  4. SubscriptionMultiplexer: New aggregation infrastructure for multi-provider support.

SmokePerps: Directly impacted - PerpsController is the core controller for all perps functionality (Add Funds, positions, orders, withdrawals, limit orders, stop-loss, liquidation, etc.). All perps smoke tests exercise this controller.

SmokeWalletPlatform: Per tag description, Perps is a section inside the Trending tab. Changes to PerpsController affect the Perps views embedded in Trending (PerpsHomeView, PerpsMarketListView, etc.).

SmokeConfirmations: Per SmokePerps tag description, Add Funds deposits are on-chain transactions requiring confirmations. Must be selected alongside SmokePerps.

The .gitattributes and .gitignore changes are infrastructure-only (adding .yalc to git tracking) and don't affect test selection.

Performance Test Selection:
The PerpsController update includes changes to performance metrics (PerpsMeasurementName enum in performanceMetrics.d.mts), new provider initialization flows (Lighter, MYX, Aggregated), disk persistence for market/user data, and new caching mechanisms. These changes directly affect the perps market loading, position management, add funds flow, and order execution - all of which are measured by @PerformancePreps. The new disk hydration and preloading mechanisms could significantly impact time-to-content for the perps screens.

View GitHub Actions results

@abretonc7s
abretonc7s marked this pull request as draft August 19, 2026 02:28
@github-actions

Copy link
Copy Markdown
Contributor

⚡ Performance Test Results

ℹ️ Performance test results are currently non-blocking and will not block this PR.

⚠️ Results incomplete — No test results found


Branch: TAT-3766-feat-lighter-webview-signer-poc · Build: E2E · Commit: 496fe93 · View full run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DO-NOT-MERGE Pull requests that should not be merged size-XL team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant