fix: NFT ownership status not refreshing across all enabled networks when pulling to refresh#28655
Merged
Conversation
4 tasks
github-merge-queue Bot
pushed a commit
to MetaMask/core
that referenced
this pull request
Apr 10, 2026
## Explanation - Replace individual `AssetsContractController` messenger calls (`getERC721OwnerOf`, `getERC1155BalanceOf`) with a new `getNftOwnershipForMultipleNfts` utility that batches ERC-721 `ownerOf` and ERC-1155 `balanceOf` calls through Multicall3's `aggregate3`, falling back to individual RPC calls on unsupported chains or when multicall fails. - Remove `checkAndUpdateSingleNftOwnershipStatus` in favor of `checkAndUpdateAllNftsOwnershipStatus`, which now batches all NFTs in a single pass. - Add an optional `standard` parameter to `isNftOwner` so callers that already know the token standard skip redundant subcalls. - `checkAndUpdateAllNftsOwnershipStatus` now removes NFTs confirmed as unowned from state rather than retaining them with `isCurrentlyOwned: false`. The "Previously Owned" NFT feature this flag powered is no longer supported. **Breaking Changes** - **`checkAndUpdateSingleNftOwnershipStatus` removed** — use `checkAndUpdateAllNftsOwnershipStatus` instead. - **`AllowedActions` narrowed** — `AssetsContractController:getERC721OwnerOf` and `AssetsContractController:getERC1155BalanceOf` are no longer required by `NftController`'s messenger. Consumers constructing the messenger must remove these from their allowed actions list. <!-- Thanks for your contribution! Take a moment to answer these questions so that reviewers have the information they need to properly understand your changes: * What is the current state of things and why does it need to change? * What is the solution your changes offer and how does it work? * Are there any changes whose purpose might not obvious to those unfamiliar with the domain? * If your primary goal was to update one package but you found you had to update another one along the way, why did you do so? * If you had to upgrade a dependency, why did you do so? --> ## References Ticket: https://consensyssoftware.atlassian.net/browse/ASSETS-2959 PR on Mobile: MetaMask/metamask-mobile#28655 PR on Extension: <!-- Are there any issues that this pull request is tied to? Are there other links that reviewers should consult to understand these changes better? Are there client or consumer pull requests to adopt any breaking changes? For example: * Fixes #12345 * Related to #67890 --> ## 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](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk due to breaking API surface (`AllowedActions` narrowed, `checkAndUpdateSingleNftOwnershipStatus` removed) and changed state semantics (unowned NFTs are deleted), plus new multicall batching logic that could affect ownership determination across networks. > > **Overview** > **NFT ownership checks are refactored to batch on-chain calls via Multicall3.** `NftController.isNftOwner` and `checkAndUpdateAllNftsOwnershipStatus` now use the new `getNftOwnershipForMultipleNfts` helper to aggregate ERC-721 `ownerOf` / ERC-1155 `balanceOf` calls (with fallback to individual calls when multicall/chain support is unavailable), and callers can pass an optional `standard` to skip unnecessary subcalls. > > **Breaking behavior changes:** `AssetsContractController:getERC721OwnerOf` and `AssetsContractController:getERC1155BalanceOf` are removed from `NftController` `AllowedActions`, `checkAndUpdateSingleNftOwnershipStatus` is removed, and ownership refresh now **removes NFTs confirmed as unowned** from state instead of setting `isCurrentlyOwned: false`. Tests and changelog are updated accordingly, and `multicall` gains comprehensive coverage for the new NFT ownership batching utility. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f782f90. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Prithpal-Sooriya
previously approved these changes
Apr 16, 2026
sahar-fehri
previously approved these changes
Apr 16, 2026
…etamask-mobile into fix/nft-refresh-use-multicall
4df107d
Contributor
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection: Performance Test Selection: |
|
Contributor
|
✅ E2E Fixture Validation — Schema is up to date |
Prithpal-Sooriya
approved these changes
Apr 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
When the user selects "All popular networks" and pulls to refresh on the NFT grid,
checkAndUpdateAllNftsOwnershipStatuswas only being called for a subset of the enabled networks — or potentially only mainnet — because the hook derived its chain list fromselectTokenNetworkFilter(aPreferencesControllervalue) intersected withselectEvmNetworkConfigurationsByChainId(networks the user has manually added). Any popular network the user hadn't explicitly added would be silently dropped.This fix replaces that incorrect source of truth with
chainIdsToDetectNftsForfrom the existinguseNftDetectionhook, which is already the canonical chain list used bydetectNfts()itself (derived fromNetworkEnablementController.enabledNetworkMap). Now bothdetectNfts()andcheckAndUpdateAllNftsOwnershipStatus()operate on the exact same set of networks, regardless of which network filter the user has selected.Additionally updates
@metamask/assets-controllersand removes the now-unusedAssetsContractController:getERC721OwnerOfandAssetsContractController:getERC1155BalanceOfmessenger action allowances from the NftController messenger (these were removed upstream).Changelog
CHANGELOG entry: fixed NFT ownership status not refreshing across all enabled networks when pulling to refresh
Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-2959 & https://consensyssoftware.atlassian.net/browse/ASSETS-2976
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Touches NFT refresh behavior and upgrades
@metamask/assets-controllers, which could subtly change which networks are queried and how the NFT controller interacts with upstream controller APIs.Overview
Fixes pull-to-refresh on the NFT grid so ownership status updates run across the same enabled chain set used by NFT detection.
useNftRefreshnow derives network client IDs fromuseNftDetection().chainIdsToDetectNftsFor(instead ofselectTokenNetworkFilter), ensuring all enabled/popular networks getcheckAndUpdateAllNftsOwnershipStatuscalls.Updates unit tests to cover the "All popular networks" case, empty-enabled-chain behavior, and undefined client IDs. Also bumps
@metamask/assets-controllersto^104.0.0and removes now-unused messenger action allowances (AssetsContractController:getERC721OwnerOf,AssetsContractController:getERC1155BalanceOf).Reviewed by Cursor Bugbot for commit 4df107d. Bugbot is set up for automated code reviews on this repo. Configure here.