fix: batch NFT ownership checks via Multicall3#8281
Conversation
| return acc; | ||
| }, | ||
| [], | ||
| ); |
There was a problem hiding this comment.
Undefined standard silently skips NFT ownership checks
Medium Severity
The filter to exclude NFTs with unrecognized standards (hasExplicitNonStandard) incorrectly treats undefined the same as an explicitly unrecognized standard like "UNKNOWN". NftMetadata.standard can be undefined at runtime (e.g., NFTs from the API when kind is falsy, or older persisted state), even though TypeScript types it as string | null. Since undefined !== null is true and normalizeNftStandard(undefined) returns null, these NFTs are silently excluded from ownership checks — they'll never be marked as no-longer-owned. The guard nft.standard !== null needs to also account for undefined (e.g., nft.standard != null using loose equality).
Additional Locations (1)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0ed9859. Configure here.
| ); | ||
| results[nftIndex].isOwned = new BN(balance.toString()).gt(new BN(0)); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Missing try-catch around multicall result decoding breaks batch
Low Severity
In getNftOwnershipViaMulticall, the forEach loop decoding multicall return data has no try-catch around decodeFunctionResult. If any single subcall returns success: true with malformed ABI data (e.g., a proxy returning unexpected bytes), the decode throws and the entire batch is lost, forcing a full fallback to individual calls for all NFTs. The individual path (getNftOwnershipIndividually) correctly wraps each decode in try-catch. Adding the same per-result error handling in the multicall path would let valid results be preserved instead of discarding the whole batch.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 0ed9859. Configure here.


Explanation
AssetsContractControllermessenger calls (getERC721OwnerOf,getERC1155BalanceOf) with a newgetNftOwnershipForMultipleNftsutility that batches ERC-721ownerOfand ERC-1155balanceOfcalls through Multicall3'saggregate3, falling back to individual RPC calls on unsupported chains or when multicall fails.checkAndUpdateSingleNftOwnershipStatusin favor ofcheckAndUpdateAllNftsOwnershipStatus, which now batches all NFTs in a single pass.standardparameter toisNftOwnerso callers that already know the token standard skip redundant subcalls.Breaking Changes
checkAndUpdateSingleNftOwnershipStatusremoved — usecheckAndUpdateAllNftsOwnershipStatusinstead.AllowedActionsnarrowed —AssetsContractController:getERC721OwnerOfandAssetsContractController:getERC1155BalanceOfare no longer required byNftController's messenger. Consumers constructing the messenger must remove these from their allowed actions list.References
https://consensyssoftware.atlassian.net/browse/ASSETS-2959
Checklist
Note
Medium Risk
Changes core NFT ownership verification logic and introduces new Multicall3 batching with fallbacks; incorrect handling could mark NFTs as owned/unowned or fail watch/add flows. Also includes breaking API/messenger surface changes that require consumer updates.
Overview
Batches NFT ownership checks via Multicall3.
NftController.isNftOwnerandcheckAndUpdateAllNftsOwnershipStatusnow call newgetNftOwnershipForMultipleNftsto batchownerOf/balanceOfcalls into fewer RPC requests, with fallback to individual RPC calls when Multicall3 is unavailable or fails.Breaking API changes. Removes
NftController.checkAndUpdateSingleNftOwnershipStatusand dropsAssetsContractController:getERC721OwnerOf/getERC1155BalanceOffromNftControllerAllowedActions; callers must stop wiring these messenger handlers. Updates tests to mock the new multicall ownership path and adds comprehensive unit coverage for the new multicall ownership helper, including standard-aware short-circuiting and unsupported/unknown-standard behavior.Reviewed by Cursor Bugbot for commit 0ed9859. Bugbot is set up for automated code reviews on this repo. Configure here.