Repository: MetaMask/metamask-extension
Pull request #31534: Ad/add solana accounts changed event emit onconnect
Author: login: adonesky1
Labels: name: team-wallet-api-platform-deprecated
description: DEPRECATED: please use "team-wallet-integrations" instead
name: INVALID-PR-TEMPLATE
description: PR's body doesn't match template
Created: 2025-04-02T20:57:44Z | Merged: 2025-04-03T19:22:54Z

Covers extra cases not handled by the [initial PR to add an accountsChanged event for Solana](https://github.com/MetaMask/metamask-extension/pull/30949)

This adds handling for emitting the event upon initial connection and emitting the event with an empty array when the Solana scope is revoked


Diff:
diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts
index 3fc529b33256..e05c24356499 100644
--- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts
+++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.test.ts
@@ -7,10 +7,10 @@ import {
 } from '@metamask/chain-agnostic-permission';
 import * as Multichain from '@metamask/chain-agnostic-permission';
 import { Json, JsonRpcRequest, JsonRpcSuccess } from '@metamask/utils';
+import { MultichainNetwork } from '@metamask/multichain-transactions-controller';
 import * as Util from '../../../util';
 import { walletCreateSession } from './handler';
 import { KnownSessionProperties } from './constants';
-import { MultichainNetwork } from '@metamask/multichain-transactions-controller';
 
 jest.mock('../../../util', () => ({
   ...jest.requireActual('../../../util'),
diff --git a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts
index 13188eb64626..b54074c35dc0 100644
--- a/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts
+++ b/app/scripts/lib/rpc-method-middleware/handlers/wallet-createSession/handler.ts
@@ -12,7 +12,6 @@ import {
   getSupportedScopeObjects,
   Caip25CaveatValue,
   setPermittedAccounts,
-  KnownWalletRpcMethods,
 } from '@metamask/chain-agnostic-permission';
 import {
   invalidParams,
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index e15c94a15886..d69f858c1eea 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -17,7 +17,15 @@ import { createEngineStream } from '@metamask/json-rpc-middleware-stream';
 import { ObservableStore } from '@metamask/obs-store';
 import { storeAsStream } from '@metamask/obs-store/dist/asStream';
 import { providerAsMiddleware } from '@metamask/eth-json-rpc-middleware';
-import { debounce, throttle, memoize, wrap, pick, cloneDeep } from 'lodash';
+import {
+  debounce,
+  throttle,
+  memoize,
+  wrap,
+  pick,
+  cloneDeep,
+  uniq,
+} from 'lodash';
 import {
   KeyringController,
   KeyringTypes,
@@ -170,6 +178,7 @@ import {
   getSessionScopes,
   setPermittedEthChainIds,
   setEthAccounts,
+  getPermittedAccountsForScopes,
 } from '@metamask/chain-agnostic-permission';
 
 import {
@@ -2869,9 +2878,87 @@ export default class MetamaskController extends EventEmitter {
                 });
               }
             });
-
             this._notifyAuthorizationChange(origin, authorization);
           }
+
+          const origins = uniq([
+            ...previousValue.keys(),
+            ...currentValue.keys(),
+          ]);
+          origins.forEach((origin) => {
+            const previousCaveatValue = previousValue.get(origin);
+            const currentCaveatValue = currentValue.get(origin);
+
+            const previousSolanaAccountChangedNotificationsEnabled = Boolean(
+              previousCaveatValue?.sessionProperties?.[
+                KnownSessionProperties.SolanaAccountChangedNotifications
+              ],
+            );
+            const currentSolanaAccountChangedNotificationsEnabled = Boolean(
+              currentCaveatValue?.sessionProperties?.[
+                KnownSessionProperties.SolanaAccountChangedNotifications
+              ],
+            );
+
+            if (
+              !previousSolanaAccountChangedNotificationsEnabled &&
+              !currentSolanaAccountChangedNotificationsEnabled
+            ) {
+              return;
+            }
+
+            const previousSolanaCaipAccountIds = previousCaveatValue
+              ? getPermittedAccountsForScopes(previousCaveatValue, [
+                  MultichainNetworks.SOLANA,
+                  MultichainNetworks.SOLANA_DEVNET,
+                  MultichainNetworks.SOLANA_TESTNET,
+                ])
+              : [];
+            const _previousSolanaHexAccountAddresses =
+              previousSolanaCaipAccountIds.map((caipAccountId) => {
+                const { address } = parseCaipAccountId(caipAccountId);
+                return address;
+              });
+            const previousSolanaHexAccountAddresses = uniq(
+              _previousSolanaHexAccountAddresses,
+            );
+            const previousSelectedSolanaAccountAddress =
+              this.sortMultichainAccountsByLastSelected(
+                previousSolanaHexAccountAddresses,
+              )[0];
+
+            const currentSolanaCaipAccountIds = currentCaveatValue
+              ? getPermittedAccountsForScopes(currentCaveatValue, [
+                  MultichainNetworks.SOLANA,
+                  MultichainNetworks.SOLANA_DEVNET,
+                  MultichainNetworks.SOLANA_TESTNET,
+                ])
+              : [];
+            const _currentSolanaHexAccountAddresses =
+              currentSolanaCaipAccountIds.map((caipAccountId) => {
+                const { address } = parseCaipAccountId(caipAccountId);
+                return address;
+              });
+            const currentSolanaHexAccountAddresses = uniq(
+              _currentSolanaHexAccountAddresses,
+            );
+            const currentSelectedSolanaAccountAddress =
+              this.sortMultichainAccountsByLastSelected(
+                currentSolanaHexAccountAddresses,
+              )[0];
+
+            if (
+              previousSelectedSolanaAccountAddress !==
+              currentSelectedSolanaAccountAddress
+            ) {
+              this._notifySolanaAccountChange(
+                origin,
+                currentSelectedSolanaAccountAddress
+                  ? [currentSelectedSolanaAccountAddress]
+                  : [],
+              );
+            }
+          });
         },
         getAuthorizedScopesByOrigin,
       );
@@ -2883,6 +2970,8 @@ export default class MetamaskController extends EventEmitter {
             account.type === 'solana:data-account' &&
             account.address !== lastSelectedSolanaAccountAddress
           ) {
+            lastSelectedSolanaAccountAddress = account.address;
+
             const originsWithSolanaAccountChangedNotifications =
               getOriginsWithSessionProperty(
                 this.permissionController.state,
@@ -2908,8 +2997,7 @@ export default class MetamaskController extends EventEmitter {
                 parsedSolanaAddresses.includes(account.address) &&
                 originsWithSolanaAccountChangedNotifications[origin]
               ) {
-                lastSelectedSolanaAccountAddress = account.address;
-                this._notifySolanaAccountChange(origin, account.address);
+                this._notifySolanaAccountChange(origin, [account.address]);
               }
             }
           }
@@ -5331,6 +5419,56 @@ export default class MetamaskController extends EventEmitter {
     });
   }
 
+  /**
+   * Sorts a list of multichain account addresses by most recently selected by using
+   * the lastSelected value for the matching InternalAccount object stored in state.
+   *
+   * @param {string[]} [accounts] - The list of accounts addresses to sort.
+   * @returns {string[]} The sorted accounts addresses.
+   */
+  sortMultichainAccountsByLastSelected(accounts) {
+    const internalAccounts = this.accountsController.listMultichainAccounts();
+
+    return accounts.sort((firstAddress, secondAddress) => {
+      const firstAccount = internalAccounts.find(
+        (internalAccount) =>
+          internalAccount.address.toLowerCase() === firstAddress.toLowerCase(),
+      );
+
+      const secondAccount = internalAccounts.find(
+        (internalAccount) =>
+          internalAccount.address.toLowerCase() === secondAddress.toLowerCase(),
+      );
+
+      if (!firstAccount) {
+        this.captureKeyringTypesWithMissingIdentities(
+          internalAccounts,
+          accounts,
+        );
+        throw new Error(`Missing identity for address: "${firstAddress}".`);
+      } else if (!secondAccount) {
+        this.captureKeyringTypesWithMissingIdentities(
+          internalAccounts,
+          accounts,
+        );
+        throw new Error(`Missing identity for address: "${secondAddress}".`);
+      } else if (
+        firstAccount.metadata.lastSelected ===
+        secondAccount.metadata.lastSelected
+      ) {
+        return 0;
+      } else if (firstAccount.metadata.lastSelected === undefined) {
+        return 1;
+      } else if (secondAccount.metadata.lastSelected === undefined) {
+        return -1;
+      }
+
+      return (
+        secondAccount.metadata.lastSelected - firstAccount.metadata.lastSelected
+      );
+    });
+  }
+
   /**
    * Gets the sorted permitted accounts for the specified origin. Returns an empty
    * array if no accounts are permitted or the wallet is locked. Returns any permitted
@@ -6213,6 +6351,53 @@ export default class MetamaskController extends EventEmitter {
       origin = new URL(sender.url).origin;
     }
 
+    // solana account changed notifications
+    let caip25Caveat;
+    try {
+      caip25Caveat = this.permissionController.getCaveat(
+        origin,
+        Caip25EndowmentPermissionName,
+        Caip25CaveatType,
+      );
+    } catch {
+      // noop
+    }
+    if (caip25Caveat) {
+      const solanaAccountsChangedNotifications =
+        caip25Caveat.value.sessionProperties[
+          KnownSessionProperties.SolanaAccountChangedNotifications
+        ];
+
+      const sessionScopes = getSessionScopes(caip25Caveat.value, {
+        getNonEvmSupportedMethods: this.getNonEvmSupportedMethods.bind(this),
+      });
+
+      const solanaScope =
+        sessionScopes[MultichainNetworks.SOLANA] ||
+        sessionScopes[MultichainNetworks.SOLANA_DEVNET] ||
+        sessionScopes[MultichainNetworks.SOLANA_TESTNET];
+
+      if (solanaAccountsChangedNotifications && solanaScope) {
+        const { accounts } = solanaScope;
+        const parsedPermittedSolanaAddresses = accounts.map((caipAccountId) => {
+          const { address } = parseCaipAccountId(caipAccountId);
+          return address;
+        });
+
+        const accountAddressToEmit = this.sortMultichainAccountsByLastSelected(
+          parsedPermittedSolanaAddresses,
+        )[0];
+
+        if (accountAddressToEmit) {
+          // delay emit so that the event is not emitted
+          // before the wallet standard script is ready to receive it
+          setTimeout(() => {
+            this._notifySolanaAccountChange(origin, [accountAddressToEmit]);
+          }, 500);
+        }
+      }
+    }
+
     if (sender.id && sender.id !== this.extension.runtime.id) {
       this.subjectMetadataController.addSubjectMetadata({
         origin,
@@ -7826,7 +8011,7 @@ export default class MetamaskController extends EventEmitter {
     );
   }
 
-  async _notifySolanaAccountChange(origin, accountAddress) {
+  async _notifySolanaAccountChange(origin, accountAddressArray) {
     this.notifyConnections(
       origin,
       {
@@ -7835,7 +8020,7 @@ export default class MetamaskController extends EventEmitter {
           scope: MultichainNetworks.SOLANA,
           notification: {
             method: NOTIFICATION_NAMES.accountsChanged,
-            params: [accountAddress],
+            params: accountAddressArray,
           },
         },
       },
diff --git a/ui/store/actions.ts b/ui/store/actions.ts
index 8d0a99d5b265..9bbee79315a7 100644
--- a/ui/store/actions.ts
+++ b/ui/store/actions.ts
@@ -12,7 +12,13 @@ import { ThunkAction } from 'redux-thunk';
 import { Action, AnyAction } from 'redux';
 import { providerErrors, serializeError } from '@metamask/rpc-errors';
 import type { DataWithOptionalCause } from '@metamask/rpc-errors';
-import type { CaipChainId, Hex, Json } from '@metamask/utils';
+import {
+  parseCaipChainId,
+  parseCaipAccountId,
+  type CaipChainId,
+  type Hex,
+  type Json,
+} from '@metamask/utils';
 import {
   AssetsContractController,
   BalanceMap,


Reviews:
user: login: jiexi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T22:19:30Z
user: login: jiexi
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-02T22:22:45Z

Review comments:
diff_hunk: @@ -2870,6 +2899,34 @@ export default class MetamaskController extends EventEmitter {
               }
             });
 
+            const addedSolanaScope =
+              sessionScopes[MultichainNetworks.SOLANA] ||
+              sessionScopes[MultichainNetworks.SOLANA_DEVNET] ||
+              sessionScopes[MultichainNetworks.SOLANA_TESTNET];
+
+            if (addedSolanaScope) {
+              const solanaAccountChangedNotifications =
+                currentValue.get(origin)?.sessionProperties?.[
+                  KnownSessionProperties.SolanaAccountChangedNotifications
+                ];
+
+              if (solanaAccountChangedNotifications) {
+                const { accounts } = addedSolanaScope;
+                const solanaFormattedAccounts = accounts.map(
+                  (caipAccountId) => {
+                    const { address } = parseCaipAccountId(caipAccountId);
+                    return address;
+                  },
+                );
+                const accountAddressToEmit = solanaFormattedAccounts.includes(
+                  lastSelectedSolanaAccountAddress,
+                )
+                  ? lastSelectedSolanaAccountAddress
+                  : solanaFormattedAccounts[0];
path: app/scripts/metamask-controller.js
user: login: jiexi
body: This logic allows for the following scenario.
Assume solana accounts A, B, C
A dapp is permitted to use Account A and B
The currently selected account in the wallet is B
The dapp last got an accountChanged event for Account B
The user changes the currently selected account in the wallet to Account C
The dapp will get an accountChanged event for Account A even though it shouldn't have gotten any event at all or at minimum the value should have stayed Account B
created_at: 2025-04-02T22:19:30Z
author_association: MEMBER
diff_hunk: @@ -2835,6 +2835,35 @@ export default class MetamaskController extends EventEmitter {
                 });
               }
             });
+
+            const removedSolanaScope =
+              sessionScopes[MultichainNetworks.SOLANA] ||
+              sessionScopes[MultichainNetworks.SOLANA_DEVNET] ||
+              sessionScopes[MultichainNetworks.SOLANA_TESTNET];
+
+            const currentValueHasNoSolanaScope =
+              !currentValue.get(origin)?.sessionScopes?.[
+                MultichainNetworks.SOLANA
+              ] &&
+              !currentValue.get(origin)?.sessionScopes?.[
+                MultichainNetworks.SOLANA_DEVNET
+              ] &&
+              !currentValue.get(origin)?.sessionScopes?.[
+                MultichainNetworks.SOLANA_TESTNET
+              ];
path: app/scripts/metamask-controller.js
user: login: jiexi
body: thoughts on just checking for if any Solana namespaced scope exists?
created_at: 2025-04-02T22:22:45Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-02T20:57:57Z
body: **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.
author_association: CONTRIBUTOR
user: login: metamaskbot
created_at: 2025-04-02T21:42:35Z
body: <details><summary>Builds ready [24060d4]</summary><ul><li>builds: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds/metamask-chrome-12.15.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-mv2/metamask-firefox-12.15.0.zip">firefox</a></li>
<li>builds (flask): <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-flask/metamask-flask-chrome-12.15.0-flask.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-flask-mv2/metamask-flask-firefox-12.15.0-flask.0.zip">firefox</a></li>
<li>builds (test): <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-test/metamask-chrome-12.15.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-test-mv2/metamask-firefox-12.15.0.zip">firefox</a></li>
<li>builds (test-flask): <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-test-flask/metamask-flask-chrome-12.15.0-flask.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/builds-test-flask-mv2/metamask-flask-firefox-12.15.0-flask.0.zip">firefox</a></li>
<li>build viz: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/build-viz/index.html">Build System</a></li>
<li>bundle size: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14229601487/bundle-size/bundle_size.json">Bundle Size Stats</a></li>
<li>user-actions-benchmark: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14229601487/benchmarks/benchmark-chrome-browserify-userActions.json">User Actions Stats</a></li>
<li>storybook: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14229601487/storybook-build/index.html">Storybook</a></li>
<li>typescript migration: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/ts-migration-dashboard/index.html">Dashboard</a></li>
<li><a href="https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/jobs/4718050/artifacts/">all CircleCI artifacts</a></li>
<li><details>
       <summary>bundle viz:</summary>
       <ul><li>background: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/background-8.html">8</a></li><li>common: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-8.html">8</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-9.html">9</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-10.html">10</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-11.html">11</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-12.html">12</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-13.html">13</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/common-14.html">14</a></li><li>ui: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-8.html">8</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-9.html">9</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-10.html">10</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-11.html">11</a>, <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/ui-12.html">12</a></li><li>content-script: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/content-script-0.html">0</a></li><li>offscreen: <a href="https://output.circle-artifacts.com/output/job/bdeb162c-b59c-483b-8dac-3349eb16a2ea/artifacts/0/build-artifacts/source-map-explorer/offscreen-0.html">0</a></li></ul>
     </details></li></ul></details>

<details><summary>UI Startup Metrics (1206 ± 69 ms)</summary><table><thead><tr><th>Platform</th><th>BuildType</th><th>Page</th><th>Metric</th><th>Mean (ms)</th><th>Min (ms)</th><th>Max (ms)</th><th>Std Dev (ms)</th><th>P 75 (ms)</th><th>P 95 (ms)</th></tr></thead><tbody><tr><td rowspan="22">Chrome</td><td rowspan="11">Browserify</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1206</td><td align="right">1087</td><td align="right">1458</td><td align="right">69</td><td align="right">1256</td><td align="right">1325</td></tr><tr><td>load</td><td align="right">1057</td><td align="right">956</td><td align="right">1299</td><td align="right">67</td><td align="right">962</td><td align="right">989</td></tr><tr><td>domContentLoaded</td><td align="right">1051</td><td align="right">949</td><td align="right">1296</td><td align="right">68</td><td align="right">962</td><td align="right">990</td></tr><tr><td>domInteractive</td><td align="right">16</td><td align="right">13</td><td align="right">38</td><td align="right">5</td><td align="right">15</td><td align="right">27</td></tr><tr><td>firstPaint</td><td align="right">755</td><td align="right">72</td><td align="right">1183</td><td align="right">414</td><td align="right">239</td><td align="right">981</td></tr><tr><td>backgroundConnect</td><td align="right">7</td><td align="right">4</td><td align="right">27</td><td align="right">4</td><td align="right">6</td><td align="right">8</td></tr><tr><td>firstReactRender</td><td align="right">19</td><td align="right">15</td><td align="right">56</td><td align="right">6</td><td align="right">19</td><td align="right">33</td></tr><tr><td>getState</td><td align="right">12</td><td align="right">4</td><td align="right">49</td><td align="right">9</td><td align="right">6</td><td align="right">8</td></tr><tr><td>initialActions</td><td align="right">0</td><td align="right">0</td><td align="right">1</td><td align="right">0</td><td align="right">0</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">802</td><td align="right">688</td><td align="right">1032</td><td align="right">68</td><td align="right">859</td><td align="right">907</td></tr><tr><td>setupStore</td><td align="right">8</td><td align="right">4</td><td align="right">25</td><td align="right">3</td><td align="right">7</td><td align="right">8</td></tr><tr><td rowspan="11">Webpack</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">2063</td><td align="right">1628</td><td align="right">2619</td><td align="right">209</td><td align="right">2207</td><td align="right">2403</td></tr><tr><td>load</td><td align="right">1605</td><td align="right">1290</td><td align="right">2028</td><td align="right">166</td><td align="right">1711</td><td align="right">1869</td></tr><tr><td>domContentLoaded</td><td align="right">1599</td><td align="right">1287</td><td align="right">2017</td><td align="right">165</td><td align="right">1707</td><td align="right">1860</td></tr><tr><td>domInteractive</td><td align="right">17</td><td align="right">12</td><td align="right">59</td><td align="right">11</td><td align="right">13</td><td align="right">53</td></tr><tr><td>firstPaint</td><td align="right">220</td><td align="right">67</td><td align="right">1523</td><td align="right">201</td><td align="right">268</td><td align="right">85</td></tr><tr><td>backgroundConnect</td><td align="right">25</td><td align="right">9</td><td align="right">245</td><td align="right">26</td><td align="right">23</td><td align="right">65</td></tr><tr><td>firstReactRender</td><td align="right">182</td><td align="right">53</td><td align="right">355</td><td align="right">115</td><td align="right">85</td><td align="right">95</td></tr><tr><td>getState</td><td align="right">11</td><td align="right">3</td><td align="right">157</td><td align="right">15</td><td align="right">8</td><td align="right">9</td></tr><tr><td>initialActions</td><td align="right">2</td><td align="right">1</td><td align="right">6</td><td align="right">1</td><td align="right">3</td><td align="right">4</td></tr><tr><td>loadScripts</td><td align="right">1595</td><td align="right">1285</td><td align="right">1995</td><td align="right">163</td><td align="right">1705</td><td align="right">1859</td></tr><tr><td>setupStore</td><td align="right">21</td><td align="right">7</td><td align="right">265</td><td align="right">37</td><td align="right">22</td><td align="right">9</td></tr><tr><td rowspan="22">Firefox</td><td rowspan="11">Browserify</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1357</td><td align="right">1156</td><td align="right">1851</td><td align="right">145</td><td align="right">1423</td><td align="right">1736</td></tr><tr><td>load</td><td align="right">1216</td><td align="right">1037</td><td align="right">1686</td><td align="right">139</td><td align="right">1286</td><td align="right">1531</td></tr><tr><td>domContentLoaded</td><td align="right">1216</td><td align="right">1037</td><td align="right">1686</td><td align="right">139</td><td align="right">1285</td><td align="right">1531</td></tr><tr><td>domInteractive</td><td align="right">98</td><td align="right">40</td><td align="right">175</td><td align="right">26</td><td align="right">87</td><td align="right">94</td></tr><tr><td>firstPaint</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td></tr><tr><td>backgroundConnect</td><td align="right">19</td><td align="right">13</td><td align="right">65</td><td align="right">6</td><td align="right">21</td><td align="right">28</td></tr><tr><td>firstReactRender</td><td align="right">23</td><td align="right">19</td><td align="right">52</td><td align="right">6</td><td align="right">23</td><td align="right">35</td></tr><tr><td>getState</td><td align="right">7</td><td align="right">4</td><td align="right">24</td><td align="right">3</td><td align="right">7</td><td align="right">9</td></tr><tr><td>initialActions</td><td align="right">0</td><td align="right">0</td><td align="right">1</td><td align="right">0</td><td align="right">0</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">1199</td><td align="right">1022</td><td align="right">1658</td><td align="right">137</td><td align="right">1272</td><td align="right">1509</td></tr><tr><td>setupStore</td><td align="right">6</td><td align="right">3</td><td align="right">19</td><td align="right">2</td><td align="right">6</td><td align="right">7</td></tr><tr><td rowspan="11">Webpack</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1561</td><td align="right">1359</td><td align="right">2107</td><td align="right">160</td><td align="right">1622</td><td align="right">1929</td></tr><tr><td>load</td><td align="right">1345</td><td align="right">1175</td><td align="right">1894</td><td align="right">147</td><td align="right">1408</td><td align="right">1681</td></tr><tr><td>domContentLoaded</td><td align="right">1345</td><td align="right">1175</td><td align="right">1894</td><td align="right">147</td><td align="right">1408</td><td align="right">1681</td></tr><tr><td>domInteractive</td><td align="right">99</td><td align="right">35</td><td align="right">182</td><td align="right">27</td><td align="right">88</td><td align="right">96</td></tr><tr><td>firstPaint</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td></tr><tr><td>backgroundConnect</td><td align="right">21</td><td align="right">14</td><td align="right">42</td><td align="right">4</td><td align="right">23</td><td align="right">28</td></tr><tr><td>firstReactRender</td><td align="right">37</td><td align="right">28</td><td align="right">60</td><td align="right">6</td><td align="right">39</td><td align="right">48</td></tr><tr><td>getState</td><td align="right">10</td><td align="right">4</td><td align="right">31</td><td align="right">8</td><td align="right">8</td><td align="right">9</td></tr><tr><td>initialActions</td><td align="right">0</td><td align="right">0</td><td align="right">2</td><td align="right">1</td><td align="right">1</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">1325</td><td align="right">1156</td><td align="right">1877</td><td align="right">147</td><td align="right">1388</td><td align="right">1659</td></tr><tr><td>setupStore</td><td align="right">9</td><td align="right">5</td><td align="right">37</td><td align="right">5</td><td align="right">8</td><td align="right">9</td></tr></tbody></table></details>


author_association: COLLABORATOR
user: login: jiexi
created_at: 2025-04-02T22:40:54Z
body: other scenario that may not be accounted for is when accounts are removed from a solana scope, but the scope itself is still permitted
author_association: MEMBER
user: login: metamaskbot
created_at: 2025-04-03T19:21:51Z
body: <details><summary>Builds ready [18d92b4]</summary><ul><li>builds: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds/metamask-chrome-12.15.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-mv2/metamask-firefox-12.15.0.zip">firefox</a></li>
<li>builds (flask): <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-flask/metamask-flask-chrome-12.15.0-flask.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-flask-mv2/metamask-flask-firefox-12.15.0-flask.0.zip">firefox</a></li>
<li>builds (test): <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-test/metamask-chrome-12.15.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-test-mv2/metamask-firefox-12.15.0.zip">firefox</a></li>
<li>builds (test-flask): <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-test-flask/metamask-flask-chrome-12.15.0-flask.0.zip">chrome</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/builds-test-flask-mv2/metamask-flask-firefox-12.15.0-flask.0.zip">firefox</a></li>
<li>build viz: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/build-viz/index.html">Build System</a></li>
<li>bundle size: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14250503951/bundle-size/bundle_size.json">Bundle Size Stats</a></li>
<li>user-actions-benchmark: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14250503951/benchmarks/benchmark-chrome-browserify-userActions.json">User Actions Stats</a></li>
<li>storybook: <a href="https://diuv6g5fj9pvx.cloudfront.net/metamask-extension/14250503951/storybook-build/index.html">Storybook</a></li>
<li>typescript migration: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/ts-migration-dashboard/index.html">Dashboard</a></li>
<li><a href="https://app.circleci.com/pipelines/github/MetaMask/metamask-extension/jobs/4723721/artifacts/">all CircleCI artifacts</a></li>
<li><details>
       <summary>bundle viz:</summary>
       <ul><li>background: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/background-8.html">8</a></li><li>common: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-8.html">8</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-9.html">9</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-10.html">10</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-11.html">11</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-12.html">12</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-13.html">13</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/common-14.html">14</a></li><li>ui: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-0.html">0</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-1.html">1</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-2.html">2</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-3.html">3</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-4.html">4</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-5.html">5</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-6.html">6</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-7.html">7</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-8.html">8</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-9.html">9</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-10.html">10</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-11.html">11</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-12.html">12</a>, <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/ui-13.html">13</a></li><li>content-script: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/content-script-0.html">0</a></li><li>offscreen: <a href="https://output.circle-artifacts.com/output/job/d8962546-e8cd-4b78-b3f2-5cd1c95828f1/artifacts/0/build-artifacts/source-map-explorer/offscreen-0.html">0</a></li></ul>
     </details></li></ul></details>

<details><summary>UI Startup Metrics (1243 ± 63 ms)</summary><table><thead><tr><th>Platform</th><th>BuildType</th><th>Page</th><th>Metric</th><th>Mean (ms)</th><th>Min (ms)</th><th>Max (ms)</th><th>Std Dev (ms)</th><th>P 75 (ms)</th><th>P 95 (ms)</th></tr></thead><tbody><tr><td rowspan="22">Chrome</td><td rowspan="11">Browserify</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1243</td><td align="right">1128</td><td align="right">1420</td><td align="right">63</td><td align="right">1284</td><td align="right">1354</td></tr><tr><td>load</td><td align="right">1091</td><td align="right">978</td><td align="right">1283</td><td align="right">64</td><td align="right">1140</td><td align="right">978</td></tr><tr><td>domContentLoaded</td><td align="right">1085</td><td align="right">975</td><td align="right">1274</td><td align="right">64</td><td align="right">1161</td><td align="right">995</td></tr><tr><td>domInteractive</td><td align="right">17</td><td align="right">13</td><td align="right">36</td><td align="right">4</td><td align="right">16</td><td align="right">28</td></tr><tr><td>firstPaint</td><td align="right">709</td><td align="right">73</td><td align="right">1283</td><td align="right">440</td><td align="right">230</td><td align="right">73</td></tr><tr><td>backgroundConnect</td><td align="right">7</td><td align="right">4</td><td align="right">40</td><td align="right">5</td><td align="right">7</td><td align="right">9</td></tr><tr><td>firstReactRender</td><td align="right">20</td><td align="right">13</td><td align="right">55</td><td align="right">6</td><td align="right">19</td><td align="right">35</td></tr><tr><td>getState</td><td align="right">11</td><td align="right">4</td><td align="right">33</td><td align="right">7</td><td align="right">6</td><td align="right">8</td></tr><tr><td>initialActions</td><td align="right">0</td><td align="right">0</td><td align="right">1</td><td align="right">0</td><td align="right">0</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">829</td><td align="right">727</td><td align="right">1007</td><td align="right">63</td><td align="right">872</td><td align="right">952</td></tr><tr><td>setupStore</td><td align="right">8</td><td align="right">5</td><td align="right">30</td><td align="right">3</td><td align="right">7</td><td align="right">8</td></tr><tr><td rowspan="11">Webpack</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">2096</td><td align="right">1693</td><td align="right">2597</td><td align="right">228</td><td align="right">2241</td><td align="right">2547</td></tr><tr><td>load</td><td align="right">1619</td><td align="right">1320</td><td align="right">2014</td><td align="right">168</td><td align="right">1719</td><td align="right">1945</td></tr><tr><td>domContentLoaded</td><td align="right">1612</td><td align="right">1317</td><td align="right">1989</td><td align="right">164</td><td align="right">1712</td><td align="right">1925</td></tr><tr><td>domInteractive</td><td align="right">17</td><td align="right">12</td><td align="right">68</td><td align="right">13</td><td align="right">14</td><td align="right">56</td></tr><tr><td>firstPaint</td><td align="right">194</td><td align="right">70</td><td align="right">407</td><td align="right">61</td><td align="right">230</td><td align="right">407</td></tr><tr><td>backgroundConnect</td><td align="right">23</td><td align="right">9</td><td align="right">76</td><td align="right">15</td><td align="right">22</td><td align="right">71</td></tr><tr><td>firstReactRender</td><td align="right">190</td><td align="right">54</td><td align="right">380</td><td align="right">119</td><td align="right">85</td><td align="right">94</td></tr><tr><td>getState</td><td align="right">9</td><td align="right">4</td><td align="right">21</td><td align="right">3</td><td align="right">8</td><td align="right">9</td></tr><tr><td>initialActions</td><td align="right">3</td><td align="right">2</td><td align="right">5</td><td align="right">1</td><td align="right">3</td><td align="right">4</td></tr><tr><td>loadScripts</td><td align="right">1608</td><td align="right">1315</td><td align="right">1968</td><td align="right">161</td><td align="right">1710</td><td align="right">1905</td></tr><tr><td>setupStore</td><td align="right">37</td><td align="right">7</td><td align="right">292</td><td align="right">71</td><td align="right">261</td><td align="right">9</td></tr><tr><td rowspan="22">Firefox</td><td rowspan="11">Browserify</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1400</td><td align="right">1186</td><td align="right">1985</td><td align="right">143</td><td align="right">1438</td><td align="right">1733</td></tr><tr><td>load</td><td align="right">1253</td><td align="right">1071</td><td align="right">1811</td><td align="right">137</td><td align="right">1305</td><td align="right">1562</td></tr><tr><td>domContentLoaded</td><td align="right">1253</td><td align="right">1070</td><td align="right">1810</td><td align="right">137</td><td align="right">1305</td><td align="right">1562</td></tr><tr><td>domInteractive</td><td align="right">97</td><td align="right">38</td><td align="right">206</td><td align="right">26</td><td align="right">88</td><td align="right">96</td></tr><tr><td>firstPaint</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td></tr><tr><td>backgroundConnect</td><td align="right">20</td><td align="right">13</td><td align="right">79</td><td align="right">9</td><td align="right">20</td><td align="right">28</td></tr><tr><td>firstReactRender</td><td align="right">23</td><td align="right">19</td><td align="right">58</td><td align="right">5</td><td align="right">23</td><td align="right">30</td></tr><tr><td>getState</td><td align="right">9</td><td align="right">4</td><td align="right">50</td><td align="right">8</td><td align="right">7</td><td align="right">8</td></tr><tr><td>initialActions</td><td align="right">0</td><td align="right">0</td><td align="right">2</td><td align="right">0</td><td align="right">0</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">1235</td><td align="right">1057</td><td align="right">1796</td><td align="right">137</td><td align="right">1292</td><td align="right">1538</td></tr><tr><td>setupStore</td><td align="right">6</td><td align="right">4</td><td align="right">31</td><td align="right">3</td><td align="right">6</td><td align="right">7</td></tr><tr><td rowspan="11">Webpack</td><td rowspan="11">Home</td><td>uiStartup</td><td align="right">1650</td><td align="right">1436</td><td align="right">2124</td><td align="right">160</td><td align="right">1738</td><td align="right">2001</td></tr><tr><td>load</td><td align="right">1412</td><td align="right">1232</td><td align="right">1887</td><td align="right">146</td><td align="right">1501</td><td align="right">1682</td></tr><tr><td>domContentLoaded</td><td align="right">1411</td><td align="right">1231</td><td align="right">1887</td><td align="right">146</td><td align="right">1500</td><td align="right">1681</td></tr><tr><td>domInteractive</td><td align="right">104</td><td align="right">41</td><td align="right">215</td><td align="right">30</td><td align="right">92</td><td align="right">98</td></tr><tr><td>firstPaint</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td><td align="right">NaN</td></tr><tr><td>backgroundConnect</td><td align="right">25</td><td align="right">16</td><td align="right">50</td><td align="right">7</td><td align="right">27</td><td align="right">43</td></tr><tr><td>firstReactRender</td><td align="right">39</td><td align="right">30</td><td align="right">72</td><td align="right">7</td><td align="right">43</td><td align="right">55</td></tr><tr><td>getState</td><td align="right">10</td><td align="right">5</td><td align="right">34</td><td align="right">7</td><td align="right">9</td><td align="right">9</td></tr><tr><td>initialActions</td><td align="right">1</td><td align="right">0</td><td align="right">2</td><td align="right">1</td><td align="right">1</td><td align="right">1</td></tr><tr><td>loadScripts</td><td align="right">1389</td><td align="right">1211</td><td align="right">1865</td><td align="right">146</td><td align="right">1476</td><td align="right">1651</td></tr><tr><td>setupStore</td><td align="right">10</td><td align="right">6</td><td align="right">48</td><td align="right">6</td><td align="right">8</td><td align="right">9</td></tr></tbody></table></details>


author_association: COLLABORATOR