Skip to content

Conversation

@tuna1207
Copy link
Member

@tuna1207 tuna1207 commented Nov 24, 2025

Description

Open in GitHub Codespaces

In transaction shield settings screen when user press on payment method, show payment modal for user to choose changing payment method if available
Handle change payment method for crypto -> crypto and crypto -> card

Figma: https://www.figma.com/design/HTAO1SrmixV4ppv7qIvLoa/Metamask-Transaction-Shield?node-id=13566-64615&t=aa5GS94Ns0xYXECP-0

Changelog

CHANGELOG entry: add change payment method from crypto -> crypto / crypto -> card (in paused state only)

Related issues

Fixes:

Manual testing steps

  1. subscribe to shield
  2. go to shield settings page
  3. have another available tokens (mUSD/USDC/USDT)
  4. click on payment method row to show method picker
  5. change payment method

Screenshots/Recordings

Before

After

Screen.Recording.2025-11-27.at.17.20.55.mov

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

Adds modal-driven payment method switching for Transaction Shield (crypto→crypto and paused crypto→card), with supporting hooks/utilities, and updates dependencies/policies accordingly.

  • UI (Transaction Shield settings):
    • Add PaymentMethodRow with modal to change payment method; supports token selection, paused/ending-soon states, and disables card option when ineligible.
    • Integrate into transaction-shield.tsx; replace prior display logic; wire up handlers.
    • Update ShieldPaymentModal to accept disableCardOption.
  • Hooks/Logic:
    • New useUpdateSubscriptionCryptoPaymentMethod to persist selection and trigger approval flow.
    • useSubscriptionCryptoApprovalTransaction now derives networkClientId from getNetworkConfigurationsByChainId.
  • Shared:
    • Add getIsShieldSubscriptionCanChangePaymentMethodToCard helper.
  • Dependencies:
    • Bump @metamask/subscription-controller to ^5.1.0 and update related packages (transaction-controller, network-controller, polling-controller, gas-fee-controller, json-rpc-engine, etc.); regenerate yarn.lock.
  • Security/Policy:
    • Expand LavaMoat policies for new/updated packages (e.g., nested subscription-controller paths, klona path changes, deep-freeze-strict, updated JSON-RPC provider/middleware).

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

@metamaskbot metamaskbot added the team-onboarding Onboarding team label Nov 24, 2025
@metamaskbot
Copy link
Collaborator

metamaskbot commented Nov 24, 2025

✨ Files requiring CODEOWNER review ✨

🧩 @MetaMask/extension-devs (6 files, +520 -22)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +125 -4
      • 📁 experimental/
        • 📄 policy.json +125 -4
      • 📁 flask/
        • 📄 policy.json +125 -4
      • 📁 main/
        • 📄 policy.json +125 -4
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +17 -4
      • 📁 mv3/
        • 📄 policy.json +3 -2

📜 @MetaMask/policy-reviewers (6 files, +520 -22)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +125 -4
      • 📁 experimental/
        • 📄 policy.json +125 -4
      • 📁 flask/
        • 📄 policy.json +125 -4
      • 📁 main/
        • 📄 policy.json +125 -4
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +17 -4
      • 📁 mv3/
        • 📄 policy.json +3 -2

Tip

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


🔗 @MetaMask/supply-chain (6 files, +520 -22)
  • 📁 lavamoat/
    • 📁 browserify/
      • 📁 beta/
        • 📄 policy.json +125 -4
      • 📁 experimental/
        • 📄 policy.json +125 -4
      • 📁 flask/
        • 📄 policy.json +125 -4
      • 📁 main/
        • 📄 policy.json +125 -4
    • 📁 webpack/
      • 📁 mv2/
        • 📄 policy.json +17 -4
      • 📁 mv3/
        • 📄 policy.json +3 -2

🔐 @MetaMask/web3auth (6 files, +518 -162)
  • 📁 shared/
    • 📁 lib/
      • 📄 shield.ts +14 -0
  • 📁 ui/
    • 📁 hooks/
      • 📁 subscription/
        • 📄 useSubscription.ts +61 -8
    • 📁 pages/
      • 📁 settings/
        • 📁 transaction-shield-tab/
          • 📄 index.scss +0 -4
          • 📄 payment-method-row.tsx +305 -0
          • 📄 transaction-shield.tsx +89 -108
      • 📁 shield-plan/
        • 📄 shield-payment-modal.tsx +49 -42

@metamaskbot
Copy link
Collaborator

Builds ready [39b482c]
UI Startup Metrics (1245 ± 117 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12451024158311712931474
load1051876142710511011253
domContentLoaded1046872142010510961248
domInteractive28151252522101
firstPaint51880143841610211214
backgroundConnect21419425511218239
firstReactRender29195283446
getState361679134463
initialActions105112
loadScripts83866512091038851019
setupStore1273541320
numNetworkReqs1257821573
BrowserifyPower User HomeuiStartup18861539336931420322643
load100287520131959911510
domContentLoaded98786920011949691502
domInteractive42153245630197
firstPaint5259520093989111445
backgroundConnect22320034819229250
firstReactRender85541311291103
getState18112738551192316
initialActions103112
loadScripts78466717891927691291
setupStore201055112448
numNetworkReqs1436630555181274
WebpackStandard HomeuiStartup784658107183811976
load61253883073630788
domContentLoaded60853582372625783
domInteractive26141192521105
firstPaint24467792175286598
backgroundConnect953641118
firstReactRender27197183138
getState251259113443
initialActions104112
loadScripts60553381571623776
setupStore1062141217
numNetworkReqs1257720573
WebpackPower User HomeuiStartup15311260285326317092133
load70661015831546931123
domContentLoaded69560415671536751112
domInteractive43182495333208
firstPaint2781001163195275654
backgroundConnect1584672031
firstReactRender89571101196106
getState16412635338169243
initialActions104113
loadScripts69260215561516721101
setupStore22970153059
numNetworkReqs1466730254181292
FirefoxBrowserifyStandard HomeuiStartup12561087171011413031493
load105592812177711071205
domContentLoaded105492812167711071205
domInteractive63311753387128
firstPaint------
backgroundConnect3722135203789
firstReactRender22185172244
getState1057210919
initialActions102012
loadScripts103291211947410771174
setupStore105818923
numNetworkReqs1156915660
BrowserifyPower User HomeuiStartup26731866369030228843146
load1176986167017112291552
domContentLoaded1174985167017112291552
domInteractive12734464103144417
firstPaint------
backgroundConnect212251097234236806
firstReactRender925214619101130
getState16379873136170398
initialActions217227
loadScripts1130954162216011521508
setupStore1637789228148761
numNetworkReqs90592073892188
WebpackStandard HomeuiStartup14251272184411014641698
load1209106314518212371404
domContentLoaded1208106314508212371404
domInteractive62302073282114
firstPaint------
backgroundConnect4219215254494
firstReactRender27205253036
getState126135141222
initialActions103012
loadScripts1183104614347412131347
setupStore12675101134
numNetworkReqs1256517663
WebpackPower User HomeuiStartup28722113381035730713662
load13921119182618915421779
domContentLoaded13911118182618915421779
domInteractive12130554119133459
firstPaint------
backgroundConnect16622854192210667
firstReactRender87441481999125
getState26487904255222830
initialActions3035537
loadScripts13591100178018515131685
setupStore110576218394742
numNetworkReqs91532174581207
📊 Page Load Benchmark Results

Current Commit: 39b482c | Date: 11/24/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±127ms) 🟡 | historical mean value: 1.05s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 729ms (±153ms) 🟢 | historical mean value: 731ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 87ms (±137ms) 🟢 | historical mean value: 79ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 127ms 1.01s 2.28s 1.05s 2.28s
domContentLoaded 729ms 153ms 697ms 2.24s 740ms 2.24s
firstPaint 87ms 137ms 56ms 1.45s 84ms 1.45s
firstContentfulPaint 87ms 137ms 56ms 1.45s 84ms 1.45s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 53 Bytes (0%)
  • ui: 4.94 KiB (0.07%)
  • common: 126 Bytes (0%)

@metamaskbot
Copy link
Collaborator

Builds ready [6a2ab08]
UI Startup Metrics (1186 ± 99 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1186104717469912191365
load100081914758610341143
domContentLoaded99381714218310271134
domInteractive2513135241989
firstPaint60895117939710131148
backgroundConnect19818028014203225
firstReactRender27194983243
getState3212100133660
initialActions107112
loadScripts803635119680838941
setupStore1162741220
numNetworkReqs1257821576
BrowserifyPower User HomeuiStartup20381557294026422062504
load97587215781429611376
domContentLoaded96186415691409471356
domInteractive33161452731117
firstPaint57610514073849161287
backgroundConnect21620224810220241
firstReactRender83471451991131
getState16713123322183203
initialActions105112
loadScripts76066913361387431164
setupStore2094892441
numNetworkReqs1586441075188364
WebpackStandard HomeuiStartup8507151137908931038
load66356596088730836
domContentLoaded65855994188723828
domInteractive27161162322100
firstPaint23082852166220689
backgroundConnect1063261426
firstReactRender2820164153338
getState261371113345
initialActions103111
loadScripts65355784382721814
setupStore1164551222
numNetworkReqs1257721573
WebpackPower User HomeuiStartup16321238213022717982032
load65858098098656974
domContentLoaded64957497399641969
domInteractive35172073531127
firstPaint24189714139252615
backgroundConnect1475671730
firstReactRender83451101593103
getState1487221417156183
initialActions104112
loadScripts64657296497639960
setupStore21870132450
numNetworkReqs1596941976195395
FirefoxBrowserifyStandard HomeuiStartup12351069165111212961460
load103491212557710881175
domContentLoaded103491212547710881175
domInteractive60291843282132
firstPaint------
backgroundConnect3719149223794
firstReactRender21174752134
getState1068011921
initialActions102112
loadScripts101389712287310661151
setupStore115427927
numNetworkReqs1156516664
BrowserifyPower User HomeuiStartup24872016311425726862921
load1133941160415111251523
domContentLoaded1132934160315111241523
domInteractive12230586113110422
firstPaint------
backgroundConnect1082852571120215
firstReactRender864814322100132
getState27334833223408783
initialActions3134427
loadScripts1093923157814310851457
setupStore1517855201173680
numNetworkReqs100633136180242
WebpackStandard HomeuiStartup14191266197711714601672
load1206105114489212661390
domContentLoaded1206105014479312661390
domInteractive58272324080132
firstPaint------
backgroundConnect3820116174184
firstReactRender2719117123038
getState11670101034
initialActions103112
loadScripts1183102314058712431362
setupStore1166491133
numNetworkReqs1156716662
WebpackPower User HomeuiStartup26972124367430428453237
load13421109195217013531744
domContentLoaded13411109195217013531743
domInteractive1103052699103363
firstPaint------
backgroundConnect953231943115176
firstReactRender85421491797112
getState26873829215375719
initialActions308237
loadScripts13111091192616913171707
setupStore1196756162118565
numNetworkReqs97533065679238
📊 Page Load Benchmark Results

Current Commit: 6a2ab08 | Date: 11/25/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±44ms) 🟡 | historical mean value: 1.03s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 716ms (±41ms) 🟢 | historical mean value: 718ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±15ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 44ms 1.01s 1.34s 1.05s 1.34s
domContentLoaded 716ms 41ms 697ms 1.00s 728ms 1.00s
firstPaint 77ms 15ms 60ms 212ms 96ms 212ms
firstContentfulPaint 77ms 15ms 60ms 212ms 96ms 212ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 53 Bytes (0%)
  • ui: 4.65 KiB (0.07%)
  • common: 20 Bytes (0%)

@metamaskbot
Copy link
Collaborator

Builds ready [0556dca]
UI Startup Metrics (1323 ± 132 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13231076176313213871570
load1055859149611311041241
domContentLoaded1048853148911110981231
domInteractive27151122422101
firstPaint53086135641110341212
backgroundConnect21619624813224242
firstReactRender4022115134461
getState62181402674124
initialActions107125
loadScripts83965612671078911011
setupStore1563461829
numNetworkReqs41271433330140
BrowserifyPower User HomeuiStartup22491857334928424342720
load1040917184714510481389
domContentLoaded1025908183314610361378
domInteractive37161993634150
firstPaint54810714443919811188
backgroundConnect271203758120242553
firstReactRender964715624114131
getState18413335332201241
initialActions103112
loadScripts81370514991398241170
setupStore20105692342
numNetworkReqs1216739265128268
WebpackStandard HomeuiStartup88672511521019221125
load67056484986738840
domContentLoaded66556084285734834
domInteractive2815122242294
firstPaint209101859144207649
backgroundConnect1053461123
firstReactRender3822202273894
getState4216120215289
initialActions104112
loadScripts66355883484732825
setupStore14469101442
numNetworkReqs41281463330142
WebpackPower User HomeuiStartup18351276250424719842329
load664585103590678890
domContentLoaded655578102991667884
domInteractive35182513433116
firstPaint28189963197326686
backgroundConnect72761415420569
firstReactRender914214423107126
getState18412669790177225
initialActions104112
loadScripts652576102089665876
setupStore21654132249
numNetworkReqs1586539669198319
FirefoxBrowserifyStandard HomeuiStartup16151220276923317102073
load1203976215015512881385
domContentLoaded1202972215015612881385
domInteractive69311993690137
firstPaint------
backgroundConnect81323505492208
firstReactRender3119144153355
getState2714142182856
initialActions214123
loadScripts1167959211115112591358
setupStore36132233828125
numNetworkReqs41281262836124
BrowserifyPower User HomeuiStartup27062100455852128934131
load1149912249624111721476
domContentLoaded1148911248924011721476
domInteractive12130981128108427
firstPaint------
backgroundConnect138331047153118428
firstReactRender90403203698144
getState30651953229465843
initialActions3181827
loadScripts1103886239719811141437
setupStore18211870208205699
numNetworkReqs102613176681244
WebpackStandard HomeuiStartup16221337227018317092076
load12691114155910213361507
domContentLoaded12691114155810213361506
domInteractive53251703280112
firstPaint------
backgroundConnect66282663778139
firstReactRender342080113861
getState289233332384
initialActions218124
loadScripts1239109614919213051429
setupStore258142252395
numNetworkReqs41291322837126
WebpackPower User HomeuiStartup31022172579781833154786
load15241140297146516162634
domContentLoaded15231140297046516162634
domInteractive16128118424298977
firstPaint------
backgroundConnect178331236229183979
firstReactRender973629347101224
getState275851715263272839
initialActions217123
loadScripts14421105294940215362501
setupStore1185717165116638
numNetworkReqs101592496078239
📊 Page Load Benchmark Results

Current Commit: 0556dca | Date: 11/26/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.05s (±41ms) 🟡 | historical mean value: 1.03s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 734ms (±39ms) 🟢 | historical mean value: 716ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±9ms) 🟢 | historical mean value: 78ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.05s 41ms 1.02s 1.35s 1.09s 1.35s
domContentLoaded 734ms 39ms 705ms 1.02s 754ms 1.02s
firstPaint 78ms 9ms 60ms 148ms 88ms 148ms
firstContentfulPaint 78ms 9ms 60ms 148ms 88ms 148ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 58 Bytes (0%)
  • ui: 4.65 KiB (0.07%)
  • common: 20 Bytes (0%)

tuna1207 and others added 3 commits November 27, 2025 14:03
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/38287?quickstart=1)

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

1. Go to this page...
2.
3.

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/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.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Replace payment method row buttons with design-system TextButton,
simplify crypto token display, and pass supported tokens to the modal;
remove related legacy styles.
> 
> - **UI (Transaction Shield settings)**:
>   - **Payment method row (`payment-method-row.tsx`)**:
> - Migrate from `ButtonLink`/legacy components to
`@metamask/design-system-react` `TextButton`/`Text`.
> - Simplify crypto display: show token symbol directly; remove
`Name`/address resolution.
> - Update error/warning states to `TextButton` with icon and utility
classes; remove explicit icon/color props.
> - Open modal via `TextButton` when crypto is selected; remove separate
click handler.
> - Add `tokensSupported` to `ShieldPaymentModal`; keep card option
gating via `canChangePaymentMethodToCard`.
>     - Adjust typography variants (`TextVariant.BodyMd`) and weights.
> - **Styles (`index.scss`)**:
> - Remove `.warning-button:hover` rule; rely on component-level
styling.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
52cf388. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@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.

@socket-security
Copy link

socket-security bot commented Nov 27, 2025

@tuna1207
Copy link
Member Author

@metamaskbot update-policies

@metamaskbot
Copy link
Collaborator

Builds ready [51d7c00]
📊 Page Load Benchmark Results

Current Commit: 51d7c00 | Date: 11/27/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±97ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 731ms (±108ms) 🟢 | historical mean value: 723ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 90ms (±159ms) 🟢 | historical mean value: 78ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 97ms 1.00s 1.76s 1.24s 1.76s
domContentLoaded 731ms 108ms 687ms 1.61s 929ms 1.61s
firstPaint 90ms 159ms 60ms 1.67s 84ms 1.67s
firstContentfulPaint 90ms 159ms 60ms 1.67s 84ms 1.67s
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: -250 Bytes (-0.01%)
  • ui: -216 Bytes (0%)
  • common: 341.56 KiB (3.88%)

@metamaskbot
Copy link
Collaborator

Policies updated.
👀 Please review the diff for suspicious new powers.

🧠 Learn how: https://lavamoat.github.io/guides/policy-diff/#what-to-look-for-when-reviewing-a-policy-diff

@metamaskbot
Copy link
Collaborator

Builds ready [c8a61ea]
UI Startup Metrics (1319 ± 122 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup13191075160912213981549
load1059883142210711191255
domContentLoaded1053879141210611151249
domInteractive2715112202282
firstPaint48110814294069971240
backgroundConnect22320427011229246
firstReactRender382381104263
getState70201653286141
initialActions107114
loadScripts83566611921038941023
setupStore1473161726
numNetworkReqs41281453330141
BrowserifyPower User HomeuiStartup21011799329826322482637
load1037910177814710381356
domContentLoaded1023902176914610251347
domInteractive35171713032124
firstPaint55110514724039621349
backgroundConnect283208791139240667
firstReactRender584098106379
getState19913467087206258
initialActions106112
loadScripts81068815421458141142
setupStore20104592442
numNetworkReqs103672855496262
WebpackStandard HomeuiStartup8517311133888731062
load63156485371644830
domContentLoaded62655984771638824
domInteractive27151182322101
firstPaint216104673133198583
backgroundConnect1053261130
firstReactRender3619120183788
getState4918149226191
initialActions104112
loadScripts62455783869636815
setupStore1564791540
numNetworkReqs41281473331143
WebpackPower User HomeuiStartup16141217218624819072017
load64756293688654899
domContentLoaded63855493089640893
domInteractive36162293233114
firstPaint31797915202561663
backgroundConnect70761515618537
firstReactRender62438896781
getState196143706101185243
initialActions103112
loadScripts63555292187638884
setupStore20852122050
numNetworkReqs1706740279207395
FirefoxBrowserifyStandard HomeuiStartup14711229206717616041784
load1131992149810911951353
domContentLoaded1130992149210911951352
domInteractive63311483487140
firstPaint------
backgroundConnect69273525373192
firstReactRender292083103354
getState2610110142652
initialActions203123
loadScripts1101977147110111741306
setupStore28111442623100
numNetworkReqs39281302634121
BrowserifyPower User HomeuiStartup25811972419938027413525
load11791018179616911781639
domContentLoaded11781018179616911781639
domInteractive13034554120113484
firstPaint------
backgroundConnect12532668104130316
firstReactRender6039155196294
getState28869903210366758
initialActions2133327
loadScripts1141996167915511341553
setupStore189111183221207689
numNetworkReqs100633216280241
WebpackStandard HomeuiStartup16851383309022117802023
load13041087266517413641515
domContentLoaded13041087266517413641515
domInteractive62281993582131
firstPaint------
backgroundConnect75203214888170
firstReactRender332194123853
getState307186312790
initialActions205122
loadScripts12741059264417213361470
setupStore2710154292295
numNetworkReqs41281262739120
WebpackPower User HomeuiStartup29552164509770231084621
load14411153303434114622006
domContentLoaded14411153303434114622006
domInteractive1152960712296458
firstPaint------
backgroundConnect141251711205131399
firstReactRender69422343569147
getState300661176260385850
initialActions2011123
loadScripts13811133286628213851823
setupStore16061112221160691
numNetworkReqs102633176281247
📊 Page Load Benchmark Results

Current Commit: c8a61ea | Date: 11/27/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±48ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 725ms (±45ms) 🟢 | historical mean value: 723ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 77ms (±11ms) 🟢 | historical mean value: 78ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 48ms 1.01s 1.32s 1.09s 1.32s
domContentLoaded 725ms 45ms 698ms 995ms 758ms 995ms
firstPaint 77ms 11ms 60ms 172ms 88ms 172ms
firstContentfulPaint 77ms 11ms 60ms 172ms 88ms 172ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: -250 Bytes (-0.01%)
  • ui: -216 Bytes (0%)
  • common: 341.56 KiB (3.88%)

"@metamask/ppom-validator>json-rpc-random-id": true
}
},
"@metamask/subscription-controller>@metamask/transaction-controller>@metamask/eth-block-tracker": {
Copy link
Member Author

Choose a reason for hiding this comment

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

added in transaction-controller 62.3.0
@MetaMask/policy-reviewers

"@metamask/ppom-validator>json-rpc-random-id": true
}
},
"@metamask/subscription-controller>@metamask/transaction-controller>@metamask/eth-block-tracker": {
Copy link
Member Author

Choose a reason for hiding this comment

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

added in transaction-controller 62.3.0
@MetaMask/policy-reviewers

"@metamask/ppom-validator>json-rpc-random-id": true
}
},
"@metamask/subscription-controller>@metamask/transaction-controller>@metamask/eth-block-tracker": {
Copy link
Member Author

Choose a reason for hiding this comment

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

added in transaction-controller 62.3.0
@MetaMask/policy-reviewers

"@metamask/ppom-validator>json-rpc-random-id": true
}
},
"@metamask/subscription-controller>@metamask/transaction-controller>@metamask/eth-block-tracker": {
Copy link
Member Author

Choose a reason for hiding this comment

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

added in transaction-controller 62.3.0
@MetaMask/policy-reviewers

@tuna1207 tuna1207 marked this pull request as ready for review November 27, 2025 11:40
@tuna1207 tuna1207 requested a review from a team as a code owner November 27, 2025 11:40
@tuna1207 tuna1207 requested review from a team as code owners November 27, 2025 11:40
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.

Bug: Missing error handling for crypto payment method update

The hasApiError variable includes updateSubscriptionCardPaymentMethodResult.error but omits updateSubscriptionCryptoPaymentMethodResult.error. Meanwhile, the loading variable was correctly updated to include updateSubscriptionCryptoPaymentMethodResult.pending at line 482. This inconsistency means that if the crypto payment method update fails, the error won't be displayed to the user since hasApiError won't be true and the ApiErrorHandler component won't render.

ui/pages/settings/transaction-shield-tab/transaction-shield.tsx#L223-L230

const hasApiError =
subscriptionsError ||
subscriptionPricingError ||
cancelSubscriptionResult.error ||
unCancelSubscriptionResult.error ||
openGetSubscriptionBillingPortalResult.error ||
updateSubscriptionCardPaymentMethodResult.error;

Fix in Cursor Fix in Web


(
displayedShieldSubscription.paymentMethod as SubscriptionCryptoPaymentMethod
).crypto.tokenSymbol,
);
Copy link

Choose a reason for hiding this comment

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

Bug: Token filter excludes same-symbol tokens across all chains

The availableTokenBalancesWithoutCurrentToken filter at lines 120-126 only checks token.symbol when filtering out the current payment token, but ignores chainId. This removes ALL tokens with the same symbol across ALL chains. For example, if the current payment method uses USDC on Ethereum, the filter excludes USDC on Polygon and other chains too, preventing users from switching to the same token type on a different chain. The filter needs to check both symbol AND chainId to only exclude the exact current token.

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.

Bug: Missing error state for crypto payment method update

The updateSubscriptionCryptoPaymentMethodResult.error is not included in hasApiError, even though updateSubscriptionCryptoPaymentMethodResult.pending is correctly added to loading. This means when the crypto payment method update fails, the error won't be displayed to users via the ApiErrorHandler component. All other async operation results have their .error property included in hasApiError, making this an inconsistent omission that prevents users from seeing error feedback for failed crypto payment method changes.

ui/pages/settings/transaction-shield-tab/transaction-shield.tsx#L223-L230

const hasApiError =
subscriptionsError ||
subscriptionPricingError ||
cancelSubscriptionResult.error ||
unCancelSubscriptionResult.error ||
openGetSubscriptionBillingPortalResult.error ||
updateSubscriptionCardPaymentMethodResult.error;

ui/pages/settings/transaction-shield-tab/transaction-shield.tsx#L476-L482

const loading =
cancelSubscriptionResult.pending ||
unCancelSubscriptionResult.pending ||
openGetSubscriptionBillingPortalResult.pending ||
updateSubscriptionCardPaymentMethodResult.pending ||
updateSubscriptionCryptoPaymentMethodResult.pending;

Fix in Cursor Fix in Web


@metamaskbot
Copy link
Collaborator

Builds ready [aeb61c5]
UI Startup Metrics (1267 ± 126 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup12671005175812613561477
load1065874145810611211267
domContentLoaded1059868144910511161259
domInteractive2716110222391
firstPaint49084148239910021215
backgroundConnect22420128013229244
firstReactRender3320117133756
getState3715114154668
initialActions107113
loadScripts84166312141028871032
setupStore1374461424
numNetworkReqs1257720573
BrowserifyPower User HomeuiStartup20671697313224921952587
load1024882173413910401359
domContentLoaded1009875172413910241352
domInteractive35181742933124
firstPaint55010914124029661282
backgroundConnect260201763108233552
firstReactRender60401141666102
getState19614064270206287
initialActions104112
loadScripts79966714811378001146
setupStore2211215222336
numNetworkReqs1056628352102263
WebpackStandard HomeuiStartup823697108483857999
load63856487372670808
domContentLoaded63356085370666802
domInteractive27141082322100
firstPaint21281852153197637
backgroundConnect1256291427
firstReactRender27207583040
getState261464103541
initialActions104111
loadScripts63055884469664793
setupStore1063751217
numNetworkReqs1257720570
WebpackPower User HomeuiStartup16611234259225818982097
load6785861313112674926
domContentLoaded6685791308112659920
domInteractive37181903331120
firstPaint266991042187279661
backgroundConnect104759918928571
firstReactRender604589106683
getState18114070187174214
initialActions103012
loadScripts6655771298110657911
setupStore21762122350
numNetworkReqs1626840379211388
FirefoxBrowserifyStandard HomeuiStartup13601107176215814601694
load1115944142711411861362
domContentLoaded1114944142711411851361
domInteractive62311843286126
firstPaint------
backgroundConnect53211943670135
firstReactRender24187192348
getState1166081019
initialActions103012
loadScripts1081927139810511451286
setupStore14518525932
numNetworkReqs1156615657
BrowserifyPower User HomeuiStartup26432131464548527503996
load1201958251519912251600
domContentLoaded1200958251520012231600
domInteractive12433601119115486
firstPaint------
backgroundConnect1012739773109299
firstReactRender60381582259116
getState26366921213252839
initialActions217124
loadScripts1168942242019211981551
setupStore2089804222302684
numNetworkReqs102613156182240
WebpackStandard HomeuiStartup14481246195813615311704
load1206106014559812621423
domContentLoaded1205105514559812621422
domInteractive56251723080105
firstPaint------
backgroundConnect4020111194290
firstReactRender26207682738
getState12691101119
initialActions103012
loadScripts1182104014409212381376
setupStore144224231135
numNetworkReqs1156716762
WebpackPower User HomeuiStartup30122144497369931044739
load14461130302333914152467
domContentLoaded14461130302333814152466
domInteractive11534532104104424
firstPaint------
backgroundConnect140301319193143289
firstReactRender69442843370116
getState293681414258390774
initialActions3136527
loadScripts13881112285927213531831
setupStore14161280203129563
numNetworkReqs102592516081238
📊 Page Load Benchmark Results

Current Commit: aeb61c5 | Date: 11/28/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±62ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 724ms (±59ms) 🟢 | historical mean value: 726ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 75ms (±12ms) 🟢 | historical mean value: 79ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 62ms 1.00s 1.32s 1.24s 1.32s
domContentLoaded 724ms 59ms 695ms 986ms 925ms 986ms
firstPaint 75ms 12ms 56ms 176ms 84ms 176ms
firstContentfulPaint 75ms 12ms 56ms 176ms 84ms 176ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: -256 Bytes (-0.01%)
  • ui: -191 Bytes (0%)
  • common: 341.56 KiB (3.88%)

token.symbol !== cryptoPayment.crypto.tokenSymbol &&
token.chainId.toLowerCase() !==
cryptoPayment.crypto.chainId.toLowerCase(),
);
Copy link

Choose a reason for hiding this comment

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

Bug: Filter logic incorrectly excludes valid alternative payment tokens

The filter condition uses && (AND) when it should use || (OR). The comment states the intent is to exclude only the current payment token, but the current logic excludes tokens where the symbol is different AND the chainId is different. This means valid alternatives like USDT on the same chain (different symbol, same chainId) or USDC on a different chain (same symbol, different chainId) are incorrectly filtered out. Only tokens that differ in both symbol AND chainId are kept, which is far too restrictive. The condition should be token.symbol !== ... || token.chainId.toLowerCase() !== ... to exclude only the exact current token.

Fix in Cursor Fix in Web

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants