Skip to content

Conversation

@vinistevam
Copy link
Contributor

@vinistevam vinistevam commented Nov 6, 2025

Description

This PR enables automatic account upgrades when Smart Transactions (STX) are turned off.
It removes the UI condition that previously blocked the flow from initiating and refines the EIP-7702 authorization handling, signature normalization, and gasless eligibility logic.

Open in GitHub Codespaces

Changelog

CHANGELOG entry: Added automatic account upgrade support

Related issues

Fixes: #35590

Manual testing steps

  1. Make sure the account has not been upgraded on the network you’re testing.
  2. Ensure the account has a sufficient USDC balance.
  3. Send a transaction from this account.
  4. When prompted to select a gas payment token, choose USDC.
  5. Verify that the transaction completes successfully.
  6. After completion, confirm that the account has been upgraded.

Screenshots/Recordings

arbitrum.auto.upgrade.webm
bnb_aut.upgrade.webm

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

Improves 7702 publish flow with nonce locking and signature normalization, simplifies gasless eligibility to relay-based check, adds hex normalization util, and updates tests.

  • Transactions/Controller:
    • Add getNextNonce using TransactionController.getNonceLock(address, networkClientId) and pass into Delegation7702PublishHook.
    • Use toHex/NetworkClientId in init; wire hook via publishHook.
  • 7702 Publish Hook (delegation-7702-publish.ts):
    • Inject getNextNonce and use transactionMeta.networkClientId; derive authorization nonce from txParams.nonce or next nonce.
    • Normalize EIP-7702 authorization signature: strip single leading zero from r/s, compute yParity with toHex.
    • Minor refactors/imports; reuse stripSingleLeadingZero.
  • UI Gasless Support:
    • useIsGaslessSupported: remove atomic-batch checks; gate 7702 by isRelaySupported(chainId) and non-deploy tx; retain smart-transaction + sendBundle path.
  • Utils:
    • Add stripSingleLeadingZero(hex) helper.
  • Tests:
    • Update delegation-7702-publish to mock getNextNonce; assert auth list/relay behavior.
    • Add tests for stripSingleLeadingZero.
    • Update useIsGaslessSupported tests to reflect relay-only 7702 gating.

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

@vinistevam vinistevam requested a review from a team as a code owner November 6, 2025 11:07
@vinistevam vinistevam added the team-confirmations Push issues to confirmations team label Nov 6, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Nov 6, 2025

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
Copy link
Collaborator

metamaskbot commented Nov 6, 2025

✨ Files requiring CODEOWNER review ✨

@MetaMask/confirmations (5 files, +41 -89)
  • 📁 app/
    • 📁 scripts/
      • 📁 controller-init/
        • 📁 confirmations/
          • 📄 transaction-controller-init.ts +17 -0
      • 📁 lib/
        • 📁 transaction/
          • 📄 util.test.ts +13 -0
          • 📄 util.ts +7 -0
  • 📁 ui/
    • 📁 pages/
      • 📁 confirmations/
        • 📁 hooks/
          • 📁 gas/
            • 📄 useIsGaslessSupported.test.ts +2 -67
            • 📄 useIsGaslessSupported.ts +2 -22

@github-actions github-actions bot added the size-M label Nov 6, 2025
@metamaskbot
Copy link
Collaborator

Builds ready [a7fe899]
UI Startup Metrics (1285 ± 92 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1285110715169213461444
load110494813058211711240
domContentLoaded109894212948111661233
domInteractive231574151966
firstPaint66196132344511101221
backgroundConnect2352202577239249
firstReactRender28194873145
getState24790142945
initialActions001001
loadScripts8687161060809351010
setupStore1262941423
numNetworkReqs1367519670
BrowserifyPower User HomeuiStartup19221686248025218742480
load1020894134416611851344
domContentLoaded1011886133616411651336
domInteractive291561175361
firstPaint74217213624159471362
backgroundConnect2342212539243253
firstReactRender302477122977
getState18111522625195226
initialActions001011
loadScripts78666410991599391099
setupStore15948101248
numNetworkReqs1177025469172254
WebpackStandard HomeuiStartup86370512461058761134
load62956698385625847
domContentLoaded62156195281618831
domInteractive17125791542
firstPaint21361956212206793
backgroundConnect261273152766
firstReactRender30187793639
getState1263151425
initialActions003001
loadScripts61855994279615820
setupStore1262741420
numNetworkReqs1367419870
WebpackPower User HomeuiStartup12571122169515413491695
load67656810181587021018
domContentLoaded64955710021366801002
domInteractive241365194065
firstPaint3539510052916271005
backgroundConnect58102025775202
firstReactRender27243122831
getState1446816627159166
initialActions001001
loadScripts644555991133660991
setupStore1162971629
numNetworkReqs1066721847165218
FirefoxBrowserifyStandard HomeuiStartup14321279197314114821761
load1209109914158212661375
domContentLoaded1209109914148212661375
domInteractive1103428447114225
firstPaint------
backgroundConnect3924104154667
firstReactRender25206352534
getState848311630
initialActions002111
loadScripts1186108013777912401346
setupStore176204281253
numNetworkReqs1266515760
BrowserifyPower User HomeuiStartup24352115290626026832906
load13781122174818715851748
domContentLoaded13781122174818715851748
domInteractive20856581185418581
firstPaint------
backgroundConnect943326268154262
firstReactRender42295695056
getState1396423541179235
initialActions001011
loadScripts13381102167117915591671
setupStore27999273899
numNetworkReqs1326531577209315
WebpackStandard HomeuiStartup16191385228816316451947
load13821194178811014401587
domContentLoaded13811193178711014401586
domInteractive1012935240112169
firstPaint------
backgroundConnect49251552553102
firstReactRender312280123271
getState11421722736
initialActions001001
loadScripts13501178173410214051555
setupStore177214251351
numNetworkReqs1367418767
WebpackPower User HomeuiStartup24772142325432425933254
load14831264194020516441940
domContentLoaded14821264193920516441939
domInteractive15735434128341434
firstPaint------
backgroundConnect11628418104187418
firstReactRender36295474254
getState1247720433136204
initialActions101011
loadScripts14331238184018816301840
setupStore23973173073
numNetworkReqs1286131689230316
📊 Page Load Benchmark Results

Current Commit: a7fe899 | Date: 11/6/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.04s (±38ms) 🟡 | historical mean value: 1.04s ⬆️ (historical data)
  • domContentLoaded-> current mean value: 727ms (±36ms) 🟢 | historical mean value: 722ms ⬆️ (historical data)
  • firstContentfulPaint-> current mean value: 78ms (±11ms) 🟢 | historical mean value: 76ms ⬆️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.04s 38ms 1.02s 1.33s 1.07s 1.33s
domContentLoaded 727ms 36ms 707ms 1.00s 753ms 1.00s
firstPaint 78ms 11ms 60ms 164ms 88ms 164ms
firstContentfulPaint 78ms 11ms 60ms 164ms 88ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 10.24 KiB (0.22%)
  • ui: 215.13 KiB (3.03%)
  • common: 17.6 KiB (0.2%)

const { from, nonce: txNonce } = txParams;
const nextNonce = await this.#getNextNonce(from, networkClientId);

const nonce = txNonce ?? nextNonce;
Copy link
Member

@matthewwalsh0 matthewwalsh0 Nov 6, 2025

Choose a reason for hiding this comment

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

In what scenario is the nonce from the transaction missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have the nonce because we set isExternalSign to true which skips it, but in the scenario where we are upgrading the account we need to pass to Sentinel the nonce.

#decodeAuthorizationSignature(signature: Hex) {
const r = signature.slice(0, 66) as Hex;
const s = `0x${signature.slice(66, 130)}` as Hex;
const r = stripSingleLeadingZero(signature.slice(0, 66)) as Hex;
Copy link
Member

@matthewwalsh0 matthewwalsh0 Nov 6, 2025

Choose a reason for hiding this comment

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

Why is this required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here, Nick mentioned that Go doesn't handle cases properly when the underlying type is an integer, and suggested using a function to strip the leading zero. It’s a bit odd, though, because we have similar logic in the Transaction Controller — it retrieves the signature from the Keyring Controller, splits it into r, s, and v, and that flow works without issues.

(result) => result.chainId.toLowerCase() === chainId.toLowerCase(),
);

// Currently requires upgraded account, can also support no `delegationAddress` in future.
Copy link
Member

Choose a reason for hiding this comment

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

We can remove this now 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@metamaskbot
Copy link
Collaborator

Builds ready [b330b88]
UI Startup Metrics (1165 ± 108 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup1165993184910812251288
load100284416449910581117
domContentLoaded99683616369910501111
domInteractive201468111852
firstPaint68971114339210391100
backgroundConnect1921742108199207
firstReactRender23175762434
getState2064282537
initialActions004001
loadScripts810663145399864920
setupStore1052531117
numNetworkReqs1367520673
BrowserifyPower User HomeuiStartup19651749253928423192539
load1048904143419913141434
domContentLoaded1036897140619213061406
domInteractive33151072658107
firstPaint6737614154599651415
backgroundConnect24222326213258262
firstReactRender28253422834
getState17216119810174198
initialActions001001
loadScripts808674117518810641175
setupStore1091211112
numNetworkReqs1197325173239251
WebpackStandard HomeuiStartup826704116278836980
load60455296166604743
domContentLoaded59754694863598731
domInteractive171273111443
firstPaint19657951197198699
backgroundConnect251077142859
firstReactRender29175583439
getState1152131215
initialActions001001
loadScripts59454493861596721
setupStore1363661329
numNetworkReqs1367619872
WebpackPower User HomeuiStartup13071159180216313281802
load665583913105767913
domContentLoaded64557388191741881
domInteractive261395233895
firstPaint34175805258605805
backgroundConnect631221168162211
firstReactRender28243732837
getState15310419122166191
initialActions001011
loadScripts64057087187730871
setupStore1363492534
numNetworkReqs1086916839164168
FirefoxBrowserifyStandard HomeuiStartup14321259197614614831817
load1214108815508912661371
domContentLoaded1214108815508912661371
domInteractive1173442360122247
firstPaint------
backgroundConnect4124141214784
firstReactRender25214642637
getState10321227622
initialActions001001
loadScripts1190107115218412441336
setupStore147126171236
numNetworkReqs1266214755
BrowserifyPower User HomeuiStartup24362138297023826912970
load13461138174320115481743
domContentLoaded13461138174320215481743
domInteractive20284661166385661
firstPaint------
backgroundConnect12733419121203419
firstReactRender40304964749
getState1429920129159201
initialActions102112
loadScripts12931119170118715101701
setupStore4261925287192
numNetworkReqs1337021963209219
WebpackStandard HomeuiStartup16301439230916816592039
load13941233176811414521658
domContentLoaded13931233176811414511658
domInteractive1053537146114176
firstPaint------
backgroundConnect49261642651116
firstReactRender29227783141
getState10419322719
initialActions005101
loadScripts13621210173510714261587
setupStore186130221575
numNetworkReqs1366917766
WebpackPower User HomeuiStartup25442307294019126732940
load15251296189219016941892
domContentLoaded15241295189119016931891
domInteractive17639537161356537
firstPaint------
backgroundConnect783322455135224
firstReactRender46321121951112
getState15310928046191280
initialActions102112
loadScripts14941275185618416681856
setupStore2671082829108
numNetworkReqs1296129373208293
📊 Page Load Benchmark Results

Current Commit: b330b88 | Date: 11/6/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±39ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 717ms (±36ms) 🟢 | historical mean value: 727ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±10ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 39ms 1.00s 1.31s 1.06s 1.31s
domContentLoaded 717ms 36ms 692ms 983ms 738ms 983ms
firstPaint 76ms 10ms 60ms 160ms 84ms 160ms
firstContentfulPaint 76ms 10ms 60ms 160ms 84ms 160ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 10.24 KiB (0.22%)
  • ui: 216.08 KiB (3.04%)
  • common: 17.73 KiB (0.2%)

@metamaskbot
Copy link
Collaborator

Builds ready [a380b69]
UI Startup Metrics (1153 ± 93 ms)
PlatformBuildTypePageMetricMean (ms)Min (ms)Max (ms)Std Dev (ms)P 75 (ms)P 95 (ms)
ChromeBrowserifyStandard HomeuiStartup115398414399312101334
load99285112168210441138
domContentLoaded98584212058110361125
domInteractive211478121950
firstPaint67276118338710191124
backgroundConnect1901742118196202
firstReactRender25175372743
getState2064882334
initialActions001001
loadScripts801671101879855945
setupStore1072631118
numNetworkReqs1367519672
BrowserifyPower User HomeuiStartup19241725247226722722472
load1044897144619113021446
domContentLoaded1036891143819012931438
domInteractive301678204678
firstPaint76014814454409881445
backgroundConnect23722126410243264
firstReactRender29254652846
getState16914422922179229
initialActions001011
loadScripts807675120618610561206
setupStore1393061230
numNetworkReqs1217326374241263
WebpackStandard HomeuiStartup8277011136968251099
load60755692186599878
domContentLoaded60055189882592861
domInteractive16115891438
firstPaint21063907211189852
backgroundConnect251185162767
firstReactRender29186893439
getState1061831216
initialActions001001
loadScripts59754988879590851
setupStore1153041218
numNetworkReqs1367519672
WebpackPower User HomeuiStartup12961140178420913941784
load655568987132684987
domContentLoaded637558935118656935
domInteractive231361163661
firstPaint33065993316608993
backgroundConnect5792197485219
firstReactRender26242812828
getState14610416919158169
initialActions001001
loadScripts633556925114646925
setupStore1263282332
numNetworkReqs1296736975169369
FirefoxBrowserifyStandard HomeuiStartup14251246187713314801724
load1214108214709112721386
domContentLoaded1213108214699112721386
domInteractive1143438059113263
firstPaint------
backgroundConnect4025126164968
firstReactRender26214862745
getState74314713
initialActions001001
loadScripts1189106314409012501357
setupStore1274971226
numNetworkReqs1267116756
BrowserifyPower User HomeuiStartup23572072306127626123061
load13551138187225016661872
domContentLoaded13551138187225016661872
domInteractive22688610194478610
firstPaint------
backgroundConnect753015039128150
firstReactRender43306584965
getState1188716729155167
initialActions101011
loadScripts13271116183624816381836
setupStore27692284392
numNetworkReqs1337030479199304
WebpackStandard HomeuiStartup15831415213114016311893
load1352119916939613841554
domContentLoaded1352119916929613841554
domInteractive963128638109164
firstPaint------
backgroundConnect46251482449111
firstReactRender302173113064
getState9417218720
initialActions001001
loadScripts1324118216239013561518
setupStore147116141235
numNetworkReqs1367218768
WebpackPower User HomeuiStartup25072190312927427323129
load15231253178716917201787
domContentLoaded15231253178616917191786
domInteractive15637440138340440
firstPaint------
backgroundConnect922919150147191
firstReactRender463174125274
getState1227226852149268
initialActions002112
loadScripts14921233174316416771743
setupStore27593305893
numNetworkReqs1286231079206310
📊 Page Load Benchmark Results

Current Commit: a380b69 | Date: 11/7/2025

📄 Localhost MetaMask Test Dapp

Samples: 100

Summary

  • pageLoadTime-> current mean value: 1.03s (±39ms) 🟡 | historical mean value: 1.04s ⬇️ (historical data)
  • domContentLoaded-> current mean value: 719ms (±37ms) 🟢 | historical mean value: 723ms ⬇️ (historical data)
  • firstContentfulPaint-> current mean value: 76ms (±11ms) 🟢 | historical mean value: 77ms ⬇️ (historical data)

📈 Detailed Results

Metric Mean Std Dev Min Max P95 P99
pageLoadTime 1.03s 39ms 1.01s 1.32s 1.07s 1.32s
domContentLoaded 719ms 37ms 700ms 1.00s 753ms 1.00s
firstPaint 76ms 11ms 56ms 164ms 84ms 164ms
firstContentfulPaint 76ms 11ms 56ms 164ms 84ms 164ms
largestContentfulPaint 0ms 0ms 0ms 0ms 0ms 0ms
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 669 Bytes (0.01%)
  • ui: -378 Bytes (-0.01%)
  • common: 20 Bytes (0%)

@vinistevam vinistevam enabled auto-merge November 7, 2025 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size-M team-confirmations Push issues to confirmations team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automatically upgrade account if smart transactions are off (extension)

6 participants