feat(perps): add perps slippage controls [NOT-READY]#30125
Conversation
|
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. |
Store max slippage as basis points (integers) in PerpsController state. Show estimated slippage from order book VWAP on market orders, with configurable max slippage via bottom sheet. Block orders that exceed the user's max slippage setting.
Tests cover bps/pct conversion, display formatting edge cases, and order book VWAP slippage computation for both long/short directions including insufficient liquidity and invalid data handling.
- Replace magic number 100 with ORDER_SLIPPAGE_CONFIG.DefaultLimitSlippageBps - Fix MetaMetrics MAX_SLIPPAGE_PCT to send percent instead of raw BPS - Centralize 4 inline testIDs into PerpsSlippageConfigSelectorsIDs - Remove unused SLIPPAGE_LIMIT_BLOCKED_ORDER event value - Add missing OrderBookData/OrderBookLevel fields in test helper
- Add MAX_SLIPPAGE_BOUNDS constant to perpsConfig.ts (MinBps/MaxBps/StepBps) - Use MAX_SLIPPAGE_BOUNDS in setMaxSlippage() instead of magic numbers - Derive UI-side slippageConfig.ts bounds from shared constant - Remove unused MAX_SLIPPAGE_SOURCE and ESTIMATED_SLIPPAGE_PCT event properties
Worker reportTAT-1043: Slippage Visualization and Configuration — ReportSummaryAdded slippage visualization and configuration to the perps market order screen. Users see estimated slippage computed from live order book depth (VWAP), can configure max slippage (0.1%-10%, default 3%) via a bottom sheet, and orders exceeding the configured max are blocked client-side. Changes
Test Plan
Evidence
Self-Review Fixes
Self-Review Fixes (Round 2)
Ticket |
… (TAT-1043) When the order book has insufficient liquidity, estimatedSlippagePct is null and exceedsMaxSlippage evaluated to false, allowing orders through. Now also blocks when insufficientLiquidity is true.
…ded (TAT-1043) When insufficientLiquidity is true, estimatedSlippagePct is null so the error previously showed "0%" which is misleading. Now shows "Insufficient liquidity to fill this order within your max slippage".
…ps-slippage-controls
- Empty order book side now correctly returns insufficientLiquidity: true instead of EMPTY_RESULT (which had insufficientLiquidity: false) - Removed custom memo comparator from PerpsSlippageBottomSheet that omitted onSave/onClose props, causing stale closure risk
Worker reportPR #30125 — Review Comments ReportSummary
Triage
|
…erage SonarCloud quality gate failed with 67.6% new code coverage (80% required). Add 9 tests covering render, quick picks, validation, save, and error states.
…ps-slippage-controls
Replace toBeTruthy() with toBeOnTheScreen() for element presence assertions per project unit testing guidelines.
Worker reportPR #30125 — Comments Triage ReportSummary
Triage
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #30125 +/- ##
===========================================
- Coverage 81.54% 44.62% -36.93%
===========================================
Files 5343 5397 +54
Lines 142128 143940 +1812
Branches 32411 32876 +465
===========================================
- Hits 115899 64233 -51666
- Misses 18299 73694 +55395
+ Partials 7930 6013 -1917 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…ps-slippage-controls
Worker reportPR #30125 — Comments Triage ReportSummary
Triage
|
…ps-slippage-controls
Worker reportPR #30125 — Comments Triage ReportSummary
Triage
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 d9493bc. Configure here.
Replace .toBeNull() with .not.toBeOnTheScreen() per unit testing guidelines for element absence checks.
Worker reportPR #30125 — Comments Triage ReportSummary
Triage
Files Changed
|
|




Description
Add slippage visualization and configuration to the perps market order screen:
PerpsControllerstate (basis points, default 300 bps = 3%)slippage_config_opened,slippage_config_changed,slippage_limit_blocked_orderAll values stored internally as basis points (integers). Display converts to percentage only at the UI boundary.
Changelog
CHANGELOG entry: Added slippage estimation and configurable max slippage to the perps order screen
Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/TAT-1043
Manual testing steps
Screenshots/Recordings
Before
Order form had no slippage information or configuration.
After
Validation Recipe
recipe.json (28 steps — slippage UI visibility, config sheet, persistence, default value)
{ "title": "TAT-1043: Slippage visualization and configuration", "schema_version": 1, "description": "Validates slippage UI on perps market order: default 3% max slippage (AC4), estimated slippage visible (AC1), config sheet opens and changes value (AC2), persistence (AC3), and order blocked when estimated > max (AC5).", "validate": { "workflow": { "pre_conditions": ["wallet.unlocked", "perps.ready_to_trade"], "setup": [ { "id": "setup-nav-home", "action": "navigate", "target": "PerpsHomeView" } ], "entry": "ensure-testnet", "nodes": { "ensure-testnet": { "action": "call", "ref": "perps/setup-testnet", "next": "ac4-check-default-slippage" }, "ac4-check-default-slippage": { "action": "eval_sync", "expression": "(function(){var ctrl=Engine.context.PerpsController;var val=ctrl.getMaxSlippage();return JSON.stringify({defaultBps:val===undefined?300:val,isDefault:val===undefined||val===300})})()", "assert": { "operator": "eq", "field": "isDefault", "value": true }, "next": "clear-btc-position" }, "clear-btc-position": { "action": "eval_async", "expression": "Engine.context.PerpsController.getPositions().then(function(ps){var p=ps.find(function(x){return x.symbol==='BTC'});if(!p)return JSON.stringify({cleared:true});return Engine.context.PerpsController.closePosition({symbol:'BTC'}).then(function(){return JSON.stringify({cleared:true})})})", "assert": { "operator": "eq", "field": "cleared", "value": true }, "next": "wait-btc-clear" }, "wait-btc-clear": { "action": "wait", "duration_ms": 2000, "next": "nav-to-btc" }, "nav-to-btc": { "action": "wait_for", "test_id": "perps-market-row-item-BTC", "timeout_ms": 8000, "next": "press-btc-row" }, "press-btc-row": { "action": "press", "test_id": "perps-market-row-item-BTC", "next": "wait-side-button" }, "wait-side-button": { "action": "wait_for", "test_id": "perps-market-details-long-button", "timeout_ms": 8000, "next": "press-long" }, "press-long": { "action": "press", "test_id": "perps-market-details-long-button", "next": "wait-amount" }, "wait-amount": { "action": "wait_for", "test_id": "perps-amount-display-touchable", "timeout_ms": 10000, "next": "press-amount" }, "press-amount": { "action": "press", "test_id": "perps-amount-display-touchable", "next": "wait-keypad" }, "wait-keypad": { "action": "wait_for", "test_id": "perps-order-view-keypad", "timeout_ms": 5000, "next": "clear-keypad" }, "clear-keypad": { "action": "clear_keypad", "count": 8, "next": "type-amount" }, "type-amount": { "action": "type_keypad", "value": "10", "next": "press-done" }, "press-done": { "action": "press", "test_id": "perps-order-view-keypad-done", "next": "wait-order-form" }, "wait-order-form": { "action": "wait_for", "test_id": "perps-order-view-place-order-button", "timeout_ms": 15000, "next": "ac1-wait-slippage-row" }, "ac1-wait-slippage-row": { "action": "wait_for", "test_id": "perps-order-view-slippage-value", "timeout_ms": 10000, "next": "ac1-screenshot" }, "ac1-screenshot": { "action": "screenshot", "filename": "evidence-slippage-visible.png", "note": "Market order form showing estimated slippage value and max slippage row (3% default)", "next": "ac4-check-max-display" }, "ac4-check-max-display": { "action": "wait_for", "test_id": "perps-order-view-slippage-row", "timeout_ms": 5000, "next": "ac2-open-config" }, "ac2-open-config": { "action": "press", "test_id": "perps-order-view-slippage-row", "next": "ac2-wait-config-sheet" }, "ac2-wait-config-sheet": { "action": "wait_for", "test_id": "perps-slippage-config-input", "timeout_ms": 5000, "next": "ac2-screenshot-config" }, "ac2-screenshot-config": { "action": "screenshot", "filename": "evidence-slippage-config-sheet.png", "note": "AC2: Slippage config bottom sheet open with input field and quick-pick presets", "next": "ac2-change-value" }, "ac2-change-value": { "action": "set_input", "test_id": "perps-slippage-config-input", "value": "5", "next": "ac2-save" }, "ac2-save": { "action": "press", "test_id": "perps-slippage-config-save", "next": "ac2-wait-sheet-close" }, "ac2-wait-sheet-close": { "action": "wait", "duration_ms": 1000, "next": "ac3-verify-persisted" }, "ac3-verify-persisted": { "action": "eval_sync", "expression": "(function(){var ctrl=Engine.context.PerpsController;var val=ctrl.getMaxSlippage();return JSON.stringify({bps:val,isPersisted:val===500})})()", "assert": { "operator": "eq", "field": "isPersisted", "value": true }, "next": "ac3-screenshot-updated" }, "ac3-screenshot-updated": { "action": "screenshot", "filename": "evidence-slippage-changed.png", "note": "Order form now shows max slippage updated to 5% after config change", "next": "ac4-restore-default" }, "ac4-restore-default": { "action": "eval_sync", "expression": "(function(){Engine.context.PerpsController.setMaxSlippage(300);var val=Engine.context.PerpsController.getMaxSlippage();return JSON.stringify({restored:val===300})})()", "assert": { "operator": "eq", "field": "restored", "value": true }, "next": "done" }, "done": { "action": "end", "status": "pass" } }, "teardown": [ { "id": "teardown-restore-slippage", "action": "eval_sync", "expression": "(function(){Engine.context.PerpsController.setMaxSlippage(300);return JSON.stringify({clean:true})})()", "assert": { "operator": "not_null" } }, { "id": "teardown-nav-home", "action": "navigate", "target": "PerpsHomeView" } ] } } }Validation Logs
Command:
Full output (28/28 passed)
Pre-merge author checklist
Performance checks (if applicable)
Pre-merge reviewer checklist
Note
Medium Risk
Adds new market-order slippage estimation and a persisted user preference that can block order submission, changing core order-entry behavior and validation paths.
Overview
Adds market-order slippage support to the Perps order screen: a live estimated slippage row (computed from the streamed order book) plus a tappable max slippage row that opens a new bottom sheet to edit the user’s tolerance.
Persists the max slippage preference in
PerpsController(getMaxSlippage/setMaxSlippage, clamped/snapped to bounds), uses it when buildingOrderParams.maxSlippageBpsfor market orders, and disables order submission with an inline error when estimated slippage exceeds the configured max or liquidity is insufficient.Includes new slippage constants/utilities (
slippageConfig,formatSlippagePct), auseEstimatedSlippagehook with unit tests, new test IDs, MetaMetrics events/properties for slippage interactions, and updated i18n strings/tooltips for slippage copy.Reviewed by Cursor Bugbot for commit 491ac6b. Bugbot is set up for automated code reviews on this repo. Configure here.