Skip to content

Commit

Permalink
Address performance issues
Browse files Browse the repository at this point in the history
  • Loading branch information
OGPoyraz committed Jul 2, 2024
1 parent 90f1269 commit 552e392
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 55 deletions.
15 changes: 6 additions & 9 deletions app/components/UI/Identicon/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { shallow } from 'enzyme';
import { render } from '@testing-library/react-native';
import Identicon from './';
import configureMockStore from 'redux-mock-store';
import { type TokenListMap } from '@metamask/assets-controllers';
import { Provider } from 'react-redux';
import useTokenList from '../../../components/hooks/DisplayName/useTokenList';

Expand All @@ -17,14 +16,12 @@ describe('Identicon', () => {

it('should render correctly when provided address found in tokenList and iconUrl is available', () => {
const addressMock = '0x0439e60f02a8900a951603950d8d4527f400c3f1';
mockUseTokenList.mockImplementation(
() =>
({
[addressMock]: {
iconUrl: 'https://example.com/icon.png',
},
} as unknown as TokenListMap),
);
mockUseTokenList.mockImplementation(() => [
{
address: addressMock,
iconUrl: 'https://example.com/icon.png',
},
]);

const initialState = {
settings: { useBlockieIcon: true },
Expand Down
12 changes: 8 additions & 4 deletions app/components/UI/Identicon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable react/prop-types */
import React, { memo } from 'react';
import { Image, ImageStyle, View } from 'react-native';
import { TokenListToken } from '@metamask/assets-controllers';
import { toDataUrl } from '../../../util/blockies';
import FadeIn from 'react-native-fade-in-image';
import Jazzicon from 'react-native-jazzicon';
Expand Down Expand Up @@ -44,12 +45,15 @@ const Identicon: React.FC<IdenticonProps> = ({
useBlockieIcon = true,
}) => {
const { colors } = useTheme();
const tokenList = useTokenList();
const tokenListArray: TokenListToken[] = useTokenList();
const normalizedAddress = address?.toLowerCase();
const tokenListIcon = tokenListArray.find(
(token: TokenListToken) => token.address === normalizedAddress,
)?.iconUrl;

if (!address) return null;

const uri = useBlockieIcon && toDataUrl(address);
const tokenListIconUrl = tokenList[address.toLowerCase()]?.iconUrl;

const styleForBlockieAndTokenIcon = [
{
Expand All @@ -60,10 +64,10 @@ const Identicon: React.FC<IdenticonProps> = ({
customStyle,
];

if (tokenListIconUrl) {
if (tokenListIcon) {
return (
<Image
source={{ uri: tokenListIconUrl }}
source={{ uri: tokenListIcon }}
style={styleForBlockieAndTokenIcon}
/>
);
Expand Down
30 changes: 16 additions & 14 deletions app/components/hooks/DisplayName/useTokenList.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React from 'react';
import { type TokenListMap } from '@metamask/assets-controllers';
import { type TokenListToken } from '@metamask/assets-controllers';
import { selectChainId } from '../../../selectors/networkController';
import { selectUseTokenDetection } from '../../../selectors/preferencesController';
import { selectTokenList } from '../../../selectors/tokenListController';
import { selectTokenListArray } from '../../../selectors/tokenListController';
import { isMainnetByChainId } from '../../../util/networks';

import useTokenList from './useTokenList';

const MAINNET_TOKEN_ADDRESS_MOCK = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
const MAINNET_TOKEN_NAME_MOCK = 'Tether USD';
const normalizedMainnetTokenListMock = {
[MAINNET_TOKEN_ADDRESS_MOCK.toLowerCase()]: {
const normalizedMainnetTokenListMock = [
{
name: MAINNET_TOKEN_NAME_MOCK,
},
};
];
jest.mock('@metamask/contract-metadata', () => ({
__esModule: true,
default: {
Expand All @@ -38,7 +38,7 @@ jest.mock('../../../selectors/preferencesController', () => ({
}));

jest.mock('../../../selectors/tokenListController', () => ({
selectTokenList: jest.fn(),
selectTokenListArray: jest.fn(),
}));

jest.mock('../../../util/networks', () => ({
Expand All @@ -48,27 +48,29 @@ jest.mock('../../../util/networks', () => ({
const CHAIN_ID_MOCK = '0x1';
const TOKEN_NAME_MOCK = 'MetaMask Token';
const TOKEN_ADDRESS_MOCK = '0x0439e60F02a8900a951603950d8D4527f400C3f1';
const TOKEN_LIST_MOCK = {
[TOKEN_ADDRESS_MOCK]: {
const TOKEN_LIST_ARRAY_MOCK = [
{
name: TOKEN_NAME_MOCK,
address: TOKEN_ADDRESS_MOCK,
},
} as unknown as TokenListMap;
const normalizedTokenListMock = {
[TOKEN_ADDRESS_MOCK.toLowerCase()]: {
] as unknown as TokenListToken[];
const normalizedTokenListMock = [
{
address: TOKEN_ADDRESS_MOCK,
name: TOKEN_NAME_MOCK,
},
};
];

describe('useTokenList', () => {
const selectChainIdMock = jest.mocked(selectChainId);
const selectUseTokenDetectionMock = jest.mocked(selectUseTokenDetection);
const selectTokenListMock = jest.mocked(selectTokenList);
const selectTokenListArrayMock = jest.mocked(selectTokenListArray);
const isMainnetByChainIdMock = jest.mocked(isMainnetByChainId);
beforeEach(() => {
jest.resetAllMocks();
selectChainIdMock.mockReturnValue(CHAIN_ID_MOCK);
selectUseTokenDetectionMock.mockReturnValue(true);
selectTokenListMock.mockReturnValue(TOKEN_LIST_MOCK);
selectTokenListArrayMock.mockReturnValue(TOKEN_LIST_ARRAY_MOCK);
isMainnetByChainIdMock.mockReturnValue(true);

const memoizedValues = new Map();
Expand Down
29 changes: 8 additions & 21 deletions app/components/hooks/DisplayName/useTokenList.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,25 @@
import { useMemo } from 'react';
import { type TokenListMap } from '@metamask/assets-controllers';
import contractMap from '@metamask/contract-metadata';

import { TokenListToken } from '@metamask/assets-controllers';
import { useSelector } from 'react-redux';
import { selectChainId } from '../../../selectors/networkController';
import { selectUseTokenDetection } from '../../../selectors/preferencesController';
import { selectTokenList } from '../../../selectors/tokenListController';
import { selectTokenListArray } from '../../../selectors/tokenListController';
import { isMainnetByChainId } from '../../../util/networks';

function normalizeTokenAddresses(tokenMap: TokenListMap) {
return Object.keys(tokenMap).reduce((acc, address) => {
const tokenMetadata = tokenMap[address];
return {
...acc,
[address.toLowerCase()]: {
...tokenMetadata,
},
};
}, {});
}

const NORMALIZED_MAINNET_TOKEN_LIST = normalizeTokenAddresses(contractMap);
const NORMALIZED_MAINNET_TOKEN_ARRAY = Object.values(contractMap);

export default function useTokenList(): TokenListMap {
export default function useTokenList(): TokenListToken[] {
const chainId = useSelector(selectChainId);
const isMainnet = isMainnetByChainId(chainId);
const isTokenDetectionEnabled = useSelector(selectUseTokenDetection);
const tokenList = useSelector(selectTokenList);
const tokenListArray = useSelector(selectTokenListArray);
const shouldUseStaticList = !isTokenDetectionEnabled && isMainnet;

return useMemo(() => {
if (shouldUseStaticList) {
return NORMALIZED_MAINNET_TOKEN_LIST;
return NORMALIZED_MAINNET_TOKEN_ARRAY;
}
return normalizeTokenAddresses(tokenList);
}, [shouldUseStaticList, tokenList]);
return tokenListArray;
}, [shouldUseStaticList, tokenListArray]);
}
9 changes: 5 additions & 4 deletions app/components/hooks/DisplayName/useTokenListEntry.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TokenListMap } from '@metamask/assets-controllers';
import { TokenListToken } from '@metamask/assets-controllers';
import { NameType } from '../../UI/Name/Name.types';
import { useTokenListEntry } from './useTokenListEntry';
import useTokenList from './useTokenList';
Expand All @@ -18,12 +18,13 @@ describe('useTokenListEntry', () => {
beforeEach(() => {
jest.resetAllMocks();

useTokenListMock.mockReturnValue({
[TOKEN_ADDRESS_MOCK.toLowerCase()]: {
useTokenListMock.mockReturnValue([
{
address: TOKEN_ADDRESS_MOCK.toLowerCase(),
name: TOKEN_NAME_MOCK,
symbol: TOKEN_SYMBOL_MOCK,
},
} as TokenListMap);
] as unknown as TokenListToken[]);
});

it('returns undefined if no token found', () => {
Expand Down
7 changes: 5 additions & 2 deletions app/components/hooks/DisplayName/useTokenListEntry.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { TokenListToken } from '@metamask/assets-controllers';
import { NameType } from '../../UI/Name/Name.types';
import useTokenList from './useTokenList';

Expand All @@ -7,7 +8,7 @@ export interface UseTokenListEntriesRequest {
}

export function useTokenListEntries(requests: UseTokenListEntriesRequest[]) {
const tokenList = useTokenList();
const tokenListArray = useTokenList();

return requests.map(({ value, type }) => {
if (type !== NameType.EthereumAddress) {
Expand All @@ -16,7 +17,9 @@ export function useTokenListEntries(requests: UseTokenListEntriesRequest[]) {

const normalizedValue = value.toLowerCase();

return tokenList[normalizedValue];
return tokenListArray.find(
(token: TokenListToken) => token.address === normalizedValue,
);
});
}

Expand Down
3 changes: 2 additions & 1 deletion app/selectors/tokenListController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { createSelector } from 'reselect';
import { TokenListState } from '@metamask/assets-controllers';
import { RootState } from '../reducers';
import { tokenListToArray } from '../util/tokens';
import { createDeepEqualSelector } from '../selectors/util';

const selectTokenLIstConstrollerState = (state: RootState) =>
state.engine.backgroundState.TokenListController;
Expand All @@ -20,7 +21,7 @@ export const selectTokenList = createSelector(
* Return token list array from TokenListController.
* Can pass directly into useSelector.
*/
export const selectTokenListArray = createSelector(
export const selectTokenListArray = createDeepEqualSelector(
selectTokenList,
tokenListToArray,
);

0 comments on commit 552e392

Please sign in to comment.