Skip to content

Conversation

@jpuri
Copy link
Contributor

@jpuri jpuri commented Oct 15, 2025

Description

Capturing DAPP Swap metrics

Changelog

CHANGELOG entry:

Related issues

Fixes: https://github.com/MetaMask/MetaMask-planning/issues/5974

Manual testing steps

  1. Submit a swap
  2. Check that metrics are captured

Screenshots/Recordings

NA

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

Add Dapp swap comparison metrics: new hooks/utils to parse swaps, fetch quotes, compute USD values, and report telemetry; conditional banner wiring; background quotes fetch; LavaMoat policy updates; and tests.

  • Confirmations UI:
    • Add DappSwapComparisonBanner and render it in base-transaction-info when remote flag dappSwapMetrics.enabled is true and origin is https://app.uniswap.org.
  • Hooks & Metrics:
    • Add useDappSwapComparisonInfo to parse swap tx data, fetch quotes, compute USD values, and emit telemetry (including latency metrics via useDappSwapComparisonLatencyMetrics).
  • Utils:
    • Add dapp-swap-comparison-utils (getDataFromSwap, getBestQuote, getTokenValueFromRecord, getBalanceChangeFromSimulationData).
    • Extend token utils with fetchAllErc20Decimals and fetchAllTokenDetails; refactor useBalanceChanges to use fetchAllErc20Decimals.
  • Background/Controllers:
    • Wire BridgeBackgroundAction.FETCH_QUOTES in metamask-controller and add store/controller-actions/bridge-controller.fetchQuotes.
  • Security Policy:
    • Update LavaMoat policies to allow @sentry/browser and internals.
  • Tests:
    • Add tests for banner, hooks, utils, and token helpers.

Written by Cursor Bugbot for commit 7e2621a. 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-confirmations Push issues to confirmations team label Oct 15, 2025
@metamaskbot
Copy link
Collaborator

metamaskbot commented Oct 15, 2025

✨ Files requiring CODEOWNER review ✨

@MetaMask/confirmations (12 files, +1467 -18)
  • 📁 ui/
    • 📁 pages/
      • 📁 confirmations/
        • 📁 components/
          • 📁 confirm/
            • 📁 dapp-swap-comparison-banner/
              • 📄 dapp-swap-comparison-banner.test.tsx +31 -0
              • 📄 dapp-swap-comparison-banner.tsx +12 -0
            • 📁 info/
              • 📁 base-transaction-info/
                • 📄 base-transaction-info.tsx +12 -0
          • 📁 simulation-details/
            • 📄 useBalanceChanges.ts +4 -17
        • 📁 hooks/
          • 📁 transactions/
            • 📄 useDappSwapComparisonInfo.test.ts +320 -0
            • 📄 useDappSwapComparisonInfo.ts +335 -0
            • 📄 useDappSwapComparisonLatencyMetrics.test.ts +76 -0
            • 📄 useDappSwapComparisonLatencyMetrics.ts +79 -0
        • 📁 utils/
          • 📄 dapp-swap-comparison-utils.test.ts +189 -0
          • 📄 dapp-swap-comparison-utils.ts +314 -0
          • 📄 token.test.ts +55 -1
          • 📄 token.ts +40 -0

🧩 @MetaMask/extension-devs (4 files, +692 -0)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +173 -0
      • 📁 experimental/
        • 📄 policy.json +173 -0
      • 📁 flask/
        • 📄 policy.json +173 -0
      • 📁 main/
        • 📄 policy.json +173 -0

📜 @MetaMask/policy-reviewers (4 files, +692 -0)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +173 -0
      • 📁 experimental/
        • 📄 policy.json +173 -0
      • 📁 flask/
        • 📄 policy.json +173 -0
      • 📁 main/
        • 📄 policy.json +173 -0

Tip

Follow the policy review process outlined in the LavaMoat Policy Review Process doc before expecting an approval from Policy Reviewers.


🔗 @MetaMask/supply-chain (4 files, +692 -0)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +173 -0
      • 📁 experimental/
        • 📄 policy.json +173 -0
      • 📁 flask/
        • 📄 policy.json +173 -0
      • 📁 main/
        • 📄 policy.json +173 -0

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: c50cf29 | Date: 10/15/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±71ms) 🟡 | historical mean value: 1.06s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 730ms (±69ms) 🟢 | historical mean value: 741ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±12ms) 🟢 | historical mean value: 78ms ⬇️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 71ms 1.01s 1.31s 1.29s 1.31s
domContentLoaded 730ms 69ms 696ms 994ms 953ms 994ms
firstPaint 76ms 12ms 60ms 172ms 84ms 172ms
firstContentfulPaint 76ms 12ms 60ms 172ms 84ms 172ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [c50cf29]
UI Startup Metrics (1137 ± 83 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyHomeuiStartup1137100114588311781307
load9648691191719931098
domContentLoaded9548291181729871092
domInteractive18134981739
firstPaint68314212723709691090
backgroundConnect20218734319204230
firstReactRender27164983145
getState1453471728
initialActions60468631
loadScripts76264498271788895
setupStore1064351020
WebpackHomeuiStartup857738112262877979
load64559794165648814
domContentLoaded63659093264641806
domInteractive16126081537
firstPaint18756911174204604
backgroundConnect22114572734
firstReactRender27174073335
getState932131115
initialActions308247
loadScripts63458892162639795
setupStore1051931214
FirefoxBrowserifyHomeuiStartup14331234205913815001703
load1197103714729112761353
domContentLoaded1196103714729112761353
domInteractive100343235397226
firstPaintNaNNaNNaNNaNNaNNaN
backgroundConnect32207183847
firstReactRender29244743038
getState95859828
initialActions6119219412
loadScripts1176102014468912561331
setupStore136147171043
WebpackHomeuiStartup1522134819029915711746
load1305117615007913581476
domContentLoaded1305117615007913581476
domInteractive92303665497198
firstPaintNaNNaNNaNNaNNaNNaN
backgroundConnect321893133654
firstReactRender3426123143374
getState83454814
initialActions41566311
loadScripts1284116014767813371459
setupStore146136191148
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 1.58 KiB (0.03%)
  • ui: 3.86 KiB (0.06%)
  • common: 8.17 KiB (0.1%)

this.controllerMessenger,
`${BRIDGE_CONTROLLER_NAME}:${BridgeBackgroundAction.TRACK_METAMETRICS_EVENT}`,
),
[BridgeBackgroundAction.FETCH_QUOTES]: this.controllerMessenger.call.bind(
Copy link
Member

Choose a reason for hiding this comment

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

Ideally this would go in the bridge-controller-init file in the api property.

Copy link
Member

Choose a reason for hiding this comment

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

Ideally we avoid adding to the legacy MetamaskController, but for the sake of time and codeowner review, not an urgent one.

@jpuri jpuri changed the title feat: Adding code to capture metrics for uniswap shield feat: Adding code to capture metrics for swaps Oct 15, 2025
@jpuri jpuri changed the title feat: Adding code to capture metrics for swaps feat: Adding code to capture metrics for dapp swaps Oct 15, 2025
@jpuri jpuri force-pushed the uni_shield branch 2 times, most recently from 02c4771 to c060e20 Compare October 15, 2025 12:22
@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: c6e3040 | Date: 10/15/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.07s (±74ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 752ms (±70ms) 🟢 | historical mean value: 740ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±12ms) 🟢 | historical mean value: 78ms ⬇️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.07s 74ms 1.01s 1.36s 1.31s 1.36s
domContentLoaded 752ms 70ms 705ms 1.04s 966ms 1.04s
firstPaint 78ms 12ms 60ms 188ms 84ms 188ms
firstContentfulPaint 78ms 12ms 60ms 188ms 84ms 188ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [c6e3040]
UI Startup Metrics (1243 ± 75 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyHomeuiStartup1243112715177512821399
load106794212486811071235
domContentLoaded106093812426711021228
domInteractive18146191738
firstPaint66678124944010741186
backgroundConnect2522382787256268
firstReactRender26177382940
getState15592101731
initialActions50426618
loadScripts814691100266849982
setupStore1062231018
WebpackHomeuiStartup8427211090738551007
load63458392272639839
domContentLoaded62757890570628832
domInteractive15114581435
firstPaint16655925164181595
backgroundConnect21105172635
firstReactRender281791123255
getState931831215
initialActions309245
loadScripts62457689568626822
setupStore1051531214
FirefoxBrowserifyHomeuiStartup14301256183513714881742
load1194107015349512661365
domContentLoaded1194106915339512651365
domInteractive98333095293230
firstPaintNaNNaNNaNNaNNaNNaN
backgroundConnect3420103143767
firstReactRender30265143037
getState12515521819
initialActions629111423
loadScripts1173105215169312431343
setupStore136141171057
WebpackHomeuiStartup15611367205313515911891
load1334119216278913891504
domContentLoaded1334119216278913881504
domInteractive993143059105184
firstPaintNaNNaNNaNNaNNaNNaN
backgroundConnect3719108174183
firstReactRender32267683441
getState11415819843
initialActions41355312
loadScripts1309117215938613611480
setupStore145137201248
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 1.81 KiB (0.04%)
  • ui: 6.15 KiB (0.1%)
  • common: 9.41 KiB (0.11%)

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Latency Calculation Error Causes NaN

The updateQuoteRequestLatency function incorrectly calculates latency. It adds requestDetectionLatency to the elapsed time from currentConfirmation?.time, effectively double-counting the initial time. This results in an inflated quoteRequestLatency and can produce NaN if requestDetectionLatency is 'N/A'.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Latency Calculation Fails on Initial 'N/A' Value

In updateQuoteRequestLatency, parseInt(requestDetectionLatency, 10) can evaluate to NaN because requestDetectionLatency might still be its initial 'N/A' value. This causes the quoteRequestLatency calculation to become NaN, resulting in an invalid latency metric.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Case-Sensitive Address Comparison Bug

The getBalanceChangeFromSimulationData function compares change.address and tokenAddress in a case-sensitive way. Because Ethereum addresses are case-insensitive, this comparison might incorrectly miss matching token balance changes. For example, getTokenValueFromRecord in this file correctly uses a case-insensitive approach.

Fix in Cursor Fix in Web

matthewwalsh0
matthewwalsh0 previously approved these changes Oct 23, 2025
@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Latency Metric Inflated by Double Counting

The updateQuoteRequestLatency function's calculation for quoteRequestLatency double-counts time. It adds requestDetectionLatency to the elapsed time, but requestDetectionLatency is already a duration measured from the confirmation's start time, leading to an inflated metric.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Unit Mismatch in Token Amount Comparison

In getBestQuote, the comparison between quote.minDestTokenAmount and amountMinInUSD directly compares a raw token amount with a USD value. This unit mismatch results in incorrect comparison logic.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Stale Data in useAsyncResult Hook

The useAsyncResult hooks' dependency arrays use tokenAddresses?.length instead of tokenAddresses. This can lead to stale token details and fiat rates if the array's contents change without its length changing.

Fix in Cursor Fix in Web

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: 6da443b | Date: 10/23/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.07s (±75ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 753ms (±72ms) 🟢 | historical mean value: 737ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 79ms (±13ms) 🟢 | historical mean value: 80ms ⬇️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.07s 75ms 1.03s 1.34s 1.33s 1.34s
domContentLoaded 753ms 72ms 714ms 1.02s 998ms 1.02s
firstPaint 79ms 13ms 60ms 192ms 92ms 192ms
firstContentfulPaint 79ms 13ms 60ms 192ms 92ms 192ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [6da443b]
UI Startup Metrics (1250 ± 70 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1250111215847012911373
load107493614276911051180
domContentLoaded106793114206910981173
domInteractive19145481743
firstPaint60988127543310901145
backgroundConnect23422237115236246
firstReactRender27189292744
getState1554271731
initialActions60689630
loadScripts840713118868869942
setupStore1064651116
BrowserifyPower User HomeuiStartup25871843356956631053569
load1226958182325915151823
domContentLoaded1212951179425415101794
domInteractive331677205777
firstPaint764196183551811681835
backgroundConnect39222917553733441755
firstReactRender25214562645
getState18516224724195247
initialActions871410140180410
loadScripts959727149322712301493
setupStore20662172862
WebpackStandard HomeuiStartup8577261151778881039
load64359193766647805
domContentLoaded63658792765641798
domInteractive16116091438
firstPaint18056762153195601
backgroundConnect23114772837
firstReactRender281776113359
getState942531114
initialActions3014247
loadScripts63258591463638787
setupStore1052431214
WebpackPower User HomeuiStartup15681122190926318521909
load64054987597712875
domContentLoaded61553983582684835
domInteractive241256164556
firstPaint49271878268708878
backgroundConnect14917322112289322
firstReactRender42172155722215
getState17212427642167276
initialActions712591225
loadScripts61153782879674828
setupStore13640102040
FirefoxBrowserifyStandard HomeuiStartup14171207173910814671629
load1212105415037712681345
domContentLoaded1212105315027712681345
domInteractive1133244053115233
firstPaint------
backgroundConnect3520101144158
firstReactRender25204962639
getState10476111138
initialActions41253310
loadScripts1188103814797512401318
setupStore1254991133
BrowserifyPower User HomeuiStartup27492349407744229734077
load14441266190919316411909
domContentLoaded14441266190919416411909
domInteractive18479468103282468
firstPaint------
backgroundConnect2012412973203671297
firstReactRender40265984459
getState1768922541220225
initialActions816415864
loadScripts14061247185317615721853
setupStore17646102646
WebpackStandard HomeuiStartup16161418232914516691951
load13861190176410414421596
domContentLoaded13861190176410414421596
domInteractive1093138862118238
firstPaint------
backgroundConnect4421293354387
firstReactRender29227793040
getState9410212914
initialActions7118720426
loadScripts13601173172510314171570
setupStore12656101137
WebpackPower User HomeuiStartup26382335318526028913185
load15781332197720417561977
domContentLoaded15781331197620317551976
domInteractive15857421101206421
firstPaint------
backgroundConnect12531394136287394
firstReactRender37275594955
getState1436725953188259
initialActions813081230
loadScripts15391295190318417221903
setupStore2751152936115
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 223 Bytes (0%)
  • ui: 492.4 KiB (7.53%)
  • common: -37 Bytes (0%)

@jpuri jpuri added this pull request to the merge queue Oct 23, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 23, 2025
@jpuri jpuri enabled auto-merge October 23, 2025 12:23
@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Latency Calculation Error: Double-Counting Issue

The updateQuoteRequestLatency function calculates quoteRequestLatency incorrectly. It adds requestDetectionLatency to the current elapsed time from currentConfirmation?.time. As requestDetectionLatency is already a duration from currentConfirmation?.time, this double-counts that initial period, resulting in an inflated latency metric.

Fix in Cursor Fix in Web

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Mismatched Units in Quote Comparison

In getBestQuote, quote.minDestTokenAmount (a raw token amount) is directly compared with amountMinInUSD (a USD value). This comparison of incompatible units leads to incorrect quote selection.

Fix in Cursor Fix in Web

@metamaskbot
Copy link
Collaborator

📊 Page Load Benchmark Results

Current Commit: 7e2621a | Date: 10/23/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.06s (±85ms) 🟡 | historical mean value: 1.05s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 746ms (±100ms) 🟢 | historical mean value: 737ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 91ms (±149ms) 🟢 | historical mean value: 81ms ⬆️ (historical data)
📈 Detailed Results
Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.06s 85ms 1.01s 1.61s 1.27s 1.61s
domContentLoaded 746ms 100ms 701ms 1.51s 945ms 1.51s
firstPaint 91ms 149ms 60ms 1.58s 84ms 1.58s
firstContentfulPaint 91ms 149ms 60ms 1.58s 84ms 1.58s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms

Results generated automatically by MetaMask CI

@metamaskbot
Copy link
Collaborator

Builds ready [7e2621a]
UI Startup Metrics (1286 ± 84 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1286112015228413461428
load110896313317711651237
domContentLoaded110295813257611591231
domInteractive20145281943
firstPaint65580133845311161213
backgroundConnect2342212598237251
firstReactRender27195672940
getState16689101834
initialActions60859615
loadScripts8747391103769331001
setupStore1073131116
BrowserifyPower User HomeuiStartup22131876320045926953200
load1107930185625813311856
domContentLoaded1098923182325313261823
domInteractive281670194470
firstPaint67815118645189741864
backgroundConnect25222534732263347
firstReactRender22202522425
getState21518142557219425
initialActions429259
loadScripts857698150222710801502
setupStore1382772427
WebpackStandard HomeuiStartup84071015241028551034
load6455721376109640883
domContentLoaded6375661356108633877
domInteractive15114881435
firstPaint203571385220193722
backgroundConnect22115872734
firstReactRender26165683135
getState932131116
initialActions3011248
loadScripts6345641342105631866
setupStore952131113
WebpackPower User HomeuiStartup16851235232435920792324
load699605983122821983
domContentLoaded677592928109792928
domInteractive231374173274
firstPaint53076932294796932
backgroundConnect18713795246215795
firstReactRender22202822328
getState1612718437177184
initialActions7150121050
loadScripts673590917105781917
setupStore1262551425
FirefoxBrowserifyStandard HomeuiStartup14621222183411215131721
load1240105615077312821364
domContentLoaded1240105615077312821364
domInteractive1223539459130288
firstPaint------
backgroundConnect3620112154168
firstReactRender25216152633
getState113148161134
initialActions5112112413
loadScripts1215103914807012561345
setupStore185314391140
BrowserifyPower User HomeuiStartup26962384329226729203292
load14361249174714415831747
domContentLoaded14361248174714415831747
domInteractive1544734688223346
firstPaint------
backgroundConnect17538459150395459
firstReactRender392765104565
getState1508521630164216
initialActions812481624
loadScripts13881206170414515091704
setupStore30675245375
WebpackStandard HomeuiStartup15981373199312716841847
load13751212174310814331624
domContentLoaded13751212174310814331624
domInteractive1093240070107283
firstPaint------
backgroundConnect3922173204472
firstReactRender28227693040
getState851931114
initialActions716011545
loadScripts13501193171910714101594
setupStore155154211159
WebpackPower User HomeuiStartup26892394314723229213147
load15781330191018617891910
domContentLoaded15781330191018617891910
domInteractive1375030568206305
firstPaint------
backgroundConnect11233387106172387
firstReactRender412795164695
getState1709823641218236
initialActions1123191731
loadScripts15451309184017717481840
setupStore3691313369131
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 223 Bytes (0%)
  • ui: 492.4 KiB (7.53%)
  • common: -37 Bytes (0%)

@jpuri jpuri added this pull request to the merge queue Oct 23, 2025
Merged via the queue into main with commit 7bf54c4 Oct 23, 2025
173 of 174 checks passed
@jpuri jpuri deleted the uni_shield branch October 23, 2025 13:21
@github-actions github-actions bot locked and limited conversation to collaborators Oct 23, 2025
@metamaskbot metamaskbot added the release-13.7.0 Issue or pull request that will be included in release 13.7.0 label Oct 23, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

no-changelog no-changelog Indicates no external facing user changes, therefore no changelog documentation needed release-13.7.0 Issue or pull request that will be included in release 13.7.0 size-XL team-confirmations Push issues to confirmations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants