diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js index 0d0a523f547..32a35e27754 100644 --- a/app/components/Nav/Main/index.js +++ b/app/components/Nav/Main/index.js @@ -492,7 +492,6 @@ const MainFlow = () => ( mode={'modal'} screenOptions={{ headerShown: false, - cardStyle: { backgroundColor: importedColors.transparent }, }} > diff --git a/app/components/UI/Name/Name.tsx b/app/components/UI/Name/Name.tsx index 1f338a8b0a7..5e44d36fe8f 100644 --- a/app/components/UI/Name/Name.tsx +++ b/app/components/UI/Name/Name.tsx @@ -47,11 +47,21 @@ const UnknownEthereumAddress: React.FC<{ address: string }> = ({ address }) => { ); }; -const Name: React.FC = ({ type, value }) => { +const Name: React.FC = ({ + chainId, + preferContractSymbol, + type, + value, +}) => { if (type !== NameType.EthereumAddress) { throw new Error('Unsupported NameType: ' + type); } - const displayName = useDisplayName(type, value); + const displayName = useDisplayName( + type, + value, + chainId, + preferContractSymbol, + ); const { styles } = useStyles(styleSheet, { displayNameVariant: displayName.variant, }); diff --git a/app/components/UI/Name/Name.types.ts b/app/components/UI/Name/Name.types.ts index 007a5077b06..45f7f241b6f 100644 --- a/app/components/UI/Name/Name.types.ts +++ b/app/components/UI/Name/Name.types.ts @@ -1,4 +1,5 @@ import { ViewProps } from 'react-native'; +import { Hex } from '@metamask/utils'; /** * The name types supported by the NameController. @@ -11,6 +12,8 @@ export enum NameType { } export interface NameProperties extends ViewProps { + chainId?: Hex; + preferContractSymbol?: boolean; type: NameType; value: string; } diff --git a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx index 1b60f771105..0c8a0685db2 100644 --- a/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx +++ b/app/components/UI/SimulationDetails/AssetPill/AssetPill.tsx @@ -61,9 +61,10 @@ const AssetPill: React.FC = ({ asset }) => { ) : ( )} diff --git a/app/core/AppStateEventListener.test.ts b/app/core/AppStateEventListener.test.ts index 3cf93c94aac..34f7c6ad07a 100644 --- a/app/core/AppStateEventListener.test.ts +++ b/app/core/AppStateEventListener.test.ts @@ -3,7 +3,7 @@ import { store } from '../store'; import Logger from '../util/Logger'; import { MetaMetrics, MetaMetricsEvents } from './Analytics'; import { AppStateEventListener } from './AppStateEventListener'; -import extractURLParams from './DeeplinkManager/ParseManager/extractURLParams'; +import { processAttribution } from './processAttribution'; jest.mock('react-native', () => ({ AppState: { @@ -27,12 +27,14 @@ jest.mock('../store', () => ({ }, })); -jest.mock('./DeeplinkManager/ParseManager/extractURLParams', () => jest.fn()); - jest.mock('../util/Logger', () => ({ error: jest.fn(), })); +jest.mock('./processAttribution', () => ({ + processAttribution: jest.fn(), +})); + describe('AppStateEventListener', () => { let appStateManager: AppStateEventListener; let mockAppStateListener: (state: AppStateStatus) => void; @@ -66,11 +68,15 @@ describe('AppStateEventListener', () => { expect(Logger.error).toHaveBeenCalledWith(new Error('store is already initialized')); }); - it('tracks event when app becomes active and conditions are met', () => { - (store.getState as jest.Mock).mockReturnValue({ - security: { dataCollectionForMarketing: true }, - }); - (extractURLParams as jest.Mock).mockReturnValue({ params: { attributionId: 'test123' } }); + it('tracks event when app becomes active and attribution data is available', () => { + const mockAttribution = { + attributionId: 'test123', + utm: 'test_utm', + utm_source: 'source', + utm_medium: 'medium', + utm_campaign: 'campaign', + }; + (processAttribution as jest.Mock).mockReturnValue(mockAttribution); appStateManager.setCurrentDeeplink('metamask://connect?attributionId=test123'); mockAppStateListener('active'); @@ -78,51 +84,31 @@ describe('AppStateEventListener', () => { expect(mockTrackEvent).toHaveBeenCalledWith( MetaMetricsEvents.APP_OPENED, - { attributionId: 'test123' }, + { attributionId: 'test123', utm_source: 'source', utm_medium: 'medium', utm_campaign: 'campaign' }, true ); }); - it('does not track event when data collection is disabled', () => { - (store.getState as jest.Mock).mockReturnValue({ - security: { dataCollectionForMarketing: false }, - }); + it('does not track event when processAttribution returns undefined', () => { + (processAttribution as jest.Mock).mockReturnValue(undefined); mockAppStateListener('active'); jest.advanceTimersByTime(2000); - expect(mockTrackEvent).toHaveBeenCalledWith( - MetaMetricsEvents.APP_OPENED, - {}, - true - ); - }); - - it('does not track event when there is no deeplink', () => { - (store.getState as jest.Mock).mockReturnValue({ - security: { dataCollectionForMarketing: true }, - }); - - mockAppStateListener('active'); - jest.advanceTimersByTime(2000); - - expect(mockTrackEvent).toHaveBeenCalledWith( - MetaMetricsEvents.APP_OPENED, - { attributionId: undefined }, - true - ); + expect(mockTrackEvent).not.toHaveBeenCalled(); }); it('handles errors gracefully', () => { - (store.getState as jest.Mock).mockImplementation(() => { - throw new Error('Test error'); + const testError = new Error('Test error'); + (processAttribution as jest.Mock).mockImplementation(() => { + throw testError; }); mockAppStateListener('active'); jest.advanceTimersByTime(2000); expect(Logger.error).toHaveBeenCalledWith( - expect.any(Error), + testError, 'AppStateManager: Error processing app state change' ); expect(mockTrackEvent).not.toHaveBeenCalled(); diff --git a/app/core/AppStateEventListener.ts b/app/core/AppStateEventListener.ts index 46752626e2a..8a9046462f6 100644 --- a/app/core/AppStateEventListener.ts +++ b/app/core/AppStateEventListener.ts @@ -51,13 +51,16 @@ export class AppStateEventListener { } try { - const attributionId = processAttribution({ currentDeeplink: this.currentDeeplink, store: this.store }); - DevLogger.log(`AppStateManager:: processAppStateChange:: sending event 'APP_OPENED' attributionId=${attributionId}`); - MetaMetrics.getInstance().trackEvent( - MetaMetricsEvents.APP_OPENED, - { attributionId }, - true - ); + const attribution = processAttribution({ currentDeeplink: this.currentDeeplink, store: this.store }); + if(attribution) { + const { attributionId, utm, ...utmParams } = attribution; + DevLogger.log(`AppStateManager:: processAppStateChange:: sending event 'APP_OPENED' attributionId=${attribution.attributionId} utm=${attribution.utm}`, utmParams); + MetaMetrics.getInstance().trackEvent( + MetaMetricsEvents.APP_OPENED, + { attributionId, ...utmParams }, + true + ); + } } catch (error) { Logger.error(error as Error, 'AppStateManager: Error processing app state change'); } diff --git a/app/core/DeeplinkManager/ParseManager/extractURLParams.test.ts b/app/core/DeeplinkManager/ParseManager/extractURLParams.test.ts index 50b942a1366..423f78628a4 100644 --- a/app/core/DeeplinkManager/ParseManager/extractURLParams.test.ts +++ b/app/core/DeeplinkManager/ParseManager/extractURLParams.test.ts @@ -43,6 +43,7 @@ describe('extractURLParams', () => { comm: 'test', v: '2', attributionId: '', + utm: '', }; mockUrlParser.mockImplementation( @@ -83,6 +84,7 @@ describe('extractURLParams', () => { pubkey: '', v: '', attributionId: '', + utm: '', }); }); @@ -116,6 +118,7 @@ describe('extractURLParams', () => { pubkey: '', v: '', attributionId: '', + utm: '', }); expect(alertSpy).toHaveBeenCalledWith( @@ -137,6 +140,7 @@ describe('extractURLParams', () => { sdkVersion: '', pubkey: 'xyz', attributionId: '', + utm: '', }; mockUrlParser.mockImplementation( diff --git a/app/core/DeeplinkManager/ParseManager/extractURLParams.ts b/app/core/DeeplinkManager/ParseManager/extractURLParams.ts index 723ce7148b7..4d992b6c3e4 100644 --- a/app/core/DeeplinkManager/ParseManager/extractURLParams.ts +++ b/app/core/DeeplinkManager/ParseManager/extractURLParams.ts @@ -20,6 +20,7 @@ export interface DeeplinkUrlParams { originatorInfo?: string; request?: string; attributionId?: string; + utm?: string; account?: string; // This is the format => "address@chainId" } @@ -41,6 +42,7 @@ function extractURLParams(url: string) { channelId: '', comm: '', attributionId: '', + utm: '', }; DevLogger.log(`extractParams:: urlObj`, urlObj); diff --git a/app/core/Engine.ts b/app/core/Engine.ts index 48cc6279e84..0c19aa58502 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine.ts @@ -569,7 +569,6 @@ class Engine { chainId: networkController.getNetworkClientById( networkController?.state.selectedNetworkClientId, ).configuration.chainId, - // @ts-expect-error TODO: Resolve bump the assets controller version. getNetworkClientById: networkController.getNetworkClientById.bind(networkController), }); @@ -654,7 +653,6 @@ class Engine { networkController?.state.selectedNetworkClientId, ).configuration.chainId, selectedAddress: preferencesController.state.selectedAddress, - // @ts-expect-error TODO: Resolve provider type mismatch provider: networkController.getProviderAndBlockTracker().provider, state: initialState.TokensController, // @ts-expect-error TODO: Resolve mismatch between base-controller versions. @@ -953,7 +951,6 @@ class Engine { networkController?.state.selectedNetworkClientId, ).configuration.chainId, ), - // @ts-expect-error TODO: Resolve mismatch between base-controller versions. getNetworkClientById: networkController.getNetworkClientById.bind(networkController), }); @@ -1529,7 +1526,6 @@ class Engine { selectedAddress: preferencesController.state.selectedAddress, tokenPricesService: codefiTokenApiV2, interval: 30 * 60 * 1000, - // @ts-expect-error TODO: Resolve mismatch between base-controller versions. getNetworkClientById: networkController.getNetworkClientById.bind(networkController), }), @@ -1780,7 +1776,6 @@ class Engine { } provider.sendAsync = provider.sendAsync.bind(provider); AccountTrackerController.configure({ provider }); - // @ts-expect-error TODO: Resolve mismatch between base-controller versions. AssetsContractController.configure({ provider }); SwapsController.configure({ diff --git a/app/core/processAttribution.test.tsx b/app/core/processAttribution.test.tsx index fa4a196a2e2..79c29c2b908 100644 --- a/app/core/processAttribution.test.tsx +++ b/app/core/processAttribution.test.tsx @@ -1,6 +1,7 @@ import { store } from '../store'; import extractURLParams from './DeeplinkManager/ParseManager/extractURLParams'; import { processAttribution } from './processAttribution'; +import Logger from '../util/Logger'; jest.mock('../store', () => ({ store: { @@ -9,22 +10,42 @@ jest.mock('../store', () => ({ })); jest.mock('./DeeplinkManager/ParseManager/extractURLParams', () => jest.fn()); +jest.mock('../util/Logger', () => ({ + error: jest.fn(), +})); describe('processAttribution', () => { beforeEach(() => { jest.clearAllMocks(); }); - it('returns attributionId when marketing is enabled and deeplink is provided', () => { + it('returns attribution data when marketing is enabled and deeplink is provided', () => { (store.getState as jest.Mock).mockReturnValue({ security: { dataCollectionForMarketing: true }, }); (extractURLParams as jest.Mock).mockReturnValue({ - params: { attributionId: 'test123' }, + params: { + attributionId: 'test123', + utm: JSON.stringify({ + source: 'twitter', + medium: 'social', + campaign: 'cmp-57731027-afbf09/', + term: null, + content: null + }) + }, }); - const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123', store }); - expect(result).toBe('test123'); + const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123&utm=...', store }); + expect(result).toEqual({ + attributionId: 'test123', + utm: expect.any(String), + utm_source: 'twitter', + utm_medium: 'social', + utm_campaign: 'cmp-57731027-afbf09/', + utm_term: null, + utm_content: null + }); }); it('returns undefined when marketing is disabled', () => { @@ -32,7 +53,7 @@ describe('processAttribution', () => { security: { dataCollectionForMarketing: false }, }); - const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123', store }); + const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123&utm=...', store }); expect(result).toBeUndefined(); }); @@ -45,15 +66,53 @@ describe('processAttribution', () => { expect(result).toBeUndefined(); }); - it('returns undefined when attributionId is not present in params', () => { + it('returns partial data when some UTM params are missing', () => { (store.getState as jest.Mock).mockReturnValue({ security: { dataCollectionForMarketing: true }, }); (extractURLParams as jest.Mock).mockReturnValue({ - params: {}, + params: { + attributionId: 'test123', + utm: JSON.stringify({ + source: 'twitter', + medium: 'social' + }) + }, }); - const result = processAttribution({ currentDeeplink: 'metamask://connect', store }); - expect(result).toBeUndefined(); + const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123&utm=...', store }); + expect(result).toEqual({ + attributionId: 'test123', + utm: expect.any(String), + utm_source: 'twitter', + utm_medium: 'social', + utm_campaign: undefined, + utm_term: undefined, + utm_content: undefined + }); + }); + + it('handles JSON parsing errors gracefully', () => { + (store.getState as jest.Mock).mockReturnValue({ + security: { dataCollectionForMarketing: true }, + }); + (extractURLParams as jest.Mock).mockReturnValue({ + params: { + attributionId: 'test123', + utm: 'invalid-json' + }, + }); + + const result = processAttribution({ currentDeeplink: 'metamask://connect?attributionId=test123&utm=invalid-json', store }); + expect(result).toEqual({ + attributionId: 'test123', + utm: 'invalid-json', + utm_source: undefined, + utm_medium: undefined, + utm_campaign: undefined, + utm_term: undefined, + utm_content: undefined + }); + expect(Logger.error).toHaveBeenCalledWith(expect.any(Error), expect.any(Error)); }); }); diff --git a/app/core/processAttribution.tsx b/app/core/processAttribution.tsx index f3a604e3cf5..d49518bdaaa 100644 --- a/app/core/processAttribution.tsx +++ b/app/core/processAttribution.tsx @@ -1,6 +1,8 @@ import extractURLParams from './DeeplinkManager/ParseManager/extractURLParams'; import { RootState } from '../reducers'; import { Store } from 'redux'; +import Logger from '../util/Logger'; +import DevLogger from './SDKConnect/utils/DevLogger'; interface ProcessAttributionParams { currentDeeplink: string | null; @@ -8,13 +10,51 @@ interface ProcessAttributionParams { store: Store; } -export function processAttribution({ currentDeeplink, store }: ProcessAttributionParams): string | undefined { - const state = store.getState(); - const isMarketingEnabled = state.security.dataCollectionForMarketing; +interface AttributionResult { + attributionId?: string; + utm?: string; + utm_source?: string; + utm_medium?: string; + utm_campaign?: string; + utm_term?: string; + utm_content?: string; +} + +export function processAttribution({ currentDeeplink, store }: ProcessAttributionParams): AttributionResult | undefined { + const { security } = store.getState(); + if (!security.dataCollectionForMarketing) { + return undefined; + } - if (isMarketingEnabled && currentDeeplink) { + if (currentDeeplink) { const { params } = extractURLParams(currentDeeplink); - return params.attributionId || undefined; // Force undefined to be returned as extractUrlParams default to empty string on error. + const attributionId = params.attributionId || undefined; + const utm = params.utm || undefined; + let utm_source, utm_medium, utm_campaign, utm_term, utm_content; + + if (utm) { + try { + const utmParams = JSON.parse(utm); + DevLogger.log('processAttribution:: UTM params', utmParams); + utm_source = utmParams.source; + utm_medium = utmParams.medium; + utm_campaign = utmParams.campaign; + utm_term = utmParams.term; + utm_content = utmParams.content; + } catch (error) { + Logger.error(new Error('Error parsing UTM params'), error); + } + } + + return { + attributionId, + utm, + utm_source, + utm_medium, + utm_campaign, + utm_term, + utm_content + }; } return undefined; diff --git a/docs/readme/testing.md b/docs/readme/testing.md index 546686c39e0..c79373ddc92 100644 --- a/docs/readme/testing.md +++ b/docs/readme/testing.md @@ -357,4 +357,4 @@ Our CI/CD process is automated through various Bitrise pipelines, each designed ### Best Practices -For more guidelines and best practices, refer to our [Best Practices Document](https://github.com/MetaMask/contributor-docs/blob/main/docs/e2e-testing.md). +For more guidelines and best practices, refer to our [Best Practices Document](https://github.com/MetaMask/contributor-docs/blob/main/docs/testing/e2e-testing.md). diff --git a/package.json b/package.json index 8ad00c34adb..97c3759e780 100644 --- a/package.json +++ b/package.json @@ -145,7 +145,7 @@ "@metamask/accounts-controller": "^18.2.1", "@metamask/address-book-controller": "^6.0.1", "@metamask/approval-controller": "^7.0.1", - "@metamask/assets-controllers": "^31.0.0", + "@metamask/assets-controllers": "^32.0.0", "@metamask/base-controller": "^7.0.1", "@metamask/composable-controller": "^3.0.0", "@metamask/contract-metadata": "^2.1.0", @@ -476,7 +476,6 @@ "prettier": "^2.2.1", "prettier-plugin-gherkin": "^1.1.1", "react-dom": "18.2.0", - "react-native-cli": "2.0.1", "react-native-flipper": "^0.263.0", "react-native-launch-arguments": "^4.0.1", "react-native-performance": "^5.1.2", diff --git a/patches/@metamask+assets-controllers++@metamask+preferences-controller+12.0.0.patch b/patches/@metamask+assets-controllers++@metamask+preferences-controller+13.0.3.patch similarity index 54% rename from patches/@metamask+assets-controllers++@metamask+preferences-controller+12.0.0.patch rename to patches/@metamask+assets-controllers++@metamask+preferences-controller+13.0.3.patch index 00f4da63438..c45e6f5109a 100644 --- a/patches/@metamask+assets-controllers++@metamask+preferences-controller+12.0.0.patch +++ b/patches/@metamask+assets-controllers++@metamask+preferences-controller+13.0.3.patch @@ -1,7 +1,7 @@ -diff --git a/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/types/PreferencesController.d.ts b/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/types/PreferencesController.d.ts -index ddf6eb4..e8dac6d 100644 ---- a/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/types/PreferencesController.d.ts -+++ b/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/types/PreferencesController.d.ts +diff --git a/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/PreferencesController.d.cts b/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/PreferencesController.d.cts +index 04a9d6f..391652d 100644 +--- a/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/PreferencesController.d.cts ++++ b/node_modules/@metamask/assets-controllers/node_modules/@metamask/preferences-controller/dist/PreferencesController.d.cts @@ -65,7 +65,7 @@ export type PreferencesState = { /** * Controls whether the OpenSea API is used diff --git a/patches/@metamask+assets-controllers+31.0.0.patch b/patches/@metamask+assets-controllers+32.0.0.patch similarity index 77% rename from patches/@metamask+assets-controllers+31.0.0.patch rename to patches/@metamask+assets-controllers+32.0.0.patch index 7de2ffecb6a..875d616b53e 100644 --- a/patches/@metamask+assets-controllers+31.0.0.patch +++ b/patches/@metamask+assets-controllers+32.0.0.patch @@ -1,10 +1,10 @@ diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-4AC3X2U5.js b/node_modules/@metamask/assets-controllers/dist/chunk-4AC3X2U5.js -index bb55790..b235cbf 100644 +index bb55790..c7e7f99 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-4AC3X2U5.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-4AC3X2U5.js -@@ -292,6 +292,18 @@ var TokensController = class extends _basecontroller.BaseController { - releaseLock(); - } +@@ -187,6 +187,18 @@ var TokensController = class extends _basecontroller.BaseController { + } + ); } + /** + * THIS FUNCTIONS IS CURRENTLY PATCHED AND STILL NEEDS TO BE IMPLEMENTED ON THE CORE REPO @@ -19,9 +19,9 @@ index bb55790..b235cbf 100644 + }); + } /** - * Add a batch of tokens. + * Adds a token to the stored token list. * -@@ -605,9 +617,14 @@ _selectedAddress = new WeakMap(); +@@ -605,9 +617,13 @@ _selectedAddress = new WeakMap(); _provider = new WeakMap(); _abortController = new WeakMap(); _onNetworkDidChange = new WeakSet(); @@ -29,7 +29,6 @@ index bb55790..b235cbf 100644 +onNetworkDidChange_fn = function({ selectedNetworkClientId }) { const { allTokens, allIgnoredTokens, allDetectedTokens } = this.state; - const { chainId } = providerConfig; -+ // This wont be needed in v32 + const selectedNetworkClient = this.messagingSystem.call( + 'NetworkController:getNetworkClientById', + selectedNetworkClientId, @@ -39,22 +38,10 @@ index bb55790..b235cbf 100644 _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _abortController, new AbortController()); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _chainId, chainId); diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-CGLUTXI7.js b/node_modules/@metamask/assets-controllers/dist/chunk-CGLUTXI7.js -index 7cc44fa..a7663b4 100644 +index 7cc44fa..7a1de65 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-CGLUTXI7.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-CGLUTXI7.js -@@ -17,7 +17,10 @@ var _basecontroller = require('@metamask/base-controller'); - - - -- -+/** -+ * Changes regarding displayNftMedia, TokenURI and error nft metadata property are not on the core repo and needed to be refactor to be removed from the patch -+ * updateNftMetadata changes will be introduced on latest versions of changes of assets controllers, v^30 or next -+ */ - - - -@@ -44,7 +47,7 @@ var getDefaultNftControllerState = () => ({ +@@ -44,7 +44,7 @@ var getDefaultNftControllerState = () => ({ allNfts: {}, ignoredNfts: [] }); @@ -63,7 +50,7 @@ index 7cc44fa..a7663b4 100644 var NftController = class extends _basecontroller.BaseController { /** * Creates an NftController instance. -@@ -53,7 +56,7 @@ var NftController = class extends _basecontroller.BaseController { +@@ -53,7 +53,7 @@ var NftController = class extends _basecontroller.BaseController { * @param options.chainId - The chain ID of the current network. * @param options.selectedAddress - The currently selected address. * @param options.ipfsGateway - The configured IPFS gateway. @@ -72,7 +59,7 @@ index 7cc44fa..a7663b4 100644 * @param options.useIpfsSubdomains - Controls whether IPFS subdomains are used. * @param options.isIpfsGatewayEnabled - Controls whether IPFS is enabled or not. * @param options.getERC721AssetName - Gets the name of the asset at the given address. -@@ -71,7 +74,7 @@ var NftController = class extends _basecontroller.BaseController { +@@ -71,7 +71,7 @@ var NftController = class extends _basecontroller.BaseController { chainId: initialChainId, selectedAddress = "", ipfsGateway = _controllerutils.IPFS_DEFAULT_GATEWAY_URL, @@ -81,7 +68,7 @@ index 7cc44fa..a7663b4 100644 useIpfsSubdomains = true, isIpfsGatewayEnabled = true, getERC721AssetName, -@@ -104,7 +107,7 @@ var NftController = class extends _basecontroller.BaseController { +@@ -104,7 +104,7 @@ var NftController = class extends _basecontroller.BaseController { * @param preferencesState - The new state of the preference controller. * @param preferencesState.selectedAddress - The current selected address. * @param preferencesState.ipfsGateway - The configured IPFS gateway. @@ -90,7 +77,7 @@ index 7cc44fa..a7663b4 100644 * @param preferencesState.isIpfsGatewayEnabled - Controls whether IPFS is enabled or not. */ _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _onPreferencesControllerStateChange); -@@ -233,7 +236,7 @@ var NftController = class extends _basecontroller.BaseController { +@@ -233,7 +233,7 @@ var NftController = class extends _basecontroller.BaseController { _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _selectedAddress, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _chainId, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _ipfsGateway, void 0); @@ -99,7 +86,7 @@ index 7cc44fa..a7663b4 100644 _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _useIpfsSubdomains, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _isIpfsGatewayEnabled, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _getERC721AssetName, void 0); -@@ -246,7 +249,7 @@ var NftController = class extends _basecontroller.BaseController { +@@ -246,7 +246,7 @@ var NftController = class extends _basecontroller.BaseController { _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _selectedAddress, selectedAddress); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _chainId, initialChainId); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _ipfsGateway, ipfsGateway); @@ -108,7 +95,7 @@ index 7cc44fa..a7663b4 100644 _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _useIpfsSubdomains, useIpfsSubdomains); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _isIpfsGatewayEnabled, isIpfsGatewayEnabled); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _getERC721AssetName, getERC721AssetName); -@@ -268,6 +271,17 @@ var NftController = class extends _basecontroller.BaseController { +@@ -268,6 +268,17 @@ var NftController = class extends _basecontroller.BaseController { getNftApi() { return `${_controllerutils.NFT_API_BASE_URL}/tokens`; } @@ -126,87 +113,7 @@ index 7cc44fa..a7663b4 100644 /** * Adds a new suggestedAsset to state. Parameters will be validated according to * asset type being watched. A `:pending` hub event will be emitted once added. -@@ -430,43 +444,48 @@ var NftController = class extends _basecontroller.BaseController { - userAddress = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress), - networkClientId - }) { -- const chainId = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getCorrectChainId, getCorrectChainId_fn).call(this, { networkClientId }); -- const nftsWithChecksumAdr = nfts.map((nft) => { -- return { -- ...nft, -- address: _controllerutils.toChecksumHexAddress.call(void 0, nft.address) -- }; -- }); -- const nftMetadataResults = await Promise.all( -- nftsWithChecksumAdr.map(async (nft) => { -- const resMetadata = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getNftInformation, getNftInformation_fn).call(this, nft.address, nft.tokenId, networkClientId); -+ const releaseLock = await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _mutex).acquire(); -+ try{ -+ const chainId = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getCorrectChainId, getCorrectChainId_fn).call(this, { networkClientId }); -+ const nftsWithChecksumAdr = nfts.map((nft) => { - return { -- nft, -- newMetadata: resMetadata -+ ...nft, -+ address: _controllerutils.toChecksumHexAddress.call(void 0, nft.address) - }; -- }) -- ); -- const nftsWithDifferentMetadata = []; -- const { allNfts } = this.state; -- const stateNfts = allNfts[userAddress]?.[chainId] || []; -- nftMetadataResults.forEach((singleNft) => { -- const existingEntry = stateNfts.find( -- (nft) => nft.address.toLowerCase() === singleNft.nft.address.toLowerCase() && nft.tokenId === singleNft.nft.tokenId -+ }); -+ const nftMetadataResults = await Promise.all( -+ nftsWithChecksumAdr.map(async (nft) => { -+ const resMetadata = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getNftInformation, getNftInformation_fn).call(this, nft.address, nft.tokenId, networkClientId); -+ return { -+ nft, -+ newMetadata: resMetadata -+ }; -+ }) - ); -- if (existingEntry) { -- const differentMetadata = _chunkNEXY7SE2js.compareNftMetadata.call(void 0, -- singleNft.newMetadata, -- existingEntry -+ const nftsWithDifferentMetadata = []; -+ const { allNfts } = this.state; -+ const stateNfts = allNfts[userAddress]?.[chainId] || []; -+ nftMetadataResults.forEach((singleNft) => { -+ const existingEntry = stateNfts.find( -+ (nft) => nft.address.toLowerCase() === singleNft.nft.address.toLowerCase() && nft.tokenId === singleNft.nft.tokenId - ); -- if (differentMetadata) { -- nftsWithDifferentMetadata.push(singleNft); -+ if (existingEntry) { -+ const differentMetadata = _chunkNEXY7SE2js.compareNftMetadata.call(void 0, -+ singleNft.newMetadata, -+ existingEntry -+ ); -+ if (differentMetadata) { -+ nftsWithDifferentMetadata.push(singleNft); -+ } - } -+ }); -+ if (nftsWithDifferentMetadata.length !== 0) { -+ nftsWithDifferentMetadata.forEach( -+ (elm) => this.updateNft(elm.nft, elm.newMetadata, userAddress, chainId) -+ ); - } -- }); -- if (nftsWithDifferentMetadata.length !== 0) { -- nftsWithDifferentMetadata.forEach( -- (elm) => this.updateNft(elm.nft, elm.newMetadata, userAddress, chainId) -- ); -+ } finally { -+ releaseLock(); - } - } - /** -@@ -771,7 +790,7 @@ _mutex = new WeakMap(); +@@ -771,7 +782,7 @@ _mutex = new WeakMap(); _selectedAddress = new WeakMap(); _chainId = new WeakMap(); _ipfsGateway = new WeakMap(); @@ -215,7 +122,7 @@ index 7cc44fa..a7663b4 100644 _useIpfsSubdomains = new WeakMap(); _isIpfsGatewayEnabled = new WeakMap(); _getERC721AssetName = new WeakMap(); -@@ -797,14 +816,14 @@ _onPreferencesControllerStateChange = new WeakSet(); +@@ -797,14 +808,14 @@ _onPreferencesControllerStateChange = new WeakSet(); onPreferencesControllerStateChange_fn = async function({ selectedAddress, ipfsGateway, @@ -233,7 +140,15 @@ index 7cc44fa..a7663b4 100644 if (needsUpdateNftMetadata) { const nfts = this.state.allNfts[selectedAddress]?.[_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _chainId)] ?? []; const nftsToUpdate = nfts.filter( -@@ -850,12 +869,25 @@ getNftInformationFromApi_fn = async function(contractAddress, tokenId) { +@@ -818,6 +829,7 @@ onPreferencesControllerStateChange_fn = async function({ + } + } + }; ++ + _updateNestedNftState = new WeakSet(); + updateNestedNftState_fn = function(newCollection, baseStateKey, { userAddress, chainId }) { + this.update((state) => { +@@ -850,12 +862,25 @@ getNftInformationFromApi_fn = async function(contractAddress, tokenId) { } } }); @@ -242,9 +157,9 @@ index 7cc44fa..a7663b4 100644 + id: `${nftInformation?.tokens[0]?.token?.collection?.id}` + }).toString(); + const collectionInformation = await _controllerutils.fetchWithErrorHandling.call(void 0, { -+ url: `${_controllerutils.NFT_API_BASE_URL}/collections?${getCollectionParams}`, -+ options: { -+ headers: { ++ url: `${_controllerutils.NFT_API_BASE_URL}/collections?${getCollectionParams}`, ++ options: { ++ headers: { + Version: '1' + } + } @@ -260,52 +175,25 @@ index 7cc44fa..a7663b4 100644 }; } const { -@@ -887,7 +919,16 @@ getNftInformationFromApi_fn = async function(contractAddress, tokenId) { +@@ -887,7 +912,16 @@ getNftInformationFromApi_fn = async function(contractAddress, tokenId) { }, rarityRank && { rarityRank }, rarity && { rarity }, - collection && { collection } + (collection || collectionInformation) && { -+ collection: { -+ ...collection || {}, -+ creator: collection?.creator || collectionInformation?.collections[0].creator, -+ openseaVerificationStatus: collectionInformation?.collections[0].openseaVerificationStatus, -+ contractDeployedAt: collectionInformation?.collections[0].contractDeployedAt, -+ ownerCount: collectionInformation?.collections[0].ownerCount, -+ topBid: collectionInformation?.collections[0].topBid ++ collection: { ++ ...collection || {}, ++ creator: collection?.creator || collectionInformation?.collections[0].creator, ++ openseaVerificationStatus: collectionInformation?.collections[0].openseaVerificationStatus, ++ contractDeployedAt: collectionInformation?.collections[0].contractDeployedAt, ++ ownerCount: collectionInformation?.collections[0].ownerCount, ++ topBid: collectionInformation?.collections[0].topBid ++ } + } -+ } ); return nftMetadata; }; -@@ -896,6 +937,17 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw - const result = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getNftURIAndStandard, getNftURIAndStandard_fn).call(this, contractAddress, tokenId, networkClientId); - let tokenURI = result[0]; - const standard = result[1]; -+ if (!_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _displayNftMedia) && !_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _isIpfsGatewayEnabled)) { -+ return { -+ image: null, -+ name: null, -+ description: null, -+ standard: standard || null, -+ favorite: false, -+ tokenURI, -+ }; -+ } -+ - const hasIpfsTokenURI = tokenURI.startsWith("ipfs://"); - if (hasIpfsTokenURI && !_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _isIpfsGatewayEnabled)) { - return { -@@ -907,7 +959,7 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw - tokenURI: tokenURI ?? null - }; - } -- const isDisplayNFTMediaToggleEnabled = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _openSeaEnabled); -+ const isDisplayNFTMediaToggleEnabled = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _displayNftMedia); - if (!hasIpfsTokenURI && !isDisplayNFTMediaToggleEnabled) { - return { - image: null, -@@ -915,7 +967,8 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw +@@ -904,10 +938,11 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw description: null, standard: standard || null, favorite: false, @@ -314,8 +202,12 @@ index 7cc44fa..a7663b4 100644 + error: 'URI import error', }; } - if (hasIpfsTokenURI) { -@@ -925,6 +978,16 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw +- const isDisplayNFTMediaToggleEnabled = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _openSeaEnabled); ++ const isDisplayNFTMediaToggleEnabled = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _displayNftMedia); + if (!hasIpfsTokenURI && !isDisplayNFTMediaToggleEnabled) { + return { + image: null, +@@ -925,6 +960,16 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _useIpfsSubdomains) ); } @@ -332,7 +224,7 @@ index 7cc44fa..a7663b4 100644 try { const object = await _controllerutils.handleFetch.call(void 0, tokenURI); const image = Object.prototype.hasOwnProperty.call(object, "image") ? "image" : ( -@@ -946,7 +1009,8 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw +@@ -946,7 +991,8 @@ getNftInformationFromTokenURI_fn = async function(contractAddress, tokenId, netw description: null, standard: standard || null, favorite: false, @@ -342,7 +234,7 @@ index 7cc44fa..a7663b4 100644 }; } }; -@@ -977,15 +1041,26 @@ getNftInformation_fn = async function(contractAddress, tokenId, networkClientId) +@@ -977,15 +1023,27 @@ getNftInformation_fn = async function(contractAddress, tokenId, networkClientId) _controllerutils.safelyExecute.call(void 0, () => _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getNftInformationFromTokenURI, getNftInformationFromTokenURI_fn).call(this, contractAddress, tokenId, networkClientId) ), @@ -351,16 +243,17 @@ index 7cc44fa..a7663b4 100644 () => _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getNftInformationFromApi, getNftInformationFromApi_fn).call(this, contractAddress, tokenId) ) : void 0 ]); ++ + if (blockchainMetadata?.error && nftApiMetadata?.error) { -+ return { -+ image: null, -+ name: null, -+ description: null, -+ standard: blockchainMetadata.standard ?? null, -+ favorite: false, -+ tokenURI: blockchainMetadata.tokenURI ?? null, -+ error: 'Both import failed', -+ }; ++ return { ++ image: null, ++ name: null, ++ description: null, ++ standard: blockchainMetadata.standard ?? null, ++ favorite: false, ++ tokenURI: blockchainMetadata.tokenURI ?? null, ++ error: 'Both import failed', ++ }; + } return { ...nftApiMetadata, @@ -371,7 +264,7 @@ index 7cc44fa..a7663b4 100644 standard: blockchainMetadata?.standard ?? nftApiMetadata?.standard ?? null, tokenURI: blockchainMetadata?.tokenURI ?? null }; -@@ -1048,7 +1123,8 @@ addIndividualNft_fn = async function(tokenAddress, tokenId, nftMetadata, nftCont +@@ -1048,7 +1106,8 @@ addIndividualNft_fn = async function(tokenAddress, tokenId, nftMetadata, nftCont nftMetadata, existingEntry ); @@ -381,7 +274,7 @@ index 7cc44fa..a7663b4 100644 return; } const indexToUpdate = nfts.findIndex( -@@ -1080,7 +1156,8 @@ addIndividualNft_fn = async function(tokenAddress, tokenId, nftMetadata, nftCont +@@ -1080,7 +1139,8 @@ addIndividualNft_fn = async function(tokenAddress, tokenId, nftMetadata, nftCont symbol: nftContract.symbol, tokenId: tokenId.toString(), standard: nftMetadata.standard, @@ -392,7 +285,7 @@ index 7cc44fa..a7663b4 100644 } } finally { diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-ELSMS5S7.js b/node_modules/@metamask/assets-controllers/dist/chunk-ELSMS5S7.js -index 45254ad..cd5f3a1 100644 +index 45254ad..f3c6204 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-ELSMS5S7.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-ELSMS5S7.js @@ -87,6 +87,7 @@ var CurrencyRateController = class extends _pollingcontroller.StaticIntervalPoll @@ -426,7 +319,7 @@ index 45254ad..cd5f3a1 100644 - currentCurrency - }; - }); -+ if (shouldUpdateState) { ++ if(shouldUpdateState) { + this.update(() => { + return { + currencyRates: { @@ -439,13 +332,13 @@ index 45254ad..cd5f3a1 100644 + }, + currentCurrency + }; -+ }) ++ }); + } } finally { releaseLock(); } diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-GU53EI7A.js b/node_modules/@metamask/assets-controllers/dist/chunk-GU53EI7A.js -index 33b048f..8815b95 100644 +index 33b048f..5867375 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-GU53EI7A.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-GU53EI7A.js @@ -61,7 +61,7 @@ var AccountTrackerController = class extends _pollingcontroller.StaticIntervalPo @@ -457,36 +350,34 @@ index 33b048f..8815b95 100644 const accountsForChain = { ...accountsByChainId[chainId] }; for (const address of accountsToUpdate) { const balance = await this.getBalanceFromChain(address, ethQuery); -@@ -80,9 +80,11 @@ var AccountTrackerController = class extends _pollingcontroller.StaticIntervalPo +@@ -80,9 +80,8 @@ var AccountTrackerController = class extends _pollingcontroller.StaticIntervalPo [chainId]: accountsForChain } }); - } catch (err) { + } finally { -+ /** -+ * This change is not present on the core repo -+ */ releaseLock(); - throw err; } }; this.defaultConfig = { diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-HDI4L2DD.js b/node_modules/@metamask/assets-controllers/dist/chunk-HDI4L2DD.js -index 76e3362..f733c85 100644 +index 76e3362..e11991d 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-HDI4L2DD.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-HDI4L2DD.js -@@ -165,7 +165,9 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo +@@ -165,7 +165,10 @@ var TokenDetectionController = class extends _pollingcontroller.StaticIntervalPo if (!this.isActive) { return; } - const addressAgainstWhichToDetect = selectedAddress ?? _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress); ++ //const addressAgainstWhichToDetect = selectedAddress ?? _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress); + const currentAddress = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress); + const currentAddressChecksum = _controllerutils.toChecksumHexAddress.call(void 0, currentAddress) + const addressAgainstWhichToDetect = _controllerutils.toChecksumHexAddress.call(void 0, selectedAddress) ?? currentAddressChecksum; const { chainId, networkClientId: selectedNetworkClientId } = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getCorrectChainIdAndNetworkClientId, getCorrectChainIdAndNetworkClientId_fn).call(this, networkClientId); const chainIdAgainstWhichToDetect = chainId; const networkClientIdAgainstWhichToDetect = selectedNetworkClientId; -@@ -224,12 +226,10 @@ registerEventListeners_fn = function() { +@@ -224,12 +227,10 @@ registerEventListeners_fn = function() { ); this.messagingSystem.subscribe( "PreferencesController:stateChange", @@ -502,7 +393,7 @@ index 76e3362..f733c85 100644 selectedAddress: _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _selectedAddress) }); diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-IBK6AXPP.js b/node_modules/@metamask/assets-controllers/dist/chunk-IBK6AXPP.js -index f7509a1..52bc67e 100644 +index f7509a1..4573718 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-IBK6AXPP.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-IBK6AXPP.js @@ -19,7 +19,7 @@ function getDefaultTokenBalancesState() { @@ -526,24 +417,23 @@ index f7509a1..52bc67e 100644 this.messagingSystem.subscribe( "TokensController:stateChange", ({ tokens: newTokens, detectedTokens }) => { -@@ -79,6 +81,16 @@ var TokenBalancesController = class extends _basecontroller.BaseController { +@@ -79,6 +81,15 @@ var TokenBalancesController = class extends _basecontroller.BaseController { disable() { _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _disabled, true); } -+ -+/** ++ /** + * THIS FUNCTIONS IS CURRENTLY PATCHED AND STILL NEEDS TO BE IMPLEMENTED ON THE CORE REPO + * Resets to the default state + */ + reset() { -+ this.update((state) => { ++ this.update((state) => { + state.contractBalances = {}; -+ }); -+ } ++ }); ++ } /** * Starts a new polling interval. * -@@ -100,27 +112,34 @@ var TokenBalancesController = class extends _basecontroller.BaseController { +@@ -100,27 +111,34 @@ var TokenBalancesController = class extends _basecontroller.BaseController { * Updates balances for all tokens. */ async updateBalances() { @@ -567,20 +457,20 @@ index f7509a1..52bc67e 100644 - } - } + const balancePromises = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _tokens).map((token) => { -+ const { address } = token; ++ const { address } = token; + return _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _getERC20BalanceOf).call(this, address, selectedAddress).then((balance) => { -+ newContractBalances[address] = _controllerutils.toHex.call(void 0, balance); -+ token = { -+ ...token, -+ hasBalanceError: false -+ }; ++ newContractBalances[address] = _controllerutils.toHex.call(void 0, balance); ++ token = { ++ ...token, ++ hasBalanceError: false ++ }; + }).catch((error) => { -+ newContractBalances[address] = _controllerutils.toHex.call(void 0, 0); -+ token = { -+ ...token, -+ hasBalanceError: true -+ }; -+ }); ++ newContractBalances[address] = _controllerutils.toHex.call(void 0, 0); ++ token = { ++ ...token, ++ hasBalanceError: true ++ }; ++ }); + }); + await Promise.all(balancePromises); this.update((state) => { @@ -590,7 +480,7 @@ index f7509a1..52bc67e 100644 } }; _handle = new WeakMap(); -@@ -128,6 +147,7 @@ _getERC20BalanceOf = new WeakMap(); +@@ -128,6 +146,7 @@ _getERC20BalanceOf = new WeakMap(); _interval = new WeakMap(); _tokens = new WeakMap(); _disabled = new WeakMap(); @@ -621,38 +511,36 @@ index 44804c8..911a6e6 100644 this.clearingTokenListData(); } else { diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-QFDTOEYR.js b/node_modules/@metamask/assets-controllers/dist/chunk-QFDTOEYR.js -index 5335fa5..ae37683 100644 +index 5335fa5..0854306 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-QFDTOEYR.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-QFDTOEYR.js -@@ -7,6 +7,8 @@ var _chunkZ4BLTVTBjs = require('./chunk-Z4BLTVTB.js'); - +@@ -8,12 +8,14 @@ var _chunkZ4BLTVTBjs = require('./chunk-Z4BLTVTB.js'); // src/NftDetectionController.ts + +- +var utils_1 = require('@metamask/utils'); +var _chunkR4HATJKUjs = require('./chunk-NEXY7SE2.js'); -@@ -14,6 +16,7 @@ var _chunkZ4BLTVTBjs = require('./chunk-Z4BLTVTB.js'); - var _controllerutils = require('@metamask/controller-utils'); +var supportedNftDetectionNetworks = [_controllerutils.ChainId.mainnet]; var _pollingcontroller = require('@metamask/polling-controller'); var DEFAULT_INTERVAL = 18e4; var controllerName = "NftDetectionController"; -@@ -24,7 +27,9 @@ var BlockaidResultType = /* @__PURE__ */ ((BlockaidResultType2) => { +@@ -24,7 +26,8 @@ var BlockaidResultType = /* @__PURE__ */ ((BlockaidResultType2) => { BlockaidResultType2["Malicious"] = "Malicious"; return BlockaidResultType2; })(BlockaidResultType || {}); -var _intervalId, _interval, _disabled, _addNft, _getNftState, _stopPolling, stopPolling_fn, _startPolling, startPolling_fn, _onPreferencesControllerStateChange, onPreferencesControllerStateChange_fn, _getOwnerNftApi, getOwnerNftApi_fn, _getOwnerNfts, getOwnerNfts_fn; -+// This patch wont be needed in v35 +var MAX_GET_COLLECTION_BATCH_SIZE = 20; +var _intervalId, _interval, _disabled, _addNft, _getNftState, _stopPolling, stopPolling_fn, _startPolling, startPolling_fn, _onPreferencesControllerStateChange, onPreferencesControllerStateChange_fn, _getOwnerNftApi, getOwnerNftApi_fn, _getOwnerNfts, getOwnerNfts_fn, _inProcessNftFetchingUpdates; var NftDetectionController = class extends _pollingcontroller.StaticIntervalPollingController { /** * The controller options -@@ -68,8 +73,10 @@ var NftDetectionController = class extends _pollingcontroller.StaticIntervalPoll +@@ -68,8 +71,10 @@ var NftDetectionController = class extends _pollingcontroller.StaticIntervalPoll _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _disabled, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _addNft, void 0); _chunkZ4BLTVTBjs.__privateAdd.call(void 0, this, _getNftState, void 0); @@ -663,19 +551,16 @@ index 5335fa5..ae37683 100644 _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _getNftState, getNftState); _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _addNft, addNft); this.messagingSystem.subscribe( -@@ -126,62 +133,154 @@ var NftDetectionController = class extends _pollingcontroller.StaticIntervalPoll +@@ -126,62 +131,152 @@ var NftDetectionController = class extends _pollingcontroller.StaticIntervalPoll */ async detectNfts(options) { const userAddress = options?.userAddress ?? this.messagingSystem.call("PreferencesController:getState").selectedAddress; - if (!this.isMainnet() || _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _disabled)) { -+ const { selectedNetworkClientId } = this.messagingSystem.call( -+ "NetworkController:getState" -+ ); -+ const { -+ configuration: { chainId } -+ } = this.messagingSystem.call( -+ "NetworkController:getNetworkClientById", -+ selectedNetworkClientId ++ ++ const { selectedNetworkClientId } = this.messagingSystem.call("NetworkController:getState"); ++ const { configuration: { chainId }} = this.messagingSystem.call( ++ "NetworkController:getNetworkClientById", ++ selectedNetworkClientId + ); + if (!supportedNftDetectionNetworks.includes(chainId) || _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _disabled)) { return; @@ -727,19 +612,18 @@ index 5335fa5..ae37683 100644 + const updateKey = `${chainId}:${userAddress}`; + if (updateKey in _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProcessNftFetchingUpdates)) { + await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProcessNftFetchingUpdates)[updateKey]; -+ return; ++ return; + } + const { -+ promise: inProgressUpdate, -+ resolve: updateSucceeded, -+ reject: updateFailed -+ } = utils_1.createDeferredPromise.call(void 0, { suppressUnhandledRejection: true }); ++ promise: inProgressUpdate, ++ resolve: updateSucceeded, ++ reject: updateFailed ++ } = utils_1.createDeferredPromise.call(void 0, { suppressUnhandledRejection: true }); + _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProcessNftFetchingUpdates)[updateKey] = inProgressUpdate; + let next; + let apiNfts = []; + let resultNftApi; -+ -+ try { ++ try{ + do { + resultNftApi = await _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getOwnerNfts, getOwnerNfts_fn).call(this, userAddress, chainId, next); + apiNfts = resultNftApi.tokens.filter( @@ -752,7 +636,7 @@ index 5335fa5..ae37683 100644 - networkClientId: options?.networkClientId + const collections = apiNfts.reduce((acc, currValue) => { + if (!acc.includes(currValue.token.contract) && currValue.token.contract === currValue?.token?.collection?.id) { -+ acc.push(currValue.token.contract); ++ acc.push(currValue.token.contract); + } + return acc; + }, []); @@ -766,108 +650,110 @@ index 5335fa5..ae37683 100644 + ); + params.append("chainId", "1"); + const collectionResponseForBatch = await _controllerutils.fetchWithErrorHandling.call(void 0, -+ { -+ url: `${_controllerutils.NFT_API_BASE_URL}/collections?${params.toString()}`, -+ options: { ++ { ++ url: `${_controllerutils.NFT_API_BASE_URL}/collections?${params.toString()}`, ++ options: { + headers: { -+ Version: '1' ++ Version: '1' + } -+ }, -+ timeout: 15000 -+ } -+ ); -+ return { ++ }, ++ timeout: 15000 ++ } ++ ); ++ return { + ...allResponses, + ...collectionResponseForBatch -+ }; -+ }, ++ }; ++ }, + initialResult: {} + }); ++ + if (collectionResponse.collections?.length) { + apiNfts.forEach((singleNFT) => { -+ const found = collectionResponse.collections.find( ++ const found = collectionResponse.collections.find( + (elm) => elm.id?.toLowerCase() === singleNFT.token.contract.toLowerCase() -+ ); -+ if (found) { -+ singleNFT.token = { -+ ...singleNFT.token, -+ collection: { -+ ...singleNFT.token.collection ?? {}, -+ creator: found?.creator, -+ openseaVerificationStatus: found?.openseaVerificationStatus, -+ contractDeployedAt: found.contractDeployedAt, -+ ownerCount: found.ownerCount, -+ topBid: found.topBid -+ } -+ }; -+ } ++ ); ++ if (found) { ++ singleNFT.token = { ++ ...singleNFT.token, ++ collection: { ++ ...singleNFT.token.collection ?? {}, ++ creator: found?.creator, ++ openseaVerificationStatus: found?.openseaVerificationStatus, ++ contractDeployedAt: found.contractDeployedAt, ++ ownerCount: found.ownerCount, ++ topBid: found.topBid ++ } ++ }; ++ } + }); + } + } ++ + const addNftPromises = apiNfts.map(async (nft) => { -+ const { ++ const { + tokenId, + contract, + kind, + image: imageUrl, -+ imageSmall: imageThumbnailUrl, -+ metadata: { imageOriginal: imageOriginalUrl } = {}, -+ name, -+ description, -+ attributes, -+ topBid, -+ lastSale, -+ rarityRank, -+ rarityScore, -+ collection -+ } = nft.token; -+ let ignored; -+ const { ignoredNfts } = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _getNftState).call(this); -+ if (ignoredNfts.length) { ++ imageSmall: imageThumbnailUrl, ++ metadata: { imageOriginal: imageOriginalUrl } = {}, ++ name, ++ description, ++ attributes, ++ topBid, ++ lastSale, ++ rarityRank, ++ rarityScore, ++ collection ++ } = nft.token; ++ let ignored; ++ const { ignoredNfts } = _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _getNftState).call(this); ++ if (ignoredNfts.length) { + ignored = ignoredNfts.find((c) => { + return c.address === _controllerutils.toChecksumHexAddress.call(void 0, contract) && c.tokenId === tokenId; + }); -+ } -+ if (!ignored) { -+ const nftMetadata = Object.assign( -+ {}, -+ { name }, -+ description && { description }, -+ imageUrl && { image: imageUrl }, -+ imageThumbnailUrl && { imageThumbnail: imageThumbnailUrl }, -+ imageOriginalUrl && { imageOriginal: imageOriginalUrl }, -+ kind && { standard: kind.toUpperCase() }, -+ lastSale && { lastSale }, -+ attributes && { attributes }, -+ topBid && { topBid }, -+ rarityRank && { rarityRank }, -+ rarityScore && { rarityScore }, -+ collection && { collection } -+ ); -+ await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _addNft).call(this, contract, tokenId, { -+ nftMetadata, -+ userAddress, -+ source: "detected" /* Detected */, -+ networkClientId: options?.networkClientId -+ }); -+ } ++ } ++ if (!ignored) { ++ const nftMetadata = Object.assign( ++ {}, ++ { name }, ++ description && { description }, ++ imageUrl && { image: imageUrl }, ++ imageThumbnailUrl && { imageThumbnail: imageThumbnailUrl }, ++ imageOriginalUrl && { imageOriginal: imageOriginalUrl }, ++ kind && { standard: kind.toUpperCase() }, ++ lastSale && { lastSale }, ++ attributes && { attributes }, ++ topBid && { topBid }, ++ rarityRank && { rarityRank }, ++ rarityScore && { rarityScore }, ++ collection && { collection } ++ ); ++ await _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _addNft).call(this, contract, tokenId, { ++ nftMetadata, ++ userAddress, ++ source: "detected" /* Detected */, ++ networkClientId: options?.networkClientId ++ }); ++ } }); - } - }); - await Promise.all(addNftPromises); + await Promise.all(addNftPromises); -+ } while (next = resultNftApi.continuation); ++ } while(next = resultNftApi.continuation) + updateSucceeded(); -+ } catch (error) { ++ }catch(error){ + updateFailed(error); + throw error; -+ } finally { ++ }finally{ + delete _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _inProcessNftFetchingUpdates)[updateKey]; + } } }; _intervalId = new WeakMap(); -@@ -190,6 +289,7 @@ _disabled = new WeakMap(); +@@ -190,6 +285,7 @@ _disabled = new WeakMap(); _addNft = new WeakMap(); _getNftState = new WeakMap(); _stopPolling = new WeakSet(); @@ -875,7 +761,7 @@ index 5335fa5..ae37683 100644 stopPolling_fn = function() { if (_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _intervalId)) { clearInterval(_chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _intervalId)); -@@ -207,41 +307,26 @@ _onPreferencesControllerStateChange = new WeakSet(); +@@ -207,41 +303,26 @@ _onPreferencesControllerStateChange = new WeakSet(); onPreferencesControllerStateChange_fn = function({ useNftDetection }) { if (!useNftDetection !== _chunkZ4BLTVTBjs.__privateGet.call(void 0, this, _disabled)) { _chunkZ4BLTVTBjs.__privateSet.call(void 0, this, _disabled, !useNftDetection); @@ -909,6 +795,13 @@ index 5335fa5..ae37683 100644 - }); - if (!nftApiResponse) { - return nfts; +- } +- const newNfts = nftApiResponse.tokens?.filter( +- (elm) => elm.token.isSpam === false && (elm.blockaidResult?.result_type ? elm.blockaidResult?.result_type === "Benign" /* Benign */ : true) +- ) ?? []; +- nfts = [...nfts, ...newNfts]; +- } while (next = nftApiResponse.continuation); +- return nfts; +getOwnerNfts_fn = async function(address, chainId, cursor) { + const convertedChainId = _controllerutils.convertHexToDecimal.call(void 0, chainId).toString(); + const url = _chunkZ4BLTVTBjs.__privateMethod.call(void 0, this, _getOwnerNftApi, getOwnerNftApi_fn).call(this, { @@ -917,15 +810,9 @@ index 5335fa5..ae37683 100644 + next: cursor + }); + const nftApiResponse = await _controllerutils.handleFetch.call(void 0, url, { -+ headers: { -+ Version: '1' - } -- const newNfts = nftApiResponse.tokens?.filter( -- (elm) => elm.token.isSpam === false && (elm.blockaidResult?.result_type ? elm.blockaidResult?.result_type === "Benign" /* Benign */ : true) -- ) ?? []; -- nfts = [...nfts, ...newNfts]; -- } while (next = nftApiResponse.continuation); -- return nfts; ++ headers: { ++ Version: '1' ++ } + }); + return nftApiResponse; }; @@ -949,14 +836,11 @@ index 6f461a4..a3573af 100644 } }); diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-UEDNQBJN.js b/node_modules/@metamask/assets-controllers/dist/chunk-UEDNQBJN.js -index 80cecfb..f625ec2 100644 +index 80cecfb..e19a2e9 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-UEDNQBJN.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-UEDNQBJN.js -@@ -378,9 +378,10 @@ fetchAndMapExchangeRatesForSupportedNativeCurrency_fn = async function({ - } - return Object.entries(contractNativeInformations).reduce( +@@ -380,7 +380,7 @@ fetchAndMapExchangeRatesForSupportedNativeCurrency_fn = async function({ (obj, [tokenAddress, token]) => { -+ // This wont be needed in v33 obj = { ...obj, - [tokenAddress.toLowerCase()]: { ...token } @@ -964,7 +848,7 @@ index 80cecfb..f625ec2 100644 }; return obj; }, -@@ -416,7 +417,7 @@ fetchAndMapExchangeRatesForUnsupportedNativeCurrency_fn = async function({ +@@ -416,7 +416,7 @@ fetchAndMapExchangeRatesForUnsupportedNativeCurrency_fn = async function({ ...acc, [tokenAddress]: { ...token, @@ -974,10 +858,10 @@ index 80cecfb..f625ec2 100644 }; return acc; diff --git a/node_modules/@metamask/assets-controllers/dist/chunk-Z6TBQQE5.js b/node_modules/@metamask/assets-controllers/dist/chunk-Z6TBQQE5.js -index 2f1b66f..8436bd9 100644 +index 2f1b66f..f4acd79 100644 --- a/node_modules/@metamask/assets-controllers/dist/chunk-Z6TBQQE5.js +++ b/node_modules/@metamask/assets-controllers/dist/chunk-Z6TBQQE5.js -@@ -295,13 +295,11 @@ var CodefiTokenPricesServiceV2 = class { +@@ -295,13 +295,12 @@ var CodefiTokenPricesServiceV2 = class { (obj, tokenAddress) => { const lowercasedTokenAddress = tokenAddress.toLowerCase(); const marketData = addressCryptoDataMap[lowercasedTokenAddress]; @@ -986,6 +870,7 @@ index 2f1b66f..8436bd9 100644 return obj; } - const { price } = marketData; ++ const token = { tokenAddress, - value: price, @@ -1089,7 +974,7 @@ index 758a85e..a4a4b72 100644 bps?: number; recipient?: string; diff --git a/node_modules/@metamask/assets-controllers/dist/types/TokenBalancesController.d.ts b/node_modules/@metamask/assets-controllers/dist/types/TokenBalancesController.d.ts -index 52bb3ac..b291078 100644 +index 52bb3ac..d4d5c0a 100644 --- a/node_modules/@metamask/assets-controllers/dist/types/TokenBalancesController.d.ts +++ b/node_modules/@metamask/assets-controllers/dist/types/TokenBalancesController.d.ts @@ -79,6 +79,11 @@ export declare class TokenBalancesController extends BaseController