fix(perps): Incorrect PnL and order size displayed in perp market page after SL execution#27906
fix(perps): Incorrect PnL and order size displayed in perp market page after SL execution#27906abretonc7s wants to merge 4 commits intomainfrom
Conversation
…e after SL execution
|
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. |
🔍 Smart E2E Test Selection⏭️ Smart E2E selection skipped - draft PR All E2E tests pre-selected. |
|
Report: TAT-2483 — Incorrect PnL and order size on Perp Market page after SL executionSummaryMulti-fill trades (e.g., stop-loss orders split across multiple price levels) displayed incorrect PnL and order size on the Perp Market screen and Perps Home screen. The deduplication key used to merge REST and WebSocket fills collapsed distinct fills into one, losing data. The Activity page was unaffected because it doesn't use Map-based dedup. Root CauseFile: The dedup key Reproduction CommitSHA: Metro log excerpt (BUG_MARKER detection): Changes
Test PlanAutomated
ManualFeature: Multi-fill trade aggregation
Scenario: SL execution with multiple fills shows correct PnL
Given user has an account with SL trades that executed as multiple fills
When user navigates to the ETH market page trades tab
Then PnL and size match the Activity page values
And PnL and size match the HyperLiquid UI aggregated viewEvidence
Ticket |



Description
Multi-fill trades (e.g., stop-loss orders split across multiple price levels by HyperLiquid) showed incorrect PnL and order size on the Perp Market screen and Perps Home screen. The deduplication key
orderId-timestampused to merge REST and WebSocket fills collapsed distinct fills with the same orderId+timestamp into one entry, losing size/PnL data. Fixed by extending the dedup key toorderId-timestamp-size-price, which preserves all distinct fills while still deduplicating identical entries from both sources. The Activity page was already correct (no Map-based dedup).Changelog
Fixed incorrect PnL and order size for multi-fill trades on the Perp Market screen and Home screen recent activity
Related issues
Fixes: TAT-2483
Manual testing steps
Screenshots/Recordings
Before
See .task/fix/tat-2483-0325-1840/artifacts/before.mp4
After
See .task/fix/tat-2483-0325-1840/artifacts/after.mp4
Validation Recipe
Automated validation recipe (validate-recipe.sh)
{ "pr": "27906", "title": "Verify aggregated PnL and order size consistency across all trade history surfaces", "jira": "TAT-2483", "acceptance_criteria": [ "Perp Market screen displays correct aggregated PnL and order size for multi-fill trades", "Perps Home screen recent activity shows identical aggregated values", "Activity page shows the same aggregated values as the other two surfaces", "Multi-fill trades (same orderId + timestamp) are properly aggregated, not collapsed by dedup" ], "validate": { "static": ["yarn lint:tsc"], "runtime": { "pre_conditions": ["wallet.unlocked", "perps.feature_enabled"], "steps": [ { "id": "check_multi_fills_exist", "description": "Verify account has multi-fill trades (prerequisite for the bug)", "action": "eval_async", "expression": "Engine.context.PerpsController.getActiveProviderOrNull().getOrderFills({aggregateByTime: false}).then(function(fills) { var grouped = {}; fills.forEach(function(f) { var key = f.orderId + '_' + f.timestamp; if (!grouped[key]) grouped[key] = 0; grouped[key] = grouped[key] + 1; }); var multiCount = 0; Object.keys(grouped).forEach(function(k) { if (grouped[k] > 1) multiCount = multiCount + 1; }); return JSON.stringify({totalFills: fills.length, multiFillKeys: multiCount}); })", "assert": { "operator": "gt", "field": "multiFillKeys", "value": 0 } }, { "id": "verify_new_dedup_preserves_fills", "description": "Assert that the fixed dedup key (orderId+timestamp+size+price) preserves all fills - this fails with old key", "action": "eval_async", "expression": "Engine.context.PerpsController.getActiveProviderOrNull().getOrderFills({aggregateByTime: false}).then(function(fills) { var oldKeyMap = {}; var newKeyMap = {}; fills.forEach(function(f) { var oldKey = f.orderId + '_' + f.timestamp; var newKey = f.orderId + '_' + f.timestamp + '_' + f.size + '_' + f.price; oldKeyMap[oldKey] = f; newKeyMap[newKey] = f; }); var oldCount = Object.keys(oldKeyMap).length; var newCount = Object.keys(newKeyMap).length; return JSON.stringify({totalFills: fills.length, oldKeyUnique: oldCount, newKeyUnique: newCount, oldKeyLost: fills.length - oldCount, newKeyLost: fills.length - newCount}); })", "assert": { "operator": "eq", "field": "newKeyLost", "value": 0 } }, { "id": "nav_market_eth", "description": "Navigate to ETH market page (has multi-fill SL trades)", "action": "flow_ref", "ref": "market-discovery", "params": { "symbol": "ETH" } }, { "id": "wait_market_render", "description": "Wait for trades list to render with REST fills", "action": "wait", "ms": 5000 }, { "id": "screenshot_market", "description": "Capture market trades list for visual review", "action": "screenshot", "filename": "market-trades-eth" }, { "id": "nav_activity", "description": "Navigate to activity page trades tab", "action": "flow_ref", "ref": "activity-view", "params": { "tab": "trades" } }, { "id": "wait_activity_render", "description": "Wait for activity data to load", "action": "wait", "ms": 3000 }, { "id": "screenshot_activity", "description": "Capture activity trades for visual comparison", "action": "screenshot", "filename": "activity-trades" } ] } } }Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Changes fill deduplication/merging used to compute displayed trade size and PnL on the Perps Home and Market pages; mistakes could cause missing or duplicated fills in activity lists. Scope is limited to client-side aggregation plus added test coverage.
Overview
Fixes Perps Home (
usePerpsHomeData) and Market (usePerpsMarketFills) fill merging so multi-fill executions (sameorderId+timestamp) are no longer collapsed into a single fill.Deduplication now keys on
orderId-timestamp-size-price, still allowing exact REST/WS duplicates to be overwritten by live data while preserving distinct partial fills; new tests cover multi-fill preservation and exact-duplicate preference.Written by Cursor Bugbot for commit e586bf1. This will update automatically on new commits. Configure here.