diff --git a/packages/assets-controllers/src/NftController.test.ts b/packages/assets-controllers/src/NftController.test.ts index 4342f80143..2100dee04e 100644 --- a/packages/assets-controllers/src/NftController.test.ts +++ b/packages/assets-controllers/src/NftController.test.ts @@ -3451,6 +3451,116 @@ describe('NftController', () => { }); }); + it('should not update metadata when state nft and fetched nft are the same', async () => { + const { nftController } = setupController(); + const { selectedAddress } = nftController.config; + const spy = jest.spyOn(nftController, 'updateNft'); + const testNetworkClientId = 'sepolia'; + await nftController.addNft('0xtest', '3', { + nftMetadata: { + name: 'toto', + description: 'description', + image: 'image.png', + standard: 'ERC721', + }, + networkClientId: testNetworkClientId, + }); + + sinon + .stub(nftController, 'getNftInformation' as keyof typeof nftController) + .returns({ + name: 'toto', + image: 'image.png', + description: 'description', + }); + const testInputNfts: Nft[] = [ + { + address: '0xtest', + description: 'description', + favorite: false, + image: 'image.png', + isCurrentlyOwned: true, + name: 'toto', + standard: 'ERC721', + tokenId: '3', + }, + ]; + + await nftController.updateNftMetadata({ + nfts: testInputNfts, + networkClientId: testNetworkClientId, + }); + + expect(spy).toHaveBeenCalledTimes(0); + expect( + nftController.state.allNfts[selectedAddress][SEPOLIA.chainId][0], + ).toStrictEqual({ + address: '0xtest', + description: 'description', + favorite: false, + image: 'image.png', + isCurrentlyOwned: true, + name: 'toto', + standard: 'ERC721', + tokenId: '3', + }); + }); + + it('should trigger update metadata when state nft and fetched nft are not the same', async () => { + const { nftController } = setupController(); + const { selectedAddress } = nftController.config; + const spy = jest.spyOn(nftController, 'updateNft'); + const testNetworkClientId = 'sepolia'; + await nftController.addNft('0xtest', '3', { + nftMetadata: { + name: 'toto', + description: 'description', + image: 'image.png', + standard: 'ERC721', + }, + networkClientId: testNetworkClientId, + }); + + sinon + .stub(nftController, 'getNftInformation' as keyof typeof nftController) + .returns({ + name: 'toto', + image: 'image-updated.png', + description: 'description', + }); + const testInputNfts: Nft[] = [ + { + address: '0xtest', + description: 'description', + favorite: false, + image: 'image.png', + isCurrentlyOwned: true, + name: 'toto', + standard: 'ERC721', + tokenId: '3', + }, + ]; + + await nftController.updateNftMetadata({ + nfts: testInputNfts, + networkClientId: testNetworkClientId, + }); + + expect(spy).toHaveBeenCalledTimes(1); + expect( + nftController.state.allNfts[selectedAddress][SEPOLIA.chainId][0], + ).toStrictEqual({ + address: '0xtest', + description: 'description', + favorite: false, + image: 'image-updated.png', + isCurrentlyOwned: true, + name: 'toto', + standard: 'ERC721', + tokenId: '3', + }); + }); + it('should not update metadata when calls to fetch metadata fail', async () => { const { nftController } = setupController(); const { selectedAddress } = nftController.config; diff --git a/packages/assets-controllers/src/NftController.ts b/packages/assets-controllers/src/NftController.ts index 9061b8f180..580f1a7c39 100644 --- a/packages/assets-controllers/src/NftController.ts +++ b/packages/assets-controllers/src/NftController.ts @@ -1416,13 +1416,37 @@ export class NftController extends BaseControllerV1 { }; }), ); + const successfulNewFetchedNfts = nftMetadataResults.filter( + (result): result is PromiseFulfilledResult => + result.status === 'fulfilled', + ); + // We want to avoid updating the state if the state and fetched nft info are the same + const nftsWithDifferentMetadata: PromiseFulfilledResult[] = []; + const { allNfts } = this.state; + const stateNfts = allNfts[userAddress]?.[chainId] || []; + + successfulNewFetchedNfts.forEach((singleNft) => { + const existingEntry: Nft | undefined = stateNfts.find( + (nft) => + nft.address.toLowerCase() === + singleNft.value.nft.address.toLowerCase() && + nft.tokenId === singleNft.value.nft.tokenId, + ); - nftMetadataResults - .filter( - (result): result is PromiseFulfilledResult => - result.status === 'fulfilled', - ) - .forEach((elm) => + if (existingEntry) { + const differentMetadata = compareNftMetadata( + singleNft.value.newMetadata, + existingEntry, + ); + + if (differentMetadata) { + nftsWithDifferentMetadata.push(singleNft); + } + } + }); + + if (nftsWithDifferentMetadata.length !== 0) { + nftsWithDifferentMetadata.forEach((elm) => this.updateNft( elm.value.nft, elm.value.newMetadata, @@ -1430,6 +1454,7 @@ export class NftController extends BaseControllerV1 { chainId, ), ); + } } /**