From 4f66dc948fee54b8491227414342ab0d373475f1 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Tue, 15 Nov 2022 15:19:42 -0330 Subject: [PATCH] Update `@metamask/controllers` to v33 (#16493) The controllers package has been updated to v33. The only breaking change in this release was to rename the term "collectible" to "NFT" wherever it appeared in the API. Changes in this PR have been kept minimal; additional renaming can be done in separate PRs. This PR only updates the controller names, controller state, controller methods, and any direct references to these things. NFTs are still called "collectibles" in most places. --- .storybook/initial-states/transactions.js | 4 +- app/scripts/controllers/metametrics.js | 21 +- app/scripts/controllers/metametrics.test.js | 12 +- app/scripts/controllers/preferences.js | 10 +- app/scripts/controllers/preferences.test.js | 12 +- app/scripts/metamask-controller.js | 115 +++----- app/scripts/migrations/076.js | 46 +++ app/scripts/migrations/076.test.js | 143 ++++++++++ app/scripts/migrations/index.js | 2 + lavamoat/browserify/flask/policy.json | 266 +++++++++++++++++- package.json | 2 +- shared/constants/tokens.js | 4 +- shared/constants/transaction.js | 4 +- shared/modules/transaction.utils.js | 2 +- test/e2e/fixture-builder.js | 10 +- test/e2e/restore/MetaMaskUserData.json | 2 +- .../collectible-details.js | 10 +- .../app/collectibles-tab/collectibles-tab.js | 16 +- .../collectibles-tab/collectibles-tab.test.js | 18 +- .../convert-token-to-nft-modal.js | 4 +- ui/ducks/metamask/metamask.js | 8 +- ui/ducks/send/helpers.js | 2 +- ui/ducks/send/helpers.test.js | 2 +- ui/ducks/send/send.js | 18 +- ui/ducks/send/send.test.js | 8 +- ui/pages/add-collectible/add-collectible.js | 12 +- .../add-collectible/add-collectible.test.js | 4 +- .../confirm-transaction-base.container.js | 4 +- .../send-amount-row.component.js | 2 +- .../send-asset-row.component.js | 6 +- .../send-content/send-content.component.js | 2 +- .../experimental-tab.component.js | 20 +- .../experimental-tab.container.js | 9 +- ui/selectors/selectors.js | 6 +- ui/store/actions.js | 57 ++-- yarn.lock | 43 +++ 36 files changed, 682 insertions(+), 224 deletions(-) create mode 100644 app/scripts/migrations/076.js create mode 100644 app/scripts/migrations/076.test.js 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"