Skip to content

Conversation

salimtb
Copy link
Contributor

@salimtb salimtb commented Aug 14, 2025

Explanation

Problem

The selectedNetworkClientId parameter was being passed as a static string value, which could become stale and frozen after controller reinitialization. This led to the controller potentially using outdated network client IDs, especially during network switches or controller restarts.

Solution

Controller Changes:

  • Modified selectedNetworkClientId parameter from string to () => string function
  • This ensures the network client ID is dynamically evaluated each time it's accessed
  • Prevents stale values from being cached during controller lifecycle

Test Updates:

  • Updated test setup function to expect function type instead of string
  • Fixed 4 test cases that were incorrectly passing string literals
  • Maintained 100% test coverage with all tests passing

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

@salimtb salimtb force-pushed the fix/add-selected-chain-as-function branch from 639453d to 09aab69 Compare August 14, 2025 15:00
@salimtb salimtb marked this pull request as ready for review August 14, 2025 15:01
@salimtb salimtb requested review from a team as code owners August 14, 2025 15:01
@ameliejyc
Copy link
Contributor

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "0.8.0-preview-09aab698",
  "@metamask-previews/accounts-controller": "32.0.2-preview-09aab698",
  "@metamask-previews/address-book-controller": "6.1.1-preview-09aab698",
  "@metamask-previews/announcement-controller": "7.0.3-preview-09aab698",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-09aab698",
  "@metamask-previews/approval-controller": "7.1.3-preview-09aab698",
  "@metamask-previews/assets-controllers": "73.1.0-preview-09aab698",
  "@metamask-previews/base-controller": "8.1.0-preview-09aab698",
  "@metamask-previews/bridge-controller": "39.0.1-preview-09aab698",
  "@metamask-previews/bridge-status-controller": "38.0.1-preview-09aab698",
  "@metamask-previews/build-utils": "3.0.3-preview-09aab698",
  "@metamask-previews/chain-agnostic-permission": "1.1.0-preview-09aab698",
  "@metamask-previews/composable-controller": "11.0.0-preview-09aab698",
  "@metamask-previews/controller-utils": "11.12.0-preview-09aab698",
  "@metamask-previews/delegation-controller": "0.6.0-preview-09aab698",
  "@metamask-previews/earn-controller": "5.0.0-preview-09aab698",
  "@metamask-previews/eip1193-permission-middleware": "1.0.0-preview-09aab698",
  "@metamask-previews/ens-controller": "17.0.1-preview-09aab698",
  "@metamask-previews/error-reporting-service": "2.0.0-preview-09aab698",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-09aab698",
  "@metamask-previews/foundryup": "1.0.1-preview-09aab698",
  "@metamask-previews/gas-fee-controller": "24.0.0-preview-09aab698",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-09aab698",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-09aab698",
  "@metamask-previews/keyring-controller": "22.1.1-preview-09aab698",
  "@metamask-previews/logging-controller": "6.0.4-preview-09aab698",
  "@metamask-previews/message-manager": "12.0.2-preview-09aab698",
  "@metamask-previews/messenger": "0.0.0-preview-09aab698",
  "@metamask-previews/multichain-account-service": "0.4.0-preview-09aab698",
  "@metamask-previews/multichain-api-middleware": "1.0.0-preview-09aab698",
  "@metamask-previews/multichain-network-controller": "0.11.1-preview-09aab698",
  "@metamask-previews/multichain-transactions-controller": "4.0.1-preview-09aab698",
  "@metamask-previews/name-controller": "8.0.3-preview-09aab698",
  "@metamask-previews/network-controller": "24.1.0-preview-09aab698",
  "@metamask-previews/network-enablement-controller": "0.1.1-preview-09aab698",
  "@metamask-previews/notification-services-controller": "16.0.0-preview-09aab698",
  "@metamask-previews/permission-controller": "11.0.6-preview-09aab698",
  "@metamask-previews/permission-log-controller": "4.0.0-preview-09aab698",
  "@metamask-previews/phishing-controller": "13.1.0-preview-09aab698",
  "@metamask-previews/polling-controller": "14.0.0-preview-09aab698",
  "@metamask-previews/preferences-controller": "18.4.1-preview-09aab698",
  "@metamask-previews/profile-sync-controller": "23.0.0-preview-09aab698",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-09aab698",
  "@metamask-previews/remote-feature-flag-controller": "1.7.0-preview-09aab698",
  "@metamask-previews/sample-controllers": "1.0.0-preview-09aab698",
  "@metamask-previews/seedless-onboarding-controller": "2.6.0-preview-09aab698",
  "@metamask-previews/selected-network-controller": "23.0.0-preview-09aab698",
  "@metamask-previews/signature-controller": "32.0.0-preview-09aab698",
  "@metamask-previews/token-search-discovery-controller": "3.3.0-preview-09aab698",
  "@metamask-previews/transaction-controller": "59.2.0-preview-09aab698",
  "@metamask-previews/user-operation-controller": "38.0.0-preview-09aab698"
}

Copy link
Contributor

@ameliejyc ameliejyc left a comment

Choose a reason for hiding this comment

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

I've tested with alongside the mobile code and it looks good to me. But to understand this edge case better, when you say the network client ID "could become stale and frozen after controller reinitialization" can you give an example of how this would happen? The network client ID is always refreshed in the networkDidChange listener so I don't see it becoming stale there.

Copy link
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Had some concerns about the approach here.

state?: Partial<EarnControllerState>;
addTransactionFn: typeof TransactionController.prototype.addTransaction;
selectedNetworkClientId: string;
selectedNetworkClientId: () => string;
Copy link
Contributor

@mcmire mcmire Aug 14, 2025

Choose a reason for hiding this comment

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

Hmm, this is not something we typically have to do in any other controller, so this is surprising to me that we have to do this. In your PR description you mention that it is necessary after the controller is reinitialized. When would this occur? I know that the Engine gets reinitialized in mobile in certain cases but usually all controllers get reinitialized when this happens and so the NetworkController should be up to date. (Edit: I see that @ameliejyc expressed some similar concerns.)

If we still think this is necessary, have you considered moving the asynchronous operations in this controller to an init function? You should then be able to get the selectedNetworkClientId from NetworkController by going through its state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mcmire the main issue was race conditions, but you're right moving to the init function should resolve it. I’ll proceed with this approach instead on the client side and close this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

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

or maybe you mean init function inside the EarnController ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Either an init method in EarnController or using the init pattern on the client side should work, whichever makes sense.

@salimtb salimtb closed this Aug 14, 2025
@salimtb salimtb reopened this Aug 14, 2025
@salimtb
Copy link
Contributor Author

salimtb commented Aug 14, 2025

The new init approach should resolve the race conditions on the client side, so I’m closing this PR.

@salimtb salimtb closed this Aug 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants