From 9bc864d0d1b9dcf9ac3cb04c1dda76e427d01989 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Wed, 12 Oct 2022 14:11:08 -0230 Subject: [PATCH 1/2] Rename "Collectible" to "NFT" The term "collectible" has been replaced by "NFT" everywhere. The term "collectible" was originally used because it was thought NFT would be more difficult for users to understand, but today in practice we all use the term NFT. Efforts to use the term "collectible" have long been abandoned. --- src/ComposableController.test.ts | 34 +- src/assets/AssetsContractController.test.ts | 24 +- src/assets/AssetsContractController.ts | 38 +- ...ntroller.test.ts => NftController.test.ts} | 922 ++++++++---------- ...ectiblesController.ts => NftController.ts} | 873 ++++++++--------- ...test.ts => NftDetectionController.test.ts} | 305 +++--- ...ontroller.ts => NftDetectionController.ts} | 288 +++--- .../ERC1155/ERC1155Standard.test.ts | 0 .../ERC1155/ERC1155Standard.ts | 0 .../ERC721/ERC721Standard.test.ts | 0 .../ERC721/ERC721Standard.ts | 4 +- src/assets/TokensController.test.ts | 16 +- src/assets/assetsUtil.test.ts | 31 +- src/assets/assetsUtil.ts | 24 +- src/constants.ts | 2 +- src/index.ts | 4 +- src/user/PreferencesController.test.ts | 8 +- src/user/PreferencesController.ts | 18 +- 18 files changed, 1162 insertions(+), 1429 deletions(-) rename src/assets/{CollectiblesController.test.ts => NftController.test.ts} (63%) rename src/assets/{CollectiblesController.ts => NftController.ts} (51%) rename src/assets/{CollectibleDetectionController.test.ts => NftDetectionController.test.ts} (66%) rename src/assets/{CollectibleDetectionController.ts => NftDetectionController.ts} (50%) rename src/assets/Standards/{CollectibleStandards => NftStandards}/ERC1155/ERC1155Standard.test.ts (100%) rename src/assets/Standards/{CollectibleStandards => NftStandards}/ERC1155/ERC1155Standard.ts (100%) rename src/assets/Standards/{CollectibleStandards => NftStandards}/ERC721/ERC721Standard.test.ts (100%) rename src/assets/Standards/{CollectibleStandards => NftStandards}/ERC721/ERC721Standard.ts (98%) diff --git a/src/ComposableController.test.ts b/src/ComposableController.test.ts index 57d45b6dc74..0f1570e7f3d 100644 --- a/src/ComposableController.test.ts +++ b/src/ComposableController.test.ts @@ -1,7 +1,7 @@ import sinon from 'sinon'; import type { Patch } from 'immer'; import { TokensController } from './assets/TokensController'; -import { CollectiblesController } from './assets/CollectiblesController'; +import { NftController } from './assets/NftController'; import { AddressBookController } from './user/AddressBookController'; import { EnsController } from './third-party/EnsController'; import { @@ -123,7 +123,7 @@ const setupControllers = () => { messenger.subscribe('NetworkController:stateChange', listener), }); - const collectiblesController = new CollectiblesController({ + const nftController = new NftController({ onPreferencesStateChange: (listener) => preferencesController.subscribe(listener), onNetworkStateChange: (listener) => @@ -146,7 +146,7 @@ const setupControllers = () => { getERC1155TokenURI: assetContractController.getERC1155TokenURI.bind( assetContractController, ), - onCollectibleAdded: jest.fn(), + onNftAdded: jest.fn(), }); const tokensController = new TokensController({ @@ -162,7 +162,7 @@ const setupControllers = () => { networkController, preferencesController, assetContractController, - collectiblesController, + nftController, tokensController, }; }; @@ -179,7 +179,7 @@ describe('ComposableController', () => { composableMessenger, networkController, assetContractController, - collectiblesController, + nftController, tokensController, preferencesController, } = setupControllers(); @@ -187,7 +187,7 @@ describe('ComposableController', () => { const controller = new ComposableController( [ new AddressBookController(), - collectiblesController, + nftController, assetContractController, new EnsController(), networkController, @@ -200,10 +200,10 @@ describe('ComposableController', () => { expect(controller.state).toStrictEqual({ AddressBookController: { addressBook: {} }, AssetsContractController: {}, - CollectiblesController: { - allCollectibleContracts: {}, - allCollectibles: {}, - ignoredCollectibles: [], + NftController: { + allNftContracts: {}, + allNfts: {}, + ignoredNfts: [], }, TokensController: { allTokens: {}, @@ -231,7 +231,7 @@ describe('ComposableController', () => { lostIdentities: {}, selectedAddress: '', useTokenDetection: true, - useCollectibleDetection: false, + useNftDetection: false, openSeaEnabled: false, }, }); @@ -245,7 +245,7 @@ describe('ComposableController', () => { composableMessenger, networkController, assetContractController, - collectiblesController, + nftController, tokensController, preferencesController, } = setupControllers(); @@ -253,7 +253,7 @@ describe('ComposableController', () => { const controller = new ComposableController( [ new AddressBookController(), - collectiblesController, + nftController, assetContractController, new EnsController(), networkController, @@ -264,14 +264,14 @@ describe('ComposableController', () => { ); expect(controller.flatState).toStrictEqual({ addressBook: {}, - allCollectibleContracts: {}, - allCollectibles: {}, + allNftContracts: {}, + allNfts: {}, allTokens: {}, ensEntries: {}, featureFlags: {}, frequentRpcList: [], identities: {}, - ignoredCollectibles: [], + ignoredNfts: [], ignoredTokens: [], allIgnoredTokens: {}, detectedTokens: [], @@ -284,7 +284,7 @@ describe('ComposableController', () => { provider: { type: 'mainnet', chainId: NetworksChainId.mainnet }, selectedAddress: '', useTokenDetection: true, - useCollectibleDetection: false, + useNftDetection: false, openSeaEnabled: false, suggestedAssets: [], tokens: [], diff --git a/src/assets/AssetsContractController.test.ts b/src/assets/AssetsContractController.test.ts index 566c1e00dbf..3f45988e26f 100644 --- a/src/assets/AssetsContractController.test.ts +++ b/src/assets/AssetsContractController.test.ts @@ -120,10 +120,10 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get ERC-721 collectible tokenId correctly', async () => { + it('should get ERC-721 NFT tokenId correctly', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const tokenId = await assetsContract.getERC721CollectibleTokenId( + const tokenId = await assetsContract.getERC721NftTokenId( ERC721_GODS_ADDRESS, '0x9a90bd8d1149a88b42a99cf62215ad955d6f498a', 0, @@ -190,7 +190,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get ERC-721 collectible tokenURI correctly', async () => { + it('should get ERC-721 NFT tokenURI correctly', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const tokenId = await assetsContract.getERC721TokenURI( @@ -201,7 +201,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should throw an error when address given is not an ERC-721 collectible', async () => { + it('should throw an error when address given is not an ERC-721 NFT', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const result = async () => { @@ -216,7 +216,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get ERC-721 collectible name', async () => { + it('should get ERC-721 NFT name', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const name = await assetsContract.getERC721AssetName(ERC721_GODS_ADDRESS); @@ -224,7 +224,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get ERC-721 collectible symbol', async () => { + it('should get ERC-721 NFT symbol', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const symbol = await assetsContract.getERC721AssetSymbol( @@ -234,7 +234,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should throw missing provider error when getting ERC-721 collectible symbol when missing provider', async () => { + it('should throw missing provider error when getting ERC-721 NFT symbol when missing provider', async () => { const { assetsContract, messenger } = setupControllers(); await expect( assetsContract.getERC721AssetSymbol(ERC721_GODS_ADDRESS), @@ -252,7 +252,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get ERC-721 collectible ownership', async () => { + it('should get ERC-721 NFT ownership', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const tokenId = await assetsContract.getERC721OwnerOf( @@ -263,7 +263,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should throw missing provider error when getting ERC-721 collectible ownership', async () => { + it('should throw missing provider error when getting ERC-721 NFT ownership', async () => { const { assetsContract, messenger } = setupControllers(); await expect( assetsContract.getERC721OwnerOf(ERC721_GODS_ADDRESS, '148332'), @@ -319,7 +319,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get the balance of a ERC-1155 collectible for a given address', async () => { + it('should get the balance of a ERC-1155 NFT for a given address', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const balance = await assetsContract.getERC1155BalanceOf( @@ -331,7 +331,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should throw missing provider error when getting the balance of a ERC-1155 collectible when missing provider', async () => { + it('should throw missing provider error when getting the balance of a ERC-1155 NFT when missing provider', async () => { const { assetsContract, messenger } = setupControllers(); await expect( assetsContract.getERC1155BalanceOf( @@ -343,7 +343,7 @@ describe('AssetsContractController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should get the URI of a ERC-1155 collectible', async () => { + it('should get the URI of a ERC-1155 NFT', async () => { const { assetsContract, messenger } = setupControllers(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const expectedUri = `https://api.opensea.io/api/v1/metadata/${ERC1155_ADDRESS}/0x{id}`; diff --git a/src/assets/AssetsContractController.ts b/src/assets/AssetsContractController.ts index 12af9dd9533..ef79c38756d 100644 --- a/src/assets/AssetsContractController.ts +++ b/src/assets/AssetsContractController.ts @@ -6,8 +6,8 @@ import type { PreferencesState } from '../user/PreferencesController'; import { IPFS_DEFAULT_GATEWAY_URL } from '../constants'; import { SupportedTokenDetectionNetworks } from '../util'; import { NetworkState } from '../network/NetworkController'; -import { ERC721Standard } from './Standards/CollectibleStandards/ERC721/ERC721Standard'; -import { ERC1155Standard } from './Standards/CollectibleStandards/ERC1155/ERC1155Standard'; +import { ERC721Standard } from './Standards/NftStandards/ERC721/ERC721Standard'; +import { ERC1155Standard } from './Standards/NftStandards/ERC1155/ERC1155Standard'; import { ERC20Standard } from './Standards/ERC20Standard'; /** @@ -170,10 +170,10 @@ export class AssetsContractController extends BaseController< * * @param address - ERC721 asset contract address. * @param selectedAddress - Current account public address. - * @param index - A collectible counter less than `balanceOf(selectedAddress)`. + * @param index - An NFT counter less than `balanceOf(selectedAddress)`. * @returns Promise resolving to token identifier for the 'index'th asset assigned to 'selectedAddress'. */ - getERC721CollectibleTokenId( + getERC721NftTokenId( address: string, selectedAddress: string, index: number, @@ -181,11 +181,7 @@ export class AssetsContractController extends BaseController< if (this.erc721Standard === undefined) { throw new Error(MISSING_PROVIDER_ERROR); } - return this.erc721Standard.getCollectibleTokenId( - address, - selectedAddress, - index, - ); + return this.erc721Standard.getNftTokenId(address, selectedAddress, index); } /** @@ -328,50 +324,50 @@ export class AssetsContractController extends BaseController< * Query for balance of a given ERC 1155 token. * * @param userAddress - Wallet public address. - * @param collectibleAddress - ERC1155 asset contract address. - * @param collectibleId - ERC1155 asset identifier. + * @param nftAddress - ERC1155 asset contract address. + * @param nftId - ERC1155 asset identifier. * @returns Promise resolving to the 'balanceOf'. */ async getERC1155BalanceOf( userAddress: string, - collectibleAddress: string, - collectibleId: string, + nftAddress: string, + nftId: string, ): Promise { if (this.erc1155Standard === undefined) { throw new Error(MISSING_PROVIDER_ERROR); } return await this.erc1155Standard.getBalanceOf( - collectibleAddress, + nftAddress, userAddress, - collectibleId, + nftId, ); } /** * Transfer single ERC1155 token. * - * @param collectibleAddress - ERC1155 token address. + * @param nftAddress - ERC1155 token address. * @param senderAddress - ERC1155 token sender. * @param recipientAddress - ERC1155 token recipient. - * @param collectibleId - ERC1155 token id. + * @param nftId - ERC1155 token id. * @param qty - Quantity of tokens to be sent. * @returns Promise resolving to the 'transferSingle' ERC1155 token. */ async transferSingleERC1155( - collectibleAddress: string, + nftAddress: string, senderAddress: string, recipientAddress: string, - collectibleId: string, + nftId: string, qty: string, ): Promise { if (this.erc1155Standard === undefined) { throw new Error(MISSING_PROVIDER_ERROR); } return await this.erc1155Standard.transferSingle( - collectibleAddress, + nftAddress, senderAddress, recipientAddress, - collectibleId, + nftId, qty, ); } diff --git a/src/assets/CollectiblesController.test.ts b/src/assets/NftController.test.ts similarity index 63% rename from src/assets/CollectiblesController.test.ts rename to src/assets/NftController.test.ts index e3d9e675d0c..bacbd839d67 100644 --- a/src/assets/CollectiblesController.test.ts +++ b/src/assets/NftController.test.ts @@ -17,16 +17,15 @@ import { } from '../constants'; import { ControllerMessenger } from '../ControllerMessenger'; import { AssetsContractController } from './AssetsContractController'; -import { CollectiblesController } from './CollectiblesController'; +import { NftController } from './NftController'; const CRYPTOPUNK_ADDRESS = '0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB'; const ERC721_KUDOSADDRESS = '0x2aEa4Add166EBf38b63d09a75dE1a7b94Aa24163'; const ERC721_KUDOS_TOKEN_ID = '1203'; -const ERC721_COLLECTIBLE_ADDRESS = '0x60F80121C31A0d46B5279700f9DF786054aa5eE5'; -const ERC721_COLLECTIBLE_ID = '1144858'; -const ERC1155_COLLECTIBLE_ADDRESS = - '0x495f947276749Ce646f68AC8c248420045cb7b5e'; -const ERC1155_COLLECTIBLE_ID = +const ERC721_NFT_ADDRESS = '0x60F80121C31A0d46B5279700f9DF786054aa5eE5'; +const ERC721_NFT_ID = '1144858'; +const ERC1155_NFT_ADDRESS = '0x495f947276749Ce646f68AC8c248420045cb7b5e'; +const ERC1155_NFT_ID = '40815311521795738946686668571398122012172359753720345430028676522525371400193'; const ERC721_DEPRESSIONIST_ADDRESS = '0x18E8E76aeB9E2d9FA2A2b88DD9CF3C8ED45c3660'; @@ -50,12 +49,12 @@ const DEPRESSIONIST_CLOUDFLARE_IPFS_SUBDOMAIN_PATH = getFormattedIpfsUrl( * Setup a test controller instance. * * @param options - Controller options. - * @param options.includeOnCollectibleAdded - Whether to include the "onCollectibleAdded" parameter. + * @param options.includeOnNftAdded - Whether to include the "onNftAdded" parameter. * @returns A collection of test controllers and stubs. */ function setupController({ - includeOnCollectibleAdded = false, -}: { includeOnCollectibleAdded?: boolean } = {}) { + includeOnNftAdded = false, +}: { includeOnNftAdded?: boolean } = {}) { const messenger: NetworkControllerMessenger = new ControllerMessenger().getRestricted({ name: 'NetworkController', @@ -72,11 +71,9 @@ function setupController({ onNetworkStateChange: (listener) => messenger.subscribe('NetworkController:stateChange', listener), }); - const onCollectibleAddedSpy = includeOnCollectibleAdded - ? jest.fn() - : undefined; + const onNftAddedSpy = includeOnNftAdded ? jest.fn() : undefined; - const collectiblesController = new CollectiblesController({ + const nftController = new NftController({ onPreferencesStateChange: (listener) => preferences.subscribe(listener), onNetworkStateChange: (listener) => messenger.subscribe('NetworkController:stateChange', listener), @@ -88,7 +85,7 @@ function setupController({ getERC1155BalanceOf: assetsContract.getERC1155BalanceOf.bind(assetsContract), getERC1155TokenURI: assetsContract.getERC1155TokenURI.bind(assetsContract), - onCollectibleAdded: onCollectibleAddedSpy, + onNftAdded: onNftAddedSpy, }); preferences.update({ @@ -98,15 +95,15 @@ function setupController({ return { assetsContract, - collectiblesController, + nftController, network, - onCollectibleAddedSpy, + onNftAddedSpy, preferences, messenger, }; } -describe('CollectiblesController', () => { +describe('NftController', () => { beforeAll(() => { nock.disableNetConnect(); }); @@ -155,7 +152,7 @@ describe('CollectiblesController', () => { .replyWithError(new TypeError('Failed to fetch')); nock(OPENSEA_PROXY_URL) - .get(`/asset/${ERC1155_COLLECTIBLE_ADDRESS}/${ERC1155_COLLECTIBLE_ID}`) + .get(`/asset/${ERC1155_NFT_ADDRESS}/${ERC1155_NFT_ID}`) .reply(200, { num_sales: 1, image_original_url: 'image.uri', @@ -178,22 +175,22 @@ describe('CollectiblesController', () => { }); it('should set default state', () => { - const { collectiblesController, messenger } = setupController(); + const { nftController, messenger } = setupController(); - expect(collectiblesController.state).toStrictEqual({ - allCollectibleContracts: {}, - allCollectibles: {}, - ignoredCollectibles: [], + expect(nftController.state).toStrictEqual({ + allNftContracts: {}, + allNfts: {}, + ignoredNfts: [], }); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - describe('addCollectible', () => { - it('should add collectible and collectible contract', async () => { - const { collectiblesController, messenger } = setupController(); + describe('addNft', () => { + it('should add NFT and NFT contract', async () => { + const { nftController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x01', '1', { + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -202,9 +199,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'description', @@ -217,9 +212,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ][0], + nftController.state.allNftContracts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'Description', @@ -232,11 +225,12 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should call onCollectibleAdded callback correctly when collectible is manually added', async () => { - const { collectiblesController, onCollectibleAddedSpy, messenger } = - setupController({ includeOnCollectibleAdded: true }); + it('should call onNftAdded callback correctly when NFT is manually added', async () => { + const { nftController, onNftAddedSpy, messenger } = setupController({ + includeOnNftAdded: true, + }); - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -244,7 +238,7 @@ describe('CollectiblesController', () => { favorite: false, }); - expect(onCollectibleAddedSpy).toHaveBeenCalledWith({ + expect(onNftAddedSpy).toHaveBeenCalledWith({ source: 'custom', tokenId: '1', address: '0x01', @@ -255,12 +249,13 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should call onCollectibleAdded callback correctly when collectible is added via detection', async () => { - const { collectiblesController, onCollectibleAddedSpy, messenger } = - setupController({ includeOnCollectibleAdded: true }); + it('should call onNftAdded callback correctly when NFT is added via detection', async () => { + const { nftController, onNftAddedSpy, messenger } = setupController({ + includeOnNftAdded: true, + }); const detectedUserAddress = '0x123'; - await collectiblesController.addCollectible( + await nftController.addNft( '0x01', '2', { @@ -270,11 +265,11 @@ describe('CollectiblesController', () => { standard: 'ERC721', favorite: false, }, - // this object in the third argument slot is only defined when the collectible is added via detection + // this object in the third argument slot is only defined when the NFT is added via detection { userAddress: detectedUserAddress, chainId: '0x2' }, ); - expect(onCollectibleAddedSpy).toHaveBeenCalledWith({ + expect(onNftAddedSpy).toHaveBeenCalledWith({ source: 'detected', tokenId: '2', address: '0x01', @@ -285,23 +280,22 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible by selected address', async () => { - const { collectiblesController, preferences, messenger } = - setupController(); - const { chainId } = collectiblesController.config; + it('should add NFT by selected address', async () => { + const { nftController, preferences, messenger } = setupController(); + const { chainId } = nftController.config; const firstAddress = '0x123'; const secondAddress = '0x321'; sinon - .stub(collectiblesController, 'getCollectibleInformation' as any) + .stub(nftController, 'getNftInformation' as any) .returns({ name: 'name', image: 'url', description: 'description' }); preferences.update({ selectedAddress: firstAddress }); - await collectiblesController.addCollectible('0x01', '1234'); + await nftController.addNft('0x01', '1234'); preferences.update({ selectedAddress: secondAddress }); - await collectiblesController.addCollectible('0x02', '4321'); + await nftController.addNft('0x02', '4321'); preferences.update({ selectedAddress: firstAddress }); expect( - collectiblesController.state.allCollectibles[firstAddress][chainId][0], + nftController.state.allNfts[firstAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'description', @@ -315,11 +309,11 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should update collectible if image is different', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + it('should update NFT if image is different', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -328,9 +322,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'description', @@ -342,7 +334,7 @@ describe('CollectiblesController', () => { isCurrentlyOwned: true, }); - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image-updated', description: 'description', @@ -351,9 +343,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'description', @@ -368,10 +358,10 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not duplicate collectible nor collectible contract if already added', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x01', '1', { + it('should not duplicate NFT nor NFT contract if already added', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -379,7 +369,7 @@ describe('CollectiblesController', () => { favorite: false, }); - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -388,27 +378,23 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], + nftController.state.allNftContracts[selectedAddress][chainId], ).toHaveLength(1); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible and get information from OpenSea', async () => { - const { collectiblesController, messenger } = setupController(); + it('should add NFT and get information from OpenSea', async () => { + const { nftController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x01', '1'); + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x01', '1'); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'Description', @@ -424,9 +410,8 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible erc721 and aggregate collectible data from both contract and OpenSea', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should add NFT erc721 and aggregate NFT data from both contract and OpenSea', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock(OPENSEA_PROXY_URL) .get(`/asset/${ERC721_KUDOSADDRESS}/${ERC721_KUDOS_TOKEN_ID}`) .reply(200, { @@ -531,23 +516,15 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; sinon - .stub( - collectiblesController, - 'getCollectibleContractInformationFromApi' as any, - ) + .stub(nftController, 'getNftContractInformationFromApi' as any) .returns(undefined); - await collectiblesController.addCollectible( - ERC721_KUDOSADDRESS, - ERC721_KUDOS_TOKEN_ID, - ); + await nftController.addNft(ERC721_KUDOSADDRESS, ERC721_KUDOS_TOKEN_ID); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: ERC721_KUDOSADDRESS, image: 'Kudos Image (directly from tokenURI)', @@ -561,9 +538,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ][0], + nftController.state.allNftContracts[selectedAddress][chainId][0], ).toStrictEqual({ address: ERC721_KUDOSADDRESS, name: 'KudosToken', @@ -573,9 +548,8 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible erc1155 and get collectible information from contract when OpenSea Proxy API fails to fetch and no OpenSeaAPI key is set', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should add NFT erc1155 and get NFT information from contract when OpenSea Proxy API fails to fetch and no OpenSeaAPI key is set', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -651,13 +625,13 @@ describe('CollectiblesController', () => { }); nock(OPENSEA_PROXY_URL) - .get(`/asset_contract/${ERC1155_COLLECTIBLE_ADDRESS}`) + .get(`/asset_contract/${ERC1155_NFT_ADDRESS}`) .replyWithError(new TypeError('Failed to fetch')); - // the tokenURI for ERC1155_COLLECTIBLE_ADDRESS + ERC1155_COLLECTIBLE_ID + // the tokenURI for ERC1155_NFT_ADDRESS + ERC1155_NFT_ID nock('https://api.opensea.io') .get( - `/api/v1/metadata/${ERC1155_COLLECTIBLE_ADDRESS}/0x5a3ca5cd63807ce5e4d7841ab32ce6b6d9bbba2d000000000000010000000001`, + `/api/v1/metadata/${ERC1155_NFT_ADDRESS}/0x5a3ca5cd63807ce5e4d7841ab32ce6b6d9bbba2d000000000000010000000001`, ) .reply(200, { name: 'name (directly from tokenURI)', @@ -668,25 +642,20 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; - expect(collectiblesController.openSeaApiKey).toBeUndefined(); + expect(nftController.openSeaApiKey).toBeUndefined(); - await collectiblesController.addCollectible( - ERC1155_COLLECTIBLE_ADDRESS, - ERC1155_COLLECTIBLE_ID, - ); + await nftController.addNft(ERC1155_NFT_ADDRESS, ERC1155_NFT_ID); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ - address: ERC1155_COLLECTIBLE_ADDRESS, + address: ERC1155_NFT_ADDRESS, image: 'image (directly from tokenURI)', name: 'name (directly from tokenURI)', description: 'description (direclty from tokenURI)', - tokenId: ERC1155_COLLECTIBLE_ID, + tokenId: ERC1155_NFT_ID, standard: ERC1155, favorite: false, isCurrentlyOwned: true, @@ -697,9 +666,8 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible erc721 and get collectible information only from contract', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should add NFT erc721 and get NFT information only from contract', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://ipfs.gitcoin.co:443') .get('/api/v0/cat/QmPmt6EAaioN78ECnW5oCL8v2YvVSpoBjLCjrXhhsAvoov') .reply(200, { @@ -783,27 +751,19 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; sinon - .stub( - collectiblesController, - 'getCollectibleContractInformationFromApi' as any, - ) + .stub(nftController, 'getNftContractInformationFromApi' as any) .returns(undefined); sinon - .stub(collectiblesController, 'getCollectibleInformationFromApi' as any) + .stub(nftController, 'getNftInformationFromApi' as any) .returns(undefined); - await collectiblesController.addCollectible( - ERC721_KUDOSADDRESS, - ERC721_KUDOS_TOKEN_ID, - ); + await nftController.addNft(ERC721_KUDOSADDRESS, ERC721_KUDOS_TOKEN_ID); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: ERC721_KUDOSADDRESS, image: 'Kudos Image (directly from tokenURI)', @@ -816,9 +776,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ][0], + nftController.state.allNftContracts[selectedAddress][chainId][0], ).toStrictEqual({ address: ERC721_KUDOSADDRESS, name: 'KudosToken', @@ -828,28 +786,28 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible by provider type', async () => { - const { collectiblesController, network, messenger } = setupController(); + it('should add NFT by provider type', async () => { + const { nftController, network, messenger } = setupController(); const firstNetworkType = 'rinkeby'; const secondNetworkType = 'ropsten'; - const { selectedAddress } = collectiblesController.config; + const { selectedAddress } = nftController.config; sinon - .stub(collectiblesController, 'getCollectibleInformation' as any) + .stub(nftController, 'getNftInformation' as any) .returns({ name: 'name', image: 'url', description: 'description' }); network.setProviderType(firstNetworkType); - await collectiblesController.addCollectible('0x01', '1234'); + await nftController.addNft('0x01', '1234'); network.setProviderType(secondNetworkType); network.setProviderType(firstNetworkType); expect( - collectiblesController.state.allCollectibles[selectedAddress]?.[ + nftController.state.allNfts[selectedAddress]?.[ NetworksChainId[secondNetworkType] ], ).toBeUndefined(); expect( - collectiblesController.state.allCollectibles[selectedAddress][ + nftController.state.allNfts[selectedAddress][ NetworksChainId[firstNetworkType] ][0], ).toStrictEqual({ @@ -865,8 +823,8 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not add collectibles with no contract information when auto detecting', async () => { - const { collectiblesController, messenger } = setupController(); + it('should not add NFTs with no contract information when auto detecting', async () => { + const { nftController, messenger } = setupController(); nock(OPENSEA_PROXY_URL) .get(`/asset/${ERC721_KUDOSADDRESS}/${ERC721_KUDOS_TOKEN_ID}`) .reply(200, { @@ -888,8 +846,8 @@ describe('CollectiblesController', () => { }, }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( '0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab', '123', undefined, @@ -900,18 +858,14 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress]?.[ - chainId - ], + nftController.state.allNfts[selectedAddress]?.[chainId], ).toBeUndefined(); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress]?.[ - chainId - ], + nftController.state.allNftContracts[selectedAddress]?.[chainId], ).toBeUndefined(); - await collectiblesController.addCollectible( + await nftController.addNft( ERC721_KUDOSADDRESS, ERC721_KUDOS_TOKEN_ID, undefined, @@ -922,7 +876,7 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toStrictEqual([ { address: ERC721_KUDOSADDRESS, @@ -938,9 +892,7 @@ describe('CollectiblesController', () => { ]); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], + nftController.state.allNftContracts[selectedAddress][chainId], ).toStrictEqual([ { address: ERC721_KUDOSADDRESS, @@ -955,18 +907,18 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not add duplicate collectibles to the ignoredCollectibles list', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + it('should not add duplicate NFTs to the ignoredNfts list', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', standard: 'standard', }); - await collectiblesController.addCollectible('0x01', '2', { + await nftController.addNft('0x01', '2', { name: 'name', image: 'image', description: 'description', @@ -974,17 +926,17 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(2); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(0); + expect(nftController.state.ignoredNfts).toHaveLength(0); - collectiblesController.removeAndIgnoreCollectible('0x01', '1'); + nftController.removeAndIgnoreNft('0x01', '1'); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(1); + expect(nftController.state.ignoredNfts).toHaveLength(1); - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', @@ -992,22 +944,21 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(2); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(1); + expect(nftController.state.ignoredNfts).toHaveLength(1); - collectiblesController.removeAndIgnoreCollectible('0x01', '1'); + nftController.removeAndIgnoreNft('0x01', '1'); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(1); + expect(nftController.state.ignoredNfts).toHaveLength(1); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible with metadata hosted in IPFS', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should add NFT with metadata hosted in IPFS', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -1085,19 +1036,17 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - collectiblesController.configure({ + nftController.configure({ ipfsGateway: IPFS_DEFAULT_GATEWAY_URL, }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, ); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ][0], + nftController.state.allNftContracts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x18E8E76aeB9E2d9FA2A2b88DD9CF3C8ED45c3660', name: "Maltjik.jpg's Depressionists", @@ -1105,9 +1054,7 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ address: '0x18E8E76aeB9E2d9FA2A2b88DD9CF3C8ED45c3660', tokenId: '36', @@ -1122,19 +1069,18 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should add collectible erc721 and get collectible information directly from OpenSea API when OpenSeaAPIkey is set and queries to OpenSea proxy fail', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should add NFT erc721 and get NFT information directly from OpenSea API when OpenSeaAPIkey is set and queries to OpenSea proxy fail', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock(OPENSEA_PROXY_URL) - .get(`/asset_contract/${ERC721_COLLECTIBLE_ADDRESS}`) + .get(`/asset_contract/${ERC721_NFT_ADDRESS}`) .replyWithError(new Error('Failed to fetch')) - .get(`/asset/${ERC721_COLLECTIBLE_ADDRESS}/${ERC721_COLLECTIBLE_ID}`) + .get(`/asset/${ERC721_NFT_ADDRESS}/${ERC721_NFT_ID}`) .replyWithError(new Error('Failed to fetch')); nock(OPENSEA_API_URL, { encodedQueryParams: true, }) - .get(`/asset_contract/${ERC721_COLLECTIBLE_ADDRESS}`) + .get(`/asset_contract/${ERC721_NFT_ADDRESS}`) .reply(200, { description: 'description (from opensea)', symbol: 'KDO', @@ -1144,7 +1090,7 @@ describe('CollectiblesController', () => { image_url: 'logo (from opensea)', }, }) - .get(`/asset/${ERC721_COLLECTIBLE_ADDRESS}/${ERC721_COLLECTIBLE_ID}`) + .get(`/asset/${ERC721_NFT_ADDRESS}/${ERC721_NFT_ID}`) .reply(200, { image_original_url: 'image (directly from opensea)', name: 'name (directly from opensea)', @@ -1161,7 +1107,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0x06fdde03', }, 'latest', @@ -1181,7 +1127,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0x95d89b41', }, 'latest', @@ -1199,7 +1145,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0x0e89341c5a3ca5cd63807ce5e4d7841ab32ce6b6d9bbba2d000000000000010000000001', }, 'latest', @@ -1219,7 +1165,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0xc87b56dd000000000000000000000000000000000000000000000000000000000011781a', }, 'latest', @@ -1233,35 +1179,28 @@ describe('CollectiblesController', () => { }); nock('https://api.opensea.io:443', { encodedQueryParams: true }) - .get( - `/api/v1/metadata/${ERC721_COLLECTIBLE_ADDRESS}/${ERC721_COLLECTIBLE_ID}`, - ) + .get(`/api/v1/metadata/${ERC721_NFT_ADDRESS}/${ERC721_NFT_ID}`) .reply(200, [ '1f8b080000000000000334ce5d6f82301480e1ffd26b1015a3913bcdd8d4c1b20f9dc31bd274b51c3d3d85b664a0f1bf2f66d9ed9bbcc97365c4b564095be440e3e168ce02f62d9db0507b30c4126a1103263b2f2d712c11e8fc1f4173755f2bef6b97441156f14019a350b64e5a61c84bf203617494ef8aed27e5611cea7836f5fdfe510dc561cf9fcb23d8d364ed8a99cd2e4db30a1fb2d57184d9d9c6c547caab27dc35cbf779dd6bdfbfa88d5abca1b079d77ea5cbf4f24a6b389c5c2f4074d39fb16201e3049adfe1656bf1cf79fb050000ffff03002c5b5b9be3000000', ]); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; - collectiblesController.setApiKey('fake-api-key'); - expect(collectiblesController.openSeaApiKey).toBe('fake-api-key'); + nftController.setApiKey('fake-api-key'); + expect(nftController.openSeaApiKey).toBe('fake-api-key'); - await collectiblesController.addCollectible( - ERC721_COLLECTIBLE_ADDRESS, - ERC721_COLLECTIBLE_ID, - ); + await nftController.addNft(ERC721_NFT_ADDRESS, ERC721_NFT_ID); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual({ - address: ERC721_COLLECTIBLE_ADDRESS, + address: ERC721_NFT_ADDRESS, image: null, imageOriginal: 'image (directly from opensea)', name: 'name (directly from opensea)', description: 'description (directly from opensea)', - tokenId: ERC721_COLLECTIBLE_ID, + tokenId: ERC721_NFT_ID, standard: ERC721, favorite: false, isCurrentlyOwned: true, @@ -1271,34 +1210,25 @@ describe('CollectiblesController', () => { }); }); - describe('addCollectibleVerifyOwnership', () => { - it('should verify ownership by selected address and add collectible', async () => { - const { collectiblesController, preferences, messenger } = - setupController(); + describe('addNftVerifyOwnership', () => { + it('should verify ownership by selected address and add NFT', async () => { + const { nftController, preferences, messenger } = setupController(); const firstAddress = '0x123'; const secondAddress = '0x321'; - const { chainId } = collectiblesController.config; + const { chainId } = nftController.config; - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(true); + sinon.stub(nftController, 'isNftOwner' as any).returns(true); sinon - .stub(collectiblesController, 'getCollectibleInformation' as any) + .stub(nftController, 'getNftInformation' as any) .returns({ name: 'name', image: 'url', description: 'description' }); preferences.update({ selectedAddress: firstAddress }); - await collectiblesController.addCollectibleVerifyOwnership( - '0x01', - '1234', - ); + await nftController.addNftVerifyOwnership('0x01', '1234'); preferences.update({ selectedAddress: secondAddress }); - await collectiblesController.addCollectibleVerifyOwnership( - '0x02', - '4321', - ); + await nftController.addNftVerifyOwnership('0x02', '4321'); preferences.update({ selectedAddress: firstAddress }); expect( - collectiblesController.state.allCollectibles[firstAddress][chainId][0], + nftController.state.allNfts[firstAddress][chainId][0], ).toStrictEqual({ address: '0x01', description: 'description', @@ -1312,102 +1242,91 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should throw an error if selected address is not owner of input collectible', async () => { - const { collectiblesController, preferences, messenger } = - setupController(); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(false); + it('should throw an error if selected address is not owner of input NFT', async () => { + const { nftController, preferences, messenger } = setupController(); + sinon.stub(nftController, 'isNftOwner' as any).returns(false); const firstAddress = '0x123'; preferences.update({ selectedAddress: firstAddress }); const result = async () => - await collectiblesController.addCollectibleVerifyOwnership( - '0x01', - '1234', - ); - const error = 'This collectible is not owned by the user'; + await nftController.addNftVerifyOwnership('0x01', '1234'); + const error = 'This NFT is not owned by the user'; await expect(result).rejects.toThrow(error); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); }); - describe('removeCollectible', () => { - it('should remove collectible and collectible contract', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + describe('removeNft', () => { + it('should remove NFT and NFT contract', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', standard: 'standard', }); - collectiblesController.removeCollectible('0x01', '1'); + nftController.removeNft('0x01', '1'); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(0); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], + nftController.state.allNftContracts[selectedAddress][chainId], ).toHaveLength(0); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not remove collectible contract if collectible still exists', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + it('should not remove NFT contract if NFT still exists', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; - await collectiblesController.addCollectible('0x01', '1', { + await nftController.addNft('0x01', '1', { name: 'name', image: 'image', description: 'description', standard: 'standard', }); - await collectiblesController.addCollectible('0x01', '2', { + await nftController.addNft('0x01', '2', { name: 'name', image: 'image', description: 'description', standard: 'standard', }); - collectiblesController.removeCollectible('0x01', '1'); + nftController.removeNft('0x01', '1'); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], + nftController.state.allNftContracts[selectedAddress][chainId], ).toHaveLength(1); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should remove collectible by selected address', async () => { - const { collectiblesController, preferences, messenger } = - setupController(); - const { chainId } = collectiblesController.config; + it('should remove NFT by selected address', async () => { + const { nftController, preferences, messenger } = setupController(); + const { chainId } = nftController.config; sinon - .stub(collectiblesController, 'getCollectibleInformation' as any) + .stub(nftController, 'getNftInformation' as any) .returns({ name: 'name', image: 'url', description: 'description' }); const firstAddress = '0x123'; const secondAddress = '0x321'; preferences.update({ selectedAddress: firstAddress }); - await collectiblesController.addCollectible('0x02', '4321'); + await nftController.addNft('0x02', '4321'); preferences.update({ selectedAddress: secondAddress }); - await collectiblesController.addCollectible('0x01', '1234'); - collectiblesController.removeCollectible('0x01', '1234'); - expect( - collectiblesController.state.allCollectibles[secondAddress][chainId], - ).toHaveLength(0); + await nftController.addNft('0x01', '1234'); + nftController.removeNft('0x01', '1234'); + expect(nftController.state.allNfts[secondAddress][chainId]).toHaveLength( + 0, + ); preferences.update({ selectedAddress: firstAddress }); expect( - collectiblesController.state.allCollectibles[firstAddress][chainId][0], + nftController.state.allNfts[firstAddress][chainId][0], ).toStrictEqual({ address: '0x02', description: 'description', @@ -1421,23 +1340,23 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should remove collectible by provider type', async () => { - const { collectiblesController, network, messenger } = setupController(); - const { selectedAddress } = collectiblesController.config; + it('should remove NFT by provider type', async () => { + const { nftController, network, messenger } = setupController(); + const { selectedAddress } = nftController.config; sinon - .stub(collectiblesController, 'getCollectibleInformation' as any) + .stub(nftController, 'getNftInformation' as any) .returns({ name: 'name', image: 'url', description: 'description' }); const firstNetworkType = 'rinkeby'; const secondNetworkType = 'ropsten'; network.setProviderType(firstNetworkType); - await collectiblesController.addCollectible('0x02', '4321'); + await nftController.addNft('0x02', '4321'); network.setProviderType(secondNetworkType); - await collectiblesController.addCollectible('0x01', '1234'); - // collectiblesController.removeToken('0x01'); - collectiblesController.removeCollectible('0x01', '1234'); + await nftController.addNft('0x01', '1234'); + // nftController.removeToken('0x01'); + nftController.removeNft('0x01', '1234'); expect( - collectiblesController.state.allCollectibles[selectedAddress][ + nftController.state.allNfts[selectedAddress][ NetworksChainId[secondNetworkType] ], ).toHaveLength(0); @@ -1445,7 +1364,7 @@ describe('CollectiblesController', () => { network.setProviderType(firstNetworkType); expect( - collectiblesController.state.allCollectibles[selectedAddress][ + nftController.state.allNfts[selectedAddress][ NetworksChainId[firstNetworkType] ][0], ).toStrictEqual({ @@ -1462,11 +1381,11 @@ describe('CollectiblesController', () => { }); }); - it('should be able to clear the ignoredCollectibles list', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + it('should be able to clear the ignoredNfts list', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; - await collectiblesController.addCollectible('0x02', '1', { + await nftController.addNft('0x02', '1', { name: 'name', image: 'image', description: 'description', @@ -1474,34 +1393,33 @@ describe('CollectiblesController', () => { favorite: false, }); - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toHaveLength(1); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(0); + expect(nftController.state.allNfts[selectedAddress][chainId]).toHaveLength( + 1, + ); + expect(nftController.state.ignoredNfts).toHaveLength(0); - collectiblesController.removeAndIgnoreCollectible('0x02', '1'); - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toHaveLength(0); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(1); + nftController.removeAndIgnoreNft('0x02', '1'); + expect(nftController.state.allNfts[selectedAddress][chainId]).toHaveLength( + 0, + ); + expect(nftController.state.ignoredNfts).toHaveLength(1); - collectiblesController.clearIgnoredCollectibles(); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(0); + nftController.clearIgnoredNfts(); + expect(nftController.state.ignoredNfts).toHaveLength(0); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); it('should set api key correctly', () => { - const { collectiblesController, messenger } = setupController(); - collectiblesController.setApiKey('new-api-key'); - expect(collectiblesController.openSeaApiKey).toBe('new-api-key'); + const { nftController, messenger } = setupController(); + nftController.setApiKey('new-api-key'); + expect(nftController.openSeaApiKey).toBe('new-api-key'); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - describe('isCollectibleOwner', () => { - it('should verify the ownership of an ERC-721 collectible with the correct owner address', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + describe('isNftOwner', () => { + it('should verify the ownership of an ERC-721 NFT with the correct owner address', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -1509,7 +1427,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0x6352211e000000000000000000000000000000000000000000000000000000000011781a', }, 'latest', @@ -1523,19 +1441,18 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const isOwner = await collectiblesController.isCollectibleOwner( + const isOwner = await nftController.isNftOwner( OWNER_ADDRESS, - ERC721_COLLECTIBLE_ADDRESS, - String(ERC721_COLLECTIBLE_ID), + ERC721_NFT_ADDRESS, + String(ERC721_NFT_ID), ); expect(isOwner).toBe(true); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not verify the ownership of an ERC-721 collectible with the wrong owner address', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should not verify the ownership of an ERC-721 NFT with the wrong owner address', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -1543,7 +1460,7 @@ describe('CollectiblesController', () => { method: 'eth_call', params: [ { - to: ERC721_COLLECTIBLE_ADDRESS, + to: ERC721_NFT_ADDRESS, data: '0x6352211e000000000000000000000000000000000000000000000000000000000011781a', }, 'latest', @@ -1557,19 +1474,18 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const isOwner = await collectiblesController.isCollectibleOwner( + const isOwner = await nftController.isNftOwner( '0x0000000000000000000000000000000000000000', - ERC721_COLLECTIBLE_ADDRESS, - String(ERC721_COLLECTIBLE_ID), + ERC721_NFT_ADDRESS, + String(ERC721_NFT_ID), ); expect(isOwner).toBe(false); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should verify the ownership of an ERC-1155 collectible with the correct owner address', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should verify the ownership of an ERC-1155 NFT with the correct owner address', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -1607,19 +1523,18 @@ describe('CollectiblesController', () => { '0x0000000000000000000000000000000000000000000000000000000000000001', }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const isOwner = await collectiblesController.isCollectibleOwner( + const isOwner = await nftController.isNftOwner( OWNER_ADDRESS, - ERC1155_COLLECTIBLE_ADDRESS, - ERC1155_COLLECTIBLE_ID, + ERC1155_NFT_ADDRESS, + ERC1155_NFT_ID, ); expect(isOwner).toBe(true); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not verify the ownership of an ERC-1155 collectible with the wrong owner address', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should not verify the ownership of an ERC-1155 NFT with the wrong owner address', async () => { + const { assetsContract, nftController, messenger } = setupController(); nock('https://mainnet.infura.io:443', { encodedQueryParams: true }) .post('/v3/ad3a368836ff4596becc3be8e2f137ac', { jsonrpc: '2.0', @@ -1658,10 +1573,10 @@ describe('CollectiblesController', () => { }); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const isOwner = await collectiblesController.isCollectibleOwner( + const isOwner = await nftController.isNftOwner( '0x0000000000000000000000000000000000000000', - ERC1155_COLLECTIBLE_ADDRESS, - ERC1155_COLLECTIBLE_ID, + ERC1155_NFT_ADDRESS, + ERC1155_NFT_ID, ); expect(isOwner).toBe(false); @@ -1669,13 +1584,12 @@ describe('CollectiblesController', () => { }); it('should throw an error for an unsupported standard', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + const { assetsContract, nftController, messenger } = setupController(); assetsContract.configure({ provider: MAINNET_PROVIDER }); const error = 'Unable to verify ownership. Probably because the standard is not supported or the chain is incorrect'; const result = async () => { - await collectiblesController.isCollectibleOwner( + await nftController.isNftOwner( '0x0000000000000000000000000000000000000000', CRYPTOPUNK_ADDRESS, '0', @@ -1687,27 +1601,24 @@ describe('CollectiblesController', () => { }); }); - describe('updateCollectibleFavoriteStatus', () => { - it('should set collectible as favorite', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + describe('updateNftFavoriteStatus', () => { + it('should set NFT as favorite', async () => { + const { assetsContract, nftController, messenger } = setupController(); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, ); - collectiblesController.updateCollectibleFavoriteStatus( + nftController.updateNftFavoriteStatus( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, true, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ address: ERC721_DEPRESSIONIST_ADDRESS, @@ -1719,26 +1630,23 @@ describe('CollectiblesController', () => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should set collectible as favorite and then unset it', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + it('should set NFT as favorite and then unset it', async () => { + const { assetsContract, nftController, messenger } = setupController(); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, ); - collectiblesController.updateCollectibleFavoriteStatus( + nftController.updateNftFavoriteStatus( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, true, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ address: ERC721_DEPRESSIONIST_ADDRESS, @@ -1747,16 +1655,14 @@ describe('CollectiblesController', () => { }), ); - collectiblesController.updateCollectibleFavoriteStatus( + nftController.updateNftFavoriteStatus( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, false, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ address: ERC721_DEPRESSIONIST_ADDRESS, @@ -1769,25 +1675,22 @@ describe('CollectiblesController', () => { }); it('should keep the favorite status as true after updating metadata', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + const { assetsContract, nftController, messenger } = setupController(); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, ); - collectiblesController.updateCollectibleFavoriteStatus( + nftController.updateNftFavoriteStatus( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, true, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ address: ERC721_DEPRESSIONIST_ADDRESS, @@ -1796,7 +1699,7 @@ describe('CollectiblesController', () => { }), ); - await collectiblesController.addCollectible( + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, { @@ -1808,9 +1711,7 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ image: 'new_image', @@ -1824,26 +1725,23 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); it('should keep the favorite status as false after updating metadata', async () => { - const { assetsContract, collectiblesController, messenger } = - setupController(); + const { assetsContract, nftController, messenger } = setupController(); assetsContract.configure({ provider: MAINNET_PROVIDER }); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible( + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ address: ERC721_DEPRESSIONIST_ADDRESS, @@ -1852,7 +1750,7 @@ describe('CollectiblesController', () => { }), ); - await collectiblesController.addCollectible( + await nftController.addNft( ERC721_DEPRESSIONIST_ADDRESS, ERC721_DEPRESSIONIST_ID, { @@ -1864,9 +1762,7 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], + nftController.state.allNfts[selectedAddress][chainId][0], ).toStrictEqual( expect.objectContaining({ image: 'new_image', @@ -1880,22 +1776,20 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], + nftController.state.allNfts[selectedAddress][chainId], ).toHaveLength(1); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - describe('checkAndUpdateCollectiblesOwnershipStatus', () => { - describe('checkAndUpdateAllCollectiblesOwnershipStatus', () => { - it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and update the isCurrentlyOwned value to false when collectible is not still owned', async () => { - const { collectiblesController, messenger } = setupController(); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(false); + describe('checkAndUpdateNftsOwnershipStatus', () => { + describe('checkAndUpdateAllNftsOwnershipStatus', () => { + it('should check whether NFTs for the current selectedAddress/chainId combination are still owned by the selectedAddress and update the isCurrentlyOwned value to false when NFT is not still owned', async () => { + const { nftController, messenger } = setupController(); + sinon.stub(nftController, 'isNftOwner' as any).returns(false); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x02', '1', { + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x02', '1', { name: 'name', image: 'image', description: 'description', @@ -1904,30 +1798,26 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus(); + await nftController.checkAndUpdateAllNftsOwnershipStatus(); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(false); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); }); - it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave/set the isCurrentlyOwned value to true when collectible is still owned', async () => { - const { collectiblesController, messenger } = setupController(); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(true); + it('should check whether NFTs for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave/set the isCurrentlyOwned value to true when NFT is still owned', async () => { + const { nftController, messenger } = setupController(); + sinon.stub(nftController, 'isNftOwner' as any).returns(true); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x02', '1', { + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x02', '1', { name: 'name', image: 'image', description: 'description', @@ -1936,29 +1826,27 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus(); + await nftController.checkAndUpdateAllNftsOwnershipStatus(); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should check whether collectibles for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave the isCurrentlyOwned value as is when collectible ownership check fails', async () => { - const { collectiblesController, messenger } = setupController(); + it('should check whether NFTs for the current selectedAddress/chainId combination are still owned by the selectedAddress and leave the isCurrentlyOwned value as is when NFT ownership check fails', async () => { + const { nftController, messenger } = setupController(); sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) + .stub(nftController, 'isNftOwner' as any) .throws(new Error('Unable to verify ownership')); - const { selectedAddress, chainId } = collectiblesController.config; - await collectiblesController.addCollectible('0x02', '1', { + const { selectedAddress, chainId } = nftController.config; + await nftController.addNft('0x02', '1', { name: 'name', image: 'image', description: 'description', @@ -1967,26 +1855,24 @@ describe('CollectiblesController', () => { }); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - await collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus(); + await nftController.checkAndUpdateAllNftsOwnershipStatus(); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - describe('checkAndUpdateSingleCollectibleOwnershipStatus', () => { - it('should check whether the passed collectible is still owned by the the current selectedAddress/chainId combination and update its isCurrentlyOwned property in state if batch is false and isCollectibleOwner returns false', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; - const collectible = { + describe('checkAndUpdateSingleNftOwnershipStatus', () => { + it('should check whether the passed NFT is still owned by the the current selectedAddress/chainId combination and update its isCurrentlyOwned property in state if batch is false and isNftOwner returns false', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; + const nft = { address: '0x02', tokenId: '1', name: 'name', @@ -1996,41 +1882,33 @@ describe('CollectiblesController', () => { favorite: false, }; - await collectiblesController.addCollectible( - collectible.address, - collectible.tokenId, - collectible, - ); + await nftController.addNft(nft.address, nft.tokenId, nft); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(false); + sinon.stub(nftController, 'isNftOwner' as any).returns(false); - await collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus( - collectible, + await nftController.checkAndUpdateSingleNftOwnershipStatus( + nft, false, ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(false); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); }); - it('should check whether the passed collectible is still owned by the the current selectedAddress/chainId combination and return the updated collectible object without updating state if batch is true', async () => { - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; - const collectible = { + it('should check whether the passed NFT is still owned by the the current selectedAddress/chainId combination and return the updated NFT object without updating state if batch is true', async () => { + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; + const nft = { address: '0x02', tokenId: '1', name: 'name', @@ -2040,41 +1918,30 @@ describe('CollectiblesController', () => { favorite: false, }; - await collectiblesController.addCollectible( - collectible.address, - collectible.tokenId, - collectible, - ); + await nftController.addNft(nft.address, nft.tokenId, nft); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(false); + sinon.stub(nftController, 'isNftOwner' as any).returns(false); - const updatedCollectible = - await collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus( - collectible, - true, - ); + const updatedNft = + await nftController.checkAndUpdateSingleNftOwnershipStatus(nft, true); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - expect(updatedCollectible.isCurrentlyOwned).toBe(false); + expect(updatedNft.isCurrentlyOwned).toBe(false); messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should check whether the passed collectible is still owned by the the selectedAddress/chainId combination passed in the accountParams argument and update its isCurrentlyOwned property in state, when the currently configured selectedAddress/chainId are different from those passed', async () => { - const { collectiblesController, network, preferences, messenger } = + it('should check whether the passed NFT is still owned by the the selectedAddress/chainId combination passed in the accountParams argument and update its isCurrentlyOwned property in state, when the currently configured selectedAddress/chainId are different from those passed', async () => { + const { nftController, network, preferences, messenger } = setupController(); const firstNetworkType = 'rinkeby'; const secondNetworkType = 'ropsten'; @@ -2082,8 +1949,8 @@ describe('CollectiblesController', () => { preferences.update({ selectedAddress: OWNER_ADDRESS }); network.setProviderType(firstNetworkType); - const { selectedAddress, chainId } = collectiblesController.config; - const collectible = { + const { selectedAddress, chainId } = nftController.config; + const nft = { address: '0x02', tokenId: '1', name: 'name', @@ -2093,36 +1960,25 @@ describe('CollectiblesController', () => { favorite: false, }; - await collectiblesController.addCollectible( - collectible.address, - collectible.tokenId, - collectible, - ); + await nftController.addNft(nft.address, nft.tokenId, nft); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].isCurrentlyOwned, + nftController.state.allNfts[selectedAddress][chainId][0] + .isCurrentlyOwned, ).toBe(true); - sinon - .stub(collectiblesController, 'isCollectibleOwner' as any) - .returns(false); + sinon.stub(nftController, 'isNftOwner' as any).returns(false); preferences.update({ selectedAddress: SECOND_OWNER_ADDRESS }); network.setProviderType(secondNetworkType); - await collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus( - collectible, - false, - { - userAddress: OWNER_ADDRESS, - chainId: NetworksChainId[firstNetworkType], - }, - ); + await nftController.checkAndUpdateSingleNftOwnershipStatus(nft, false, { + userAddress: OWNER_ADDRESS, + chainId: NetworksChainId[firstNetworkType], + }); expect( - collectiblesController.state.allCollectibles[OWNER_ADDRESS][ + nftController.state.allNfts[OWNER_ADDRESS][ NetworksChainId[firstNetworkType] ][0].isCurrentlyOwned, ).toBe(false); @@ -2132,8 +1988,8 @@ describe('CollectiblesController', () => { }); }); - describe('findCollectibleByAddressAndTokenId', () => { - const mockCollectible = { + describe('findNftByAddressAndTokenId', () => { + const mockNft = { address: '0x02', tokenId: '1', name: 'name', @@ -2142,45 +1998,45 @@ describe('CollectiblesController', () => { standard: 'standard', favorite: false, }; - const { collectiblesController, messenger } = setupController(); - const { selectedAddress, chainId } = collectiblesController.config; + const { nftController, messenger } = setupController(); + const { selectedAddress, chainId } = nftController.config; afterAll(() => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should return null if the collectible does not exist in the state', async () => { + it('should return null if the NFT does not exist in the state', async () => { expect( - collectiblesController.findCollectibleByAddressAndTokenId( - mockCollectible.address, - mockCollectible.tokenId, + nftController.findNftByAddressAndTokenId( + mockNft.address, + mockNft.tokenId, selectedAddress, chainId, ), ).toBeNull(); }); - it('should return the collectible by the address and tokenId', () => { - collectiblesController.state.allCollectibles = { - [selectedAddress]: { [chainId]: [mockCollectible] }, + it('should return the NFT by the address and tokenId', () => { + nftController.state.allNfts = { + [selectedAddress]: { [chainId]: [mockNft] }, }; expect( - collectiblesController.findCollectibleByAddressAndTokenId( - mockCollectible.address, - mockCollectible.tokenId, + nftController.findNftByAddressAndTokenId( + mockNft.address, + mockNft.tokenId, selectedAddress, chainId, ), - ).toStrictEqual({ collectible: mockCollectible, index: 0 }); + ).toStrictEqual({ nft: mockNft, index: 0 }); }); }); - describe('updateCollectibleByAddressAndTokenId', () => { - const { collectiblesController, messenger } = setupController(); + describe('updateNftByAddressAndTokenId', () => { + const { nftController, messenger } = setupController(); const mockTransactionId = '60d36710-b150-11ec-8a49-c377fbd05e27'; - const mockCollectible = { + const mockNft = { address: '0x02', tokenId: '1', name: 'name', @@ -2190,7 +2046,7 @@ describe('CollectiblesController', () => { favorite: false, }; - const expectedMockCollectible = { + const expectedMockNft = { address: '0x02', description: 'description', favorite: false, @@ -2201,19 +2057,19 @@ describe('CollectiblesController', () => { transactionId: mockTransactionId, }; - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; afterAll(() => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should update the collectible if the collectible exist', async () => { - collectiblesController.state.allCollectibles = { - [selectedAddress]: { [chainId]: [mockCollectible] }, + it('should update the NFT if the NFT exist', async () => { + nftController.state.allNfts = { + [selectedAddress]: { [chainId]: [mockNft] }, }; - collectiblesController.updateCollectible( - mockCollectible, + nftController.updateNft( + mockNft, { transactionId: mockTransactionId, }, @@ -2222,16 +2078,14 @@ describe('CollectiblesController', () => { ); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0], - ).toStrictEqual(expectedMockCollectible); + nftController.state.allNfts[selectedAddress][chainId][0], + ).toStrictEqual(expectedMockNft); }); - it('should return undefined if the collectible does not exist', () => { + it('should return undefined if the NFT does not exist', () => { expect( - collectiblesController.updateCollectible( - mockCollectible, + nftController.updateNft( + mockNft, { transactionId: mockTransactionId, }, @@ -2242,13 +2096,13 @@ describe('CollectiblesController', () => { }); }); - describe('resetCollectibleTransactionStatusByTransactionId', () => { - const { collectiblesController, messenger } = setupController(); + describe('resetNftTransactionStatusByTransactionId', () => { + const { nftController, messenger } = setupController(); const mockTransactionId = '60d36710-b150-11ec-8a49-c377fbd05e27'; const nonExistTransactionId = '0123'; - const mockCollectible = { + const mockNft = { address: '0x02', tokenId: '1', name: 'name', @@ -2259,15 +2113,15 @@ describe('CollectiblesController', () => { transactionId: mockTransactionId, }; - const { selectedAddress, chainId } = collectiblesController.config; + const { selectedAddress, chainId } = nftController.config; afterAll(() => { messenger.clearEventSubscriptions('NetworkController:stateChange'); }); - it('should not update any collectible state and should return false when passed a transaction id that does not match that of any collectible', async () => { + it('should not update any NFT state and should return false when passed a transaction id that does not match that of any NFT', async () => { expect( - collectiblesController.resetCollectibleTransactionStatusByTransactionId( + nftController.resetNftTransactionStatusByTransactionId( nonExistTransactionId, selectedAddress, chainId, @@ -2275,19 +2129,17 @@ describe('CollectiblesController', () => { ).toBe(false); }); - it('should set the transaction id of a collectible in state to undefined, and return true when it has successfully updated this state', async () => { - collectiblesController.state.allCollectibles = { - [selectedAddress]: { [chainId]: [mockCollectible] }, + it('should set the transaction id of an NFT in state to undefined, and return true when it has successfully updated this state', async () => { + nftController.state.allNfts = { + [selectedAddress]: { [chainId]: [mockNft] }, }; expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].transactionId, + nftController.state.allNfts[selectedAddress][chainId][0].transactionId, ).toBe(mockTransactionId); expect( - collectiblesController.resetCollectibleTransactionStatusByTransactionId( + nftController.resetNftTransactionStatusByTransactionId( mockTransactionId, selectedAddress, chainId, @@ -2295,9 +2147,7 @@ describe('CollectiblesController', () => { ).toBe(true); expect( - collectiblesController.state.allCollectibles[selectedAddress][ - chainId - ][0].transactionId, + nftController.state.allNfts[selectedAddress][chainId][0].transactionId, ).toBeUndefined(); }); }); diff --git a/src/assets/CollectiblesController.ts b/src/assets/NftController.ts similarity index 51% rename from src/assets/CollectiblesController.ts rename to src/assets/NftController.ts index 9849e8cb6fc..9365e7013a4 100644 --- a/src/assets/CollectiblesController.ts +++ b/src/assets/NftController.ts @@ -25,57 +25,57 @@ import { } from '../constants'; import type { - ApiCollectible, - ApiCollectibleCreator, - ApiCollectibleContract, - ApiCollectibleLastSale, -} from './CollectibleDetectionController'; + ApiNft, + ApiNftCreator, + ApiNftContract, + ApiNftLastSale, +} from './NftDetectionController'; import type { AssetsContractController } from './AssetsContractController'; -import { compareCollectiblesMetadata } from './assetsUtil'; +import { compareNftMetadata } from './assetsUtil'; /** - * @type Collectible + * @type Nft * - * Collectible representation + * NFT representation * @property address - Hex address of a ERC721 contract - * @property description - The collectible description - * @property image - URI of custom collectible image associated with this tokenId + * @property description - The NFT description + * @property image - URI of custom NFT image associated with this tokenId * @property name - Name associated with this tokenId and contract address - * @property tokenId - The collectible identifier + * @property tokenId - The NFT identifier * @property numberOfSales - Number of sales * @property backgroundColor - The background color to be displayed with the item - * @property imagePreview - URI of a smaller image associated with this collectible - * @property imageThumbnail - URI of a thumbnail image associated with this collectible - * @property imageOriginal - URI of the original image associated with this collectible - * @property animation - URI of a animation associated with this collectible - * @property animationOriginal - URI of the original animation associated with this collectible + * @property imagePreview - URI of a smaller image associated with this NFT + * @property imageThumbnail - URI of a thumbnail image associated with this NFT + * @property imageOriginal - URI of the original image associated with this NFT + * @property animation - URI of a animation associated with this NFT + * @property animationOriginal - URI of the original animation associated with this NFT * @property externalLink - External link containing additional information - * @property creator - The collectible owner information object - * @property isCurrentlyOwned - Boolean indicating whether the address/chainId combination where it's currently stored currently owns this collectible - * @property transactionId - Transaction Id associated with the collectible + * @property creator - The NFT owner information object + * @property isCurrentlyOwned - Boolean indicating whether the address/chainId combination where it's currently stored currently owns this NFT + * @property transactionId - Transaction Id associated with the NFT */ -export interface Collectible extends CollectibleMetadata { +export interface Nft extends NftMetadata { tokenId: string; address: string; isCurrentlyOwned?: boolean; } /** - * @type CollectibleContract + * @type NftContract * - * Collectible contract information representation + * NFT contract information representation * @property name - Contract name * @property logo - Contract logo * @property address - Contract address * @property symbol - Contract symbol * @property description - Contract description - * @property totalSupply - Total supply of collectibles - * @property assetContractType - The collectible type, it could be `semi-fungible` or `non-fungible` + * @property totalSupply - Total supply of NFTs + * @property assetContractType - The NFT type, it could be `semi-fungible` or `non-fungible` * @property createdDate - Creation date * @property schemaName - The schema followed by the contract, it could be `ERC721` or `ERC1155` * @property externalLink - External link containing additional information */ -export interface CollectibleContract { +export interface NftContract { name?: string; logo?: string; address: string; @@ -89,24 +89,24 @@ export interface CollectibleContract { } /** - * @type CollectibleMetadata + * @type NftMetadata * - * Collectible custom information - * @property name - Collectible custom name - * @property description - The collectible description + * NFT custom information + * @property name - NFT custom name + * @property description - The NFT description * @property numberOfSales - Number of sales * @property backgroundColor - The background color to be displayed with the item * @property image - Image custom image URI - * @property imagePreview - URI of a smaller image associated with this collectible - * @property imageThumbnail - URI of a thumbnail image associated with this collectible - * @property imageOriginal - URI of the original image associated with this collectible - * @property animation - URI of a animation associated with this collectible - * @property animationOriginal - URI of the original animation associated with this collectible + * @property imagePreview - URI of a smaller image associated with this NFT + * @property imageThumbnail - URI of a thumbnail image associated with this NFT + * @property imageOriginal - URI of the original image associated with this NFT + * @property animation - URI of a animation associated with this NFT + * @property animationOriginal - URI of the original animation associated with this NFT * @property externalLink - External link containing additional information - * @property creator - The collectible owner information object - * @property standard - NFT standard name for the collectible, e.g., ERC-721 or ERC-1155 + * @property creator - The NFT owner information object + * @property standard - NFT standard name for the NFT, e.g., ERC-721 or ERC-1155 */ -export interface CollectibleMetadata { +export interface NftMetadata { name: string | null; description: string | null; image: string | null; @@ -120,8 +120,8 @@ export interface CollectibleMetadata { animation?: string; animationOriginal?: string; externalLink?: string; - creator?: ApiCollectibleCreator; - lastSale?: ApiCollectibleLastSale; + creator?: ApiNftCreator; + lastSale?: ApiNftLastSale; transactionId?: string; } @@ -131,13 +131,13 @@ interface AccountParams { } /** - * @type CollectiblesConfig + * @type NftConfig * - * Collectibles controller configuration + * NFT controller configuration * @property networkType - Network ID as per net_version * @property selectedAddress - Vault selected address */ -export interface CollectiblesConfig extends BaseConfig { +export interface NftConfig extends BaseConfig { networkType: NetworkType; selectedAddress: string; chainId: string; @@ -147,36 +147,31 @@ export interface CollectiblesConfig extends BaseConfig { } /** - * @type CollectiblesState + * @type NftState * - * Assets controller state - * @property allCollectibleContracts - Object containing collectibles contract information - * @property allCollectibles - Object containing collectibles per account and network - * @property collectibleContracts - List of collectibles contracts associated with the active vault - * @property collectibles - List of collectibles associated with the active vault - * @property ignoredCollectibles - List of collectibles that should be ignored + * NFT controller state + * @property allNftContracts - Object containing NFT contract information + * @property allNfts - Object containing NFTs per account and network + * @property ignoredNfts - List of NFTs that should be ignored */ -export interface CollectiblesState extends BaseState { - allCollectibleContracts: { - [key: string]: { [key: string]: CollectibleContract[] }; +export interface NftState extends BaseState { + allNftContracts: { + [key: string]: { [key: string]: NftContract[] }; }; - allCollectibles: { [key: string]: { [key: string]: Collectible[] } }; - ignoredCollectibles: Collectible[]; + allNfts: { [key: string]: { [key: string]: Nft[] } }; + ignoredNfts: Nft[]; } -const ALL_COLLECTIBLES_STATE_KEY = 'allCollectibles'; -const ALL_COLLECTIBLES_CONTRACTS_STATE_KEY = 'allCollectibleContracts'; +const ALL_NFTS_STATE_KEY = 'allNfts'; +const ALL_NFTS_CONTRACTS_STATE_KEY = 'allNftContracts'; /** * Controller that stores assets and exposes convenience methods */ -export class CollectiblesController extends BaseController< - CollectiblesConfig, - CollectiblesState -> { +export class NftController extends BaseController { private mutex = new Mutex(); - private getCollectibleApi({ + private getNftApi({ contractAddress, tokenId, useProxy, @@ -195,7 +190,7 @@ export class CollectiblesController extends BaseController< : `${OPENSEA_API_URL}/asset/${contractAddress}/${tokenId}`; } - private getCollectibleContractInformationApi({ + private getNftContractInformationApi({ contractAddress, useProxy, }: { @@ -214,17 +209,17 @@ export class CollectiblesController extends BaseController< } /** - * Helper method to update nested state for allCollectibles and allCollectibleContracts. + * Helper method to update nested state for allNfts and allNftContracts. * * @param newCollection - the modified piece of state to update in the controller's store * @param baseStateKey - The root key in the store to update. * @param passedConfig - An object containing the selectedAddress and chainId that are passed through the auto-detection flow. - * @param passedConfig.userAddress - the address passed through the collectible detection flow to ensure detected assets are stored to the correct account - * @param passedConfig.chainId - the chainId passed through the collectible detection flow to ensure detected assets are stored to the correct account + * @param passedConfig.userAddress - the address passed through the NFT detection flow to ensure detected assets are stored to the correct account + * @param passedConfig.chainId - the chainId passed through the NFT detection flow to ensure detected assets are stored to the correct account */ - private updateNestedCollectibleState( - newCollection: Collectible[] | CollectibleContract[], - baseStateKey: 'allCollectibles' | 'allCollectibleContracts', + private updateNestedNftState( + newCollection: Nft[] | NftContract[], + baseStateKey: 'allNfts' | 'allNftContracts', { userAddress, chainId }: AccountParams | undefined = { userAddress: this.config.selectedAddress, chainId: this.config.chainId, @@ -248,30 +243,29 @@ export class CollectiblesController extends BaseController< } /** - * Request individual collectible information from OpenSea API. + * Request individual NFT information from OpenSea API. * - * @param contractAddress - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. - * @returns Promise resolving to the current collectible name and image. + * @param contractAddress - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. + * @returns Promise resolving to the current NFT name and image. */ - private async getCollectibleInformationFromApi( + private async getNftInformationFromApi( contractAddress: string, tokenId: string, - ): Promise { + ): Promise { // Attempt to fetch the data with the proxy - let collectibleInformation: ApiCollectible | undefined = - await fetchWithErrorHandling({ - url: this.getCollectibleApi({ - contractAddress, - tokenId, - useProxy: true, - }), - }); + let nftInformation: ApiNft | undefined = await fetchWithErrorHandling({ + url: this.getNftApi({ + contractAddress, + tokenId, + useProxy: true, + }), + }); // if an openSeaApiKey is set we should attempt to refetch calling directly to OpenSea - if (!collectibleInformation && this.openSeaApiKey) { - collectibleInformation = await fetchWithErrorHandling({ - url: this.getCollectibleApi({ + if (!nftInformation && this.openSeaApiKey) { + nftInformation = await fetchWithErrorHandling({ + url: this.getNftApi({ contractAddress, tokenId, useProxy: false, @@ -284,8 +278,8 @@ export class CollectiblesController extends BaseController< }); } - // if we were still unable to fetch the data we return out the default/null of `CollectibleMetadata` - if (!collectibleInformation) { + // if we were still unable to fetch the data we return out the default/null of `NftMetadata` + if (!nftInformation) { return { name: null, description: null, @@ -294,8 +288,8 @@ export class CollectiblesController extends BaseController< }; } - // if we've reached this point, we have successfully fetched some data for collectibleInformation - // now we reconfigure the data to conform to the `CollectibleMetadata` type for storage. + // if we've reached this point, we have successfully fetched some data for nftInformation + // now we reconfigure the data to conform to the `NftMetadata` type for storage. const { num_sales, background_color, @@ -311,10 +305,10 @@ export class CollectiblesController extends BaseController< creator, last_sale, asset_contract: { schema_name }, - } = collectibleInformation; + } = nftInformation; /* istanbul ignore next */ - const collectibleMetadata: CollectibleMetadata = Object.assign( + const nftMetadata: NftMetadata = Object.assign( {}, { name: name || null }, { description: description || null }, @@ -334,25 +328,22 @@ export class CollectiblesController extends BaseController< schema_name && { standard: schema_name }, ); - return collectibleMetadata; + return nftMetadata; } /** - * Request individual collectible information from contracts that follows Metadata Interface. + * Request individual NFT information from contracts that follows Metadata Interface. * - * @param contractAddress - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. - * @returns Promise resolving to the current collectible name and image. + * @param contractAddress - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. + * @returns Promise resolving to the current NFT name and image. */ - private async getCollectibleInformationFromTokenURI( + private async getNftInformationFromTokenURI( contractAddress: string, tokenId: string, - ): Promise { + ): Promise { const { ipfsGateway, useIPFSSubdomains } = this.config; - const result = await this.getCollectibleURIAndStandard( - contractAddress, - tokenId, - ); + const result = await this.getNftURIAndStandard(contractAddress, tokenId); let tokenURI = result[0]; const standard = result[1]; @@ -386,13 +377,13 @@ export class CollectiblesController extends BaseController< } /** - * Retrieve collectible uri with metadata. TODO Update method to use IPFS. + * Retrieve NFT uri with metadata. TODO Update method to use IPFS. * - * @param contractAddress - Collectible contract address. - * @param tokenId - Collectible token id. - * @returns Promise resolving collectible uri and token standard. + * @param contractAddress - NFT contract address. + * @param tokenId - NFT token id. + * @returns Promise resolving NFT uri and token standard. */ - private async getCollectibleURIAndStandard( + private async getNftURIAndStandard( contractAddress: string, tokenId: string, ): Promise<[string, string]> { @@ -430,30 +421,24 @@ export class CollectiblesController extends BaseController< } /** - * Request individual collectible information (name, image url and description). + * Request individual NFT information (name, image url and description). * - * @param contractAddress - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. - * @returns Promise resolving to the current collectible name and image. + * @param contractAddress - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. + * @returns Promise resolving to the current NFT name and image. */ - private async getCollectibleInformation( + private async getNftInformation( contractAddress: string, tokenId: string, - ): Promise { + ): Promise { const blockchainMetadata = await safelyExecute(async () => { - return await this.getCollectibleInformationFromTokenURI( - contractAddress, - tokenId, - ); + return await this.getNftInformationFromTokenURI(contractAddress, tokenId); }); let openSeaMetadata; if (this.config.openSeaEnabled) { openSeaMetadata = await safelyExecute(async () => { - return await this.getCollectibleInformationFromApi( - contractAddress, - tokenId, - ); + return await this.getNftInformationFromApi(contractAddress, tokenId); }); } return { @@ -468,33 +453,33 @@ export class CollectiblesController extends BaseController< } /** - * Request collectible contract information from OpenSea API. + * Request NFT contract information from OpenSea API. * - * @param contractAddress - Hex address of the collectible contract. - * @returns Promise resolving to the current collectible name and image. + * @param contractAddress - Hex address of the NFT contract. + * @returns Promise resolving to the current NFT name and image. */ - private async getCollectibleContractInformationFromApi( + private async getNftContractInformationFromApi( contractAddress: string, - ): Promise { + ): Promise { /* istanbul ignore if */ - let apiCollectibleContractObject: ApiCollectibleContract | undefined = + let apiNftContractObject: ApiNftContract | undefined = await fetchWithErrorHandling({ - url: this.getCollectibleContractInformationApi({ + url: this.getNftContractInformationApi({ contractAddress, useProxy: true, }), }); // if we successfully fetched return the fetched data immediately - if (apiCollectibleContractObject) { - return apiCollectibleContractObject; + if (apiNftContractObject) { + return apiNftContractObject; } // if we were unsuccessful in fetching from the API and an OpenSea API key is present // attempt to refetch directly against the OpenSea API and if successful return the data immediately if (this.openSeaApiKey) { - apiCollectibleContractObject = await fetchWithErrorHandling({ - url: this.getCollectibleContractInformationApi({ + apiNftContractObject = await fetchWithErrorHandling({ + url: this.getNftContractInformationApi({ contractAddress, useProxy: false, }), @@ -505,13 +490,13 @@ export class CollectiblesController extends BaseController< errorCodesToCatch: [403], }); - if (apiCollectibleContractObject) { - return apiCollectibleContractObject; + if (apiNftContractObject) { + return apiNftContractObject; } } // If we've reached this point we were unable to fetch data from either the proxy or opensea so we return - // the default/null of ApiCollectibleContract + // the default/null of ApiNftContract return { address: contractAddress, asset_contract_type: null, @@ -529,17 +514,17 @@ export class CollectiblesController extends BaseController< } /** - * Request collectible contract information from the contract itself. + * Request NFT contract information from the contract itself. * - * @param contractAddress - Hex address of the collectible contract. - * @returns Promise resolving to the current collectible name and image. + * @param contractAddress - Hex address of the NFT contract. + * @returns Promise resolving to the current NFT name and image. */ - private async getCollectibleContractInformationFromContract( + private async getNftContractInformationFromContract( contractAddress: string, ): Promise< - Partial & - Pick & - Pick + Partial & + Pick & + Pick > { const name = await this.getERC721AssetName(contractAddress); const symbol = await this.getERC721AssetSymbol(contractAddress); @@ -551,34 +536,28 @@ export class CollectiblesController extends BaseController< } /** - * Request collectible contract information from OpenSea API. + * Request NFT contract information from OpenSea API. * - * @param contractAddress - Hex address of the collectible contract. - * @returns Promise resolving to the collectible contract name, image and description. + * @param contractAddress - Hex address of the NFT contract. + * @returns Promise resolving to the NFT contract name, image and description. */ - private async getCollectibleContractInformation( + private async getNftContractInformation( contractAddress: string, ): Promise< - Partial & - Pick & - Pick + Partial & + Pick & + Pick > { - const blockchainContractData: Partial & - Pick & - Pick = await safelyExecute( - async () => { - return await this.getCollectibleContractInformationFromContract( - contractAddress, - ); - }, - ); + const blockchainContractData: Partial & + Pick & + Pick = await safelyExecute(async () => { + return await this.getNftContractInformationFromContract(contractAddress); + }); - let openSeaContractData: Partial | undefined; + let openSeaContractData: Partial | undefined; if (this.config.openSeaEnabled) { openSeaContractData = await safelyExecute(async () => { - return await this.getCollectibleContractInformationFromApi( - contractAddress, - ); + return await this.getNftContractInformationFromApi(contractAddress); }); } @@ -609,27 +588,27 @@ export class CollectiblesController extends BaseController< } /** - * Adds an individual collectible to the stored collectible list. + * Adds an individual NFT to the stored NFT list. * - * @param address - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. - * @param collectibleMetadata - Collectible optional information (name, image and description). - * @param collectibleContract - An object containing contract data of the collectible being added. - * @param detection - The chain ID and address of the currently selected network and account at the moment the collectible was detected. - * @returns Promise resolving to the current collectible list. + * @param address - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. + * @param nftMetadata - NFT optional information (name, image and description). + * @param nftContract - An object containing contract data of the NFT being added. + * @param detection - The chain ID and address of the currently selected network and account at the moment the NFT was detected. + * @returns Promise resolving to the current NFT list. */ - private async addIndividualCollectible( + private async addIndividualNft( address: string, tokenId: string, - collectibleMetadata: CollectibleMetadata, - collectibleContract: CollectibleContract, + nftMetadata: NftMetadata, + nftContract: NftContract, detection?: AccountParams, - ): Promise { + ): Promise { // TODO: Remove unused return const releaseLock = await this.mutex.acquire(); try { address = toChecksumHexAddress(address); - const { allCollectibles } = this.state; + const { allNfts } = this.state; let chainId, selectedAddress; if (detection) { @@ -640,81 +619,80 @@ export class CollectiblesController extends BaseController< selectedAddress = this.config.selectedAddress; } - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; + const nfts = allNfts[selectedAddress]?.[chainId] || []; - const existingEntry: Collectible | undefined = collectibles.find( - (collectible) => - collectible.address.toLowerCase() === address.toLowerCase() && - collectible.tokenId === tokenId, + const existingEntry: Nft | undefined = nfts.find( + (nft) => + nft.address.toLowerCase() === address.toLowerCase() && + nft.tokenId === tokenId, ); if (existingEntry) { - const differentMetadata = compareCollectiblesMetadata( - collectibleMetadata, + const differentMetadata = compareNftMetadata( + nftMetadata, existingEntry, ); if (differentMetadata) { // TODO: Switch to indexToUpdate - const indexToRemove = collectibles.findIndex( - (collectible) => - collectible.address.toLowerCase() === address.toLowerCase() && - collectible.tokenId === tokenId, + const indexToRemove = nfts.findIndex( + (nft) => + nft.address.toLowerCase() === address.toLowerCase() && + nft.tokenId === tokenId, ); /* istanbul ignore next */ if (indexToRemove !== -1) { - collectibles.splice(indexToRemove, 1); + nfts.splice(indexToRemove, 1); } } else { - return collectibles; + return nfts; } } - const newEntry: Collectible = { + const newEntry: Nft = { address, tokenId, favorite: existingEntry?.favorite || false, isCurrentlyOwned: true, - ...collectibleMetadata, + ...nftMetadata, }; - const newCollectibles = [...collectibles, newEntry]; - this.updateNestedCollectibleState( - newCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - { chainId, userAddress: selectedAddress }, - ); + const newNfts = [...nfts, newEntry]; + this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY, { + chainId, + userAddress: selectedAddress, + }); - if (this.onCollectibleAdded) { - this.onCollectibleAdded({ + if (this.onNftAdded) { + this.onNftAdded({ address, - symbol: collectibleContract.symbol, + symbol: nftContract.symbol, tokenId: tokenId.toString(), - standard: collectibleMetadata.standard, + standard: nftMetadata.standard, source: detection ? 'detected' : 'custom', }); } - return newCollectibles; + return newNfts; } finally { releaseLock(); } } /** - * Adds a collectible contract to the stored collectible contracts list. + * Adds an NFT contract to the stored NFT contracts list. * - * @param address - Hex address of the collectible contract. - * @param detection - The chain ID and address of the currently selected network and account at the moment the collectible was detected. - * @returns Promise resolving to the current collectible contracts list. + * @param address - Hex address of the NFT contract. + * @param detection - The chain ID and address of the currently selected network and account at the moment the NFT was detected. + * @returns Promise resolving to the current NFT contracts list. */ - private async addCollectibleContract( + private async addNftContract( address: string, detection?: AccountParams, - ): Promise { + ): Promise { const releaseLock = await this.mutex.acquire(); try { address = toChecksumHexAddress(address); - const { allCollectibleContracts } = this.state; + const { allNftContracts } = this.state; let chainId, selectedAddress; if (detection) { @@ -725,19 +703,16 @@ export class CollectiblesController extends BaseController< selectedAddress = this.config.selectedAddress; } - const collectibleContracts = - allCollectibleContracts[selectedAddress]?.[chainId] || []; + const nftContracts = allNftContracts[selectedAddress]?.[chainId] || []; - const existingEntry = collectibleContracts.find( - (collectibleContract) => - collectibleContract.address.toLowerCase() === address.toLowerCase(), + const existingEntry = nftContracts.find( + (nftContract) => + nftContract.address.toLowerCase() === address.toLowerCase(), ); if (existingEntry) { - return collectibleContracts; + return nftContracts; } - const contractInformation = await this.getCollectibleContractInformation( - address, - ); + const contractInformation = await this.getNftContractInformation(address); const { asset_contract_type, @@ -755,11 +730,11 @@ export class CollectiblesController extends BaseController< (detection && !name) || Object.keys(contractInformation).length === 0 ) { - return collectibleContracts; + return nftContracts; } /* istanbul ignore next */ - const newEntry: CollectibleContract = Object.assign( + const newEntry: NftContract = Object.assign( {}, { address }, description && { description }, @@ -773,105 +748,91 @@ export class CollectiblesController extends BaseController< schema_name && { schemaName: schema_name }, external_link && { externalLink: external_link }, ); - const newCollectibleContracts = [...collectibleContracts, newEntry]; - this.updateNestedCollectibleState( - newCollectibleContracts, - ALL_COLLECTIBLES_CONTRACTS_STATE_KEY, - { chainId, userAddress: selectedAddress }, - ); + const newNftContracts = [...nftContracts, newEntry]; + this.updateNestedNftState(newNftContracts, ALL_NFTS_CONTRACTS_STATE_KEY, { + chainId, + userAddress: selectedAddress, + }); - return newCollectibleContracts; + return newNftContracts; } finally { releaseLock(); } } /** - * Removes an individual collectible from the stored token list and saves it in ignored collectibles list. + * Removes an individual NFT from the stored token list and saves it in ignored NFTs list. * - * @param address - Hex address of the collectible contract. - * @param tokenId - Token identifier of the collectible. + * @param address - Hex address of the NFT contract. + * @param tokenId - Token identifier of the NFT. */ - private removeAndIgnoreIndividualCollectible( - address: string, - tokenId: string, - ) { + private removeAndIgnoreIndividualNft(address: string, tokenId: string) { address = toChecksumHexAddress(address); - const { allCollectibles, ignoredCollectibles } = this.state; + const { allNfts, ignoredNfts } = this.state; const { chainId, selectedAddress } = this.config; - const newIgnoredCollectibles = [...ignoredCollectibles]; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const newCollectibles = collectibles.filter((collectible) => { + const newIgnoredNfts = [...ignoredNfts]; + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const newNfts = nfts.filter((nft) => { if ( - collectible.address.toLowerCase() === address.toLowerCase() && - collectible.tokenId === tokenId + nft.address.toLowerCase() === address.toLowerCase() && + nft.tokenId === tokenId ) { - const alreadyIgnored = newIgnoredCollectibles.find( + const alreadyIgnored = newIgnoredNfts.find( (c) => c.address === address && c.tokenId === tokenId, ); - !alreadyIgnored && newIgnoredCollectibles.push(collectible); + !alreadyIgnored && newIgnoredNfts.push(nft); return false; } return true; }); - this.updateNestedCollectibleState( - newCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - ); + this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY); this.update({ - ignoredCollectibles: newIgnoredCollectibles, + ignoredNfts: newIgnoredNfts, }); } /** - * Removes an individual collectible from the stored token list. + * Removes an individual NFT from the stored token list. * - * @param address - Hex address of the collectible contract. - * @param tokenId - Token identifier of the collectible. + * @param address - Hex address of the NFT contract. + * @param tokenId - Token identifier of the NFT. */ - private removeIndividualCollectible(address: string, tokenId: string) { + private removeIndividualNft(address: string, tokenId: string) { address = toChecksumHexAddress(address); - const { allCollectibles } = this.state; + const { allNfts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const newCollectibles = collectibles.filter( - (collectible) => + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const newNfts = nfts.filter( + (nft) => !( - collectible.address.toLowerCase() === address.toLowerCase() && - collectible.tokenId === tokenId + nft.address.toLowerCase() === address.toLowerCase() && + nft.tokenId === tokenId ), ); - this.updateNestedCollectibleState( - newCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - ); + this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY); } /** - * Removes a collectible contract to the stored collectible contracts list. + * Removes an NFT contract to the stored NFT contracts list. * - * @param address - Hex address of the collectible contract. - * @returns Promise resolving to the current collectible contracts list. + * @param address - Hex address of the NFT contract. + * @returns Promise resolving to the current NFT contracts list. */ - private removeCollectibleContract(address: string): CollectibleContract[] { + private removeNftContract(address: string): NftContract[] { address = toChecksumHexAddress(address); - const { allCollectibleContracts } = this.state; + const { allNftContracts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibleContracts = - allCollectibleContracts[selectedAddress]?.[chainId] || []; + const nftContracts = allNftContracts[selectedAddress]?.[chainId] || []; - const newCollectibleContracts = collectibleContracts.filter( - (collectibleContract) => - !(collectibleContract.address.toLowerCase() === address.toLowerCase()), - ); - this.updateNestedCollectibleState( - newCollectibleContracts, - ALL_COLLECTIBLES_CONTRACTS_STATE_KEY, + const newNftContracts = nftContracts.filter( + (nftContract) => + !(nftContract.address.toLowerCase() === address.toLowerCase()), ); + this.updateNestedNftState(newNftContracts, ALL_NFTS_CONTRACTS_STATE_KEY); - return newCollectibleContracts; + return newNftContracts; } /** @@ -887,7 +848,7 @@ export class CollectiblesController extends BaseController< /** * Name of this controller used during composition */ - override name = 'CollectiblesController'; + override name = 'NftController'; private getERC721AssetName: AssetsContractController['getERC721AssetName']; @@ -901,7 +862,7 @@ export class CollectiblesController extends BaseController< private getERC1155TokenURI: AssetsContractController['getERC1155TokenURI']; - private onCollectibleAdded?: (data: { + private onNftAdded?: (data: { address: string; symbol: string | undefined; tokenId: string; @@ -910,7 +871,7 @@ export class CollectiblesController extends BaseController< }) => void; /** - * Creates a CollectiblesController instance. + * Creates a NftController instance. * * @param options - The controller options. * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes. @@ -918,11 +879,11 @@ export class CollectiblesController extends BaseController< * @param options.getERC721AssetName - Gets the name of the asset at the given address. * @param options.getERC721AssetSymbol - Gets the symbol of the asset at the given address. * @param options.getERC721TokenURI - Gets the URI of the ERC721 token at the given address, with the given ID. - * @param options.getERC721OwnerOf - Get the owner of a ERC-721 collectible. - * @param options.getERC1155BalanceOf - Gets balance of a ERC-1155 collectible. + * @param options.getERC721OwnerOf - Get the owner of a ERC-721 NFT. + * @param options.getERC1155BalanceOf - Gets balance of a ERC-1155 NFT. * @param options.getERC1155TokenURI - Gets the URI of the ERC1155 token at the given address, with the given ID. - * @param options.onCollectibleAdded - Callback that is called when a collectible is added. Currently used pass data - * for tracking the collectible added event. + * @param options.onNftAdded - Callback that is called when an NFT is added. Currently used pass data + * for tracking the NFT added event. * @param config - Initial options used to configure this controller. * @param state - Initial state to set on this controller. */ @@ -936,7 +897,7 @@ export class CollectiblesController extends BaseController< getERC721OwnerOf, getERC1155BalanceOf, getERC1155TokenURI, - onCollectibleAdded, + onNftAdded, }: { onPreferencesStateChange: ( listener: (preferencesState: PreferencesState) => void, @@ -950,7 +911,7 @@ export class CollectiblesController extends BaseController< getERC721OwnerOf: AssetsContractController['getERC721OwnerOf']; getERC1155BalanceOf: AssetsContractController['getERC1155BalanceOf']; getERC1155TokenURI: AssetsContractController['getERC1155TokenURI']; - onCollectibleAdded?: (data: { + onNftAdded?: (data: { address: string; symbol: string | undefined; tokenId: string; @@ -959,7 +920,7 @@ export class CollectiblesController extends BaseController< }) => void; }, config?: Partial, - state?: Partial, + state?: Partial, ) { super(config, state); this.defaultConfig = { @@ -972,9 +933,9 @@ export class CollectiblesController extends BaseController< }; this.defaultState = { - allCollectibleContracts: {}, - allCollectibles: {}, - ignoredCollectibles: [], + allNftContracts: {}, + allNfts: {}, + ignoredNfts: [], }; this.initialize(); this.getERC721AssetName = getERC721AssetName; @@ -983,7 +944,7 @@ export class CollectiblesController extends BaseController< this.getERC721OwnerOf = getERC721OwnerOf; this.getERC1155BalanceOf = getERC1155BalanceOf; this.getERC1155TokenURI = getERC1155TokenURI; - this.onCollectibleAdded = onCollectibleAdded; + this.onNftAdded = onNftAdded; onPreferencesStateChange( ({ selectedAddress, ipfsGateway, openSeaEnabled }) => { @@ -998,7 +959,7 @@ export class CollectiblesController extends BaseController< } /** - * Sets an OpenSea API key to retrieve collectible information. + * Sets an OpenSea API key to retrieve NFT information. * * @param openSeaApiKey - OpenSea API key. */ @@ -1007,24 +968,21 @@ export class CollectiblesController extends BaseController< } /** - * Checks the ownership of a ERC-721 or ERC-1155 collectible for a given address. + * Checks the ownership of a ERC-721 or ERC-1155 NFT for a given address. * * @param ownerAddress - User public address. - * @param collectibleAddress - Collectible contract address. - * @param collectibleId - Collectible token ID. - * @returns Promise resolving the collectible ownership. + * @param nftAddress - NFT contract address. + * @param nftId - NFT token ID. + * @returns Promise resolving the NFT ownership. */ - async isCollectibleOwner( + async isNftOwner( ownerAddress: string, - collectibleAddress: string, - collectibleId: string, + nftAddress: string, + nftId: string, ): Promise { // Checks the ownership for ERC-721. try { - const owner = await this.getERC721OwnerOf( - collectibleAddress, - collectibleId, - ); + const owner = await this.getERC721OwnerOf(nftAddress, nftId); return ownerAddress.toLowerCase() === owner.toLowerCase(); // eslint-disable-next-line no-empty } catch { @@ -1035,8 +993,8 @@ export class CollectiblesController extends BaseController< try { const balance = await this.getERC1155BalanceOf( ownerAddress, - collectibleAddress, - collectibleId, + nftAddress, + nftId, ); return balance > 0; // eslint-disable-next-line no-empty @@ -1050,133 +1008,127 @@ export class CollectiblesController extends BaseController< } /** - * Verifies currently selected address owns entered collectible address/tokenId combo and - * adds the collectible and respective collectible contract to the stored collectible and collectible contracts lists. + * Verifies currently selected address owns entered NFT address/tokenId combo and + * adds the NFT and respective NFT contract to the stored NFT and NFT contracts lists. * - * @param address - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. + * @param address - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. */ - async addCollectibleVerifyOwnership(address: string, tokenId: string) { + async addNftVerifyOwnership(address: string, tokenId: string) { const { selectedAddress } = this.config; - if (!(await this.isCollectibleOwner(selectedAddress, address, tokenId))) { - throw new Error('This collectible is not owned by the user'); + if (!(await this.isNftOwner(selectedAddress, address, tokenId))) { + throw new Error('This NFT is not owned by the user'); } - await this.addCollectible(address, tokenId); + await this.addNft(address, tokenId); } /** - * Adds a collectible and respective collectible contract to the stored collectible and collectible contracts lists. + * Adds an NFT and respective NFT contract to the stored NFT and NFT contracts lists. * - * @param address - Hex address of the collectible contract. - * @param tokenId - The collectible identifier. - * @param collectibleMetadata - Collectible optional metadata. - * @param detection - The chain ID and address of the currently selected network and account at the moment the collectible was detected. - * @returns Promise resolving to the current collectible list. + * @param address - Hex address of the NFT contract. + * @param tokenId - The NFT identifier. + * @param nftMetadata - NFT optional metadata. + * @param detection - The chain ID and address of the currently selected network and account at the moment the NFT was detected. + * @returns Promise resolving to the current NFT list. */ - async addCollectible( + async addNft( address: string, tokenId: string, - collectibleMetadata?: CollectibleMetadata, + nftMetadata?: NftMetadata, detection?: AccountParams, ) { address = toChecksumHexAddress(address); - const newCollectibleContracts = await this.addCollectibleContract( - address, - detection, - ); - collectibleMetadata = - collectibleMetadata || - (await this.getCollectibleInformation(address, tokenId)); + const newNftContracts = await this.addNftContract(address, detection); + nftMetadata = + nftMetadata || (await this.getNftInformation(address, tokenId)); - // If collectible contract was not added, do not add individual collectible - const collectibleContract = newCollectibleContracts.find( + // If NFT contract was not added, do not add individual NFT + const nftContract = newNftContracts.find( (contract) => contract.address.toLowerCase() === address.toLowerCase(), ); - // If collectible contract information, add individual collectible - if (collectibleContract) { - await this.addIndividualCollectible( + // If NFT contract information, add individual NFT + if (nftContract) { + await this.addIndividualNft( address, tokenId, - collectibleMetadata, - collectibleContract, + nftMetadata, + nftContract, detection, ); } } /** - * Removes a collectible from the stored token list. + * Removes an NFT from the stored token list. * - * @param address - Hex address of the collectible contract. - * @param tokenId - Token identifier of the collectible. + * @param address - Hex address of the NFT contract. + * @param tokenId - Token identifier of the NFT. */ - removeCollectible(address: string, tokenId: string) { + removeNft(address: string, tokenId: string) { address = toChecksumHexAddress(address); - this.removeIndividualCollectible(address, tokenId); - const { allCollectibles } = this.state; + this.removeIndividualNft(address, tokenId); + const { allNfts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const remainingCollectible = collectibles.find( - (collectible) => - collectible.address.toLowerCase() === address.toLowerCase(), + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const remainingNft = nfts.find( + (nft) => nft.address.toLowerCase() === address.toLowerCase(), ); - if (!remainingCollectible) { - this.removeCollectibleContract(address); + if (!remainingNft) { + this.removeNftContract(address); } } /** - * Removes a collectible from the stored token list and saves it in ignored collectibles list. + * Removes an NFT from the stored token list and saves it in ignored NFTs list. * - * @param address - Hex address of the collectible contract. - * @param tokenId - Token identifier of the collectible. + * @param address - Hex address of the NFT contract. + * @param tokenId - Token identifier of the NFT. */ - removeAndIgnoreCollectible(address: string, tokenId: string) { + removeAndIgnoreNft(address: string, tokenId: string) { address = toChecksumHexAddress(address); - this.removeAndIgnoreIndividualCollectible(address, tokenId); - const { allCollectibles } = this.state; + this.removeAndIgnoreIndividualNft(address, tokenId); + const { allNfts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const remainingCollectible = collectibles.find( - (collectible) => - collectible.address.toLowerCase() === address.toLowerCase(), + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const remainingNft = nfts.find( + (nft) => nft.address.toLowerCase() === address.toLowerCase(), ); - if (!remainingCollectible) { - this.removeCollectibleContract(address); + if (!remainingNft) { + this.removeNftContract(address); } } /** - * Removes all collectibles from the ignored list. + * Removes all NFTs from the ignored list. */ - clearIgnoredCollectibles() { - this.update({ ignoredCollectibles: [] }); + clearIgnoredNfts() { + this.update({ ignoredNfts: [] }); } /** - * Checks whether input collectible is still owned by the user - * And updates the isCurrentlyOwned value on the collectible object accordingly. + * Checks whether input NFT is still owned by the user + * And updates the isCurrentlyOwned value on the NFT object accordingly. * - * @param collectible - The collectible object to check and update. + * @param nft - The NFT object to check and update. * @param batch - A boolean indicating whether this method is being called as part of a batch or single update. * @param accountParams - The userAddress and chainId to check ownership against * @param accountParams.userAddress - the address passed through the confirmed transaction flow to ensure detected assets are stored to the correct account * @param accountParams.chainId - the chainId passed through the confirmed transaction flow to ensure detected assets are stored to the correct account - * @returns the collectible with the updated isCurrentlyOwned value + * @returns the NFT with the updated isCurrentlyOwned value */ - async checkAndUpdateSingleCollectibleOwnershipStatus( - collectible: Collectible, + async checkAndUpdateSingleNftOwnershipStatus( + nft: Nft, batch: boolean, { userAddress, chainId }: AccountParams | undefined = { userAddress: this.config.selectedAddress, chainId: this.config.chainId, }, ) { - const { address, tokenId } = collectible; - let isOwned = collectible.isCurrentlyOwned; + const { address, tokenId } = nft; + let isOwned = nft.isCurrentlyOwned; try { - isOwned = await this.isCollectibleOwner(userAddress, address, tokenId); + isOwned = await this.isNftOwner(userAddress, address, tokenId); } catch (error) { if ( !( @@ -1188,208 +1140,187 @@ export class CollectiblesController extends BaseController< } } - collectible.isCurrentlyOwned = isOwned; + nft.isCurrentlyOwned = isOwned; if (batch === true) { - return collectible; + return nft; } - // if this is not part of a batched update we update this one collectible in state - const { allCollectibles } = this.state; - const collectibles = allCollectibles[userAddress]?.[chainId] || []; - const collectibleToUpdate = collectibles.find( + // if this is not part of a batched update we update this one NFT in state + const { allNfts } = this.state; + const nfts = allNfts[userAddress]?.[chainId] || []; + const nftToUpdate = nfts.find( (item) => item.tokenId === tokenId && item.address.toLowerCase() === address.toLowerCase(), ); - if (collectibleToUpdate) { - collectibleToUpdate.isCurrentlyOwned = isOwned; - this.updateNestedCollectibleState( - collectibles, - ALL_COLLECTIBLES_STATE_KEY, - { userAddress, chainId }, - ); + if (nftToUpdate) { + nftToUpdate.isCurrentlyOwned = isOwned; + this.updateNestedNftState(nfts, ALL_NFTS_STATE_KEY, { + userAddress, + chainId, + }); } - return collectible; + return nft; } /** - * Checks whether Collectibles associated with current selectedAddress/chainId combination are still owned by the user + * Checks whether NFTs associated with current selectedAddress/chainId combination are still owned by the user * And updates the isCurrentlyOwned value on each accordingly. */ - async checkAndUpdateAllCollectiblesOwnershipStatus() { - const { allCollectibles } = this.state; + async checkAndUpdateAllNftsOwnershipStatus() { + const { allNfts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const updatedCollectibles = await Promise.all( - collectibles.map(async (collectible) => { + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const updatedNfts = await Promise.all( + nfts.map(async (nft) => { return ( - (await this.checkAndUpdateSingleCollectibleOwnershipStatus( - collectible, - true, - )) ?? collectible + (await this.checkAndUpdateSingleNftOwnershipStatus(nft, true)) ?? nft ); }), ); - this.updateNestedCollectibleState( - updatedCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - ); + this.updateNestedNftState(updatedNfts, ALL_NFTS_STATE_KEY); } /** - * Update collectible favorite status. + * Update NFT favorite status. * - * @param address - Hex address of the collectible contract. - * @param tokenId - Hex address of the collectible contract. - * @param favorite - Collectible new favorite status. + * @param address - Hex address of the NFT contract. + * @param tokenId - Hex address of the NFT contract. + * @param favorite - NFT new favorite status. */ - updateCollectibleFavoriteStatus( - address: string, - tokenId: string, - favorite: boolean, - ) { - const { allCollectibles } = this.state; + updateNftFavoriteStatus(address: string, tokenId: string, favorite: boolean) { + const { allNfts } = this.state; const { chainId, selectedAddress } = this.config; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const index: number = collectibles.findIndex( - (collectible) => - collectible.address === address && collectible.tokenId === tokenId, + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const index: number = nfts.findIndex( + (nft) => nft.address === address && nft.tokenId === tokenId, ); if (index === -1) { return; } - const updatedCollectible: Collectible = { - ...collectibles[index], + const updatedNft: Nft = { + ...nfts[index], favorite, }; - // Update Collectibles array - collectibles[index] = updatedCollectible; + // Update Nfts array + nfts[index] = updatedNft; - this.updateNestedCollectibleState(collectibles, ALL_COLLECTIBLES_STATE_KEY); + this.updateNestedNftState(nfts, ALL_NFTS_STATE_KEY); } /** - * Returns the collectible by the address and token id. + * Returns an NFT by the address and token id. * - * @param address - Hex address of the collectible contract. + * @param address - Hex address of the NFT contract. * @param tokenId - Number that represents the id of the token. * @param selectedAddress - Hex address of the user account. * @param chainId - Id of the current network. - * @returns Object containing the Collectible and their position in the array + * @returns Object containing the NFT and its position in the array */ - findCollectibleByAddressAndTokenId( + findNftByAddressAndTokenId( address: string, tokenId: string, selectedAddress: string, chainId: string, - ): { collectible: Collectible; index: number } | null { - const { allCollectibles } = this.state; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - - const index: number = collectibles.findIndex( - (collectible) => - collectible.address.toLowerCase() === address.toLowerCase() && - collectible.tokenId === tokenId, + ): { nft: Nft; index: number } | null { + const { allNfts } = this.state; + const nfts = allNfts[selectedAddress]?.[chainId] || []; + + const index: number = nfts.findIndex( + (nft) => + nft.address.toLowerCase() === address.toLowerCase() && + nft.tokenId === tokenId, ); if (index === -1) { return null; } - return { collectible: collectibles[index], index }; + return { nft: nfts[index], index }; } /** - * Update collectible data. + * Update NFT data. * - * @param collectible - Collectible object to find the right collectible to updates. - * @param updates - Collectible partial object to update properties of the collectible. + * @param nft - NFT object to find the right NFT to updates. + * @param updates - NFT partial object to update properties of the NFT. * @param selectedAddress - Hex address of the user account. * @param chainId - Id of the current network. */ - updateCollectible( - collectible: Collectible, - updates: Partial, + updateNft( + nft: Nft, + updates: Partial, selectedAddress: string, chainId: string, ) { - const { allCollectibles } = this.state; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const collectibleInfo = this.findCollectibleByAddressAndTokenId( - collectible.address, - collectible.tokenId, + const { allNfts } = this.state; + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const nftInfo = this.findNftByAddressAndTokenId( + nft.address, + nft.tokenId, selectedAddress, chainId, ); - if (!collectibleInfo) { + if (!nftInfo) { return; } - const updatedCollectible: Collectible = { - ...collectible, + const updatedNft: Nft = { + ...nft, ...updates, }; - // Update Collectibles array - - const newCollectibles = [ - ...collectibles.slice(0, collectibleInfo.index), - updatedCollectible, - ...collectibles.slice(collectibleInfo.index + 1), + const newNfts = [ + ...nfts.slice(0, nftInfo.index), + updatedNft, + ...nfts.slice(nftInfo.index + 1), ]; - this.updateNestedCollectibleState( - newCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - ); + this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY); } /** - * Resets the transaction status of a collectible. + * Resets the transaction status of an NFT. * - * @param transactionId - Collectible transaction id. + * @param transactionId - NFT transaction id. * @param selectedAddress - Hex address of the user account. * @param chainId - Id of the current network. * @returns a boolean indicating if the reset was well succeded or not */ - resetCollectibleTransactionStatusByTransactionId( + resetNftTransactionStatusByTransactionId( transactionId: string, selectedAddress: string, chainId: string, ): boolean { - const { allCollectibles } = this.state; - const collectibles = allCollectibles[selectedAddress]?.[chainId] || []; - const index: number = collectibles.findIndex( - (collectible) => collectible.transactionId === transactionId, + const { allNfts } = this.state; + const nfts = allNfts[selectedAddress]?.[chainId] || []; + const index: number = nfts.findIndex( + (nft) => nft.transactionId === transactionId, ); if (index === -1) { return false; } - const updatedCollectible: Collectible = { - ...collectibles[index], + const updatedNft: Nft = { + ...nfts[index], transactionId: undefined, }; - // Update Collectibles array - const newCollectibles = [ - ...collectibles.slice(0, index), - updatedCollectible, - ...collectibles.slice(index + 1), + const newNfts = [ + ...nfts.slice(0, index), + updatedNft, + ...nfts.slice(index + 1), ]; - this.updateNestedCollectibleState( - newCollectibles, - ALL_COLLECTIBLES_STATE_KEY, - ); + this.updateNestedNftState(newNfts, ALL_NFTS_STATE_KEY); return true; } } -export default CollectiblesController; +export default NftController; diff --git a/src/assets/CollectibleDetectionController.test.ts b/src/assets/NftDetectionController.test.ts similarity index 66% rename from src/assets/CollectibleDetectionController.test.ts rename to src/assets/NftDetectionController.test.ts index b6d73e7055d..480838f7af2 100644 --- a/src/assets/CollectibleDetectionController.test.ts +++ b/src/assets/NftDetectionController.test.ts @@ -7,18 +7,18 @@ import { import { PreferencesController } from '../user/PreferencesController'; import { OPENSEA_PROXY_URL } from '../constants'; import { ControllerMessenger } from '../ControllerMessenger'; -import { CollectiblesController } from './CollectiblesController'; +import { NftController } from './NftController'; import { AssetsContractController } from './AssetsContractController'; -import { CollectibleDetectionController } from './CollectibleDetectionController'; +import { NftDetectionController } from './NftDetectionController'; const DEFAULT_INTERVAL = 180000; const MAINNET = 'mainnet'; const ROPSTEN = 'ropsten'; -describe('CollectibleDetectionController', () => { - let collectibleDetection: CollectibleDetectionController; +describe('NftDetectionController', () => { + let nftDetection: NftDetectionController; let preferences: PreferencesController; - let collectiblesController: CollectiblesController; + let nftController: NftController; let assetsContract: AssetsContractController; let messenger: NetworkControllerMessenger; @@ -49,7 +49,7 @@ describe('CollectibleDetectionController', () => { messenger.subscribe('NetworkController:stateChange', listener), }); - collectiblesController = new CollectiblesController({ + nftController = new NftController({ onPreferencesStateChange: (listener) => preferences.subscribe(listener), onNetworkStateChange: (listener) => messenger.subscribe('NetworkController:stateChange', listener), @@ -63,25 +63,22 @@ describe('CollectibleDetectionController', () => { assetsContract.getERC1155BalanceOf.bind(assetsContract), getERC1155TokenURI: assetsContract.getERC1155TokenURI.bind(assetsContract), - onCollectibleAdded: jest.fn(), + onNftAdded: jest.fn(), }); - collectibleDetection = new CollectibleDetectionController({ - onCollectiblesStateChange: (listener) => - collectiblesController.subscribe(listener), + nftDetection = new NftDetectionController({ + onNftsStateChange: (listener) => nftController.subscribe(listener), onPreferencesStateChange: (listener) => preferences.subscribe(listener), onNetworkStateChange: (listener) => messenger.subscribe('NetworkController:stateChange', listener), getOpenSeaApiKey: getOpenSeaApiKeyStub, - addCollectible: collectiblesController.addCollectible.bind( - collectiblesController, - ), - getCollectiblesState: () => collectiblesController.state, + addNft: nftController.addNft.bind(nftController), + getNftState: () => nftController.state, }); - collectiblesController.configure({ chainId: '1', selectedAddress: '0x1' }); + nftController.configure({ chainId: '1', selectedAddress: '0x1' }); preferences.setOpenSeaEnabled(true); - preferences.setUseCollectibleDetection(true); + preferences.setUseNftDetection(true); nock(OPENSEA_PROXY_URL) .get(`/assets?owner=0x2&offset=0&limit=50`) @@ -219,8 +216,8 @@ describe('CollectibleDetectionController', () => { }); it('should set default config', () => { - preferences.setUseCollectibleDetection(false); - expect(collectibleDetection.config).toStrictEqual({ + preferences.setUseNftDetection(false); + expect(nftDetection.config).toStrictEqual({ interval: DEFAULT_INTERVAL, networkType: 'mainnet', chainId: '1', @@ -229,92 +226,84 @@ describe('CollectibleDetectionController', () => { }); }); - it('should poll and detect collectibles on interval while on mainnet', async () => { + it('should poll and detect NFTs on interval while on mainnet', async () => { await new Promise((resolve) => { - const mockCollectibles = sinon.stub( - CollectibleDetectionController.prototype, - 'detectCollectibles', + const mockNfts = sinon.stub( + NftDetectionController.prototype, + 'detectNfts', ); - const collectiblesDetectionController = - new CollectibleDetectionController( - { - onCollectiblesStateChange: (listener) => - collectiblesController.subscribe(listener), - onPreferencesStateChange: (listener) => - preferences.subscribe(listener), - onNetworkStateChange: (listener) => - messenger.subscribe('NetworkController:stateChange', listener), - getOpenSeaApiKey: () => collectiblesController.openSeaApiKey, - addCollectible: collectiblesController.addCollectible.bind( - collectiblesController, - ), - getCollectiblesState: () => collectiblesController.state, - }, - { interval: 10 }, - ); - collectiblesDetectionController.configure({ disabled: false }); - collectiblesDetectionController.start(); - expect(mockCollectibles.calledOnce).toBe(true); + const nftsDetectionController = new NftDetectionController( + { + onNftsStateChange: (listener) => nftController.subscribe(listener), + onPreferencesStateChange: (listener) => + preferences.subscribe(listener), + onNetworkStateChange: (listener) => + messenger.subscribe('NetworkController:stateChange', listener), + getOpenSeaApiKey: () => nftController.openSeaApiKey, + addNft: nftController.addNft.bind(nftController), + getNftState: () => nftController.state, + }, + { interval: 10 }, + ); + nftsDetectionController.configure({ disabled: false }); + nftsDetectionController.start(); + expect(mockNfts.calledOnce).toBe(true); setTimeout(() => { - expect(mockCollectibles.calledTwice).toBe(true); + expect(mockNfts.calledTwice).toBe(true); resolve(''); }, 15); }); }); it('should detect mainnet correctly', () => { - collectibleDetection.configure({ networkType: MAINNET }); - expect(collectibleDetection.isMainnet()).toStrictEqual(true); - collectibleDetection.configure({ networkType: ROPSTEN }); - expect(collectibleDetection.isMainnet()).toStrictEqual(false); + nftDetection.configure({ networkType: MAINNET }); + expect(nftDetection.isMainnet()).toStrictEqual(true); + nftDetection.configure({ networkType: ROPSTEN }); + expect(nftDetection.isMainnet()).toStrictEqual(false); }); it('should not autodetect while not on mainnet', async () => { await new Promise((resolve) => { - const mockCollectibles = sinon.stub( - CollectibleDetectionController.prototype, - 'detectCollectibles', + const mockNfts = sinon.stub( + NftDetectionController.prototype, + 'detectNfts', ); - new CollectibleDetectionController( + new NftDetectionController( { - onCollectiblesStateChange: (listener) => - collectiblesController.subscribe(listener), + onNftsStateChange: (listener) => nftController.subscribe(listener), onPreferencesStateChange: (listener) => preferences.subscribe(listener), onNetworkStateChange: (listener) => messenger.subscribe('NetworkController:stateChange', listener), - getOpenSeaApiKey: () => collectiblesController.openSeaApiKey, - addCollectible: collectiblesController.addCollectible.bind( - collectiblesController, - ), - getCollectiblesState: () => collectiblesController.state, + getOpenSeaApiKey: () => nftController.openSeaApiKey, + addNft: nftController.addNft.bind(nftController), + getNftState: () => nftController.state, }, { interval: 10, networkType: ROPSTEN }, ); - expect(mockCollectibles.called).toBe(false); + expect(mockNfts.called).toBe(false); resolve(''); }); }); - it('should detect and add collectibles correctly', async () => { + it('should detect and add NFTs correctly', async () => { const selectedAddress = '0x1'; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - collectiblesController.configure({ + nftController.configure({ networkType: MAINNET, selectedAddress, }); - const { chainId } = collectibleDetection.config; + const { chainId } = nftDetection.config; - await collectibleDetection.detectCollectibles(); + await nftDetection.detectNfts(); - const collectibles = - collectiblesController.state.allCollectibles[selectedAddress][chainId]; - expect(collectibles).toStrictEqual([ + const nfts = nftController.state.allNfts[selectedAddress][chainId]; + expect(nfts).toStrictEqual([ { address: '0xebE4e5E773AFD2bAc25De0cFafa084CFb3cBf1eD', description: 'Description 2574', @@ -328,17 +317,17 @@ describe('CollectibleDetectionController', () => { ]); }); - it('should detect, add collectibles and do nor remove not detected collectibles correctly', async () => { + it('should detect, add NFTs and do nor remove not detected NFTs correctly', async () => { const selectedAddress = '0x1'; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - collectiblesController.configure({ selectedAddress }); + nftController.configure({ selectedAddress }); - const { chainId } = collectibleDetection.config; + const { chainId } = nftDetection.config; - await collectiblesController.addCollectible( + await nftController.addNft( '0xebE4e5E773AFD2bAc25De0cFafa084CFb3cBf1eD', '2573', { @@ -349,12 +338,11 @@ describe('CollectibleDetectionController', () => { }, ); - await collectibleDetection.detectCollectibles(); + await nftDetection.detectNfts(); - const collectibles = - collectiblesController.state.allCollectibles[selectedAddress][chainId]; + const nfts = nftController.state.allNfts[selectedAddress][chainId]; - expect(collectibles).toStrictEqual([ + expect(nfts).toStrictEqual([ { address: '0xebE4e5E773AFD2bAc25De0cFafa084CFb3cBf1eD', description: 'Description 2573', @@ -378,96 +366,96 @@ describe('CollectibleDetectionController', () => { ]); }); - it('should not autodetect collectibles that exist in the ignoreList', async () => { + it('should not autodetect NFTs that exist in the ignoreList', async () => { const selectedAddress = '0x2'; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress: '0x2', }); - collectiblesController.configure({ selectedAddress }); + nftController.configure({ selectedAddress }); - const { chainId } = collectibleDetection.config; + const { chainId } = nftDetection.config; - await collectibleDetection.detectCollectibles(); - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toHaveLength(1); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(0); - collectiblesController.removeAndIgnoreCollectible( + await nftDetection.detectNfts(); + expect(nftController.state.allNfts[selectedAddress][chainId]).toHaveLength( + 1, + ); + expect(nftController.state.ignoredNfts).toHaveLength(0); + nftController.removeAndIgnoreNft( '0x1d963688FE2209A98dB35C67A041524822Cf04ff', '2577', ); - expect(collectiblesController.state.ignoredCollectibles).toHaveLength(1); - await collectibleDetection.detectCollectibles(); - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toHaveLength(0); + expect(nftController.state.ignoredNfts).toHaveLength(1); + await nftDetection.detectNfts(); + expect(nftController.state.allNfts[selectedAddress][chainId]).toHaveLength( + 0, + ); }); - it('should not detect and add collectibles if there is no selectedAddress', async () => { + it('should not detect and add NFTs if there is no selectedAddress', async () => { const selectedAddress = ''; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - const { chainId } = collectibleDetection.config; - await collectibleDetection.detectCollectibles(); - const { allCollectibles } = collectiblesController.state; - expect(allCollectibles[selectedAddress]?.[chainId]).toBeUndefined(); + const { chainId } = nftDetection.config; + await nftDetection.detectNfts(); + const { allNfts } = nftController.state; + expect(allNfts[selectedAddress]?.[chainId]).toBeUndefined(); }); - it('should not detect and add collectibles to the wrong selectedAddress', async () => { - collectibleDetection.configure({ + it('should not detect and add NFTs to the wrong selectedAddress', async () => { + nftDetection.configure({ networkType: MAINNET, selectedAddress: '0x9', }); - const { chainId } = collectibleDetection.config; + const { chainId } = nftDetection.config; - collectiblesController.configure({ selectedAddress: '0x9' }); - collectibleDetection.detectCollectibles(); - collectibleDetection.configure({ selectedAddress: '0x12' }); - collectiblesController.configure({ selectedAddress: '0x12' }); + nftController.configure({ selectedAddress: '0x9' }); + nftDetection.detectNfts(); + nftDetection.configure({ selectedAddress: '0x12' }); + nftController.configure({ selectedAddress: '0x12' }); await new Promise((res) => setTimeout(() => res(true), 1000)); - expect(collectibleDetection.config.selectedAddress).toStrictEqual('0x12'); + expect(nftDetection.config.selectedAddress).toStrictEqual('0x12'); expect( - collectiblesController.state.allCollectibles[ - collectibleDetection.config.selectedAddress - ]?.[chainId], + nftController.state.allNfts[nftDetection.config.selectedAddress]?.[ + chainId + ], ).toBeUndefined(); }); - it('should not detect and add collectibles if preferences controller useCollectibleDetection is set to false', async () => { - preferences.setUseCollectibleDetection(false); + it('should not detect and add NFTs if preferences controller useNftDetection is set to false', async () => { + preferences.setUseNftDetection(false); const selectedAddress = '0x9'; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - const { chainId } = collectiblesController.config; - collectibleDetection.detectCollectibles(); + const { chainId } = nftController.config; + nftDetection.detectNfts(); expect( - collectiblesController.state.allCollectibles[selectedAddress]?.[chainId], + nftController.state.allNfts[selectedAddress]?.[chainId], ).toBeUndefined(); }); - it('should not detect and add collectibles if preferences controller openSeaEnabled is set to false', async () => { + it('should not detect and add NFTs if preferences controller openSeaEnabled is set to false', async () => { preferences.setOpenSeaEnabled(false); const selectedAddress = '0x9'; - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - const { chainId } = collectiblesController.config; - collectibleDetection.detectCollectibles(); + const { chainId } = nftController.config; + nftDetection.detectNfts(); expect( - collectiblesController.state.allCollectibles[selectedAddress]?.[chainId], + nftController.state.allNfts[selectedAddress]?.[chainId], ).toBeUndefined(); }); - it('should not add collectible if collectible or collectible contract has no information to display', async () => { - const collectibleHH2574 = { + it('should not add NFT if NFT or NFT contract has no information to display', async () => { + const nftHH2574 = { address: '0xebE4e5E773AFD2bAc25De0cFafa084CFb3cBf1eD', description: 'Description 2574', image: 'image/2574.png', @@ -477,7 +465,7 @@ describe('CollectibleDetectionController', () => { favorite: false, isCurrentlyOwned: true, }; - const collectibleGG2574 = { + const nftGG2574 = { address: '0xCE7ec4B2DfB30eB6c0BB5656D33aAd6BFb4001Fc', description: 'Description 2574', image: 'image/2574.png', @@ -487,7 +475,7 @@ describe('CollectibleDetectionController', () => { favorite: false, isCurrentlyOwned: true, }; - const collectibleII2577 = { + const nftII2577 = { address: '0x0B0fa4fF58D28A88d63235bd0756EDca69e49e6d', description: 'Description 2577', image: 'image/2577.png', @@ -497,7 +485,7 @@ describe('CollectibleDetectionController', () => { favorite: false, isCurrentlyOwned: true, }; - const collectibleContractHH = { + const nftContractHH = { address: '0xebE4e5E773AFD2bAc25De0cFafa084CFb3cBf1eD', description: 'Description HH', logo: 'url HH', @@ -505,7 +493,7 @@ describe('CollectibleDetectionController', () => { symbol: 'HH', totalSupply: 10, }; - const collectibleContractGG = { + const nftContractGG = { address: '0xCE7ec4B2DfB30eB6c0BB5656D33aAd6BFb4001Fc', description: 'Description GG', logo: 'url GG', @@ -513,7 +501,7 @@ describe('CollectibleDetectionController', () => { symbol: 'GG', totalSupply: 10, }; - const collectibleContractII = { + const nftContractII = { address: '0x0B0fa4fF58D28A88d63235bd0756EDca69e49e6d', description: 'Description II', logo: 'url II', @@ -523,28 +511,26 @@ describe('CollectibleDetectionController', () => { }; const selectedAddress = '0x1'; - collectibleDetection.configure({ + nftDetection.configure({ selectedAddress, networkType: MAINNET, }); - collectiblesController.configure({ + nftController.configure({ selectedAddress, networkType: MAINNET, }); - const { chainId } = collectibleDetection.config; - await collectibleDetection.detectCollectibles(); + const { chainId } = nftDetection.config; + await nftDetection.detectNfts(); // First fetch to API, only gets information from contract ending in HH - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toStrictEqual([collectibleHH2574]); + expect(nftController.state.allNfts[selectedAddress][chainId]).toStrictEqual( + [nftHH2574], + ); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], - ).toStrictEqual([collectibleContractHH]); + nftController.state.allNftContracts[selectedAddress][chainId], + ).toStrictEqual([nftContractHH]); // During next call of assets detection, API succeds returning contract ending in gg information nock(OPENSEA_PROXY_URL) @@ -620,28 +606,22 @@ describe('CollectibleDetectionController', () => { assets: [], }); - // Now user should have respective collectibles - await collectibleDetection.detectCollectibles(); + // Now user should have respective NFTs + await nftDetection.detectNfts(); expect( - collectiblesController.state.allCollectibleContracts[selectedAddress][ - chainId - ], - ).toStrictEqual([ - collectibleContractHH, - collectibleContractII, - collectibleContractGG, - ]); + nftController.state.allNftContracts[selectedAddress][chainId], + ).toStrictEqual([nftContractHH, nftContractII, nftContractGG]); - expect( - collectiblesController.state.allCollectibles[selectedAddress][chainId], - ).toStrictEqual([collectibleHH2574, collectibleII2577, collectibleGG2574]); + expect(nftController.state.allNfts[selectedAddress][chainId]).toStrictEqual( + [nftHH2574, nftII2577, nftGG2574], + ); }); it('should fallback to use OpenSea API directly when the OpenSea proxy server is down or responds with a failure', async () => { const selectedAddress = '0x3'; getOpenSeaApiKeyStub.mockImplementation(() => 'FAKE API KEY'); - collectiblesController.setApiKey('FAKE API KEY'); + nftController.setApiKey('FAKE API KEY'); nock('https://proxy.metaswap.codefi.network:443', { encodedQueryParams: true, @@ -700,23 +680,22 @@ describe('CollectibleDetectionController', () => { }, }); - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - collectiblesController.configure({ + nftController.configure({ networkType: MAINNET, selectedAddress, }); - const { chainId } = collectibleDetection.config; + const { chainId } = nftDetection.config; - await collectibleDetection.detectCollectibles(); + await nftDetection.detectNfts(); - const collectibles = - collectiblesController.state.allCollectibles[selectedAddress][chainId]; - expect(collectibles).toStrictEqual([ + const nfts = nftController.state.allNfts[selectedAddress][chainId]; + expect(nfts).toStrictEqual([ { address: '0x1d963688FE2209A98dB35C67A041524822Cf04ff', description: 'DESCRIPTION: DIRECT FROM OPENSEA', @@ -739,18 +718,18 @@ describe('CollectibleDetectionController', () => { .query({ owner: selectedAddress, offset: '0', limit: '50' }) .replyWithError(new Error('UNEXPECTED ERROR')); - collectibleDetection.configure({ + nftDetection.configure({ networkType: MAINNET, selectedAddress, }); - collectiblesController.configure({ + nftController.configure({ networkType: MAINNET, selectedAddress, }); - await expect(() => - collectibleDetection.detectCollectibles(), - ).rejects.toThrow('UNEXPECTED ERROR'); + await expect(() => nftDetection.detectNfts()).rejects.toThrow( + 'UNEXPECTED ERROR', + ); }); }); diff --git a/src/assets/CollectibleDetectionController.ts b/src/assets/NftDetectionController.ts similarity index 50% rename from src/assets/CollectibleDetectionController.ts rename to src/assets/NftDetectionController.ts index 1914a21c370..ff43b2dce36 100644 --- a/src/assets/CollectibleDetectionController.ts +++ b/src/assets/NftDetectionController.ts @@ -4,35 +4,31 @@ import type { PreferencesState } from '../user/PreferencesController'; import { fetchWithErrorHandling, toChecksumHexAddress } from '../util'; import { MAINNET, OPENSEA_PROXY_URL, OPENSEA_API_URL } from '../constants'; -import type { - CollectiblesController, - CollectiblesState, - CollectibleMetadata, -} from './CollectiblesController'; +import type { NftController, NftState, NftMetadata } from './NftController'; const DEFAULT_INTERVAL = 180000; /** - * @type ApiCollectible + * @type ApiNft * - * Collectible object coming from OpenSea api - * @property token_id - The collectible identifier + * NFT object coming from OpenSea api + * @property token_id - The NFT identifier * @property num_sales - Number of sales * @property background_color - The background color to be displayed with the item - * @property image_url - URI of an image associated with this collectible - * @property image_preview_url - URI of a smaller image associated with this collectible - * @property image_thumbnail_url - URI of a thumbnail image associated with this collectible - * @property image_original_url - URI of the original image associated with this collectible - * @property animation_url - URI of a animation associated with this collectible - * @property animation_original_url - URI of the original animation associated with this collectible - * @property name - The collectible name - * @property description - The collectible description + * @property image_url - URI of an image associated with this NFT + * @property image_preview_url - URI of a smaller image associated with this NFT + * @property image_thumbnail_url - URI of a thumbnail image associated with this NFT + * @property image_original_url - URI of the original image associated with this NFT + * @property animation_url - URI of a animation associated with this NFT + * @property animation_original_url - URI of the original animation associated with this NFT + * @property name - The NFT name + * @property description - The NFT description * @property external_link - External link containing additional information - * @property assetContract - The collectible contract information object - * @property creator - The collectible owner information object + * @property assetContract - The NFT contract information object + * @property creator - The NFT owner information object * @property lastSale - When this item was last sold */ -export interface ApiCollectible { +export interface ApiNft { token_id: string; num_sales: number | null; background_color: string | null; @@ -45,26 +41,26 @@ export interface ApiCollectible { name: string | null; description: string | null; external_link: string | null; - asset_contract: ApiCollectibleContract; - creator: ApiCollectibleCreator; - last_sale: ApiCollectibleLastSale | null; + asset_contract: ApiNftContract; + creator: ApiNftCreator; + last_sale: ApiNftLastSale | null; } /** - * @type ApiCollectibleContract + * @type ApiNftContract * - * Collectible contract object coming from OpenSea api - * @property address - Address of the collectible contract - * @property asset_contract_type - The collectible type, it could be `semi-fungible` or `non-fungible` + * NFT contract object coming from OpenSea api + * @property address - Address of the NFT contract + * @property asset_contract_type - The NFT type, it could be `semi-fungible` or `non-fungible` * @property created_date - Creation date * @property collection - Object containing the contract name and URI of an image associated * @property schema_name - The schema followed by the contract, it could be `ERC721` or `ERC1155` - * @property symbol - The collectible contract symbol - * @property total_supply - Total supply of collectibles - * @property description - The collectible contract description + * @property symbol - The NFT contract symbol + * @property total_supply - Total supply of NFTs + * @property description - The NFT contract description * @property external_link - External link containing additional information */ -export interface ApiCollectibleContract { +export interface ApiNftContract { address: string; asset_contract_type: string | null; created_date: string | null; @@ -80,43 +76,43 @@ export interface ApiCollectibleContract { } /** - * @type ApiCollectibleLastSale + * @type ApiNftLastSale * - * Collectible sale object coming from OpenSea api + * NFT sale object coming from OpenSea api * @property event_timestamp - Object containing a `username` - * @property total_price - URI of collectible image associated with this owner + * @property total_price - URI of NFT image associated with this owner * @property transaction - Object containing transaction_hash and block_hash */ -export interface ApiCollectibleLastSale { +export interface ApiNftLastSale { event_timestamp: string; total_price: string; transaction: { transaction_hash: string; block_hash: string }; } /** - * @type ApiCollectibleCreator + * @type ApiNftCreator * - * Collectible creator object coming from OpenSea api + * NFT creator object coming from OpenSea api * @property user - Object containing a `username` - * @property profile_img_url - URI of collectible image associated with this owner + * @property profile_img_url - URI of NFT image associated with this owner * @property address - The owner address */ -export interface ApiCollectibleCreator { +export interface ApiNftCreator { user: { username: string }; profile_img_url: string; address: string; } /** - * @type CollectibleDetectionConfig + * @type NftDetectionConfig * - * CollectibleDetection configuration + * NftDetection configuration * @property interval - Polling interval used to fetch new token rates * @property networkType - Network type ID as per net_version * @property selectedAddress - Vault selected address * @property tokens - List of tokens associated with the active vault */ -export interface CollectibleDetectionConfig extends BaseConfig { +export interface NftDetectionConfig extends BaseConfig { interval: number; networkType: NetworkType; chainId: `0x${string}` | `${number}` | number; @@ -124,15 +120,15 @@ export interface CollectibleDetectionConfig extends BaseConfig { } /** - * Controller that passively polls on a set interval for Collectibles auto detection + * Controller that passively polls on a set interval for NFT auto detection */ -export class CollectibleDetectionController extends BaseController< - CollectibleDetectionConfig, +export class NftDetectionController extends BaseController< + NftDetectionConfig, BaseState > { private intervalId?: NodeJS.Timeout; - private getOwnerCollectiblesApi({ + private getOwnerNftApi({ address, offset, useProxy, @@ -146,22 +142,22 @@ export class CollectibleDetectionController extends BaseController< : `${OPENSEA_API_URL}/assets?owner=${address}&offset=${offset}&limit=50`; } - private async getOwnerCollectibles(address: string) { - let collectiblesApiResponse: { assets: ApiCollectible[] }; - let collectibles: ApiCollectible[] = []; + private async getOwnerNfts(address: string) { + let nftApiResponse: { assets: ApiNft[] }; + let nfts: ApiNft[] = []; const openSeaApiKey = this.getOpenSeaApiKey(); let offset = 0; let pagingFinish = false; /* istanbul ignore if */ do { - collectiblesApiResponse = await fetchWithErrorHandling({ - url: this.getOwnerCollectiblesApi({ address, offset, useProxy: true }), + nftApiResponse = await fetchWithErrorHandling({ + url: this.getOwnerNftApi({ address, offset, useProxy: true }), timeout: 15000, }); - if (openSeaApiKey && !collectiblesApiResponse) { - collectiblesApiResponse = await fetchWithErrorHandling({ - url: this.getOwnerCollectiblesApi({ + if (openSeaApiKey && !nftApiResponse) { + nftApiResponse = await fetchWithErrorHandling({ + url: this.getOwnerNftApi({ address, offset, useProxy: false, @@ -173,40 +169,40 @@ export class CollectibleDetectionController extends BaseController< }); } - if (!collectiblesApiResponse) { - return collectibles; + if (!nftApiResponse) { + return nfts; } - collectiblesApiResponse?.assets?.length !== 0 - ? (collectibles = [...collectibles, ...collectiblesApiResponse.assets]) + nftApiResponse?.assets?.length !== 0 + ? (nfts = [...nfts, ...nftApiResponse.assets]) : (pagingFinish = true); offset += 50; } while (!pagingFinish); - return collectibles; + return nfts; } /** * Name of this controller used during composition */ - override name = 'CollectibleDetectionController'; + override name = 'NftDetectionController'; private getOpenSeaApiKey: () => string | undefined; - private addCollectible: CollectiblesController['addCollectible']; + private addNft: NftController['addNft']; - private getCollectiblesState: () => CollectiblesState; + private getNftState: () => NftState; /** - * Creates a CollectibleDetectionController instance. + * Creates a NftDetectionController instance. * * @param options - The controller options. - * @param options.onCollectiblesStateChange - Allows subscribing to assets controller state changes. + * @param options.onNftsStateChange - Allows subscribing to assets controller state changes. * @param options.onPreferencesStateChange - Allows subscribing to preferences controller state changes. * @param options.onNetworkStateChange - Allows subscribing to network controller state changes. * @param options.getOpenSeaApiKey - Gets the OpenSea API key, if one is set. - * @param options.addCollectible - Add a collectible. - * @param options.getCollectiblesState - Gets the current state of the Assets controller. + * @param options.addNft - Add an NFT. + * @param options.getNftState - Gets the current state of the Assets controller. * @param config - Initial options used to configure this controller. * @param state - Initial state to set on this controller. */ @@ -215,12 +211,10 @@ export class CollectibleDetectionController extends BaseController< onPreferencesStateChange, onNetworkStateChange, getOpenSeaApiKey, - addCollectible, - getCollectiblesState, + addNft, + getNftState, }: { - onCollectiblesStateChange: ( - listener: (collectiblesState: CollectiblesState) => void, - ) => void; + onNftsStateChange: (listener: (nftsState: NftState) => void) => void; onPreferencesStateChange: ( listener: (preferencesState: PreferencesState) => void, ) => void; @@ -228,10 +222,10 @@ export class CollectibleDetectionController extends BaseController< listener: (networkState: NetworkState) => void, ) => void; getOpenSeaApiKey: () => string | undefined; - addCollectible: CollectiblesController['addCollectible']; - getCollectiblesState: () => CollectiblesState; + addNft: NftController['addNft']; + getNftState: () => NftState; }, - config?: Partial, + config?: Partial, state?: Partial, ) { super(config, state); @@ -243,20 +237,20 @@ export class CollectibleDetectionController extends BaseController< disabled: true, }; this.initialize(); - this.getCollectiblesState = getCollectiblesState; - onPreferencesStateChange(({ selectedAddress, useCollectibleDetection }) => { + this.getNftState = getNftState; + onPreferencesStateChange(({ selectedAddress, useNftDetection }) => { const { selectedAddress: previouslySelectedAddress, disabled } = this.config; if ( selectedAddress !== previouslySelectedAddress || - !useCollectibleDetection !== disabled + !useNftDetection !== disabled ) { - this.configure({ selectedAddress, disabled: !useCollectibleDetection }); + this.configure({ selectedAddress, disabled: !useNftDetection }); } - if (useCollectibleDetection !== undefined) { - if (useCollectibleDetection) { + if (useNftDetection !== undefined) { + if (useNftDetection) { this.start(); } else { this.stop(); @@ -267,11 +261,11 @@ export class CollectibleDetectionController extends BaseController< onNetworkStateChange(({ provider }) => { this.configure({ networkType: provider.type, - chainId: provider.chainId as CollectibleDetectionConfig['chainId'], + chainId: provider.chainId as NftDetectionConfig['chainId'], }); }); this.getOpenSeaApiKey = getOpenSeaApiKey; - this.addCollectible = addCollectible; + this.addNft = addNft; } /** @@ -306,9 +300,9 @@ export class CollectibleDetectionController extends BaseController< private async startPolling(interval?: number): Promise { interval && this.configure({ interval }, false, false); this.stopPolling(); - await this.detectCollectibles(); + await this.detectNfts(); this.intervalId = setInterval(async () => { - await this.detectCollectibles(); + await this.detectNfts(); }, this.config.interval); } @@ -320,10 +314,10 @@ export class CollectibleDetectionController extends BaseController< isMainnet = (): boolean => this.config.networkType === MAINNET; /** - * Triggers asset ERC721 token auto detection on mainnet. Any newly detected collectibles are + * Triggers asset ERC721 token auto detection on mainnet. Any newly detected NFTs are * added. */ - async detectCollectibles() { + async detectNfts() { /* istanbul ignore if */ if (!this.isMainnet() || this.disabled) { return; @@ -335,72 +329,70 @@ export class CollectibleDetectionController extends BaseController< return; } - const apiCollectibles = await this.getOwnerCollectibles(selectedAddress); - const addCollectiblesPromises = apiCollectibles.map( - async (collectible: ApiCollectible) => { - const { - token_id, - num_sales, - background_color, - image_url, - image_preview_url, - image_thumbnail_url, - image_original_url, - animation_url, - animation_original_url, - name, - description, - external_link, - creator, - asset_contract: { address, schema_name }, - last_sale, - } = collectible; - - let ignored; - /* istanbul ignore else */ - const { ignoredCollectibles } = this.getCollectiblesState(); - if (ignoredCollectibles.length) { - ignored = ignoredCollectibles.find((c) => { - /* istanbul ignore next */ - return ( - c.address === toChecksumHexAddress(address) && - c.tokenId === token_id - ); - }); - } - - /* istanbul ignore else */ - if (!ignored) { + const apiNfts = await this.getOwnerNfts(selectedAddress); + const addNftPromises = apiNfts.map(async (nft: ApiNft) => { + const { + token_id, + num_sales, + background_color, + image_url, + image_preview_url, + image_thumbnail_url, + image_original_url, + animation_url, + animation_original_url, + name, + description, + external_link, + creator, + asset_contract: { address, schema_name }, + last_sale, + } = nft; + + let ignored; + /* istanbul ignore else */ + const { ignoredNfts } = this.getNftState(); + if (ignoredNfts.length) { + ignored = ignoredNfts.find((c) => { /* istanbul ignore next */ - const collectibleMetadata: CollectibleMetadata = Object.assign( - {}, - { name }, - creator && { creator }, - description && { description }, - image_url && { image: image_url }, - num_sales && { numberOfSales: num_sales }, - background_color && { backgroundColor: background_color }, - image_preview_url && { imagePreview: image_preview_url }, - image_thumbnail_url && { imageThumbnail: image_thumbnail_url }, - image_original_url && { imageOriginal: image_original_url }, - animation_url && { animation: animation_url }, - animation_original_url && { - animationOriginal: animation_original_url, - }, - schema_name && { standard: schema_name }, - external_link && { externalLink: external_link }, - last_sale && { lastSale: last_sale }, + return ( + c.address === toChecksumHexAddress(address) && + c.tokenId === token_id ); + }); + } - await this.addCollectible(address, token_id, collectibleMetadata, { - userAddress: selectedAddress, - chainId: chainId as string, - }); - } - }, - ); - await Promise.all(addCollectiblesPromises); + /* istanbul ignore else */ + if (!ignored) { + /* istanbul ignore next */ + const nftMetadata: NftMetadata = Object.assign( + {}, + { name }, + creator && { creator }, + description && { description }, + image_url && { image: image_url }, + num_sales && { numberOfSales: num_sales }, + background_color && { backgroundColor: background_color }, + image_preview_url && { imagePreview: image_preview_url }, + image_thumbnail_url && { imageThumbnail: image_thumbnail_url }, + image_original_url && { imageOriginal: image_original_url }, + animation_url && { animation: animation_url }, + animation_original_url && { + animationOriginal: animation_original_url, + }, + schema_name && { standard: schema_name }, + external_link && { externalLink: external_link }, + last_sale && { lastSale: last_sale }, + ); + + await this.addNft(address, token_id, nftMetadata, { + userAddress: selectedAddress, + chainId: chainId as string, + }); + } + }); + await Promise.all(addNftPromises); } } -export default CollectibleDetectionController; +export default NftDetectionController; diff --git a/src/assets/Standards/CollectibleStandards/ERC1155/ERC1155Standard.test.ts b/src/assets/Standards/NftStandards/ERC1155/ERC1155Standard.test.ts similarity index 100% rename from src/assets/Standards/CollectibleStandards/ERC1155/ERC1155Standard.test.ts rename to src/assets/Standards/NftStandards/ERC1155/ERC1155Standard.test.ts diff --git a/src/assets/Standards/CollectibleStandards/ERC1155/ERC1155Standard.ts b/src/assets/Standards/NftStandards/ERC1155/ERC1155Standard.ts similarity index 100% rename from src/assets/Standards/CollectibleStandards/ERC1155/ERC1155Standard.ts rename to src/assets/Standards/NftStandards/ERC1155/ERC1155Standard.ts diff --git a/src/assets/Standards/CollectibleStandards/ERC721/ERC721Standard.test.ts b/src/assets/Standards/NftStandards/ERC721/ERC721Standard.test.ts similarity index 100% rename from src/assets/Standards/CollectibleStandards/ERC721/ERC721Standard.test.ts rename to src/assets/Standards/NftStandards/ERC721/ERC721Standard.test.ts diff --git a/src/assets/Standards/CollectibleStandards/ERC721/ERC721Standard.ts b/src/assets/Standards/NftStandards/ERC721/ERC721Standard.ts similarity index 98% rename from src/assets/Standards/CollectibleStandards/ERC721/ERC721Standard.ts rename to src/assets/Standards/NftStandards/ERC721/ERC721Standard.ts index ca4f9eebb84..048ea19905d 100644 --- a/src/assets/Standards/CollectibleStandards/ERC721/ERC721Standard.ts +++ b/src/assets/Standards/NftStandards/ERC721/ERC721Standard.ts @@ -62,10 +62,10 @@ export class ERC721Standard { * * @param address - ERC721 asset contract address. * @param selectedAddress - Current account public address. - * @param index - A collectible counter less than `balanceOf(selectedAddress)`. + * @param index - An NFT counter less than `balanceOf(selectedAddress)`. * @returns Promise resolving to token identifier for the 'index'th asset assigned to 'selectedAddress'. */ - getCollectibleTokenId = async ( + getNftTokenId = async ( address: string, selectedAddress: string, index: number, diff --git a/src/assets/TokensController.test.ts b/src/assets/TokensController.test.ts index dd5a24366cd..41c11a1a066 100644 --- a/src/assets/TokensController.test.ts +++ b/src/assets/TokensController.test.ts @@ -488,7 +488,7 @@ describe('TokensController', () => { describe('isERC721 flag', function () { describe('updateTokenType method', function () { - it('should add isERC721 = true to token object already in state when token is collectible and in our contract-metadata repo', async function () { + it('should add isERC721 = true to token object already in state when token is NFT and in our contract-metadata repo', async function () { const contractAddresses = Object.keys(contractMaps); const erc721ContractAddresses = contractAddresses.filter( (contractAddress) => contractMaps[contractAddress].erc721 === true, @@ -502,7 +502,7 @@ describe('TokensController', () => { expect(result.isERC721).toBe(true); }); - it('should add isERC721 = false to token object already in state when token is not a collectible and is in our contract-metadata repo', async function () { + it('should add isERC721 = false to token object already in state when token is not an NFT and is in our contract-metadata repo', async function () { const contractAddresses = Object.keys(contractMaps); const erc20ContractAddresses = contractAddresses.filter( (contractAddress) => contractMaps[contractAddress].erc20 === true, @@ -516,7 +516,7 @@ describe('TokensController', () => { expect(result.isERC721).toBe(false); }); - it('should add isERC721 = true to token object already in state when token is collectible and is not in our contract-metadata repo', async function () { + it('should add isERC721 = true to token object already in state when token is NFT and is not in our contract-metadata repo', async function () { const stub = stubCreateEthers(tokensController, true); const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d'; tokensController.update({ @@ -535,7 +535,7 @@ describe('TokensController', () => { stub.restore(); }); - it('should add isERC721 = false to token object already in state when token is not a collectible and not in our contract-metadata repo', async function () { + it('should add isERC721 = false to token object already in state when token is not an NFT and not in our contract-metadata repo', async function () { const stub = stubCreateEthers(tokensController, false); const tokenAddress = '0xda5584cc586d07c7141aa427224a4bd58e64af7d'; tokensController.update({ @@ -556,7 +556,7 @@ describe('TokensController', () => { }); describe('addToken method', function () { - it('should add isERC721 = true when token is a collectible and is in our contract-metadata repo', async function () { + it('should add isERC721 = true when token is an NFT and is in our contract-metadata repo', async function () { const contractAddresses = Object.keys(contractMaps); const erc721ContractAddresses = contractAddresses.filter( (contractAddress) => contractMaps[contractAddress].erc721 === true, @@ -575,7 +575,7 @@ describe('TokensController', () => { ]); }); - it('should add isERC721 = true when the token is a collectible but not in our contract-metadata repo', async function () { + it('should add isERC721 = true when the token is an NFT but not in our contract-metadata repo', async function () { const stub = stubCreateEthers(tokensController, true); const tokenAddress = '0xDA5584Cc586d07c7141aA427224A4Bd58E64aF7D'; @@ -596,7 +596,7 @@ describe('TokensController', () => { stub.restore(); }); - it('should add isERC721 = false to token object already in state when token is not a collectible and in our contract-metadata repo', async function () { + it('should add isERC721 = false to token object already in state when token is not an NFT and in our contract-metadata repo', async function () { const contractAddresses = Object.keys(contractMaps); const erc20ContractAddresses = contractAddresses.filter( (contractAddress) => contractMaps[contractAddress].erc20 === true, @@ -616,7 +616,7 @@ describe('TokensController', () => { ]); }); - it('should add isERC721 = false when the token is not a collectible and not in our contract-metadata repo', async function () { + it('should add isERC721 = false when the token is not an NFT and not in our contract-metadata repo', async function () { const stub = stubCreateEthers(tokensController, false); const tokenAddress = '0xDA5584Cc586d07c7141aA427224A4Bd58E64aF7D'; diff --git a/src/assets/assetsUtil.test.ts b/src/assets/assetsUtil.test.ts index cabb6efacc0..a67925867b6 100644 --- a/src/assets/assetsUtil.test.ts +++ b/src/assets/assetsUtil.test.ts @@ -1,11 +1,11 @@ import { NetworksChainId } from '../network/NetworkController'; import * as assetsUtil from './assetsUtil'; -import { Collectible, CollectibleMetadata } from './CollectiblesController'; +import { Nft, NftMetadata } from './NftController'; describe('assetsUtil', () => { - describe('compareCollectiblesMetadata', () => { + describe('compareNftMetadata', () => { it('should resolve true if any key is different', () => { - const collectibleMetadata: CollectibleMetadata = { + const nftMetadata: NftMetadata = { name: 'name', image: 'image', description: 'description', @@ -18,7 +18,7 @@ describe('assetsUtil', () => { animationOriginal: 'animationOriginal', externalLink: 'externalLink-123', }; - const collectible: Collectible = { + const nft: Nft = { address: 'address', tokenId: '123', name: 'name', @@ -33,22 +33,19 @@ describe('assetsUtil', () => { animationOriginal: 'animationOriginal', externalLink: 'externalLink', }; - const different = assetsUtil.compareCollectiblesMetadata( - collectibleMetadata, - collectible, - ); + const different = assetsUtil.compareNftMetadata(nftMetadata, nft); expect(different).toStrictEqual(true); }); it('should resolve true if any key is different as always as metadata is not undefined', () => { - const collectibleMetadata: CollectibleMetadata = { + const nftMetadata: NftMetadata = { name: 'name', image: 'image', description: 'description', standard: 'standard', externalLink: 'externalLink', }; - const collectible: Collectible = { + const nft: Nft = { address: 'address', tokenId: '123', name: 'name', @@ -58,15 +55,12 @@ describe('assetsUtil', () => { backgroundColor: 'backgroundColor', externalLink: 'externalLink', }; - const different = assetsUtil.compareCollectiblesMetadata( - collectibleMetadata, - collectible, - ); + const different = assetsUtil.compareNftMetadata(nftMetadata, nft); expect(different).toStrictEqual(false); }); it('should resolve false if no key is different', () => { - const collectibleMetadata: CollectibleMetadata = { + const nftMetadata: NftMetadata = { name: 'name', image: 'image', description: 'description', @@ -79,7 +73,7 @@ describe('assetsUtil', () => { animationOriginal: 'animationOriginal', externalLink: 'externalLink', }; - const collectible: Collectible = { + const nft: Nft = { address: 'address', tokenId: '123', name: 'name', @@ -94,10 +88,7 @@ describe('assetsUtil', () => { animationOriginal: 'animationOriginal', externalLink: 'externalLink', }; - const different = assetsUtil.compareCollectiblesMetadata( - collectibleMetadata, - collectible, - ); + const different = assetsUtil.compareNftMetadata(nftMetadata, nft); expect(different).toStrictEqual(false); }); diff --git a/src/assets/assetsUtil.ts b/src/assets/assetsUtil.ts index f12b2c298b2..ee02087f627 100644 --- a/src/assets/assetsUtil.ts +++ b/src/assets/assetsUtil.ts @@ -1,20 +1,17 @@ import { convertHexToDecimal } from '../util'; -import { Collectible, CollectibleMetadata } from './CollectiblesController'; +import { Nft, NftMetadata } from './NftController'; /** - * Compares collectible metadata entries to any collectible entry. - * We need this method when comparing a new fetched collectible metadata, in case a entry changed to a defined value, - * there's a need to update the collectible in state. + * Compares NFT metadata entries to any NFT entry. + * We need this method when comparing a new fetched NFT metadata, in case a entry changed to a defined value, + * there's a need to update the NFT in state. * - * @param newCollectibleMetadata - Collectible metadata object. - * @param collectible - Collectible object to compare with. + * @param newNftMetadata - NFT metadata object. + * @param nft - NFT object to compare with. * @returns Whether there are differences. */ -export function compareCollectiblesMetadata( - newCollectibleMetadata: CollectibleMetadata, - collectible: Collectible, -) { - const keys: (keyof CollectibleMetadata)[] = [ +export function compareNftMetadata(newNftMetadata: NftMetadata, nft: Nft) { + const keys: (keyof NftMetadata)[] = [ 'image', 'backgroundColor', 'imagePreview', @@ -25,10 +22,7 @@ export function compareCollectiblesMetadata( 'externalLink', ]; const differentValues = keys.reduce((value, key) => { - if ( - newCollectibleMetadata[key] && - newCollectibleMetadata[key] !== collectible[key] - ) { + if (newNftMetadata[key] && newNftMetadata[key] !== nft[key]) { return value + 1; } return value; diff --git a/src/constants.ts b/src/constants.ts index 5ce57a214f3..e1a16dd9195 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -32,7 +32,7 @@ export const ESTIMATE_GAS_ERROR = 'eth_estimateGas rpc method error'; export const ASSET_TYPES = { NATIVE: 'NATIVE', TOKEN: 'TOKEN', - COLLECTIBLE: 'COLLECTIBLE', + NFT: 'NFT', UNKNOWN: 'UNKNOWN', }; diff --git a/src/index.ts b/src/index.ts index 240872deaf1..816ed3b0f67 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,9 +33,9 @@ export * from './announcement/AnnouncementController'; export * from './assets/TokenListController'; export * from './gas/GasFeeController'; export * from './assets/TokensController'; -export * from './assets/CollectiblesController'; +export * from './assets/NftController'; export * from './assets/TokenDetectionController'; -export * from './assets/CollectibleDetectionController'; +export * from './assets/NftDetectionController'; export * from './permissions'; export * from './subject-metadata'; export * from './ratelimit/RateLimitController'; diff --git a/src/user/PreferencesController.test.ts b/src/user/PreferencesController.test.ts index ce48dc5bba5..73dc46efab1 100644 --- a/src/user/PreferencesController.test.ts +++ b/src/user/PreferencesController.test.ts @@ -11,7 +11,7 @@ describe('PreferencesController', () => { lostIdentities: {}, selectedAddress: '', useTokenDetection: true, - useCollectibleDetection: false, + useNftDetection: false, openSeaEnabled: false, }); }); @@ -219,10 +219,10 @@ describe('PreferencesController', () => { expect(controller.state.useTokenDetection).toStrictEqual(true); }); - it('should set useCollectibleDetection', () => { + it('should set useNftDetection', () => { const controller = new PreferencesController(); controller.setOpenSeaEnabled(true); - controller.setUseCollectibleDetection(true); - expect(controller.state.useCollectibleDetection).toStrictEqual(true); + controller.setUseNftDetection(true); + expect(controller.state.useNftDetection).toStrictEqual(true); }); }); diff --git a/src/user/PreferencesController.ts b/src/user/PreferencesController.ts index 374ef128d96..6d13bc6cd10 100644 --- a/src/user/PreferencesController.ts +++ b/src/user/PreferencesController.ts @@ -46,7 +46,7 @@ export interface PreferencesState extends BaseState { lostIdentities: { [address: string]: ContactEntry }; selectedAddress: string; useTokenDetection: boolean; - useCollectibleDetection: boolean; + useNftDetection: boolean; openSeaEnabled: boolean; } @@ -78,7 +78,7 @@ export class PreferencesController extends BaseController< lostIdentities: {}, selectedAddress: '', useTokenDetection: true, - useCollectibleDetection: false, + useNftDetection: false, openSeaEnabled: false, }; this.initialize(); @@ -298,17 +298,17 @@ export class PreferencesController extends BaseController< } /** - * Toggle the collectible detection setting. + * Toggle the NFT detection setting. * - * @param useCollectibleDetection - Boolean indicating user preference on collectible detection. + * @param useNftDetection - Boolean indicating user preference on NFT detection. */ - setUseCollectibleDetection(useCollectibleDetection: boolean) { - if (useCollectibleDetection && !this.state.openSeaEnabled) { + setUseNftDetection(useNftDetection: boolean) { + if (useNftDetection && !this.state.openSeaEnabled) { throw new Error( - 'useCollectibleDetection cannot be enabled if openSeaEnabled is false', + 'useNftDetection cannot be enabled if openSeaEnabled is false', ); } - this.update({ useCollectibleDetection }); + this.update({ useNftDetection }); } /** @@ -319,7 +319,7 @@ export class PreferencesController extends BaseController< setOpenSeaEnabled(openSeaEnabled: boolean) { this.update({ openSeaEnabled }); if (!openSeaEnabled) { - this.update({ useCollectibleDetection: false }); + this.update({ useNftDetection: false }); } } } From 380b2fbfd0cf771b5074a9021145db8f30ef366c Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Wed, 12 Oct 2022 18:35:50 -0230 Subject: [PATCH 2/2] Fix typo --- src/assets/NftController.ts | 2 +- src/assets/NftDetectionController.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/assets/NftController.ts b/src/assets/NftController.ts index 9365e7013a4..6bc1fc42cb1 100644 --- a/src/assets/NftController.ts +++ b/src/assets/NftController.ts @@ -871,7 +871,7 @@ export class NftController extends BaseController { }) => void; /** - * Creates a NftController instance. + * Creates an NftController instance. * * @param options - The controller options. * @param options.onPreferencesStateChange - Allows subscribing to preference controller state changes. diff --git a/src/assets/NftDetectionController.ts b/src/assets/NftDetectionController.ts index ff43b2dce36..019222bbcd3 100644 --- a/src/assets/NftDetectionController.ts +++ b/src/assets/NftDetectionController.ts @@ -194,7 +194,7 @@ export class NftDetectionController extends BaseController< private getNftState: () => NftState; /** - * Creates a NftDetectionController instance. + * Creates an NftDetectionController instance. * * @param options - The controller options. * @param options.onNftsStateChange - Allows subscribing to assets controller state changes.