diff --git a/.storybook/initial-states/transactions.js b/.storybook/initial-states/transactions.js index fefafefc4bf5..70885e4a606d 100644 --- a/.storybook/initial-states/transactions.js +++ b/.storybook/initial-states/transactions.js @@ -1454,7 +1454,7 @@ export const MOCK_TRANSACTION_BY_TYPE = { dappSuggestedGasFees: null, sendFlowHistory: [ { - entry: 'sendFlow - user set asset type to COLLECTIBLE', + entry: 'sendFlow - user set asset type to NFT', timestamp: 1653457317999, }, { @@ -1504,7 +1504,7 @@ export const MOCK_TRANSACTION_BY_TYPE = { dappSuggestedGasFees: null, sendFlowHistory: [ { - entry: 'sendFlow - user set asset type to COLLECTIBLE', + entry: 'sendFlow - user set asset type to NFT', timestamp: 1653457317999, }, { diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index f8bfc527e5a8..1c2c8489e93c 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -706,15 +706,14 @@ export default class MetaMetricsController { }, [], ), - [TRAITS.NFT_AUTODETECTION_ENABLED]: metamaskState.useCollectibleDetection, + [TRAITS.NFT_AUTODETECTION_ENABLED]: metamaskState.useNftDetection, [TRAITS.NUMBER_OF_ACCOUNTS]: Object.values(metamaskState.identities) .length, [TRAITS.NUMBER_OF_NFT_COLLECTIONS]: this._getAllUniqueNFTAddressesLength( - metamaskState.allCollectibles, + metamaskState.allNfts, ), - [TRAITS.NUMBER_OF_NFTS]: this._getAllNFTsFlattened( - metamaskState.allCollectibles, - ).length, + [TRAITS.NUMBER_OF_NFTS]: this._getAllNFTsFlattened(metamaskState.allNfts) + .length, [TRAITS.NUMBER_OF_TOKENS]: this._getNumberOfTokens(metamaskState), [TRAITS.OPENSEA_API_ENABLED]: metamaskState.openSeaEnabled, [TRAITS.THREE_BOX_ENABLED]: false, // deprecated, hard-coded as false @@ -765,11 +764,11 @@ export default class MetaMetricsController { * Returns an array of all of the collectibles/NFTs the user * possesses across all networks and accounts. * - * @param {object} allCollectibles + * @param {object} allNfts * @returns {[]} */ - _getAllNFTsFlattened = memoize((allCollectibles = {}) => { - return Object.values(allCollectibles).reduce((result, chainNFTs) => { + _getAllNFTsFlattened = memoize((allNfts = {}) => { + return Object.values(allNfts).reduce((result, chainNFTs) => { return result.concat(...Object.values(chainNFTs)); }, []); }); @@ -778,11 +777,11 @@ export default class MetaMetricsController { * Returns the number of unique collectible/NFT addresses the user * possesses across all networks and accounts. * - * @param {object} allCollectibles + * @param {object} allNfts * @returns {number} */ - _getAllUniqueNFTAddressesLength(allCollectibles = {}) { - const allNFTAddresses = this._getAllNFTsFlattened(allCollectibles).map( + _getAllUniqueNFTAddressesLength(allNfts = {}) { + const allNFTAddresses = this._getAllNFTsFlattened(allNfts).map( (nft) => nft.address, ); const uniqueAddresses = new Set(allNFTAddresses); diff --git a/app/scripts/controllers/metametrics.test.js b/app/scripts/controllers/metametrics.test.js index 5d29426d0726..297a219123ed 100644 --- a/app/scripts/controllers/metametrics.test.js +++ b/app/scripts/controllers/metametrics.test.js @@ -717,7 +717,7 @@ describe('MetaMetricsController', function () { [CHAIN_IDS.MAINNET]: [{ address: '0x' }], [CHAIN_IDS.GOERLI]: [{ address: '0x' }, { address: '0x0' }], }, - allCollectibles: { + allNfts: { '0xac706cE8A9BF27Afecf080fB298d0ee13cfb978A': { 56: [ { @@ -752,7 +752,7 @@ describe('MetaMetricsController', function () { identities: [{}, {}], ledgerTransportType: 'web-hid', openSeaEnabled: true, - useCollectibleDetection: false, + useNftDetection: false, theme: 'default', useTokenDetection: true, }); @@ -790,7 +790,7 @@ describe('MetaMetricsController', function () { ledgerTransportType: 'web-hid', openSeaEnabled: true, identities: [{}, {}], - useCollectibleDetection: false, + useNftDetection: false, theme: 'default', useTokenDetection: true, }); @@ -810,7 +810,7 @@ describe('MetaMetricsController', function () { ledgerTransportType: 'web-hid', openSeaEnabled: false, identities: [{}, {}, {}], - useCollectibleDetection: false, + useNftDetection: false, theme: 'default', useTokenDetection: true, }); @@ -838,7 +838,7 @@ describe('MetaMetricsController', function () { ledgerTransportType: 'web-hid', openSeaEnabled: true, identities: [{}, {}], - useCollectibleDetection: true, + useNftDetection: true, theme: 'default', useTokenDetection: true, }); @@ -856,7 +856,7 @@ describe('MetaMetricsController', function () { ledgerTransportType: 'web-hid', openSeaEnabled: true, identities: [{}, {}], - useCollectibleDetection: true, + useNftDetection: true, theme: 'default', useTokenDetection: true, }); diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index ebda556c71c0..569d09750547 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -39,7 +39,7 @@ export default class PreferencesController { // set to true means the dynamic list from the API is being used // set to false will be using the static list from contract-metadata useTokenDetection: false, - useCollectibleDetection: false, + useNftDetection: false, openSeaEnabled: false, advancedGasFee: null, @@ -142,12 +142,12 @@ export default class PreferencesController { } /** - * Setter for the `useCollectibleDetection` property + * Setter for the `useNftDetection` property * - * @param {boolean} useCollectibleDetection - Whether or not the user prefers to autodetect collectibles. + * @param {boolean} useNftDetection - Whether or not the user prefers to autodetect collectibles. */ - setUseCollectibleDetection(useCollectibleDetection) { - this.store.updateState({ useCollectibleDetection }); + setUseNftDetection(useNftDetection) { + this.store.updateState({ useNftDetection }); } /** diff --git a/app/scripts/controllers/preferences.test.js b/app/scripts/controllers/preferences.test.js index ee19e216fbf0..488e03010f98 100644 --- a/app/scripts/controllers/preferences.test.js +++ b/app/scripts/controllers/preferences.test.js @@ -308,21 +308,21 @@ describe('preferences controller', function () { }); }); - describe('setUseCollectibleDetection', function () { + describe('setUseNftDetection', function () { it('should default to false', function () { const state = preferencesController.store.getState(); - assert.equal(state.useCollectibleDetection, false); + assert.equal(state.useNftDetection, false); }); - it('should set the useCollectibleDetection property in state', function () { + it('should set the useNftDetection property in state', function () { assert.equal( - preferencesController.store.getState().useCollectibleDetection, + preferencesController.store.getState().useNftDetection, false, ); preferencesController.setOpenSeaEnabled(true); - preferencesController.setUseCollectibleDetection(true); + preferencesController.setUseNftDetection(true); assert.equal( - preferencesController.store.getState().useCollectibleDetection, + preferencesController.store.getState().useNftDetection, true, ); }); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 99821fed2d03..95d2e0b1b2dc 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -34,9 +34,9 @@ import { TokenListController, TokensController, TokenRatesController, - CollectiblesController, + NftController, AssetsContractController, - CollectibleDetectionController, + NftDetectionController, PermissionController, SubjectMetadataController, PermissionsRequestNotFoundError, @@ -314,7 +314,7 @@ export default class MetamaskController extends EventEmitter { initState.AssetsContractController, ); - this.collectiblesController = new CollectiblesController( + this.nftController = new NftController( { onPreferencesStateChange: this.preferencesController.store.subscribe.bind( @@ -345,14 +345,14 @@ export default class MetamaskController extends EventEmitter { this.assetsContractController.getERC1155TokenURI.bind( this.assetsContractController, ), - onCollectibleAdded: ({ address, symbol, tokenId, standard, source }) => + onNftAdded: ({ address, symbol, tokenId, standard, source }) => this.metaMetricsController.trackEvent({ event: EVENT_NAMES.NFT_ADDED, category: EVENT.CATEGORIES.WALLET, properties: { token_contract_address: address, token_symbol: symbol, - asset_type: ASSET_TYPES.COLLECTIBLE, + asset_type: ASSET_TYPES.NFT, token_standard: standard, source, }, @@ -362,34 +362,29 @@ export default class MetamaskController extends EventEmitter { }), }, {}, - initState.CollectiblesController, + initState.NftController, ); - this.collectiblesController.setApiKey(process.env.OPENSEA_KEY); + this.nftController.setApiKey(process.env.OPENSEA_KEY); process.env.COLLECTIBLES_V1 && - (this.collectibleDetectionController = new CollectibleDetectionController( - { - onCollectiblesStateChange: (listener) => - this.collectiblesController.subscribe(listener), - onPreferencesStateChange: - this.preferencesController.store.subscribe.bind( - this.preferencesController.store, - ), - onNetworkStateChange: this.networkController.store.subscribe.bind( - this.networkController.store, + (this.nftDetectionController = new NftDetectionController({ + onNftsStateChange: (listener) => this.nftController.subscribe(listener), + onPreferencesStateChange: + this.preferencesController.store.subscribe.bind( + this.preferencesController.store, ), - getOpenSeaApiKey: () => this.collectiblesController.openSeaApiKey, - getBalancesInSingleCall: - this.assetsContractController.getBalancesInSingleCall.bind( - this.assetsContractController, - ), - addCollectible: this.collectiblesController.addCollectible.bind( - this.collectiblesController, + onNetworkStateChange: this.networkController.store.subscribe.bind( + this.networkController.store, + ), + getOpenSeaApiKey: () => this.nftController.openSeaApiKey, + getBalancesInSingleCall: + this.assetsContractController.getBalancesInSingleCall.bind( + this.assetsContractController, ), - getCollectiblesState: () => this.collectiblesController.state, - }, - )); + addNft: this.nftController.addNft.bind(this.nftController), + getNftState: () => this.nftController.state, + })); this.metaMetricsController = new MetaMetricsController({ segment, @@ -897,12 +892,10 @@ export default class MetamaskController extends EventEmitter { const transactionDataTokenId = getTokenIdParam(transactionData) ?? getTokenValueParam(transactionData); - const { allCollectibles } = this.collectiblesController.state; + const { allNfts } = this.nftController.state; // check if its a known collectible - const knownCollectible = allCollectibles?.[userAddress]?.[ - chainId - ].find( + const knownCollectible = allNfts?.[userAddress]?.[chainId].find( ({ address, tokenId }) => isEqualCaseInsensitive(address, contractAddress) && tokenId === transactionDataTokenId, @@ -910,7 +903,7 @@ export default class MetamaskController extends EventEmitter { // if it is we check and update ownership status. if (knownCollectible) { - this.collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus( + this.nftController.checkAndUpdateSingleNftOwnershipStatus( knownCollectible, false, { userAddress, chainId }, @@ -1058,7 +1051,7 @@ export default class MetamaskController extends EventEmitter { TokenListController: this.tokenListController, TokensController: this.tokensController, SmartTransactionsController: this.smartTransactionsController, - CollectiblesController: this.collectiblesController, + NftController: this.nftController, ///: BEGIN:ONLY_INCLUDE_IN(flask) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -1100,7 +1093,7 @@ export default class MetamaskController extends EventEmitter { TokenListController: this.tokenListController, TokensController: this.tokensController, SmartTransactionsController: this.smartTransactionsController, - CollectiblesController: this.collectiblesController, + NftController: this.nftController, ///: BEGIN:ONLY_INCLUDE_IN(flask) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -1504,8 +1497,8 @@ export default class MetamaskController extends EventEmitter { addressBookController, alertController, appStateController, - collectiblesController, - collectibleDetectionController, + nftController, + nftDetectionController, currencyRateController, detectTokensController, ensController, @@ -1544,10 +1537,9 @@ export default class MetamaskController extends EventEmitter { setUseTokenDetection: preferencesController.setUseTokenDetection.bind( preferencesController, ), - setUseCollectibleDetection: - preferencesController.setUseCollectibleDetection.bind( - preferencesController, - ), + setUseNftDetection: preferencesController.setUseNftDetection.bind( + preferencesController, + ), setOpenSeaEnabled: preferencesController.setOpenSeaEnabled.bind( preferencesController, ), @@ -1657,38 +1649,25 @@ export default class MetamaskController extends EventEmitter { // AssetsContractController getTokenStandardAndDetails: this.getTokenStandardAndDetails.bind(this), - // CollectiblesController - addCollectible: collectiblesController.addCollectible.bind( - collectiblesController, - ), + // NftController + addNft: nftController.addNft.bind(nftController), - addCollectibleVerifyOwnership: - collectiblesController.addCollectibleVerifyOwnership.bind( - collectiblesController, - ), + addNftVerifyOwnership: + nftController.addNftVerifyOwnership.bind(nftController), - removeAndIgnoreCollectible: - collectiblesController.removeAndIgnoreCollectible.bind( - collectiblesController, - ), + removeAndIgnoreNft: nftController.removeAndIgnoreNft.bind(nftController), - removeCollectible: collectiblesController.removeCollectible.bind( - collectiblesController, - ), + removeNft: nftController.removeNft.bind(nftController), - checkAndUpdateAllCollectiblesOwnershipStatus: - collectiblesController.checkAndUpdateAllCollectiblesOwnershipStatus.bind( - collectiblesController, - ), + checkAndUpdateAllNftsOwnershipStatus: + nftController.checkAndUpdateAllNftsOwnershipStatus.bind(nftController), - checkAndUpdateSingleCollectibleOwnershipStatus: - collectiblesController.checkAndUpdateSingleCollectibleOwnershipStatus.bind( - collectiblesController, + checkAndUpdateSingleNftOwnershipStatus: + nftController.checkAndUpdateSingleNftOwnershipStatus.bind( + nftController, ), - isCollectibleOwner: collectiblesController.isCollectibleOwner.bind( - collectiblesController, - ), + isNftOwner: nftController.isNftOwner.bind(nftController), // AddressController setAddressBook: addressBookController.set.bind(addressBookController), @@ -1968,10 +1947,8 @@ export default class MetamaskController extends EventEmitter { ), // DetectCollectibleController - detectCollectibles: process.env.COLLECTIBLES_V1 - ? collectibleDetectionController.detectCollectibles.bind( - collectibleDetectionController, - ) + detectNfts: process.env.COLLECTIBLES_V1 + ? nftDetectionController.detectNfts.bind(nftDetectionController) : null, /** Token Detection V2 */ diff --git a/app/scripts/migrations/076.js b/app/scripts/migrations/076.js new file mode 100644 index 000000000000..98ca9e29f4cb --- /dev/null +++ b/app/scripts/migrations/076.js @@ -0,0 +1,46 @@ +import { cloneDeep } from 'lodash'; + +const version = 76; + +/** + * Update to `@metamask/controllers@33.0.0` (rename "Collectible" to "NFT"). + */ +export default { + version, + async migrate(originalVersionedData) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + const state = versionedData.data; + const newState = transformState(state); + versionedData.data = newState; + return versionedData; + }, +}; + +function transformState(state) { + if (state.CollectiblesController) { + const { + allCollectibleContracts, + allCollectibles, + ignoredCollectibles, + ...remainingState + } = state.CollectiblesController; + state.NftController = { + ...(allCollectibleContracts + ? { allNftContracts: allCollectibleContracts } + : {}), + ...(allCollectibles ? { allNfts: allCollectibles } : {}), + ...(ignoredCollectibles ? { ignoredNfts: ignoredCollectibles } : {}), + ...remainingState, + }; + delete state.CollectiblesController; + } + + if (state.PreferencesController?.useCollectibleDetection) { + state.PreferencesController.useNftDetection = + state.PreferencesController.useCollectibleDetection; + delete state.PreferencesController.useCollectibleDetection; + } + + return state; +} diff --git a/app/scripts/migrations/076.test.js b/app/scripts/migrations/076.test.js new file mode 100644 index 000000000000..c25c04e6c485 --- /dev/null +++ b/app/scripts/migrations/076.test.js @@ -0,0 +1,143 @@ +import migration76 from './076'; + +describe('migration #76', () => { + it('should update the version metadata', async () => { + const oldStorage = { + meta: { + version: 75, + }, + data: {}, + }; + + const newStorage = await migration76.migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ + version: 76, + }); + }); + + it('should migrate known controller state properties', async () => { + const oldStorage = { + meta: { + version: 75, + }, + data: { + CollectiblesController: { + allCollectibleContracts: 'foo', + allCollectibles: 'bar', + ignoredCollectibles: 'baz', + }, + PreferencesController: { + useCollectibleDetection: 'foobar', + }, + }, + }; + + const newStorage = await migration76.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 76, + }, + data: { + NftController: { + allNftContracts: 'foo', + allNfts: 'bar', + ignoredNfts: 'baz', + }, + PreferencesController: { + useNftDetection: 'foobar', + }, + }, + }); + }); + + it('should migrate unknown controller state properties', async () => { + const oldStorage = { + meta: { + version: 75, + }, + data: { + CollectiblesController: { + allCollectibleContracts: 'foo', + allCollectibles: 'bar', + ignoredCollectibles: 'baz', + extra: 'extra', + }, + PreferencesController: { + extra: 'extra', + useCollectibleDetection: 'foobar', + }, + }, + }; + + const newStorage = await migration76.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 76, + }, + data: { + NftController: { + allNftContracts: 'foo', + allNfts: 'bar', + ignoredNfts: 'baz', + extra: 'extra', + }, + PreferencesController: { + extra: 'extra', + useNftDetection: 'foobar', + }, + }, + }); + }); + + it('should handle missing controller state', async () => { + const oldStorage = { + meta: { + version: 75, + }, + data: { + CollectiblesController: { + extra: 'extra', + }, + PreferencesController: { + extra: 'extra', + }, + }, + }; + + const newStorage = await migration76.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 76, + }, + data: { + NftController: { + extra: 'extra', + }, + PreferencesController: { + extra: 'extra', + }, + }, + }); + }); + + it('should handle missing CollectiblesController and PreferencesController', async () => { + const oldStorage = { + meta: { + version: 75, + }, + data: { + FooController: { a: 'b' }, + }, + }; + + const newStorage = await migration76.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 76, + }, + data: { + FooController: { a: 'b' }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index ab7c6b3d5504..f3c65061bdd5 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -79,6 +79,7 @@ import m072 from './072'; import m073 from './073'; import m074 from './074'; import m075 from './075'; +import m076 from './076'; const migrations = [ m002, @@ -155,6 +156,7 @@ const migrations = [ m073, m074, m075, + m076, ]; export default migrations; diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index d3e4bd68d0b2..371245738950 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1430,7 +1430,7 @@ "console.warn": true }, "packages": { - "@metamask/controllers": true, + "@metamask/rpc-methods>@metamask/controllers": true, "@metamask/rpc-methods>@metamask/key-tree": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snap-utils": true, @@ -1439,6 +1439,137 @@ "eth-rpc-errors": true } }, + "@metamask/rpc-methods>@metamask/controllers": { + "globals": { + "Headers": true, + "URL": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "@metamask/contract-metadata": true, + "@metamask/controllers>@ethersproject/abi": true, + "@metamask/controllers>@ethersproject/contracts": true, + "@metamask/controllers>@ethersproject/providers": true, + "@metamask/controllers>abort-controller": true, + "@metamask/controllers>async-mutex": true, + "@metamask/controllers>eth-json-rpc-infura": true, + "@metamask/controllers>eth-phishing-detect": true, + "@metamask/controllers>isomorphic-fetch": true, + "@metamask/controllers>multiformats": true, + "@metamask/controllers>web3": true, + "@metamask/controllers>web3-provider-engine": true, + "@metamask/metamask-eth-abis": true, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry": true, + "@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": true, + "@metamask/rpc-methods>nanoid": true, + "browserify>buffer": true, + "browserify>events": true, + "deep-freeze-strict": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "eth-keyring-controller": true, + "eth-query": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true, + "immer": true, + "json-rpc-engine": true, + "jsonschema": true, + "punycode": true, + "single-call-balance-checker-abi": true, + "uuid": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry": { + "packages": { + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true, + "browserify>buffer": true, + "ethjs>ethjs-filter": true, + "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-unit": true, + "ethjs>ethjs-util": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": { + "packages": { + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": { + "packages": { + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true, + "ethjs-query>babel-runtime": true, + "ethjs>ethjs-filter": true, + "ethjs>ethjs-util": true, + "ethjs>js-sha3": true, + "promise-to-callback": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": { + "packages": { + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "ethjs-query>babel-runtime": true, + "ethjs-query>ethjs-format": true, + "ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet": { + "packages": { + "@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethers>@ethersproject/json-wallets>scrypt-js": true + } + }, + "@metamask/rpc-methods>@metamask/controllers>ethereumjs-wallet>uuid": { + "globals": { + "crypto": true, + "msCrypto": true + } + }, "@metamask/rpc-methods>@metamask/key-tree": { "packages": { "@metamask/rpc-methods>@metamask/key-tree>@noble/ed25519": true, @@ -1659,11 +1790,11 @@ "setTimeout": true }, "packages": { - "@metamask/controllers": true, "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, "@metamask/rpc-methods": true, "@metamask/snap-controllers>@metamask/browser-passworder": true, + "@metamask/snap-controllers>@metamask/controllers": true, "@metamask/snap-controllers>@xstate/fsm": true, "@metamask/snap-controllers>concat-stream": true, "@metamask/snap-controllers>gunzip-maybe": true, @@ -1691,6 +1822,137 @@ "browserify>buffer": true } }, + "@metamask/snap-controllers>@metamask/controllers": { + "globals": { + "Headers": true, + "URL": true, + "clearInterval": true, + "clearTimeout": true, + "console.error": true, + "console.log": true, + "fetch": true, + "setInterval": true, + "setTimeout": true + }, + "packages": { + "@ethereumjs/common": true, + "@ethereumjs/tx": true, + "@metamask/contract-metadata": true, + "@metamask/controllers>@ethersproject/abi": true, + "@metamask/controllers>@ethersproject/contracts": true, + "@metamask/controllers>@ethersproject/providers": true, + "@metamask/controllers>abort-controller": true, + "@metamask/controllers>async-mutex": true, + "@metamask/controllers>eth-json-rpc-infura": true, + "@metamask/controllers>eth-phishing-detect": true, + "@metamask/controllers>isomorphic-fetch": true, + "@metamask/controllers>multiformats": true, + "@metamask/controllers>web3": true, + "@metamask/controllers>web3-provider-engine": true, + "@metamask/metamask-eth-abis": true, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry": true, + "@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": true, + "@metamask/snap-controllers>nanoid": true, + "browserify>buffer": true, + "browserify>events": true, + "deep-freeze-strict": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "eth-keyring-controller": true, + "eth-query": true, + "eth-rpc-errors": true, + "eth-sig-util": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true, + "immer": true, + "json-rpc-engine": true, + "jsonschema": true, + "punycode": true, + "single-call-balance-checker-abi": true, + "uuid": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry": { + "packages": { + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs": { + "globals": { + "clearInterval": true, + "setInterval": true + }, + "packages": { + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": true, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": true, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": true, + "browserify>buffer": true, + "ethjs>ethjs-filter": true, + "ethjs>ethjs-provider-http": true, + "ethjs>ethjs-unit": true, + "ethjs>ethjs-util": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-abi": { + "packages": { + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract": { + "packages": { + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": true, + "ethjs-query>babel-runtime": true, + "ethjs>ethjs-filter": true, + "ethjs>ethjs-util": true, + "ethjs>js-sha3": true, + "promise-to-callback": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-contract>ethjs-abi": { + "packages": { + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>bn.js": true, + "browserify>buffer": true, + "ethjs>js-sha3": true, + "ethjs>number-to-bn": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>eth-method-registry>ethjs>ethjs-query": { + "globals": { + "console": true + }, + "packages": { + "ethjs-query>babel-runtime": true, + "ethjs-query>ethjs-format": true, + "ethjs-query>ethjs-rpc": true, + "promise-to-callback": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet": { + "packages": { + "@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": true, + "@truffle/codec>utf8": true, + "browserify>buffer": true, + "browserify>crypto-browserify": true, + "ethereumjs-util": true, + "ethereumjs-util>ethereum-cryptography": true, + "ethereumjs-wallet>aes-js": true, + "ethereumjs-wallet>bs58check": true, + "ethereumjs-wallet>randombytes": true, + "ethers>@ethersproject/json-wallets>scrypt-js": true + } + }, + "@metamask/snap-controllers>@metamask/controllers>ethereumjs-wallet>uuid": { + "globals": { + "crypto": true, + "msCrypto": true + } + }, "@metamask/snap-controllers>concat-stream": { "packages": { "@metamask/snap-controllers>concat-stream>readable-stream": true, diff --git a/package.json b/package.json index 09e5bb6b3ce5..6a20ea793f16 100644 --- a/package.json +++ b/package.json @@ -111,7 +111,7 @@ "@keystonehq/metamask-airgapped-keyring": "^0.6.1", "@material-ui/core": "^4.11.0", "@metamask/contract-metadata": "^1.31.0", - "@metamask/controllers": "^32.0.2", + "@metamask/controllers": "^33.0.0", "@metamask/design-tokens": "^1.9.0", "@metamask/eth-json-rpc-infura": "^7.0.0", "@metamask/eth-ledger-bridge-keyring": "^0.13.0", diff --git a/shared/constants/tokens.js b/shared/constants/tokens.js index c846fff183b8..ef9e7f76aac5 100644 --- a/shared/constants/tokens.js +++ b/shared/constants/tokens.js @@ -12,11 +12,11 @@ export const LISTED_CONTRACT_ADDRESSES = Object.keys(contractMap).map( /** * @typedef {object} TokenDetails * @property {string} address - The address of the selected 'TOKEN' or - * 'COLLECTIBLE' contract. + * 'NFT' contract. * @property {string} [symbol] - The symbol of the token. * @property {number} [decimals] - The number of decimals of the selected * 'ERC20' asset. - * @property {number} [tokenId] - The id of the selected 'COLLECTIBLE' asset. + * @property {number} [tokenId] - The id of the selected 'NFT' asset. * @property {TokenStandardStrings} [standard] - The standard of the selected * asset. * @property {boolean} [isERC721] - True when the asset is a ERC721 token. diff --git a/shared/constants/transaction.js b/shared/constants/transaction.js index 9564f066cb90..37c2e45e3b96 100644 --- a/shared/constants/transaction.js +++ b/shared/constants/transaction.js @@ -364,7 +364,7 @@ export const TRANSACTION_EVENTS = { * @property {'NATIVE'} NATIVE - The native asset for the current network, such * as ETH * @property {'TOKEN'} TOKEN - An ERC20 token. - * @property {'COLLECTIBLE'} COLLECTIBLE - An ERC721 or ERC1155 token. + * @property {'NFT'} NFT - An ERC721 or ERC1155 token. * @property {'UNKNOWN'} UNKNOWN - A transaction interacting with a contract * that isn't a token method interaction will be marked as dealing with an * unknown asset type. @@ -385,7 +385,7 @@ export const TRANSACTION_EVENTS = { export const ASSET_TYPES = { NATIVE: 'NATIVE', TOKEN: 'TOKEN', - COLLECTIBLE: 'COLLECTIBLE', + NFT: 'NFT', UNKNOWN: 'UNKNOWN', }; diff --git a/shared/modules/transaction.utils.js b/shared/modules/transaction.utils.js index 1cf471ed7556..d7fd45801faa 100644 --- a/shared/modules/transaction.utils.js +++ b/shared/modules/transaction.utils.js @@ -259,7 +259,7 @@ export async function determineTransactionAssetType( assetType: details.standard === TOKEN_STANDARDS.ERC20 ? ASSET_TYPES.TOKEN - : ASSET_TYPES.COLLECTIBLE, + : ASSET_TYPES.NFT, tokenStandard: details.standard, }; } diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 0eca41d41d1c..1a48188392f5 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -225,7 +225,7 @@ function defaultFixture() { selectedAddress: '0x5cfe73b6021e818b776b421b1c4db2474086a7e1', theme: 'light', useBlockie: false, - useCollectibleDetection: false, + useNftDetection: false, useNonceField: false, usePhishDetect: true, useTokenDetection: false, @@ -338,7 +338,7 @@ function onboardingFixture() { }, theme: 'light', useBlockie: false, - useCollectibleDetection: false, + useNftDetection: false, useNonceField: false, usePhishDetect: true, useTokenDetection: false, @@ -407,9 +407,9 @@ class FixtureBuilder { withCollectiblesController(data) { merge( - this.fixture.data.CollectiblesController - ? this.fixture.data.CollectiblesController - : (this.fixture.data.CollectiblesController = {}), + this.fixture.data.NftController + ? this.fixture.data.NftController + : (this.fixture.data.NftController = {}), data, ); return this; diff --git a/test/e2e/restore/MetaMaskUserData.json b/test/e2e/restore/MetaMaskUserData.json index abea11e149b9..cb9dffefb50b 100644 --- a/test/e2e/restore/MetaMaskUserData.json +++ b/test/e2e/restore/MetaMaskUserData.json @@ -42,7 +42,7 @@ }, "theme": "light", "useBlockie": false, - "useCollectibleDetection": false, + "useNftDetection": false, "useNonceField": false, "usePhishDetect": true, "useTokenDetection": false diff --git a/ui/components/app/collectible-details/collectible-details.js b/ui/components/app/collectible-details/collectible-details.js index d2e6a9100924..213eeb353706 100644 --- a/ui/components/app/collectible-details/collectible-details.js +++ b/ui/components/app/collectible-details/collectible-details.js @@ -30,8 +30,8 @@ import Copy from '../../ui/icon/copy-icon.component'; import { getCollectibleContracts } from '../../../ducks/metamask/metamask'; import { DEFAULT_ROUTE, SEND_ROUTE } from '../../../helpers/constants/routes'; import { - checkAndUpdateSingleCollectibleOwnershipStatus, - removeAndIgnoreCollectible, + checkAndUpdateSingleNftOwnershipStatus, + removeAndIgnoreNft, } from '../../../store/actions'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { getEnvironmentType } from '../../../../app/scripts/lib/util'; @@ -79,14 +79,14 @@ export default function CollectibleDetails({ collectible }) { ); const onRemove = () => { - dispatch(removeAndIgnoreCollectible(address, tokenId)); + dispatch(removeAndIgnoreNft(address, tokenId)); history.push(DEFAULT_ROUTE); }; const prevCollectible = usePrevious(collectible); useEffect(() => { if (!isEqual(prevCollectible, collectible)) { - checkAndUpdateSingleCollectibleOwnershipStatus(collectible); + checkAndUpdateSingleNftOwnershipStatus(collectible); } }, [collectible, prevCollectible]); @@ -111,7 +111,7 @@ export default function CollectibleDetails({ collectible }) { const onSend = async () => { await dispatch( startNewDraftTransaction({ - type: ASSET_TYPES.COLLECTIBLE, + type: ASSET_TYPES.NFT, details: collectible, }), ); diff --git a/ui/components/app/collectibles-tab/collectibles-tab.js b/ui/components/app/collectibles-tab/collectibles-tab.js index 6b7c748433cf..3f228f0abde9 100644 --- a/ui/components/app/collectibles-tab/collectibles-tab.js +++ b/ui/components/app/collectibles-tab/collectibles-tab.js @@ -18,17 +18,17 @@ import { } from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { getCollectiblesDetectionNoticeDismissed } from '../../../ducks/metamask/metamask'; -import { getIsMainnet, getUseCollectibleDetection } from '../../../selectors'; +import { getIsMainnet, getUseNftDetection } from '../../../selectors'; import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes'; import { - checkAndUpdateAllCollectiblesOwnershipStatus, - detectCollectibles, + checkAndUpdateAllNftsOwnershipStatus, + detectNfts, } from '../../../store/actions'; import { useCollectiblesCollections } from '../../../hooks/useCollectiblesCollections'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; export default function CollectiblesTab({ onAddNFT }) { - const useCollectibleDetection = useSelector(getUseCollectibleDetection); + const useNftDetection = useSelector(getUseNftDetection); const isMainnet = useSelector(getIsMainnet); const collectibleDetectionNoticeDismissed = useSelector( getCollectiblesDetectionNoticeDismissed, @@ -46,9 +46,9 @@ export default function CollectiblesTab({ onAddNFT }) { const onRefresh = () => { if (isMainnet) { - dispatch(detectCollectibles()); + dispatch(detectNfts()); } - checkAndUpdateAllCollectiblesOwnershipStatus(); + checkAndUpdateAllNftsOwnershipStatus(); }; if (collectiblesLoading) { @@ -66,7 +66,7 @@ export default function CollectiblesTab({ onAddNFT }) { ) : ( <> {isMainnet && - !useCollectibleDetection && + !useNftDetection && !collectibleDetectionNoticeDismissed ? ( ) : null} @@ -123,7 +123,7 @@ export default function CollectiblesTab({ onAddNFT }) { className="collectibles-tab__link" justifyContent={JUSTIFY_CONTENT.FLEX_END} > - {isMainnet && !useCollectibleDetection ? ( + {isMainnet && !useNftDetection ? ( diff --git a/ui/components/app/collectibles-tab/collectibles-tab.test.js b/ui/components/app/collectibles-tab/collectibles-tab.test.js index 2e1b6b692846..e9d10278d68f 100644 --- a/ui/components/app/collectibles-tab/collectibles-tab.test.js +++ b/ui/components/app/collectibles-tab/collectibles-tab.test.js @@ -150,17 +150,17 @@ const render = ({ selectedAddress, chainId = '0x1', collectiblesDetectionNoticeDismissed = false, - useCollectibleDetection, + useNftDetection, onAddNFT = jest.fn(), }) => { const store = configureStore({ metamask: { - allCollectibles: { + allNfts: { [ACCOUNT_1]: { [chainId]: collectibles, }, }, - allCollectibleContracts: { + allNftContracts: { [ACCOUNT_1]: { [chainId]: collectibleContracts, }, @@ -168,7 +168,7 @@ const render = ({ provider: { chainId }, selectedAddress, collectiblesDetectionNoticeDismissed, - useCollectibleDetection, + useNftDetection, collectiblesDropdownState, }, }); @@ -184,9 +184,9 @@ describe('Collectible Items', () => { setBackgroundConnection({ setCollectiblesDetectionNoticeDismissed: setCollectiblesDetectionNoticeDismissedStub, - detectCollectibles: detectCollectiblesStub, + detectNfts: detectCollectiblesStub, getState: getStateStub, - checkAndUpdateAllCollectiblesOwnershipStatus: + checkAndUpdateAllNftsOwnershipStatus: checkAndUpdateAllCollectiblesOwnershipStatusStub, updateCollectibleDropDownState: updateCollectibleDropDownStateStub, }); @@ -231,7 +231,7 @@ describe('Collectible Items', () => { render({ selectedAddress: ACCOUNT_1, collectibles: COLLECTIBLES, - useCollectibleDetection: true, + useNftDetection: true, }); expect(screen.queryByText('New! NFT detection')).not.toBeInTheDocument(); }); @@ -284,7 +284,7 @@ describe('Collectible Items', () => { render({ selectedAddress: ACCOUNT_1, collectibles: COLLECTIBLES, - useCollectibleDetection: true, + useNftDetection: true, }); expect(detectCollectiblesStub).not.toHaveBeenCalled(); expect( @@ -302,7 +302,7 @@ describe('Collectible Items', () => { chainId: '0x5', selectedAddress: ACCOUNT_1, collectibles: COLLECTIBLES, - useCollectibleDetection: true, + useNftDetection: true, }); expect( checkAndUpdateAllCollectiblesOwnershipStatusStub, diff --git a/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js b/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js index 6b5cc9673f70..edc0fd47aefb 100644 --- a/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js +++ b/ui/components/app/modals/convert-token-to-nft-modal/convert-token-to-nft-modal.js @@ -19,8 +19,8 @@ const ConvertTokenToNFTModal = ({ hideModal, tokenAddress }) => { const history = useHistory(); const t = useI18nContext(); const dispatch = useDispatch(); - const allCollectibles = useSelector(getCollectibles); - const tokenAddedAsNFT = allCollectibles.find(({ address }) => + const allNfts = useSelector(getCollectibles); + const tokenAddedAsNFT = allNfts.find(({ address }) => isEqualCaseInsensitive(address, tokenAddress), ); diff --git a/ui/ducks/metamask/metamask.js b/ui/ducks/metamask/metamask.js index 596c6c8f7fed..5e0c925c975f 100644 --- a/ui/ducks/metamask/metamask.js +++ b/ui/ducks/metamask/metamask.js @@ -278,25 +278,25 @@ export function getEnableEIP1559V2NoticeDismissed(state) { export const getCollectibles = (state) => { const { metamask: { - allCollectibles, + allNfts, provider: { chainId }, selectedAddress, }, } = state; - return allCollectibles?.[selectedAddress]?.[chainId] ?? []; + return allNfts?.[selectedAddress]?.[chainId] ?? []; }; export const getCollectibleContracts = (state) => { const { metamask: { - allCollectibleContracts, + allNftContracts, provider: { chainId }, selectedAddress, }, } = state; - return allCollectibleContracts?.[selectedAddress]?.[chainId] ?? []; + return allNftContracts?.[selectedAddress]?.[chainId] ?? []; }; export function getBlockGasLimit(state) { diff --git a/ui/ducks/send/helpers.js b/ui/ducks/send/helpers.js index 3e7a3bbf4999..6cf35b5f0875 100644 --- a/ui/ducks/send/helpers.js +++ b/ui/ducks/send/helpers.js @@ -204,7 +204,7 @@ export function generateTransactionParams(sendState) { sendToken: draftTransaction.asset.details, }); break; - case ASSET_TYPES.COLLECTIBLE: + case ASSET_TYPES.NFT: // When sending a token the to address is the contract address of // the token being sent. The value is set to '0x0' and the data // is generated from the recipient address, token being sent and diff --git a/ui/ducks/send/helpers.test.js b/ui/ducks/send/helpers.test.js index 90b1bcb557cc..404c29d71964 100644 --- a/ui/ducks/send/helpers.test.js +++ b/ui/ducks/send/helpers.test.js @@ -64,7 +64,7 @@ describe('Send Slice Helpers', () => { value: '0x1', }, asset: { - type: ASSET_TYPES.COLLECTIBLE, + type: ASSET_TYPES.NFT, balance: '0xaf', details: { address: '0xToken', diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index 37f7e0bf6186..f73a95120118 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -51,7 +51,7 @@ import { updateTransactionGasFees, addPollingTokenToAppState, removePollingTokenFromAppState, - isCollectibleOwner, + isNftOwner, getTokenStandardAndDetails, showModal, addUnapprovedTransactionAndRouteToConfirmationPage, @@ -298,7 +298,7 @@ export const RECIPIENT_SEARCH_MODES = { * with the asset. * @property {AssetTypesString} type - The type of asset that the user * is attempting to send. Defaults to 'NATIVE' which represents the native - * asset of the chain. Can also be 'TOKEN' or 'COLLECTIBLE'. + * asset of the chain. Can also be 'TOKEN' or 'NFT'. */ /** @@ -562,7 +562,7 @@ export const computeEstimatedGasLimit = createAsyncThunk( * @typedef {object} Asset * @property {AssetTypesString} type - The type of asset that the user * is attempting to send. Defaults to 'NATIVE' which represents the native - * asset of the chain. Can also be 'TOKEN' or 'COLLECTIBLE'. + * asset of the chain. Can also be 'TOKEN' or 'NFT'. * @property {string} balance - A hex string representing the balance * that the user holds of the asset that they are attempting to send. * @property {TokenDetails} [details] - An object that describes the @@ -660,7 +660,7 @@ export const initializeSendState = createAsyncThunk( ) { gasLimit = draftTransaction.asset.type === ASSET_TYPES.TOKEN || - draftTransaction.asset.type === ASSET_TYPES.COLLECTIBLE + draftTransaction.asset.type === ASSET_TYPES.NFT ? GAS_LIMITS.BASE_TOKEN_ESTIMATE : GAS_LIMITS.SIMPLE; // Run our estimateGasLimit logic to get a more accurate estimation of @@ -960,7 +960,7 @@ const slice = createSlice({ if ( draftTransaction.asset.type === ASSET_TYPES.TOKEN || - draftTransaction.asset.type === ASSET_TYPES.COLLECTIBLE + draftTransaction.asset.type === ASSET_TYPES.NFT ) { draftTransaction.asset.details = asset.details; } else { @@ -1782,7 +1782,7 @@ export function editExistingTransaction(assetType, transactionId) { type: assetType, details: { address: transaction.txParams.to, - ...(assetType === ASSET_TYPES.COLLECTIBLE + ...(assetType === ASSET_TYPES.NFT ? { tokenId: getTokenIdParam(tokenData) ?? @@ -2069,7 +2069,7 @@ export function updateSendAsset( ); } else if ( details.standard === TOKEN_STANDARDS.ERC1155 && - type === ASSET_TYPES.COLLECTIBLE + type === ASSET_TYPES.NFT ) { throw new Error('Sends of ERC1155 tokens are not currently supported'); } else if ( @@ -2088,7 +2088,7 @@ export function updateSendAsset( } else { let isCurrentOwner = true; try { - isCurrentOwner = await isCollectibleOwner( + isCurrentOwner = await isNftOwner( sendingAddress, details.address, details.tokenId, @@ -2292,7 +2292,7 @@ export function signTransaction() { if (draftTransaction.asset.type !== ASSET_TYPES.NATIVE) { transactionType = - draftTransaction.asset.type === ASSET_TYPES.COLLECTIBLE + draftTransaction.asset.type === ASSET_TYPES.NFT ? TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM : TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER; } diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 1610c022d2d5..47c7adec40d3 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -128,7 +128,7 @@ describe('Send Slice', () => { .spyOn(Actions, 'updateTokenType') .mockImplementation(() => Promise.resolve({ isERC721: false })); jest - .spyOn(Actions, 'isCollectibleOwner') + .spyOn(Actions, 'isNftOwner') .mockImplementation(() => Promise.resolve(true)); jest.spyOn(Actions, 'updateEditableParams').mockImplementation(() => ({ type: 'UPDATE_TRANSACTION_EDITABLE_PARAMS', @@ -2566,9 +2566,7 @@ describe('Send Slice', () => { const store = mockStore(editTransactionState); - await store.dispatch( - editExistingTransaction(ASSET_TYPES.COLLECTIBLE, 1), - ); + await store.dispatch(editExistingTransaction(ASSET_TYPES.NFT, 1)); const actionResult = store.getActions(); expect(actionResult).toHaveLength(9); expect(actionResult[0]).toMatchObject({ @@ -2635,7 +2633,7 @@ describe('Send Slice', () => { tokenId: '15000', }, error: null, - type: ASSET_TYPES.COLLECTIBLE, + type: ASSET_TYPES.NFT, }, initialAssetSet: true, }, diff --git a/ui/pages/add-collectible/add-collectible.js b/ui/pages/add-collectible/add-collectible.js index fd923d1ee411..f357558a9b4b 100644 --- a/ui/pages/add-collectible/add-collectible.js +++ b/ui/pages/add-collectible/add-collectible.js @@ -15,13 +15,13 @@ import Typography from '../../components/ui/typography'; import ActionableMessage from '../../components/ui/actionable-message'; import PageContainer from '../../components/ui/page-container'; import { - addCollectibleVerifyOwnership, + addNftVerifyOwnership, getTokenStandardAndDetails, ignoreTokens, setNewCollectibleAddedMessage, } from '../../store/actions'; import FormField from '../../components/ui/form-field'; -import { getIsMainnet, getUseCollectibleDetection } from '../../selectors'; +import { getIsMainnet, getUseNftDetection } from '../../selectors'; import { getCollectiblesDetectionNoticeDismissed } from '../../ducks/metamask/metamask'; import CollectiblesDetectionNotice from '../../components/app/collectibles-detection-notice'; import { MetaMetricsContext } from '../../contexts/metametrics'; @@ -32,7 +32,7 @@ export default function AddCollectible() { const t = useI18nContext(); const history = useHistory(); const dispatch = useDispatch(); - const useCollectibleDetection = useSelector(getUseCollectibleDetection); + const useNftDetection = useSelector(getUseNftDetection); const isMainnet = useSelector(getIsMainnet); const collectibleDetectionNoticeDismissed = useSelector( getCollectiblesDetectionNoticeDismissed, @@ -54,7 +54,7 @@ export default function AddCollectible() { const handleAddCollectible = async () => { try { - await dispatch(addCollectibleVerifyOwnership(address, tokenId)); + await dispatch(addNftVerifyOwnership(address, tokenId)); } catch (error) { const { message } = error; dispatch(setNewCollectibleAddedMessage(message)); @@ -84,7 +84,7 @@ export default function AddCollectible() { token_contract_address: address, token_symbol: tokenDetails?.symbol, tokenId: tokenId.toString(), - asset_type: ASSET_TYPES.COLLECTIBLE, + asset_type: ASSET_TYPES.NFT, token_standard: tokenDetails?.standard, source: EVENT.SOURCE.TOKEN.CUSTOM, }, @@ -120,7 +120,7 @@ export default function AddCollectible() { contentComponent={ {isMainnet && - !useCollectibleDetection && + !useNftDetection && !collectibleDetectionNoticeDismissed ? ( ) : null} diff --git a/ui/pages/add-collectible/add-collectible.test.js b/ui/pages/add-collectible/add-collectible.test.js index be693e444447..da452f75404d 100644 --- a/ui/pages/add-collectible/add-collectible.test.js +++ b/ui/pages/add-collectible/add-collectible.test.js @@ -53,7 +53,7 @@ describe('AddCollectible', () => { expect(getByText('Add')).not.toBeEnabled(); }); - it('should call addCollectibleVerifyOwnership action with correct values (tokenId should not be in scientific notation)', () => { + it('should call addNftVerifyOwnership action with correct values (tokenId should not be in scientific notation)', () => { const { getByTestId, getByText } = renderWithProvider( , store, @@ -67,7 +67,7 @@ describe('AddCollectible', () => { }); const addCollectibleVerifyOwnershipSpy = jest.spyOn( Actions, - 'addCollectibleVerifyOwnership', + 'addNftVerifyOwnership', ); fireEvent.click(getByText('Add')); diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index 88e13936d737..28be31ed94c4 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -97,7 +97,7 @@ const mapStateToProps = (state, ownProps) => { network, unapprovedTxs, nextNonce, - allCollectibleContracts, + allNftContracts, selectedAddress, provider: { chainId }, } = metamask; @@ -175,7 +175,7 @@ const mapStateToProps = (state, ownProps) => { ); const isCollectibleTransfer = Boolean( - allCollectibleContracts?.[selectedAddress]?.[chainId]?.find((contract) => { + allNftContracts?.[selectedAddress]?.[chainId]?.find((contract) => { return isEqualCaseInsensitive(contract.address, fullTxData.txParams.to); }), ); diff --git a/ui/pages/send/send-content/send-amount-row/send-amount-row.component.js b/ui/pages/send/send-content/send-amount-row/send-amount-row.component.js index 469cf117440b..3320bf414c89 100644 --- a/ui/pages/send/send-content/send-amount-row/send-amount-row.component.js +++ b/ui/pages/send/send-content/send-amount-row/send-amount-row.component.js @@ -44,7 +44,7 @@ export default class SendAmountRow extends Component { render() { const { inError, asset } = this.props; - if (asset.type === ASSET_TYPES.COLLECTIBLE) { + if (asset.type === ASSET_TYPES.NFT) { return null; } diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js index 98d7eecdf6d3..9bbda50acc28 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -79,7 +79,7 @@ export default class SendAssetRow extends Component { return this.props.nativeCurrency; case ASSET_TYPES.TOKEN: return ERC20; - case ASSET_TYPES.COLLECTIBLE: + case ASSET_TYPES.NFT: return token?.standard; default: return null; @@ -144,7 +144,7 @@ export default class SendAssetRow extends Component { if (token) { return this.renderToken(token); } - } else if (type === ASSET_TYPES.COLLECTIBLE) { + } else if (type === ASSET_TYPES.NFT) { const collectible = collectibles.find( ({ address, tokenId }) => isEqualCaseInsensitive(address, details.address) && @@ -268,7 +268,7 @@ export default class SendAssetRow extends Component {
this.selectToken(ASSET_TYPES.COLLECTIBLE, collectible)} + onClick={() => this.selectToken(ASSET_TYPES.NFT, collectible)} >
diff --git a/ui/pages/send/send-content/send-content.component.js b/ui/pages/send/send-content/send-content.component.js index a856624d12fa..9a157c0b7d11 100644 --- a/ui/pages/send/send-content/send-content.component.js +++ b/ui/pages/send/send-content/send-content.component.js @@ -71,7 +71,7 @@ export default class SendContent extends Component { const showHexData = this.props.showHexData && asset.type !== ASSET_TYPES.TOKEN && - asset.type !== ASSET_TYPES.COLLECTIBLE; + asset.type !== ASSET_TYPES.NFT; const showKnownRecipientWarning = recipient.warning === 'knownAddressRecipient'; diff --git a/ui/pages/settings/experimental-tab/experimental-tab.component.js b/ui/pages/settings/experimental-tab/experimental-tab.component.js index 3f644bb4b5fb..fc05a862076c 100644 --- a/ui/pages/settings/experimental-tab/experimental-tab.component.js +++ b/ui/pages/settings/experimental-tab/experimental-tab.component.js @@ -14,8 +14,8 @@ export default class ExperimentalTab extends PureComponent { }; static propTypes = { - useCollectibleDetection: PropTypes.bool, - setUseCollectibleDetection: PropTypes.func, + useNftDetection: PropTypes.bool, + setUseNftDetection: PropTypes.func, setOpenSeaEnabled: PropTypes.func, openSeaEnabled: PropTypes.bool, eip1559V2Enabled: PropTypes.bool, @@ -52,8 +52,8 @@ export default class ExperimentalTab extends PureComponent { const { t } = this.context; const { - useCollectibleDetection, - setUseCollectibleDetection, + useNftDetection, + setUseNftDetection, openSeaEnabled, setOpenSeaEnabled, } = this.props; @@ -72,7 +72,7 @@ export default class ExperimentalTab extends PureComponent {
{ this.context.trackEvent({ category: EVENT.CATEGORIES.SETTINGS, @@ -85,7 +85,7 @@ export default class ExperimentalTab extends PureComponent { if (!value && !openSeaEnabled) { setOpenSeaEnabled(!value); } - setUseCollectibleDetection(!value); + setUseNftDetection(!value); }} offLabel={t('off')} onLabel={t('on')} @@ -104,8 +104,8 @@ export default class ExperimentalTab extends PureComponent { const { openSeaEnabled, setOpenSeaEnabled, - useCollectibleDetection, - setUseCollectibleDetection, + useNftDetection, + setUseNftDetection, } = this.props; return ( @@ -133,8 +133,8 @@ export default class ExperimentalTab extends PureComponent { }, }); // value is positive when being toggled off - if (value && useCollectibleDetection) { - setUseCollectibleDetection(false); + if (value && useNftDetection) { + setUseNftDetection(false); } setOpenSeaEnabled(!value); }} diff --git a/ui/pages/settings/experimental-tab/experimental-tab.container.js b/ui/pages/settings/experimental-tab/experimental-tab.container.js index aa4f8b2cf0c2..16d2fbfb3dd9 100644 --- a/ui/pages/settings/experimental-tab/experimental-tab.container.js +++ b/ui/pages/settings/experimental-tab/experimental-tab.container.js @@ -2,13 +2,13 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; import { - setUseCollectibleDetection, + setUseNftDetection, setOpenSeaEnabled, setEIP1559V2Enabled, setImprovedTokenAllowanceEnabled, } from '../../../store/actions'; import { - getUseCollectibleDetection, + getUseNftDetection, getOpenSeaEnabled, getEIP1559V2Enabled, getIsImprovedTokenAllowanceEnabled, @@ -17,7 +17,7 @@ import ExperimentalTab from './experimental-tab.component'; const mapStateToProps = (state) => { return { - useCollectibleDetection: getUseCollectibleDetection(state), + useNftDetection: getUseNftDetection(state), openSeaEnabled: getOpenSeaEnabled(state), eip1559V2Enabled: getEIP1559V2Enabled(state), improvedTokenAllowanceEnabled: getIsImprovedTokenAllowanceEnabled(state), @@ -26,8 +26,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => { return { - setUseCollectibleDetection: (val) => - dispatch(setUseCollectibleDetection(val)), + setUseNftDetection: (val) => dispatch(setUseNftDetection(val)), setOpenSeaEnabled: (val) => dispatch(setOpenSeaEnabled(val)), setEIP1559V2Enabled: (val) => dispatch(setEIP1559V2Enabled(val)), setImprovedTokenAllowanceEnabled: (val) => diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index a4ce54be8ef7..74305d7e9e79 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -1023,13 +1023,13 @@ export function getUseTokenDetection(state) { } /** - * To get the useCollectibleDetection flag which determines whether we autodetect NFTs + * To get the useNftDetection flag which determines whether we autodetect NFTs * * @param {*} state * @returns Boolean */ -export function getUseCollectibleDetection(state) { - return Boolean(state.metamask.useCollectibleDetection); +export function getUseNftDetection(state) { + return Boolean(state.metamask.useNftDetection); } /** diff --git a/ui/store/actions.js b/ui/store/actions.js index d2c61284636d..ab46d03641fd 100644 --- a/ui/store/actions.js +++ b/ui/store/actions.js @@ -1781,7 +1781,7 @@ export async function getBalancesInSingleCall(tokens) { return await submitRequestToBackground('getBalancesInSingleCall', [tokens]); } -export function addCollectible(address, tokenID, dontShowLoadingIndicator) { +export function addNft(address, tokenID, dontShowLoadingIndicator) { return async (dispatch) => { if (!address) { throw new Error('MetaMask - Cannot add collectible without address'); @@ -1793,7 +1793,7 @@ export function addCollectible(address, tokenID, dontShowLoadingIndicator) { dispatch(showLoadingIndication()); } try { - await submitRequestToBackground('addCollectible', [address, tokenID]); + await submitRequestToBackground('addNft', [address, tokenID]); } catch (error) { log.error(error); dispatch(displayWarning(error.message)); @@ -1804,7 +1804,7 @@ export function addCollectible(address, tokenID, dontShowLoadingIndicator) { }; } -export function addCollectibleVerifyOwnership( +export function addNftVerifyOwnership( address, tokenID, dontShowLoadingIndicator, @@ -1820,7 +1820,7 @@ export function addCollectibleVerifyOwnership( dispatch(showLoadingIndication()); } try { - await submitRequestToBackground('addCollectibleVerifyOwnership', [ + await submitRequestToBackground('addNftVerifyOwnership', [ address, tokenID, ]); @@ -1841,11 +1841,7 @@ export function addCollectibleVerifyOwnership( }; } -export function removeAndIgnoreCollectible( - address, - tokenID, - dontShowLoadingIndicator, -) { +export function removeAndIgnoreNft(address, tokenID, dontShowLoadingIndicator) { return async (dispatch) => { if (!address) { throw new Error('MetaMask - Cannot ignore collectible without address'); @@ -1857,10 +1853,7 @@ export function removeAndIgnoreCollectible( dispatch(showLoadingIndication()); } try { - await submitRequestToBackground('removeAndIgnoreCollectible', [ - address, - tokenID, - ]); + await submitRequestToBackground('removeAndIgnoreNft', [address, tokenID]); } catch (error) { log.error(error); dispatch(displayWarning(error.message)); @@ -1871,7 +1864,7 @@ export function removeAndIgnoreCollectible( }; } -export function removeCollectible(address, tokenID, dontShowLoadingIndicator) { +export function removeNft(address, tokenID, dontShowLoadingIndicator) { return async (dispatch) => { if (!address) { throw new Error('MetaMask - Cannot remove collectible without address'); @@ -1883,7 +1876,7 @@ export function removeCollectible(address, tokenID, dontShowLoadingIndicator) { dispatch(showLoadingIndication()); } try { - await submitRequestToBackground('removeCollectible', [address, tokenID]); + await submitRequestToBackground('removeNft', [address, tokenID]); } catch (error) { log.error(error); dispatch(displayWarning(error.message)); @@ -1894,31 +1887,27 @@ export function removeCollectible(address, tokenID, dontShowLoadingIndicator) { }; } -export async function checkAndUpdateAllCollectiblesOwnershipStatus() { - await submitRequestToBackground( - 'checkAndUpdateAllCollectiblesOwnershipStatus', - ); +export async function checkAndUpdateAllNftsOwnershipStatus() { + await submitRequestToBackground('checkAndUpdateAllNftsOwnershipStatus'); } -export async function isCollectibleOwner( +export async function isNftOwner( ownerAddress, collectibleAddress, collectibleId, ) { - return await submitRequestToBackground('isCollectibleOwner', [ + return await submitRequestToBackground('isNftOwner', [ ownerAddress, collectibleAddress, collectibleId, ]); } -export async function checkAndUpdateSingleCollectibleOwnershipStatus( - collectible, -) { - await submitRequestToBackground( - 'checkAndUpdateSingleCollectibleOwnershipStatus', - [collectible, false], - ); +export async function checkAndUpdateSingleNftOwnershipStatus(collectible) { + await submitRequestToBackground('checkAndUpdateSingleNftOwnershipStatus', [ + collectible, + false, + ]); } export async function getTokenStandardAndDetails( @@ -2729,11 +2718,11 @@ export function setUseTokenDetection(val) { }; } -export function setUseCollectibleDetection(val) { +export function setUseNftDetection(val) { return (dispatch) => { dispatch(showLoadingIndication()); - log.debug(`background.setUseCollectibleDetection`); - callBackgroundMethod('setUseCollectibleDetection', [val], (err) => { + log.debug(`background.setUseNftDetection`); + callBackgroundMethod('setUseNftDetection', [val], (err) => { dispatch(hideLoadingIndication()); if (err) { dispatch(displayWarning(err.message)); @@ -2755,11 +2744,11 @@ export function setOpenSeaEnabled(val) { }; } -export function detectCollectibles() { +export function detectNfts() { return async (dispatch) => { dispatch(showLoadingIndication()); - log.debug(`background.detectCollectibles`); - await submitRequestToBackground('detectCollectibles'); + log.debug(`background.detectNfts`); + await submitRequestToBackground('detectNfts'); dispatch(hideLoadingIndication()); await forceUpdateMetamaskState(dispatch); }; diff --git a/yarn.lock b/yarn.lock index 6afea26c5f5a..a84ca04f44ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2909,6 +2909,49 @@ web3 "^0.20.7" web3-provider-engine "^16.0.3" +"@metamask/controllers@^33.0.0": + version "33.0.0" + resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-33.0.0.tgz#908c05f6bee741c0beecd9d85d50c304afa38f2b" + integrity sha512-ImnoLztyyE9qswPAv6zk7d40d5FTMPiJYqAjjnJz+hEYhhGPGYI87+2OF/i+kVLv3gatyBQzNxvE1qtQSDWJsg== + dependencies: + "@ethereumjs/common" "^2.3.1" + "@ethereumjs/tx" "^3.2.1" + "@ethersproject/abi" "^5.7.0" + "@ethersproject/contracts" "^5.7.0" + "@ethersproject/providers" "^5.7.0" + "@keystonehq/metamask-airgapped-keyring" "^0.6.1" + "@metamask/contract-metadata" "^1.35.0" + "@metamask/metamask-eth-abis" "3.0.0" + "@metamask/types" "^1.1.0" + "@types/uuid" "^8.3.0" + abort-controller "^3.0.0" + async-mutex "^0.2.6" + babel-runtime "^6.26.0" + deep-freeze-strict "^1.1.1" + eth-ens-namehash "^2.0.8" + eth-json-rpc-infura "^5.1.0" + eth-keyring-controller "^7.0.2" + eth-method-registry "1.1.0" + eth-phishing-detect "^1.2.0" + eth-query "^2.1.2" + eth-rpc-errors "^4.0.0" + eth-sig-util "^3.0.0" + ethereumjs-util "^7.0.10" + ethereumjs-wallet "^1.0.1" + ethjs-unit "^0.1.6" + fast-deep-equal "^3.1.3" + immer "^9.0.6" + isomorphic-fetch "^3.0.0" + json-rpc-engine "^6.1.0" + jsonschema "^1.2.4" + multiformats "^9.5.2" + nanoid "^3.1.31" + punycode "^2.1.1" + single-call-balance-checker-abi "^1.0.0" + uuid "^8.3.2" + web3 "^0.20.7" + web3-provider-engine "^16.0.3" + "@metamask/design-tokens@^1.6.0", "@metamask/design-tokens@^1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@metamask/design-tokens/-/design-tokens-1.9.0.tgz#2b173c671f36b0d3faa2e31ea4bf66e811a7ff49"