Skip to content

feat(perps): add environment_type to controller-emitted perps events on extension (split from TAT-3175) - #10899

Merged
abretonc7s merged 6 commits into
mainfrom
TAT-4006-feat-add-environment-type-perps-eve
Oct 22, 2026
Merged

abretonc7s merged 6 commits into
mainfrom
TAT-4006-feat-add-environment-type-perps-eve

Conversation

@abretonc7s

@abretonc7s abretonc7s commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Explanation

Controller perps events did not record which screen started the action. PERPS_EVENT_PROPERTY.ENVIRONMENT_TYPE already maps to environment_type, and no caller copied a value onto it.

TrackingData, TPSLTrackingData, and WithdrawParams now accept an optional environmentType string. Trade, close, cancel, order, flip, and TP/SL events that already copy attribution include environment_type when the string is set. An order edit includes only environment_type from newOrder.trackingData. It does not copy entry_point, discovery_source, perp_discovery_source, or hl_fee_rate. The withdrawal executed event and both withdrawal failed events include environment_type the same way. When the field is absent, those events stay unchanged.

The controller emits no deposit event, so deposit params are unchanged and the deposit clause of TAT-4006 is deferred.

The value is not stored on withdrawal requests, and it is not sent to the venue. Later withdrawal completion events still omit it, because they no longer have the original params.

Extension still has to pass getEnvironmentType() from buildTrackingData, buildTpslTrackingData, and the withdraw call site. That is not enough on its own. createMetrics().trackPerpsEvent in app/scripts/controllers/perps/infrastructure.ts calls trackEvent without options, and buildTrackEventPayload in app/scripts/controllers/analytics/analytics.ts spreads the properties, then sets environment_type to options.environmentType, which defaults to background. trackPerpsEvent must pass properties.environment_type as the environmentType option, or the Core value is overwritten. Deposit call sites have nothing to pass until a registered deposit event exists. That client work follows this package release.

A client recipe builds PerpsController with a real messenger. It calls placeOrder, updatePositionTPSL, and withdraw with environmentType set to sidepanel, then again without the field. The messenger captures AnalyticsController:trackEvent. The sidepanel calls emit environment_type=sidepanel. The calls without the field omit the key. depositWithConfirmation emits no controller analytics event. Unit tests still cover order edits.

References

Validation Recipe

recipe.json (16 nodes — Perps environment_type through PerpsController)
{
  "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
  "title": "Perps environment_type through PerpsController",
  "description": "Drives PerpsController the way Extension does. A real Messenger receives AnalyticsController:trackEvent. placeOrder, updatePositionTPSL, and withdraw run with environmentType sidepanel, then again without it. The HyperLiquid SDK is replaced at the network boundary. depositWithConfirmation is a guard: the controller emits no deposit analytics event, so the field has nothing to attach to.",
  "proofTargets": [
    {
      "id": "AC-1",
      "kind": "acceptance",
      "proofMode": "state",
      "claim": "Core (`@metamask/perps-controller`): accept an optional `environmentType` in `TrackingData` / `TPSLTrackingData` and in the withdraw/deposit params. Emit it as `PERPS_EVENT_PROPERTY.ENVIRONMENT_TYPE` (the key already exists)."
    },
    {
      "id": "AC-2",
      "kind": "acceptance",
      "proofMode": "state",
      "claim": "When `environmentType` is absent, event properties are unchanged; unit tests cover `environmentType` present and absent on trade, TP/SL, withdraw and deposit events."
    }
  ],
  "workflow": {
    "entry": "build-controller",
    "nodes": {
      "build-controller": {
        "action": "command",
        "intent": "Compile @metamask/perps-controller so the client import matches this checkout",
        "cmd": "yarn workspace @metamask/perps-controller run build",
        "timeout_ms": 300000,
        "next": "run-trade-present"
      },
      "run-trade-present": {
        "action": "command",
        "intent": "placeOrder with trackingData.environmentType sidepanel",
        "timeout_ms": 120000,
        "allow_failure": true,
        "next": "assert-trade-present"
      },
      "assert-trade-present": {
        "action": "assert_output",
        "intent": "The trade event includes environment_type sidepanel",
        "source": "run-trade-present",
        "stream": "stdout",
        "contains": "PROOF trade present event=\"Perp Trade Transaction\" environment_type=sidepanel",
        "proves": [
          "AC-1",
          "AC-2"
        ],
        "next": "run-trade-absent"
      },
      "run-trade-absent": {
        "action": "command",
        "intent": "placeOrder with no environmentType",
        "timeout_ms": 120000,
        "next": "assert-trade-absent"
      },
      "assert-trade-absent": {
        "action": "assert_output",
        "intent": "The trade event omits environment_type",
        "source": "run-trade-absent",
        "stream": "stdout",
        "contains": "PROOF trade absent event=\"Perp Trade Transaction\" environment_type_absent",
        "proves": [
          "AC-2"
        ],
        "next": "run-tpsl-present"
      },
      "run-tpsl-present": {
        "action": "command",
        "intent": "updatePositionTPSL with trackingData.environmentType sidepanel",
        "timeout_ms": 120000,
        "allow_failure": true,
        "next": "assert-tpsl-present"
      },
      "assert-tpsl-present": {
        "action": "assert_output",
        "intent": "The TP/SL event includes environment_type sidepanel",
        "source": "run-tpsl-present",
        "stream": "stdout",
        "contains": "PROOF tpsl present event=\"Perp Risk Management\" environment_type=sidepanel",
        "proves": [
          "AC-1",
          "AC-2"
        ],
        "next": "run-tpsl-absent"
      },
      "run-tpsl-absent": {
        "action": "command",
        "intent": "updatePositionTPSL with no environmentType",
        "timeout_ms": 120000,
        "next": "assert-tpsl-absent"
      },
      "assert-tpsl-absent": {
        "action": "assert_output",
        "intent": "The TP/SL event omits environment_type",
        "source": "run-tpsl-absent",
        "stream": "stdout",
        "contains": "PROOF tpsl absent event=\"Perp Risk Management\" environment_type_absent",
        "proves": [
          "AC-2"
        ],
        "next": "run-withdraw-present"
      },
      "run-withdraw-present": {
        "action": "command",
        "intent": "withdraw with environmentType sidepanel",
        "timeout_ms": 120000,
        "allow_failure": true,
        "next": "assert-withdraw-present"
      },
      "assert-withdraw-present": {
        "action": "assert_output",
        "intent": "The withdrawal event includes environment_type sidepanel",
        "source": "run-withdraw-present",
        "stream": "stdout",
        "contains": "PROOF withdraw present event=\"Perp Withdrawal Transaction\" environment_type=sidepanel",
        "proves": [
          "AC-1",
          "AC-2"
        ],
        "next": "run-withdraw-absent"
      },
      "run-withdraw-absent": {
        "action": "command",
        "intent": "withdraw with no environmentType",
        "timeout_ms": 120000,
        "next": "assert-withdraw-absent"
      },
      "assert-withdraw-absent": {
        "action": "assert_output",
        "intent": "The withdrawal event omits environment_type",
        "source": "run-withdraw-absent",
        "stream": "stdout",
        "contains": "PROOF withdraw absent event=\"Perp Withdrawal Transaction\" environment_type_absent",
        "proves": [
          "AC-2"
        ],
        "next": "run-deposit-none"
      },
      "run-deposit-none": {
        "action": "command",
        "intent": "depositWithConfirmation emits no controller analytics event",
        "timeout_ms": 120000,
        "next": "assert-deposit-none"
      },
      "assert-deposit-none": {
        "action": "assert_output",
        "intent": "Deposit has no controller analytics event to carry environment_type",
        "source": "run-deposit-none",
        "stream": "stdout",
        "contains": "PROOF deposit none analytics_events=0",
        "next": "done"
      },
      "done": {
        "action": "end",
        "status": "pass"
      }
    }
  }
}

Validation Logs

Run: f55b84c3-a90f-4b8d-948e-3dc70f183593

Runner: @metamask/recipe-runner

Runner revision: unknown

Recipe digest: sha256:8fd47e936c57d84ed2da64dca6e1be55c83e94d4ec8b2f4cf3e0444aa405ba56

Full output (16/16 passed, pass)
# MetaMask Recipe Run

Status: pass
Duration: 22s
Nodes: 16/16 passed

## Steps
- PASS build-controller (command, 3.4s): exitCode=0
- PASS run-trade-present (command, 2.1s): exitCode=0, stdout=PROOF trade present event="Perp Trade Transaction" environment_type=sidepanel

- PASS assert-trade-present (assert_output, 147ms): source=run-trade-present, stream=stdout, contains=PROOF trade present event="Perp Trade Transaction" environment_type=sidepanel
- PASS run-trade-absent (command, 2.6s): exitCode=0, stdout=PROOF trade absent event="Perp Trade Transaction" environment_type_absent

- PASS assert-trade-absent (assert_output, 156ms): source=run-trade-absent, stream=stdout, contains=PROOF trade absent event="Perp Trade Transaction" environment_type_absent
- PASS run-tpsl-present (command, 2.5s): exitCode=0, stdout=PROOF tpsl present event="Perp Risk Management" environment_type=sidepanel

- PASS assert-tpsl-present (assert_output, 289ms): source=run-tpsl-present, stream=stdout, contains=PROOF tpsl present event="Perp Risk Management" environment_type=sidepanel
- PASS run-tpsl-absent (command, 3.4s): exitCode=0, stdout=PROOF tpsl absent event="Perp Risk Management" environment_type_absent

- PASS assert-tpsl-absent (assert_output, 88ms): source=run-tpsl-absent, stream=stdout, contains=PROOF tpsl absent event="Perp Risk Management" environment_type_absent
- PASS run-withdraw-present (command, 1.6s): exitCode=0, stdout=PROOF withdraw present event="Perp Withdrawal Transaction" environment_type=sidepanel

- PASS assert-withdraw-present (assert_output, 176ms): source=run-withdraw-present, stream=stdout, contains=PROOF withdraw present event="Perp Withdrawal Transaction" environment_type=sidepanel
- PASS run-withdraw-absent (command, 1.8s): exitCode=0, stdout=PROOF withdraw absent event="Perp Withdrawal Transaction" environment_type_absent

- PASS assert-withdraw-absent (assert_output, 113ms): source=run-withdraw-absent, stream=stdout, contains=PROOF withdraw absent event="Perp Withdrawal Transaction" environment_type_absent
- PASS run-deposit-none (command, 1.7s): exitCode=0, stdout=PROOF deposit none analytics_events=0

- PASS assert-deposit-none (assert_output, 147ms): source=run-deposit-none, stream=stdout, contains=PROOF deposit none analytics_events=0
- PASS done (end, 0ms)

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Publication approval

Arthur · person · arthur · 2026-10-20T07:54:16.756Z
Package: 4f15b6a70f50d82a11d9a97ff1fb1438c92d52e3201c259f59dde77012781528. Visual receipts: none.

Accepted review findings

Accepted by Arthur (arthur) at 2026-10-20T07:54:16.756Z.
Head: ec2db26d96db4155d25123b57288d67d721d9108. Findings digest: sha256:5795a70a7ce39001832b15612a6eecc12ebc28451c1768adc0d5b40e8ab1c8f7.

Reason:

Deposit descoped: the controller emits no deposit analytics event. AC-1/AC-2 proven for trade, TP/SL and withdraw.

Accepted findings:

  • temp/tasks/feat/tat-4006-1019-171024/artifacts/acceptance-status.json:10: Owner gate decision. No code change is requested. AC-1 and AC-2 are marked proven (lines 10 and 32), and recipe-coverage.md:5-8 reports 2/2 PROVEN with untestable: none. Both criteria name deposit. DepositParams (packages/perps-controller/src/types/index.ts:1294) and DepositWithConfirmationParams (:1303) take no environmentType, and no deposit present/absent test exists. Leaving deposit out of the code is correct, because PerpsAnalyticsEvent has no deposit event. recipe-quality.json (warn, deposit-clause-unproven) states the gap. The mm-harness validator refused a separate deposit claim. The owner must descope the deposit clause, mark it untestable with a reason, or amend TAT-4006 at the gate before AC-1 and AC-2 count as met. The round-7 mechanical findings are cleared: the CHANGELOG line is committed in ec2db26, and the evidence-manifest summary cites run 20261019141414956-15828. The changelog PR-link placeholder is pending a PR number. (review review-7721a02b-ceda-431a-a741-d743837c40b4-844d8a6e-246c-4c1b-a818-d9578c3b5588)

Note

Low Risk
Analytics-only optional fields and property spreading; no trading, withdrawal routing, or persistence behavior changes.

Overview
Adds optional environmentType on TrackingData, TPSLTrackingData, and WithdrawParams so clients can tag which UI surface started a perps action.

A shared environmentTypeProperty helper maps that value to the existing environment_type analytics key and is omitted when unset. Trading flows that already spread attribution (trade, close, cancel, flip, TP/SL, etc.) now include environment_type when provided; order edit events only add environment_type from newOrder.trackingData, not other attribution fields. withdraw() adds it on executed and failed withdrawal events; later withdrawal status/completion paths are unchanged.

Unit tests cover present vs absent environment_type for place order, edit order, TP/SL, and withdraw.

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

@abretonc7s abretonc7s changed the title chore: prepare farmslot publication pkg-7721a02b-mvg95of6 feat(perps): add environment_type to controller-emitted perps events on extension (split from TAT-3175) Oct 20, 2026
@abretonc7s
abretonc7s marked this pull request as ready for review October 20, 2026 09:04
@abretonc7s
abretonc7s requested review from a team as code owners October 20, 2026 09:04
Accept an optional environmentType string on TrackingData, TPSLTrackingData, and WithdrawParams. Copy it to environment_type on trade, close, cancel, order, flip, and TP/SL events, on an order edit, and on the withdrawal executed event and both withdrawal failed events. Omit the key when the field is absent.

Deposit params are unchanged. The controller emits no deposit event, so the deposit clause of TAT-4006 is deferred.
Add the changelog PR-link placeholder. No pull request number exists yet.
@abretonc7s
abretonc7s force-pushed the TAT-4006-feat-add-environment-type-perps-eve branch from ec2db26 to debda2c Compare October 20, 2026 09:51
@abretonc7s
abretonc7s enabled auto-merge October 20, 2026 12:03
@abretonc7s
abretonc7s added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 1b0726b Oct 22, 2026
48 checks passed
@abretonc7s
abretonc7s deleted the TAT-4006-feat-add-environment-type-perps-eve branch October 22, 2026 15:06
This was referenced Oct 23, 2026
SnowingFox pushed a commit to SnowingFox/core-1 that referenced this pull request Oct 24, 2026
## Explanation

Major release of `@metamask/perps-controller` (`21.0.0` → `22.0.0`).

- **Breaking:** testnet deposit and withdrawal routes use Arbitrum
Sepolia USDC2 (`0x1baAbB04529D43a73232B713C0FE471f7c7334d5`).
`USDC_ARBITRUM_TESTNET_ADDRESS` and
`HYPERLIQUID_ASSET_CONFIGS.usdc.testnet` change to that address, and
`withdraw` rejects the previous testnet asset ID.
`depositWithConfirmation` prepares an Arbitrum Sepolia transfer to the
Hyperliquid testnet bridge.
([MetaMask#10991](MetaMask#10991))
- `TrackingData`, `TPSLTrackingData`, and `WithdrawParams` accept an
optional `environmentType`. Events that already copy attribution include
`environment_type` when it is set.
([MetaMask#10899](MetaMask#10899))
- New export `@metamask/perps-controller/providers/lighter`, plus
optional `LighterCredentials.loadProvider`, so a web client can bundle
Lighter itself. `switchProvider('lighter')` reports why the provider
failed to load. A missing Lighter module is debug-logged instead of sent
through `logger.error`.
([MetaMask#10996](MetaMask#10996))
- The `closePositions` summary event includes `order_type: 'market'`.
([MetaMask#11027](MetaMask#11027))
- Engines allow Node.js 26.
([MetaMask#10981](MetaMask#10981))

## References

- [MetaMask#10991](MetaMask#10991)
- [MetaMask#10899](MetaMask#10899)
- [MetaMask#10996](MetaMask#10996)
- [MetaMask#11027](MetaMask#11027)
- [MetaMask#10981](MetaMask#10981)

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] 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)
- [ ] 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

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Major perps-controller release with breaking testnet token/bridge
behavior; this PR only bumps versions but consumers picking up 22.0.0
inherit that risk.
> 
> **Overview**
> **Monorepo release 1359.0.0** that publishes
**`@metamask/perps-controller` 22.0.0** and bumps
**`@metamask/transaction-pay-middleware`** to depend on `^22.0.0` (plus
`yarn.lock` and root package version).
> 
> The diff is mostly versioning and changelog housekeeping; the shipped
**22.0.0** behavior (already merged) includes a **breaking testnet USDC2
/ Arbitrum Sepolia deposit path** change, optional **`environmentType`**
on perps tracking/withdraw params, **Lighter** `loadProvider` + public
provider export, **`closePositions`** analytics `order_type: 'market'`,
and **Node.js 26** engine support.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
8356d7d. 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

2 participants