Skip to content

feat(perps): integrate Lighter with funded Lite order entry - #34865

Merged
abretonc7s merged 61 commits into
mainfrom
TAT-3766-feat-lighter-webview-signer-poc
Sep 23, 2026
Merged

abretonc7s merged 61 commits into
mainfrom
TAT-3766-feat-lighter-webview-signer-poc

Conversation

@abretonc7s

@abretonc7s abretonc7s commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Description

Initial feature-gated Lighter POC using published @metamask/perps-controller@17.3.0, a pinned embedded WebView signer, and funded Lite order entry. Aggregated Lighter orders switch to Lighter before reading balance and market metadata. Hyperliquid retains its existing funding path.

The follow-up constrains registration plaintext, blocks signer network APIs/subresources, recovers WASM/Go startup failures, cancels retired keychain/setup work, and records terminal failures. It also adds funded-screen telemetry, validates optional signer indices, collects the Metro test in CI, and prevents an unsupported Lighter deposit route. Controller 17.3.0 includes the upstream canceled-order filled-size fix; the temporary Yarn patch has been removed.

Capabilities, fees and POC limits · Pinned signer provenance and trust boundary

Controller upgrade verification at fd68ef7d27: installed unpatched 17.3.0; 225 unit tests, 6 component-view tests, TypeScript, lint and formatting passed. Earlier trading captures retain the source/build provenance documented below.

Bundle isolation at 365d4a12029: MM_PERPS_LIGHTER_PROVIDER_ENABLED=true is now required in every build, including local development. Normal production already excluded the signer; development no longer includes it automatically. Real iOS bundles with the flag off contain no signer host/HTML in their source maps and no embedded WASM payload: production 20,804 modules, development 21,098 modules. Enabled POC builds still inline the local signer; this is build-time exclusion, not runtime code splitting. 235 focused unit tests, 7 component-view tests, TypeScript, lint and formatting passed.

CI follow-up: Jest stubs the native signer asset instead of inlining 10 MB into each test VM. Component-view coverage now reports exercised files, matching the integration layer; unit tests retain repository-wide coverage. The previously failing shard passed locally with the same 12 GiB limit (36 suites / 425 tests) and all three component-view shards passed in CI on 903d04f13cc. Merged main 638585d253f, including its wallet compatibility fix from #36671, and removed this PR's wallet-version override. No patch files or patch resolutions differ from main. 144 wallet-adapter and order-normalization tests, immutable install and TypeScript passed after the merge.

Changelog

CHANGELOG entry: Added initial Lighter integration with funded-balance order entry in Lite mode.

Related issues

Upstream controller fix: MetaMask/core#10308, merged and released in @metamask/perps-controller@17.3.0, now consumed directly without a Yarn patch. Core live cancellation recipe calls PerpsController.getOrders() directly: the same Lighter receipt fails with the old filled-size calculation and passes with the upstream fix, without placing new orders.

Refs: MetaMask/core#10187

Tracking: TAT-3766.

Manual testing steps

  1. Set MM_PERPS_LIGHTER_PROVIDER_ENABLED=true in .js.env and restart Metro with a cleared cache, select an owned funded Lighter testnet account with an existing signer slot, and reserve an empty BTC market.
  2. In Lite, submit a small market Long. Confirm the accepted size, then close through the UI and verify BTC is flat.
  3. In Pro, place a non-crossing limit Long and cancel it individually. Verify no BTC orders/positions remain and canceled filled size is zero.
  4. Open history and match the opening, closing and canceled records to their exact Lighter venue IDs.

Native build prerequisite: the current branch requires ExpoGlassEffect, added to main on September 17. Runway 35154767219, the newest downloadable iOS artifact checked on September 21, predates that module and can crash after unlock when Trade renders. Use a native development build matching this branch or a newer compatible Runway. When rebuilding an existing Runway fixture locally, preserve its keychain encryption configuration so saved signer credentials remain readable.

Native compatibility follow-up on 717df71d4a: installed a local iOS development build with ExpoGlassEffect and the original fixture encryption configuration. Actual lock/unlock and existing Lighter signer recovery passed 15/15 nodes; native module availability and the Trade menu passed 9/9. No new key registration or trades in this follow-up. The trading receipts below retain their original build provenance.

Executed Lighter proof

iOS simulator mm-1, Runway development build 35154767219, existing four-account fixture, dev1, Lighter testnet account 59, existing slot 8. No funding or key registration. The unrelated ETH position was preserved.

Trading captures used the runtime source committed as 74d8077aa7; only test formatting followed the captures. Post-commit launch verification and exact-row history validation passed. The library recipes explicitly select Lighter, assert the mounted order inputs, and reconcile run-scoped UI client IDs with Lighter's accountInactiveOrders endpoint and controller records bearing providerId: lighter.

Operation UI client receipt Lighter venue order Result
Lite market Long 68315437830547 844424924481651 Filled 0.00012 BTC
UI close 174228495428506 562949959175979 Filled 0.00012 BTC
Pro limit/cancel 258575485365276 844424924480362 Canceled, filled size 0

Market cycle: 39/39 nodes. Limit cycle: 35/35 nodes. History: 17/17 nodes. Both trading cycles ended with no BTC residue. The earlier failed receipt check is retained; Lighter's inactive-order read lagged cancellation acknowledgement, so the reusable assertion now polls only the exact IDs for a bounded period.

The real iOS signer probe denied ten transport APIs and observed CSP violations for external image/script loads. Signing continued to work. No iframe CSP event was observed. Focused checks passed: 135 unit tests, 7 funded-screen component-view tests, TypeScript, lint, formatting and normal CI test discovery.

Reusable recipes are now on the Perps library main branch, pinned revision 32e9d79. The reproduction contract covers venue selection, owned fixture/signer prerequisites, limits and cleanup.

The published limit recipe additionally refuses an ambiguous cancellation target across markets. Its final replay passed 38/38, with Lighter order 844424924468408 canceled and filled size 0. The screenshots above come from the earlier receipt table's runs.

Replay the published recipes

Use @deeeed/metamask-harness@0.61.1 or newer. It includes @farmslot/recipe-harness@0.18.1, which retains typed invocation inputs for portable artifact validation.

Use a funded, owned Lighter testnet fixture and an already registered key slot. Reserve the selected market, start with no BTC orders/positions, and restart the app before each trading journey. Set these variables to your fixture's public metadata; they are not credentials.

export RECIPE_LIBRARY_PATH="perps=/path/to/experimental-metamask-recipe-perps"
export METAMASK_RECIPE_AUTO_HUD=0
LIGHTER_PROOF_ARGS=(
  account="$FIXTURE_ACCOUNT" account_index="$LIGHTER_ACCOUNT_INDEX"
  api_key_index="$LIGHTER_KEY_SLOT" market=BTC market_index="$LIGHTER_BTC_INDEX"
  expected_leverage=2 min_spendable_usd=20 exclusive_testnet_market=true
)

# Inspect each plan before replacing --plan with a new --artifacts-dir path.
mm-harness run perps.lighter-lite-market-cycle "${LIGHTER_PROOF_ARGS[@]}" \
  'amount_usd="10"' --plan
mm-harness run perps.lighter-pro-limit-cycle "${LIGHTER_PROOF_ARGS[@]}" \
  'amount_usd="20"' "limit_price=\"$NON_CROSSING_BID\"" --plan

# Use the exact activity IDs returned by the receipt verification nodes.
mm-harness run perps.lighter-history account="$FIXTURE_ACCOUNT" market=BTC \
  open_activity_id="$OPEN_ACTIVITY_ID" close_activity_id="$CLOSE_ACTIVITY_ID" \
  canceled_activity_id="$CANCELED_ACTIVITY_ID" --artifacts-dir temp/lighter-history-proof

Remaining limits: Android runtime, mainnet financial trading, Extension compilation parity and a full audit/reproducible build of the deployed signer remain unverified. The registration protocol's L1 plaintext has no chain field; the pinned signer remains trusted for cryptography. The signer CSP now permits only the four embedded scripts by hash; Chromium and WebKit both loaded the real signer and blocked an extra inline script. The non-required PR-size check remains above its 1,000-line threshold. All required checks pass on c3666c30fe5, including unit, component-view, integration, all Android smoke shards and Sonar. The full CI run on that revision completed successfully, including the Android performance follow-up. Bugbot passed with no unresolved review threads. CI and Bugbot are rerunning on 365d4a12029; reviewer approval is still required.

Review follow-up, c25aa718c5

Wallet lock now retires pending signer work and removes the native WebView; unlocking creates a fresh page. The iOS wallet lifecycle recipe passed 15/15 nodes: locked keyring, zero native signers, rejected signing, then a new native page and successful read-token signing after unlock. Unit coverage includes pending work and rapid lock/unlock with stale page messages.

The shared market router now selects the explicit Pro venue before mounting its order form and keeps the form closed on switch failure. Runtime proof recorded aggregated BTC metadata at Hyperliquid's 40x limit, switched to Lighter's 50x metadata, then placed and canceled the Lighter limit order. Client receipt 188515645512169 matched venue order 844424924447876, canceled with filled size 0; BTC ended flat. The combined run's final receipt node exceeded its bounded wait, and a separate exact-ID read subsequently passed. Both traces are retained.

Focused unit/component-view checks, TypeScript and lint passed. Follow-up 717df71d4a keeps Lite available after a failed Pro venue switch; its regression failed before the fix and the six router view tests pass afterward. The obsolete profiling-analyzer discussion and the Lite-mode follow-up were replied to and resolved.

Screenshots/Recordings

Recipe visual evidence
Screenshots are grouped for quick reviewer comparison.
Lighter: market Long filled, 0.00012 BTC
Lighter: market Long filled, 0.00012 BTC
Lighter: full-position UI close
Lighter: full-position UI close
Lighter: resting 0.00029 BTC limit at $70,000
Lighter: resting 0.00029 BTC limit at $70,000
Lighter: individual cancel, no open BTC orders
Lighter: individual cancel, no open BTC orders
Lighter: exact opening and closing fills
Lighter: exact opening and closing fills
Lighter: canceled limit and filled market orders
Lighter: canceled limit and filled market orders

After

Actual Lighter testnet trades, backed by the exact venue receipts above. The shared UI does not display a venue label. The developer control remains visible.

Before

N/A. Initial provider integration.

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs and Coding Standards.
  • I've completed the PR template to the best of my ability.
  • I've included tests if applicable.
  • I've documented my code using JSDoc format if applicable.
  • I've applied the right labels on the PR.

Performance checks (if applicable)

  • I've assessed Android testing: not run for this iOS POC; remains a validation gap.
  • I've assessed power-user testing: not run; no performance sign-off claimed.
  • I've assessed Sentry tracing: funded-screen measurement added and tested; production delivery unverified.

Pre-merge reviewer checklist

  • I've manually tested the PR.
  • I confirm the acceptance criteria and testing evidence are sufficient.

Note

High Risk
Changes add off-device-adjacent cryptographic signing, private-key persistence, and a pinned WASM trust boundary—core wallet and trading security surface.

Overview
Adds feature-gated Lighter perps configuration in .js.env.example (MM_PERPS_LIGHTER_PROVIDER_ENABLED plus optional testnet account and API-key index overrides).

Introduces a mobile Lighter signing stack: a hidden WebView loads a local embedded Go/WASM page (network APIs stubbed, navigation restricted to https://localhost/, hash-locked CSP) and talks to React Native via a strict postMessage protocol. A module-level lighterSignerBridge implements the @metamask/perps-controller signer interface—queues work until the page is ready, persists signer keys in SecureKeychain (chain/account/slot scoped), validates Register Lighter Account plaintext before registration reaches the controller, and enforces wallet-lock behavior by tearing down the WebView and failing in-flight calls.

Lifecycle hardening includes exponential-backoff reloads after WASM init or renderer crashes (with reload counters reset after a successful ready), terminal unavailability after repeated failures, and extensive unit tests (including a lightweight HTML mock for CI). wasm-provenance.md documents the pinned testnet WASM artifact and trust boundaries. A small lighterOrderNormalization test guards the upstream canceled-order filled-size behavior in the installed controller adapter.

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

@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
@abretonc7s
abretonc7s requested review from a team as code owners August 17, 2026 10:54
@abretonc7s abretonc7s added the DO-NOT-MERGE Pull requests that should not be merged label Aug 17, 2026
@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/hooks/usePerpsOrderExecution.test.ts 0/115 0/195 0/390

AI-detected flaky patterns

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

  • J10 — jest.spyOn without restoreAllMocks()/mockRestore() afterward (medium)
    • The test 'records a negative toast_position_delta_ms when the position renders before the toast' installs a jest.spyOn(Date, 'now') spy inside a try block. If the finally block does not call nowSpy.mockRestore() (or if there is no finally block), the Date.now mock leaks into subsequent tests. Any test that relies on real wall-clock time from Date.now() will then receive the monotonically-incrementing fake clock value instead, causing non-deterministic failures. The file is large and compressed, so the finally block cannot be confirmed from the visible snippet — but the pattern is a known risk. Adding jest.restoreAllMocks() in an afterEach at the describe level eliminates the risk entirely regardless of whether individual tests clean up.
    • Suggested fix in app/components/UI/Perps/hooks/usePerpsOrderExecution.test.ts:900:
      -it('records a negative toast_position_delta_ms when the position renders before the toast', async () => {
      -  let clock = 1_000_000;
      -  const nowSpy = jest.spyOn(Date, 'now').mockImplementation(() => {
      -    clock += 10;
      -    return clock;
      -  });
      -  try {
      +// Add to the describe('usePerpsOrderExecution') block:
      +afterEach(() => {
      +  jest.restoreAllMocks();
      +});
      +
      +// The individual test can then drop the try/finally restore:
      +it('records a negative toast_position_delta_ms when the position renders before the toast', async () => {
      +  let clock = 1_000_000;
      +  jest.spyOn(Date, 'now').mockImplementation(() => {
      +    clock += 10;
      +    return clock;
      +  });
      +  // ... test body (no try/finally needed — afterEach restores)
      +});

This check is informational only and does not block merging.

Comment thread app/components/UI/Perps/adapters/mobileInfrastructure.test.ts
Comment thread recipes/lighter-lib/recipes/lighter/history.recipe.json Outdated
Comment thread recipes/lighter-lib/recipes/lighter/history.recipe.json Outdated
Comment thread app/components/UI/Perps/hooks/usePerpsOrderForm.ts Outdated
@metamask-ci metamask-ci Bot removed the INVALID-PR-TEMPLATE PR's body doesn't match template label Aug 19, 2026
@abretonc7s
abretonc7s marked this pull request as draft August 19, 2026 02:28
pull Bot pushed a commit to Reality2byte/core that referenced this pull request Aug 31, 2026
…on, flag-gated) (MetaMask#9889)

## Explanation

**TAT-3766: add Lighter as a second perps venue.** Started as a spike,
now a full `LighterProvider` in `@metamask/perps-controller`, hardened
through 23 rounds of adversarial cross-review and validated end-to-end
against live Lighter testnet.

### What's in it

- **Full trading surface** behind the `PerpsProvider` interface:
place/cancel/close orders, venue-linked OCO TP/SL (grouped trigger
orders), isolated margin add/remove, leverage updates, signed L2
withdraw, historical orders/fills/funding/ledger, and live streams
(prices, account, positions, orders, fills, order book, candles) over a
shared WebSocket with REST-polling fallback.
- **Signer model**: deterministic venue-key derivation via
`personal_sign` (raw EVM key never leaves the keyring — hardware-wallet
compatible). The Go/WASM signer is injected through a
`LighterSignerBridge` seam so mobile's WebView bridge and the headless
Node adapter are interchangeable.
- **Financial-safety architecture** (the bulk of the review rounds): a
durable nonce-dispatch ledger with exact tx-hash reconciliation — an
ambiguous dispatch is never blindly retried; proven-committed outcomes
are quarantined until explicitly acknowledged per-outcome
(`getRecoveredDispatches`/`acknowledgeRecoveredDispatch`); a TP/SL
settlement journal that survives crashes and restores nothing it cannot
prove, parking unprovable protection as durable manual recovery
(`getPendingManualRecoveries`); process-wide serialization of venue
writes, the ledger, and the bridge's singleton WASM client; session
fences on every account switch.
- **Controller wiring behind a flag**: `PerpsProviderType` gains
`'lighter'`; enablement via `providerCredentials.lighter.enabled` or the
`perpsLighterProviderEnabled` remote flag. New controller actions expose
the safety states to clients.

### How it was validated

- **Unit**: 213 provider tests (3,031 package-wide), including
deterministic fault-injection proofs for response loss, masked commits,
restarts, account switches mid-flight, concurrent providers, and storage
failures. Every review-round fix was proven RED against the prior commit
before landing.
- **Live testnet e2e** (real venue, real WASM signer built from source):
sign-only 9/9 (pinned WASM identity contract), key registration,
order-lifecycle 7/7, TP/SL 12/12 (including a real venue-linked OCO
pair), close-position 5/5 with both fills observed on the trades stream,
margin/leverage 7/7 on a fresh faucet account.
- **Mainnet read path**: 227 active perp markets, full-catalog WS
snapshot, candles.
- **On-device (iOS simulator)**: live prices/candles/positions over
WS-only transport; WASM signer mount→ready ~2.1 s, round-trip 32–78 ms.

### Open items

- `editOrder` deliberately returns an error: Lighter accepts
`ModifyOrder` submissions without executing the reprice — raised with
the venue; cancel + re-place instead.
- Mobile client integration (WebView signer bridge + recovery-state UI):
MetaMask/metamask-mobile#34865 (draft, consumes this package).

## References

- https://consensyssoftware.atlassian.net/browse/TAT-3766
- Signer reference:
https://github.com/elliottech/lighter-go/tree/web-wasm
- Risk context: https://l2beat.com/scaling/projects/lighter

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [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)
- [x] 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 — not applicable: no breaking changes

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Introduces a new trading venue, client signer bridge, and durable
dispatch/recovery flows for ambiguous L2 submissions—areas that affect
funds, leverage, and order settlement even when feature-gated.
> 
> **Overview**
> Adds **Lighter** as an opt-in perps venue (`PerpsProviderType` now
includes `'lighter'`, a breaking change for exhaustive switches).
Registration mirrors MYX: dynamic import of `LighterProvider`, gated by
`providerCredentials.lighter.enabled` or remote
`perpsLighterProviderEnabled` **only when** the client supplies
`LighterSignerBridge` (venue keys stay client-side; no deposit ads until
bridge deposit flow exists). `PROVIDER_CONFIG.LIGHTER_TESTNET_ONLY` and
cache keys follow the same pattern as MYX.
> 
> Exposes **durable settlement** on the controller and aggregator:
`getPendingManualRecoveries`, `getRecoveredDispatches`, and
`acknowledgeRecoveredDispatch`, with exported
`PerpsPendingManualRecovery` / `PerpsRecoveredDispatch` types.
Aggregated mode fans these out across providers that implement the
contract.
> 
> **Multi-provider routing** for margin math: optional `providerId` on
liquidation/maintenance params and on `getMaxLeverage(asset,
providerId?)`, with `AggregatedPerpsProvider` delegating to the owning
venue instead of always using the default.
> 
> Ships Lighter **constants/types exports** (`lighterConfig`, signer
bridge types) and changelog notes for the initial (disabled-by-default)
implementation.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f8a378e. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@abretonc7s
abretonc7s marked this pull request as ready for review September 1, 2026 03:47

@geositta geositta 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.

Thanks for documenting the POC constraints and adding focused coverage around bridge reset, recovery refresh ordering, leverage limits, and fill transforms. I am requesting changes because the current branch contains correctness and release blockers that need to be resolved before this can move out of its POC state.

Please address the inline comments, rebase onto current main, replace the temporary .yalc dependency with a published controller version, remove the temporary recipes and evidence, and rerun CI. GitHub currently reports merge conflicts, 18 failed checks, 2 pending checks, and the DO-NOT-MERGE label.

Validation performed: yarn lint:tsc passed; focused ESLint completed with no errors and one React Compiler warning; four focused suites passed 60 tests with coverage disabled. A broader focused run reported all six suites as PASS before the process exhausted its 4 GB heap, consistent with the cost of the inlined signer asset. The Hyperliquid behavior was checked against the official fills, PnL, and perpetual metadata documentation.

Comment thread app/components/Views/Root/index.tsx
Comment thread app/components/UI/Perps/utils/transactionTransforms.ts Outdated
Comment thread app/components/UI/Perps/utils/transactionTransforms.ts Outdated
Comment thread app/components/UI/Perps/Lighter/LighterSignerWebView.tsx Outdated
Comment thread app/components/UI/Perps/Lighter/LighterSignerWebView.tsx Outdated
Comment thread app/components/UI/Perps/hooks/usePerpsOrderForm.ts
Comment thread package.json Outdated
abretonc7s added a commit that referenced this pull request Sep 4, 2026
@abretonc7s
abretonc7s force-pushed the TAT-3766-feat-lighter-webview-signer-poc branch from a93b2a4 to 11f64b4 Compare September 4, 2026 05:56
@abretonc7s
abretonc7s requested a review from a team as a code owner September 4, 2026 05:56
@abretonc7s

Copy link
Copy Markdown
Contributor Author

Flaky-test detection triage:

  • Infrastructure VIP selector default: REAL — reset in every test setup in 11f64b4.
  • Order-form DevLogger spy leak: REAL — all spies are restored after each test in 11f64b4.
  • Two connection-manager real-timer races: REAL — replaced with fake timers and explicit disconnect-start gates in 11f64b4.
  • Root route-param reset: already resolved on the rebased HEAD; no additional change was needed.
  • Transaction-transform console-spy cleanup: already resolved on the rebased HEAD; no additional change was needed.

@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.

Stale Bugbot comment from a previous run.

Comment thread app/components/UI/Perps/Lighter/LighterSignerWebView.tsx
Comment thread app/components/UI/Perps/Lighter/LighterSignerWebView.tsx
@github-actions github-actions Bot added the risk:high AI analysis: high risk label Sep 4, 2026

@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.

Stale Bugbot comment from a previous run.

geositta
geositta previously approved these changes Sep 21, 2026

@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.

Stale Bugbot comment from a previous run.

Comment thread app/components/UI/Perps/Lighter/lighterSignerBridge.ts Outdated
geositta
geositta previously approved these changes Sep 21, 2026

@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.

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 64560c6. Configure here.

Comment thread app/components/UI/Perps/Lighter/lighterSignerBridge.ts

@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.

🔒 Agentic Security Review — 1 finding(s).

  • [MEDIUM] app/components/UI/Perps/Lighter/wasm-wrapper.standalone.html:616 — The Lighter signer WebView vendors a ~7.7MB Go/WASM blob copied from Lighter’s live testnet frontend CDN. The revision is not in public lighter-go, provenance.md says it is not a reproducible local build, and CI never asserts the documented WASM digest. That binary is WebAssembly.instantiate’d and then given the SecureKeychain venue private key for orders, cancels, leverage, margin, withdrawals, and auth tokens, including mainnet chain IDs.
    • Impact: This PR newly executes an unreproducible third-party signer with custody of the Lighter venue key. A backdoored copy-time CDN artifact (or a later unpinned blob swap that also updates CSP hashes) can emit attacker-chosen L2 signatures or disclose that key. That is a public-artifact / lockfile-equivalent integrity failure on a signing execution boundary, not a UI-only POC issue. Default store production still omits the lighter fence unless MM_PERPS_LIGHTER_PROVIDER_ENABLED=true or METAMASK_ENVIRONMENT=dev, but those opt-in/dev builds are exactly the path this signer is wired for, and client params allow LIGHTER_MAINNET_CHAIN_ID.
    • Remediation: Do not ship a live testnet Vite asset as the production/mainnet-capable signer. Vendor a signer built from a tagged public revision or a Lighter-signed release, record that digest in CI against decoded wasmBase64 (not markdown-only; CSP self-consistency is not a pin), and keep mainnet chain IDs disabled until that rebuild path exists.

@aganglada aganglada 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.

Main blocker for me is not lazy loading the wasm, we should make it so it's lazy loaded only if the provider is enabled

Bigshmow
Bigshmow previously approved these changes Sep 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeAccounts, SmokeConfirmations, SmokeNetworkAbstractions, SmokeNetworkExpansion, SmokeSwap, SmokeStake, SmokeWalletPlatform, SmokeMoney, SmokePerps, SmokeMultiChainAPI, SmokePredictions, SmokeSeedlessOnboarding, SmokeBrowser, SmokeSnaps, SmokeMMConnect
  • Selected Performance tags: @PerformancePreps
  • Risk Level: high
  • AI Confidence: 100%
click to see 🤖 AI reasoning details

E2E Test Selection:
Hard rule (controller-version-update): @MetaMask controller package version updated in package.json: @metamask/perps-controller. Running all tests.

Performance Test Selection:
The PR introduces significant changes to the Perps feature: a new Lighter WASM signer WebView mounted in Root (adds a hidden WebView to the app's root component tree), new BalanceOrderView screen, provider-aware market resolution logic, and perps-controller version bump (17.1.0 → 17.3.0). The LighterSignerWebView is a persistent hidden WebView that loads a ~10MB WASM binary, which could impact app performance metrics including launch time and memory. The @PerformancePreps tag covers perps market loading, position management, add funds flow, and order execution - all of which are affected by the provider routing changes and new Lighter integration. The @PerformanceLaunch tag could also be relevant due to the new WebView in Root, but since the Lighter feature is gated behind a build-time flag (MM_PERPS_LIGHTER_PROVIDER_ENABLED), it won't affect standard production builds, so @PerformancePreps is the most targeted selection.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Performance Test Results

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

❌ 2 tests failed · 2 tests · 1 device

📱 Devices tested (1)

Android: Google Pixel 8 Pro (v14.0)

❌ Failed Tests (2)

🔬 App profiling vs main is included under each failed scenario that has a prior baseline.

@mm-perps-engineering-team

Perps add funds

Platform Device Reason Recording
Android Google Pixel 8 Pro (v14.0) no_performance_metrics 📹 Watch

🔬 App profiling check · Current run 35845018597 · Baseline (last green on main) run 34935384411 @ 4e14632

Summary: ✅ No metrics over the +10% baseline margin.

ℹ️ API calls unavailable: Network logs API error: Bad Request

Full metric table (+10% variance rules)

Disclaimer — allowed variance: a +10% margin over the baseline is permitted.

  • If Current <= Baseline + 10%, treated as acceptable noise.
  • If Current > Baseline + 10%, Current and variance % are highlighted with ⚠️.
Metric Baseline Current Δ
CPU avg 9.95% 8.29% -1.66 (-16.7%)
CPU max 22.93% 22.06% -0.87 (-3.8%)
Memory avg 702.75 MB 674.27 MB -28.48 (-4%)
Memory max 877.25 MB 819.58 MB -57.67 (-6.6%)
Slow frames 15.97% 11.67% -4.3 (-26.9%)
Frozen frames 0% 0% 0 (0%)
ANRs 0 0 0 (0%)
Issues 2 1 -1 (-50%)
Critical issues 1 1 0 (0%)
App size 394.88 MB 396.73 MB +1.85 (+0.5%)

Perps open position and close it

Platform Device Reason Recording
Android Google Pixel 8 Pro (v14.0) no_performance_metrics 📹 Watch

🔬 App profiling check · Current run 35845018597 · Baseline (last green on main) run 34966774120 @ acda9d8

Summary: ⚠️ 1 metric over +10%: Slow frames (+14.8 (+160.9%))

ℹ️ API calls unavailable: Network logs API error: Bad Request

Full metric table (+10% variance rules)

Disclaimer — allowed variance: a +10% margin over the baseline is permitted.

  • If Current <= Baseline + 10%, treated as acceptable noise.
  • If Current > Baseline + 10%, Current and variance % are highlighted with ⚠️.
Metric Baseline Current Δ
CPU avg 8.17% 8.42% +0.25 (+3.1%)
CPU max 25.69% 23.64% -2.05 (-8%)
Memory avg 826.35 MB 796.19 MB -30.16 (-3.6%)
Memory max 1069.37 MB 989.57 MB -79.8 (-7.5%)
Slow frames 9.2% 24% +14.8 (+160.9%) ⚠️
Frozen frames 0% 0% 0 (0%)
ANRs 0 0 0 (0%)
Issues 2 2 0 (0%)
Critical issues 2 2 0 (0%)
App size 394.9 MB 396.73 MB +1.83 (+0.5%)

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

Comment thread metro.transform.js
}

// Exposed for focused code-fencing tests only.
module.exports.getBuildTypeFeatures = getBuildTypeFeatures;

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.

We will remove code fencing soon, it is already removed on extension

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

Labels

release-8.14.0 Issue or pull request that will be included in release 8.14.0 risk:high AI analysis: high risk size-XL team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants