Skip to content

feat: Perps UI#40076

Merged
gambinish merged 60 commits intomainfrom
perps/poc-controller-integration-minimal
Feb 17, 2026
Merged

feat: Perps UI#40076
gambinish merged 60 commits intomainfrom
perps/poc-controller-integration-minimal

Conversation

@gambinish
Copy link
Member

@gambinish gambinish commented Feb 13, 2026

Description

This PR implements a mock provider infrastructure for the Perps feature to enable UI development and integration without depending on the preview @metamask/perps-controller package. This allows us to merge Perps UI components into the main branch while keeping the actual controller integration isolated in an upstream branch.

The upstream branch #40078 is rebased to this one so that the controller integration can be isolated to it's individual branch independent of UI.

Background

The Perps feature requires integration with @metamask/perps-controller, which is currently a preview package that cannot be merged into the main branch. To unblock UI development and allow incremental merges, we need a way to develop and test Perps UI components without the actual controller dependency.

Approach

This PR introduces a mock provider pattern that mirrors the real controller/provider API but returns static
mock data. This approach provides several benefits:

  1. Unblocks UI Development: Teams can build and test Perps UI components without waiting for controller
    stabilization
  2. Incremental Merging: UI components can be merged to main while controller integration stays in a feature
    branch
  3. Zero Runtime Impact: Mock providers are structured to be drop-in replacements - switching to real providers
    later requires no UI code changes, only alias update.
  4. Development Velocity: Developers can work on UI/UX independently of backend integration

Changes Made

1. Mock Infrastructure Pattern

Established a consistent mocking pattern across the codebase:

ui/{hooks,providers}/perps/[module]/
├── index.ts (re-exports from index.mock.ts)
└── index.mock.ts (mock implementation)

This pattern ensures:

  • Import paths remain unchanged when switching from mock to real implementation

  • Clear separation between mock and real code

  • Easy to identify and remove mocks when ready (or to alternatively keep them for unit/e2e integration)

Migration Path

Imports of @metamask/perps-controller are currently aliased to the mock implementation. Once the production package is publishhed, we can remove this alias in the upstream branch and do the following:

  1. Update imports in ui/providers/perps/index.ts from ./index.mock to real implementations
  2. Update imports in ui/hooks/perps/stream/index.ts from ./index.mock to real implementations
  3. Update imports in ui/providers/perps/PerpsStreamManager/index.ts from ./index.mock to real implementation
  4. Remove .mock.ts files
  5. No changes needed to UI components - all imports remain the same

Alternatively, these files can be kept and altered for a robust unit test and e2e suite.

Testing

Manual Testing

The Perps UI should work with mock data:

  • ✅ Tokens tab → Perps tab navigation works
  • ✅ Perps tab shows mock positions and orders
  • ✅ Activity tab loads without errors (empty transaction history)
  • ✅ Market detail pages load with mock data
  • ✅ No console errors related to missing controller methods

What Won't Work (Expected)

Since these are mocks returning static/empty data:

  • Real-time price updates (returns static mock prices)
  • Order placement (logs to console, no real transaction)
  • Transaction history (returns empty arrays)
  • Position management (simulated with delays)

Benefits

  1. UI Development Unblocked: Teams can now develop Perps UI components in parallel with controller development
  2. Incremental Delivery: Perps UI can be merged to main behind feature flags while controller stays in feature
    branch
  3. Import Stability: When switching to real implementation, minimal code needs to change.
  4. Clear Boundaries: Mock code is clearly identified and isolated in .mock.ts files

Related PRs

  • Upstream branch with real controller integration: perps/poc-controller-integration-minimal

Changelog

CHANGELOG entry: Adds initial Perps UI

Related issues

Fixes:

Manual testing steps

  1. Go to this page...

Screenshots/Recordings

Before

After

Pre-merge author checklist

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.

Note

Medium Risk
Moderate risk due to new build/test module aliasing for @metamask/perps-controller and a large mock surface area that can mask integration issues when swapped for the real controller.

Overview
Introduces a local mock implementation of @metamask/perps-controller under ui/__mocks__/perps/perps-controller, and wires it in via webpack alias, Jest moduleNameMapper, and TypeScript paths to unblock Perps UI development without the real package; depcheck is updated to ignore the dependency.

Expands the Perps UI surface: adds an EditMarginExpandable component (with unit tests) that calls updateMargin, refreshes positions via the stream manager, and shows liquidation/risk info computed by usePerpsMarginCalculations/marginUtils. Order cards are updated to display Long/Short labeling, computed USD order value formatting, and click handling expectations; Perps constants gain HIP-3 market typing/mappings and chart config renames ChartDuration to TimeDuration.

Updates i18n strings (adds new perps copy/tooltips and refactors sort/filter keys) and adjusts mock perps data structures/types to align with the controller-style types used by the new UI.

Written by Cursor Bugbot for commit f551d27. This will update automatically on new commits. Configure here.

@github-actions
Copy link
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.

@metamaskbot metamaskbot added the team-perps Perps team label Feb 13, 2026
@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 13, 2026

✨ Files requiring CODEOWNER review ✨

👨‍🔧 @MetaMask/perps (8 files, +3178 -62)
  • 📁 ui/
    • 📁 __mocks__/
      • 📁 perps/
        • 📁 perps-controller/
          • 📄 index.ts +2133 -0
    • 📁 components/
      • 📁 app/
        • 📁 perps/
          • 📁 constants/
            • 📄 chartConfig.ts +29 -26
          • 📁 edit-margin/
            • 📄 edit-margin-expandable.test.tsx +237 -0
            • 📄 edit-margin-expandable.tsx +477 -0
            • 📄 index.ts +2 -0
            • 📄 constants.ts +124 -0
            • 📄 index.ts +19 -36
            • 📄 MOCKS_README.md +157 -0

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 13, 2026

Builds ready [35e5639]
UI Startup Metrics (1400 ± 107 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup14001209181210714471574
load1201103315959512421360
domContentLoaded1194101515829512351351
domInteractive2717102192479
firstPaint2116712882632161046
backgroundConnect25623534318263287
firstReactRender209164202028
initialActions105113
loadScripts9537741324949981118
setupStore1363651722
numNetworkReqs231586201582
BrowserifyPower User HomeuiStartup18371497317922618742251
load12401086228419012151707
domContentLoaded12261079227518712061678
domInteractive4120242363995
firstPaint19581662101254358
backgroundConnect34730744222359383
firstReactRender23174972439
initialActions104111
loadScripts95482119771839211419
setupStore1684471729
numNetworkReqs1054425846132181
WebpackStandard HomeuiStartup86870613211249611118
load7566321240115818956
domContentLoaded7506281233114813948
domInteractive281795182484
firstPaint1216439957151217
backgroundConnect26196373041
firstReactRender15113541821
initialActions104112
loadScripts7476261231114811945
setupStore1273351222
numNetworkReqs231593211584
WebpackPower User HomeuiStartup1245926232319013391537
load72361714981307101038
domContentLoaded71461114851307011030
domInteractive39192063336118
firstPaint1446753786158322
backgroundConnect17113038153180296
firstReactRender23175552429
initialActions102111
loadScripts71160914741286991021
setupStore1344271430
numNetworkReqs1054427951137181
FirefoxBrowserifyStandard HomeuiStartup15471334255020015581981
load13351143227316013521636
domContentLoaded13341138227216113511635
domInteractive69323094791141
firstPaint------
backgroundConnect5526241275496
firstReactRender1292211213
initialActions102012
loadScripts13101126223815613291612
setupStore166222271235
numNetworkReqs241294221688
BrowserifyPower User HomeuiStartup27612116380834228903496
load15721309229221116362054
domContentLoaded15721309229121116352053
domInteractive11436676107114352
firstPaint------
backgroundConnect329111980264423929
firstReactRender19148181923
initialActions206122
loadScripts15211273226619415761960
setupStore1448730193159618
numNetworkReqs64331333183127
WebpackStandard HomeuiStartup15661348213313716341784
load13541135184211614171536
domContentLoaded13531135184111614161536
domInteractive70292044194133
firstPaint------
backgroundConnect5025149225590
firstReactRender14115451423
initialActions102122
loadScripts13311121180411113941505
setupStore146162201237
numNetworkReqs231298191877
WebpackPower User HomeuiStartup26951971375440727943568
load15361226237628016792214
domContentLoaded15361226237528016792214
domInteractive11028829120107258
firstPaint------
backgroundConnect284118931222283881
firstReactRender20156462329
initialActions203122
loadScripts14981212232226216432169
setupStore1697802230227723
numNetworkReqs63341353184125
📊 Page Load Benchmark Results

Current Commit: 35e5639 | Date: 2/13/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±38ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 725ms (±36ms) 🟢 | historical mean value: 739ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 82ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 38ms 1.01s 1.32s 1.04s 1.32s
domContentLoaded 725ms 36ms 705ms 995ms 732ms 995ms
firstPaint 77ms 11ms 64ms 176ms 84ms 176ms
firstContentfulPaint 77ms 11ms 64ms 176ms 84ms 176ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 32.83 KiB (0.41%)
  • common: 20 Bytes (0%)

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 13, 2026

Builds ready [3c428d4]
UI Startup Metrics (1427 ± 102 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup14271243186910214691605
load1234102816169612731367
domContentLoaded1227102515829412681357
domInteractive2917133202580
firstPaint191721288171228328
backgroundConnect26524035017270293
firstReactRender1810161151927
initialActions106113
loadScripts97878813259610231115
setupStore1465981728
numNetworkReqs221584191578
BrowserifyPower User HomeuiStartup18211469257617518722186
load12341100209619512021754
domContentLoaded12151091201217811921722
domInteractive42202113637136
firstPaint215772023261250437
backgroundConnect34831041323362392
firstReactRender23164952430
initialActions108111
loadScripts94683017341739091438
setupStore1675471731
numNetworkReqs1114625146137193
WebpackStandard HomeuiStartup86270612431049281053
load73963198592798912
domContentLoaded73462697992793906
domInteractive2917102202578
firstPaint1196426453154229
backgroundConnect2918151143245
firstReactRender16114151926
initialActions104112
loadScripts73162497791791896
setupStore1363961325
numNetworkReqs231588201582
WebpackPower User HomeuiStartup1267906182017313421545
load72263712061267101061
domContentLoaded71363011981266981051
domInteractive39181933535133
firstPaint1446555790171283
backgroundConnect16613136046173276
firstReactRender23173532428
initialActions102011
loadScripts71062811871236961039
setupStore1345061419
numNetworkReqs1184427352143258
FirefoxBrowserifyStandard HomeuiStartup16331425220114416501984
load14091221175910514391652
domContentLoaded14081221175910514391651
domInteractive893430651118168
firstPaint------
backgroundConnect5829156206090
firstReactRender13112731317
initialActions103122
loadScripts13811196172110214141618
setupStore166192231346
numNetworkReqs241390201781
BrowserifyPower User HomeuiStartup26201959410238327473379
load15431219229126016252105
domContentLoaded15431219229126016242105
domInteractive12637790136113400
firstPaint------
backgroundConnect214109867168192786
firstReactRender18146181726
initialActions203122
loadScripts15041197226224715712058
setupStore117768817499543
numNetworkReqs65351492985121
WebpackStandard HomeuiStartup16471361206414017181918
load14181186169311214911625
domContentLoaded14181186169111214911625
domInteractive903023349132167
firstPaint------
backgroundConnect56241512859130
firstReactRender15126461521
initialActions103112
loadScripts13931172166510614661546
setupStore186170271251
numNetworkReqs2313100191774
WebpackPower User HomeuiStartup26672022361339927873458
load15631266230127616932194
domContentLoaded15621265230127616932194
domInteractive13336926163110508
firstPaint------
backgroundConnect2561071171195261722
firstReactRender21157172228
initialActions208122
loadScripts15161244227524616302104
setupStore15891080230159652
numNetworkReqs64341623499127
📊 Page Load Benchmark Results

Current Commit: 3c428d4 | Date: 2/13/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±41ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 738ms (±39ms) 🟢 | historical mean value: 739ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 82ms (±11ms) 🟢 | historical mean value: 82ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 41ms 1.02s 1.36s 1.06s 1.36s
domContentLoaded 738ms 39ms 715ms 1.04s 747ms 1.04s
firstPaint 82ms 11ms 64ms 176ms 88ms 176ms
firstContentfulPaint 82ms 11ms 64ms 176ms 88ms 176ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 63.68 KiB (0.79%)
  • common: 20 Bytes (0%)

Copy link
Contributor

@geositta geositta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few bugs I noticed that might help with linting.


// Preset percentage options for quick selection
const TP_PRESETS = [10, 25, 50, 100];
const SL_PRESETS = [10, 25, 50, 75];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Short TP preset can produce zero price

Medium Severity

TP_PRESETS includes 100, but percentToPrice computes short take-profit as entryPrice * (1 - percent/100). For short positions, the +100% preset produces 0.00, creating an invalid TP price and incorrect auto-close behavior.

Additional Locations (1)

Fix in Cursor Fix in Web

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 14, 2026

Builds ready [263fbbb]
UI Startup Metrics (1443 ± 112 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup14431226186311215051634
load12381025156110112981409
domContentLoaded12321019154210012901403
domInteractive2917110192581
firstPaint173691348178212264
backgroundConnect25823632816262286
firstReactRender17116761823
initialActions103112
loadScripts990784129310010541154
setupStore1364051522
numNetworkReqs231587201584
BrowserifyPower User HomeuiStartup17591393231716618172150
load11871075180616811571672
domContentLoaded11711057176516311431654
domInteractive38202033135114
firstPaint192771704169237302
backgroundConnect33730341822349369
firstReactRender23155972440
initialActions103111
loadScripts91380115161638861401
setupStore1775181833
numNetworkReqs1064825446134187
WebpackStandard HomeuiStartup86771512651159661055
load7536281110106807940
domContentLoaded7486241102105803933
domInteractive2816130212483
firstPaint1126534454119224
backgroundConnect26185173038
firstReactRender15103451825
initialActions103112
loadScripts7456221092105801931
setupStore1272031318
numNetworkReqs231592201582
WebpackPower User HomeuiStartup1236907203818413341556
load72863713081247171060
domContentLoaded71962912841237041052
domInteractive38182003336106
firstPaint156691103136169437
backgroundConnect17013046856169283
firstReactRender23183842630
initialActions101011
loadScripts71662712771217021044
setupStore1353861422
numNetworkReqs1144728251143241
FirefoxBrowserifyStandard HomeuiStartup15601365233618215941877
load13501181207415113951618
domContentLoaded13481180206815113951615
domInteractive66332213886134
firstPaint------
backgroundConnect5127117155473
firstReactRender12101511314
initialActions102112
loadScripts13251156204514813641591
setupStore146172211239
numNetworkReqs231290201780
BrowserifyPower User HomeuiStartup28072241452640529383587
load16131308271927616742184
domContentLoaded16121308271927616702184
domInteractive12135539111117411
firstPaint------
backgroundConnect3181211114261339899
firstReactRender221581122130
initialActions202122
loadScripts15671270266226016062075
setupStore1278755187111534
numNetworkReqs66361343294127
WebpackStandard HomeuiStartup15521314200413916181885
load13371158163410113981525
domContentLoaded13361158163410113981525
domInteractive70292684396133
firstPaint------
backgroundConnect56261512762122
firstReactRender14112631420
initialActions102012
loadScripts1312113916009613741493
setupStore175151251254
numNetworkReqs241289191879
WebpackPower User HomeuiStartup27571948412144130103552
load15841277250229317302217
domContentLoaded15831277250129317292217
domInteractive12031932145108449
firstPaint------
backgroundConnect319128966250351905
firstReactRender22166862530
initialActions203122
loadScripts15401253248528716672177
setupStore1547768205153590
numNetworkReqs63341403290124
📊 Page Load Benchmark Results

Current Commit: 263fbbb | Date: 2/14/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 982ms (±39ms) 🟢 | historical mean value: 1.06s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 689ms (±37ms) 🟢 | historical mean value: 747ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±11ms) 🟢 | historical mean value: 85ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 982ms 39ms 957ms 1.27s 1.03s 1.27s
domContentLoaded 689ms 37ms 666ms 959ms 729ms 959ms
firstPaint 78ms 11ms 64ms 180ms 84ms 180ms
firstContentfulPaint 78ms 11ms 64ms 180ms 84ms 180ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 89.8 KiB (1.11%)
  • common: 2.43 KiB (0.02%)

const freshPositions = await controller.getPositions({
skipCache: true,
});
streamManager.pushPositionsWithOverrides(freshPositions);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Margin update can be falsely reported failed

Medium Severity

handleSaveMargin treats getPositions refresh failures as if updateMargin failed. After a successful updateMargin, an error during getPositions falls into the same catch, sets marginError, and skips onToggle. This can leave users seeing a failure even though margin was already changed.

Additional Locations (1)

Fix in Cursor Fix in Web

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 14, 2026

Builds ready [5f5632f]
UI Startup Metrics (1384 ± 108 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13841197188210814281582
load1191101715899312441349
domContentLoaded1185101415839212351339
domInteractive2816131212477
firstPaint170691203155220288
backgroundConnect25023231513252276
firstReactRender16103031822
initialActions106113
loadScripts95077513279110001105
setupStore156196201425
numNetworkReqs231588201581
BrowserifyPower User HomeuiStartup17351384228616117962095
load11931077181017311771663
domContentLoaded11781065176716911581655
domInteractive38191582737105
firstPaint197771139129262331
backgroundConnect33730148126345373
firstReactRender22154852332
initialActions106111
loadScripts91780315081618921355
setupStore1583761633
numNetworkReqs1094527248133197
WebpackStandard HomeuiStartup87168011181199811058
load7575981012115844959
domContentLoaded7515931005114834953
domInteractive2817114182676
firstPaint1266264179163226
backgroundConnect261670112849
firstReactRender15103741723
initialActions102112
loadScripts7485911003114830950
setupStore1153951221
numNetworkReqs2315100221586
WebpackPower User HomeuiStartup1233872214119413021610
load72562813211237171059
domContentLoaded71662212971237051050
domInteractive37171603035113
firstPaint1437037372179288
backgroundConnect16713239649164252
firstReactRender22183442430
initialActions101011
loadScripts71362012821207031039
setupStore1243441419
numNetworkReqs1184628552142243
FirefoxBrowserifyStandard HomeuiStartup15581340236119715951945
load13531172212116013951601
domContentLoaded13521166211616013951601
domInteractive68362204187148
firstPaint------
backgroundConnect54281321954105
firstReactRender1292521314
initialActions103122
loadScripts13271151209215413631569
setupStore14663121340
numNetworkReqs2412101221787
BrowserifyPower User HomeuiStartup27982024458848729463824
load15711325242425616542123
domContentLoaded15701325242325616542123
domInteractive1113568693112328
firstPaint------
backgroundConnect2791191277243240894
firstReactRender19147082027
initialActions103122
loadScripts15311243239724716072092
setupStore1358768191152578
numNetworkReqs65361362990120
WebpackStandard HomeuiStartup15801322294721516112039
load13661185270617614061576
domContentLoaded13651185270617614061576
domInteractive76283034998146
firstPaint------
backgroundConnect55243134352148
firstReactRender14115551421
initialActions103122
loadScripts13401169265116713781511
setupStore146151211139
numNetworkReqs231286181777
WebpackPower User HomeuiStartup27291953385943028123631
load15601310246226916572150
domContentLoaded15601305246226916572149
domInteractive10732647104101360
firstPaint------
backgroundConnect298116953237291910
firstReactRender241574102532
initialActions207123
loadScripts15191265244725316212061
setupStore1438775196170655
numNetworkReqs63351503292124
📊 Page Load Benchmark Results

Current Commit: 5f5632f | Date: 2/14/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±39ms) 🟡 | historical mean value: 1.06s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 733ms (±37ms) 🟢 | historical mean value: 747ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 82ms (±13ms) 🟢 | historical mean value: 85ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 39ms 1.02s 1.34s 1.07s 1.34s
domContentLoaded 733ms 37ms 710ms 1.01s 758ms 1.01s
firstPaint 82ms 13ms 60ms 204ms 88ms 204ms
firstContentfulPaint 82ms 13ms 60ms 204ms 88ms 204ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 90.54 KiB (1.12%)
  • common: 2.43 KiB (0.02%)

const newPrice = percentToPrice(numValue, false);
onStopLossPriceChange(newPrice);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Percent input breaks on comma locales

Medium Severity

tpPercent/slPercent are rendered with locale-aware formatNumber, but percent input parsing only accepts dot-decimal via /^-?\d*\.?\d*$/ and parseFloat. In comma-decimal locales, displayed values like 10,0 cannot be edited reliably and can be parsed incorrectly, causing wrong TP/SL price updates.

Additional Locations (2)

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

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.

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 16, 2026

Builds ready [f4d031b]
UI Startup Metrics (1393 ± 89 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1393120416488914351544
load1206101314058312581353
domContentLoaded1200101014008412471344
domInteractive271794172472
firstPaint165661243130211289
backgroundConnect25323330412256280
firstReactRender17114051827
initialActions105113
loadScripts95977311518210111101
setupStore1272951520
numNetworkReqs231589201583
BrowserifyPower User HomeuiStartup16911315240718817442128
load1102977188216510741492
domContentLoaded1085970173815410611474
domInteractive3318163223482
firstPaint204671755195232358
backgroundConnect31026747638318387
firstReactRender22154762334
initialActions103112
loadScripts86275414631438371231
setupStore1473361629
numNetworkReqs1164927546140208
WebpackStandard HomeuiStartup8516931118989271030
load73761797786805883
domContentLoaded73261497085801878
domInteractive2616103182473
firstPaint1156226251150219
backgroundConnect27185783040
firstReactRender15103961728
initialActions102112
loadScripts72961296884799876
setupStore1163141217
numNetworkReqs231591211585
WebpackPower User HomeuiStartup1270867230920813341704
load74364213301307271099
domContentLoaded73463713231317141092
domInteractive38201703036117
firstPaint1487350887154303
backgroundConnect17513344964167306
firstReactRender23193542530
initialActions102011
loadScripts73163413131287121077
setupStore1253651419
numNetworkReqs1204727753145262
FirefoxBrowserifyStandard HomeuiStartup15431334239718315621899
load13331160199914313611605
domContentLoaded13311156199214313581605
domInteractive67332033692138
firstPaint------
backgroundConnect55321832352115
firstReactRender12102221215
initialActions102022
loadScripts13071135196813813371579
setupStore136112141137
numNetworkReqs241295221787
BrowserifyPower User HomeuiStartup27812124398939228873612
load16381325262429216932280
domContentLoaded16381324262429216922280
domInteractive12236566105114409
firstPaint------
backgroundConnect307120964253310912
firstReactRender20156872025
initialActions203122
loadScripts15941303259227516522207
setupStore1259732188108647
numNetworkReqs69381473498135
WebpackStandard HomeuiStartup15611365194412216111810
load13531194161710014061553
domContentLoaded13521194161710114061553
domInteractive763024946106151
firstPaint------
backgroundConnect5226147245997
firstReactRender14112731521
initialActions103122
loadScripts1329118115909513881509
setupStore146115141241
numNetworkReqs241297211784
WebpackPower User HomeuiStartup27371967422945628343800
load15821281250431517172357
domContentLoaded15821281250431517172357
domInteractive14031866172110618
firstPaint------
backgroundConnect3291191296278376929
firstReactRender22174652530
initialActions203123
loadScripts15361259247728416622143
setupStore18671157234277674
numNetworkReqs66361383399128
📊 Page Load Benchmark Results

Current Commit: f4d031b | Date: 2/16/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±43ms) 🟡 | historical mean value: 1.06s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 736ms (±40ms) 🟢 | historical mean value: 746ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 80ms (±10ms) 🟢 | historical mean value: 85ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 43ms 1.02s 1.36s 1.10s 1.36s
domContentLoaded 736ms 40ms 714ms 1.04s 769ms 1.04s
firstPaint 80ms 10ms 64ms 164ms 92ms 164ms
firstContentfulPaint 80ms 10ms 64ms 164ms 92ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 84.36 KiB (1.03%)
  • common: 1.74 KiB (0.02%)

Copy link
Contributor

@geositta geositta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found two issues that I will create separate tasks for.

// Format price for display (with locale-aware formatting)
const formatPrice = useCallback(
(value: number): string => {
return formatNumber(value, {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I noticed formatPrice (which wraps formatNumber from useFormatters) is locale-aware via Intl.NumberFormat, so in comma decimal locales it can produce values like 1.234,56. Since this formatted string is stored directly as the form value, the blur handler's parseFloat(limitPrice.replace(/,/gu, '')) would turn that into 1.234.56, and parseFloat silently truncates at the second dot -> 1.234. The value degrades with each focus/blur cycle.

Worth revisiting in separate issue to store the canonical value as a plain dot-decimal string (e.g. numValue.toFixed(2)) and only use formatPrice for display purposes, or parse using a locale aware approach that round-trips cleanly.

Consider this non-blocking for landing behind the feature flag since it only manifests in non-English locales, but I will create a ticket to avoid incorrect limit prices for those users.

@metamaskbotv2
Copy link
Contributor

metamaskbotv2 bot commented Feb 16, 2026

Builds ready [f551d27]
UI Startup Metrics (1413 ± 102 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup14131224173710214661586
load1210101814308812641373
domContentLoaded1205101314218712581366
domInteractive271796172578
firstPaint155711086117198323
backgroundConnect25723733316259281
firstReactRender1810102101826
initialActions1011113
loadScripts96378511658710141124
setupStore1363351521
numNetworkReqs231588201582
BrowserifyPower User HomeuiStartup17481394232017017932098
load11881052184418011641699
domContentLoaded11721048176517111481686
domInteractive37191552636109
firstPaint190731727177233347
backgroundConnect33629540624352385
firstReactRender23166672435
initialActions102112
loadScripts91479314541668961406
setupStore1684671735
numNetworkReqs1214326248143246
WebpackStandard HomeuiStartup92674713011129861128
load8116411147102878971
domContentLoaded8056361141101872966
domInteractive3116113212687
firstPaint1246932054149227
backgroundConnect29195583343
firstReactRender16114461926
initialActions103112
loadScripts8026341138100870964
setupStore1363961326
numNetworkReqs231589201580
WebpackPower User HomeuiStartup1295917186415813701564
load74365212861227321074
domContentLoaded73364612761227231065
domInteractive39191943438122
firstPaint1526847781189306
backgroundConnect17213533648181272
firstReactRender24173642731
initialActions102011
loadScripts73064312621207211055
setupStore1453951520
numNetworkReqs1194628755142264
FirefoxBrowserifyStandard HomeuiStartup15661349233117516031948
load13511182209114013851618
domContentLoaded13501178208514013841618
domInteractive69302013891136
firstPaint------
backgroundConnect5529171205497
firstReactRender1292121314
initialActions102012
loadScripts13251156206313713581593
setupStore156132171347
numNetworkReqs241298211784
BrowserifyPower User HomeuiStartup27632150413840928363627
load15841326258024816032154
domContentLoaded15831320258024816032152
domInteractive13336684132115457
firstPaint------
backgroundConnect3241201214271344914
firstReactRender2115121132025
initialActions103122
loadScripts15451297254723515672110
setupStore14210734185175556
numNetworkReqs66341593788137
WebpackStandard HomeuiStartup15671340194712816371822
load13671178170410314391515
domContentLoaded13661178170410314391515
domInteractive732915739106135
firstPaint------
backgroundConnect51241372459104
firstReactRender14115251422
initialActions103122
loadScripts1344115816799714231482
setupStore126166171121
numNetworkReqs231591181773
WebpackPower User HomeuiStartup28882057475957431194008
load17141355313838218122563
domContentLoaded17131355313738218112563
domInteractive13236741150106553
firstPaint------
backgroundConnect280691051199285832
firstReactRender2616189192636
initialActions208123
loadScripts16731323308036717582526
setupStore17271203232203674
numNetworkReqs65331873984148
📊 Page Load Benchmark Results

Current Commit: f551d27 | Date: 2/16/2026

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.06s (±44ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 742ms (±41ms) 🟢 | historical mean value: 743ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 83ms (±16ms) 🟢 | historical mean value: 86ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.06s 44ms 1.01s 1.38s 1.12s 1.38s
domContentLoaded 742ms 41ms 708ms 1.06s 789ms 1.06s
firstPaint 83ms 16ms 68ms 216ms 88ms 216ms
firstContentfulPaint 83ms 16ms 68ms 216ms 88ms 216ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 84.36 KiB (1.03%)
  • common: 1.74 KiB (0.02%)

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

Labels

release-13.20.0 Issue or pull request that will be included in release 13.20.0 size-XL team-perps Perps team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants