Commit bbec92d
authored
fix(perps): Incorrect PnL and order size displayed in perp market page after SL execution (#28593)
## **Description**
The Activity page showed incorrect (lower) PnL and size for trades
executed via multiple sub-fills (e.g. a Stop Loss split into 10 partial
fills). The `mergedTransactions` useMemo in `usePerpsTransactionHistory`
aggregated WebSocket fills into `PerpsTransaction` objects before
merging with REST data, allowing the WS partial snapshot to overwrite
the correctly aggregated REST result. The fix merges raw `OrderFill`
objects at the fill level first (same pattern as `usePerpsHomeData`),
then transforms once on the complete set.
## **Changelog**
CHANGELOG entry: Fixed a bug where the Activity page showed incorrect
PnL and order size for trades executed via multiple partial fills (e.g.
Stop Loss).
## **Related issues**
Fixes:
[TAT-2483](https://consensyssoftware.atlassian.net/browse/TAT-2483)
## **Manual testing steps**
```gherkin
Feature: Activity page PnL correctness after multi-fill trade
Scenario: Stop Loss execution with multiple sub-fills shows correct aggregated PnL
Given wallet is unlocked and perps feature is enabled
And a Stop Loss order was executed via multiple partial sub-fills
When user navigates to Activity page → Trades tab
Then the trade row PnL matches the value shown on the market detail page
And no TypeError appears in Metro logs
And no BUG_MARKER fires in Metro logs
```
## **Screenshots/Recordings**
### **Before**
<!-- before.mp4 — Activity page showing incorrect PnL (WS partial
snapshot overwrites REST aggregate) -->
### **After**
<!-- after.mp4 — Activity page showing correct PnL after raw-fill-level
merge -->
## **Pre-merge author checklist**
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
## **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.
## **Validation Recipe**
<details>
<summary>recipe.json — TAT-2483: Activity page shows correct aggregated
PnL after multi-fill trade</summary>
```json
{
"title": "TAT-2483: Activity page shows correct aggregated PnL after multi-fill trade",
"jira": "TAT-2483",
"acceptance_criteria": [
"Activity page Trades tab loads without error",
"Trade transactions are present in the Trades tab",
"No BUG_MARKER fires in metro logs (WS overwrite does not corrupt aggregated data)",
"No TypeError or undefined errors in metro logs during Activity page render"
],
"validate": {
"static": ["yarn lint:tsc"],
"workflow": {
"pre_conditions": ["wallet.unlocked", "perps.feature_enabled"],
"entry": "nav-activity",
"nodes": {
"nav-activity": {
"action": "navigate",
"target": "PerpsActivity",
"params": { "redirectToPerpsTransactions": true },
"next": "wait-render"
},
"wait-render": {
"action": "wait_for",
"route": "PerpsActivity",
"next": "check-no-errors"
},
"check-no-errors": {
"action": "log_watch",
"window_seconds": 5,
"must_not_appear": ["BUG_MARKER", "TypeError", "undefined is not an object"],
"watch_for": ["User fills received"],
"next": "check-state"
},
"check-state": {
"action": "eval_sync",
"expression": "JSON.stringify(Engine.context.PerpsController.state.accountState)",
"assert": { "operator": "not_null" },
"next": "screenshot-activity"
},
"screenshot-activity": {
"action": "screenshot",
"filename": "evidence-activity-trades.png",
"next": "done"
},
"done": {
"action": "end",
"status": "pass"
}
}
}
}
}
```
</details>
[TAT-2483]:
https://consensyssoftware.atlassian.net/browse/TAT-2483?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes the perps activity/trade merging logic to merge raw REST and
WebSocket fills before transforming, which affects user-facing PnL/size
calculations and deduplication across multiple screens.
>
> **Overview**
> Fixes incorrect trade PnL/size for multi-subfill executions (e.g.,
Stop Loss/Take Profit) by **merging REST and WebSocket data at the raw
`OrderFill` level before transforming into `PerpsTransaction`s** in
`usePerpsTransactionHistory`.
>
> Extracts the fill dedupe/merge behavior into a shared
`mergeOrderFills` helper (preserving REST
`detailedOrderType`/`liquidation` when WS lacks it) and reuses it in
`usePerpsHomeData` and `usePerpsMarketFills`. Updates transaction
history tests to exercise the real merge behavior and to assert ordering
and `detailedOrderType` preservation.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6645108. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent c3b271a commit bbec92d
5 files changed
Lines changed: 260 additions & 249 deletions
File tree
- app/components/UI/Perps
- hooks
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
20 | 23 | | |
21 | 24 | | |
22 | 25 | | |
| |||
123 | 126 | | |
124 | 127 | | |
125 | 128 | | |
126 | | - | |
127 | | - | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
160 | 133 | | |
161 | 134 | | |
162 | 135 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
133 | 134 | | |
134 | 135 | | |
135 | 136 | | |
136 | | - | |
137 | | - | |
138 | | - | |
139 | | - | |
140 | | - | |
141 | | - | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | | - | |
148 | | - | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
161 | | - | |
162 | | - | |
163 | | - | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
164 | 145 | | |
165 | 146 | | |
166 | 147 | | |
| |||
0 commit comments