diff --git a/packages/assets-controllers/CHANGELOG.md b/packages/assets-controllers/CHANGELOG.md index 79b8034bde..c4ae907d22 100644 --- a/packages/assets-controllers/CHANGELOG.md +++ b/packages/assets-controllers/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Correct Somnia (`5031`/`0x13a7`)'s `SPOT_PRICES_SUPPORT_INFO` entry in `codefi-v2.ts` from the invented `slip44:111115031` placeholder to `slip44:5031`, now that Somnia has a real SLIP-44 registry entry ([#9811](https://github.com/MetaMask/core/pull/9811)) +- Fix `addNft` and `addNftVerifyOwnership` not restoring `isCurrentlyOwned` when re-adding an NFT that was previously flagged as not currently owned, which left re-acquired NFTs permanently hidden in the UI ([#9787](https://github.com/MetaMask/core/issues/9787)) ## [111.1.0] diff --git a/packages/assets-controllers/src/NftController.test.ts b/packages/assets-controllers/src/NftController.test.ts index 9ebbc5e640..6198421d84 100644 --- a/packages/assets-controllers/src/NftController.test.ts +++ b/packages/assets-controllers/src/NftController.test.ts @@ -3483,6 +3483,53 @@ describe('NftController', () => { tokenURI, }); }); + + it('should restore isCurrentlyOwned when re-adding an NFT that was previously flagged as not currently owned', async () => { + const tokenURI = 'https://url/'; + const mockGetERC721TokenURI = jest.fn().mockResolvedValue(tokenURI); + const { nftController } = setupController({ + getERC721TokenURI: mockGetERC721TokenURI, + options: { + state: { + allNfts: { + [OWNER_ACCOUNT.address]: { + [ChainId.mainnet]: [ + { + address: '0x01', + chainId: convertHexToDecimal(ChainId.mainnet), + description: 'description', + image: 'url', + name: 'name', + tokenId: '1234', + standard: ERC721, + favorite: false, + isCurrentlyOwned: false, + tokenURI, + }, + ], + }, + }, + }, + }, + }); + + jest.spyOn(nftController, 'isNftOwner').mockResolvedValue(true); + + nock('https://url') + .get('/') + .reply(200, { + name: 'name', + image: 'url', + description: 'description', + }) + .persist(); + await nftController.addNftVerifyOwnership('0x01', '1234', 'mainnet'); + + expect( + nftController.state.allNfts[OWNER_ACCOUNT.address][ChainId.mainnet][0] + .isCurrentlyOwned, + ).toBe(true); + }); }); describe('removeNft', () => { diff --git a/packages/assets-controllers/src/NftController.ts b/packages/assets-controllers/src/NftController.ts index fd516e70e5..0d3654db27 100644 --- a/packages/assets-controllers/src/NftController.ts +++ b/packages/assets-controllers/src/NftController.ts @@ -951,6 +951,13 @@ export class NftController extends BaseController< allNftsForUserPerChain[chainId][indexToUpdate] = { ...existingEntry, ...nftMetadata, + // Ownership is re-confirmed on the manual import path + // (Source.Custom reaches this code only after ownership has + // been verified on-chain), so restore the flag instead of + // preserving a stale `isCurrentlyOwned: false`. + ...(source === Source.Custom + ? { isCurrentlyOwned: true } + : {}), }; } } else {