From b8fec4aa4584dc5bdb2d26356ab0f409e5da28c1 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 09:58:05 +0400 Subject: [PATCH 01/17] refactor: mv fetchErc20Decimals to utils/token --- .../simulation-details/useBalanceChanges.ts | 25 +++---------------- ui/pages/confirmations/constants/token.ts | 1 + ui/pages/confirmations/utils/token.ts | 22 ++++++++++++++++ 3 files changed, 26 insertions(+), 22 deletions(-) create mode 100644 ui/pages/confirmations/constants/token.ts create mode 100644 ui/pages/confirmations/utils/token.ts diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts index 6f2a033cc567..e53e5979a2b6 100644 --- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts +++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts @@ -9,11 +9,13 @@ import { import { BigNumber } from 'bignumber.js'; import { ContractExchangeRates } from '@metamask/assets-controllers'; import { useAsyncResultOrThrow } from '../../../../hooks/useAsyncResult'; -import { getTokenStandardAndDetails } from '../../../../store/actions'; import { TokenStandard } from '../../../../../shared/constants/transaction'; import { getConversionRate } from '../../../../ducks/metamask/metamask'; import { getCurrentChainId, getCurrentCurrency } from '../../../../selectors'; import { fetchTokenExchangeRates } from '../../../../helpers/utils/util'; +import { ERC20_DEFAULT_DECIMALS } from '../../constants/token'; +import { fetchErc20Decimals } from '../../utils/token'; + import { BalanceChange, FIAT_UNAVAILABLE, @@ -23,8 +25,6 @@ import { const NATIVE_DECIMALS = 18; -const ERC20_DEFAULT_DECIMALS = 18; - // See https://github.com/MikeMcl/bignumber.js/issues/11#issuecomment-23053776 function convertNumberToStringWithPrecisionWarning(value: number): string { return String(value); @@ -57,25 +57,6 @@ function getAssetAmount( ); } -// Fetches the decimals for the given token address. -async function fetchErc20Decimals(address: Hex): Promise { - try { - const { decimals: decStr } = await getTokenStandardAndDetails(address); - if (!decStr) { - return ERC20_DEFAULT_DECIMALS; - } - for (const radix of [10, 16]) { - const parsedDec = parseInt(decStr, radix); - if (isFinite(parsedDec)) { - return parsedDec; - } - } - return ERC20_DEFAULT_DECIMALS; - } catch { - return ERC20_DEFAULT_DECIMALS; - } -} - // Fetches token details for all the token addresses in the SimulationTokenBalanceChanges async function fetchAllErc20Decimals( addresses: Hex[], diff --git a/ui/pages/confirmations/constants/token.ts b/ui/pages/confirmations/constants/token.ts new file mode 100644 index 000000000000..bf9afbc0a6be --- /dev/null +++ b/ui/pages/confirmations/constants/token.ts @@ -0,0 +1 @@ +export const ERC20_DEFAULT_DECIMALS = 18; \ No newline at end of file diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts new file mode 100644 index 000000000000..1977d46ec6b6 --- /dev/null +++ b/ui/pages/confirmations/utils/token.ts @@ -0,0 +1,22 @@ +import { Hex } from '@metamask/utils'; +import { getTokenStandardAndDetails } from '../../../store/actions'; +import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; + +// Fetches the decimals for the given token address. +export async function fetchErc20Decimals(address: Hex): Promise { + try { + const { decimals: decStr } = await getTokenStandardAndDetails(address); + if (!decStr) { + return ERC20_DEFAULT_DECIMALS; + } + for (const radix of [10, 16]) { + const parsedDec = parseInt(decStr, radix); + if (isFinite(parsedDec)) { + return parsedDec; + } + } + return ERC20_DEFAULT_DECIMALS; + } catch { + return ERC20_DEFAULT_DECIMALS; + } +} \ No newline at end of file From d9913ab58b06404702f2929487fa172902fdcfe5 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:27:35 +0400 Subject: [PATCH 02/17] fix: lint needs EOL --- ui/pages/confirmations/constants/token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/constants/token.ts b/ui/pages/confirmations/constants/token.ts index bf9afbc0a6be..4520a77d3585 100644 --- a/ui/pages/confirmations/constants/token.ts +++ b/ui/pages/confirmations/constants/token.ts @@ -1 +1 @@ -export const ERC20_DEFAULT_DECIMALS = 18; \ No newline at end of file +export const ERC20_DEFAULT_DECIMALS = 18; From 171c4a1316c47334e7986a80e0a60b489bfcc84c Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 10:34:58 +0400 Subject: [PATCH 03/17] refactor: use fetchErc20Decimals in permit simulation and dataTree --- .../value-display/value-display.tsx | 14 ++++---------- .../components/confirm/row/dataTree.tsx | 14 ++++++-------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx index d0cd9c529d0e..d35373077676 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { NameType } from '@metamask/name-controller'; +import { Hex } from '@metamask/utils'; import { captureException } from '@sentry/browser'; -import { getTokenStandardAndDetails } from '../../../../../../../../store/actions'; import { shortenString } from '../../../../../../../../helpers/utils/util'; import { calcTokenAmount } from '../../../../../../../../../shared/lib/transactions-controller-utils'; @@ -27,23 +27,17 @@ import { TextAlign, } from '../../../../../../../../helpers/constants/design-system'; import Name from '../../../../../../../../components/app/name/name'; - -const getTokenDecimals = async (tokenContract: string) => { - const tokenDetails = await getTokenStandardAndDetails(tokenContract); - const tokenDecimals = tokenDetails?.decimals; - - return parseInt(tokenDecimals ?? '0', 10); -}; +import { fetchErc20Decimals } from '../../../../../../utils/token'; const PermitSimulationValueDisplay: React.FC<{ primaryType?: string; - tokenContract: string; + tokenContract: Hex; value: number | string; }> = ({ primaryType, tokenContract, value }) => { const exchangeRate = useTokenExchangeRate(tokenContract); const { value: tokenDecimals } = useAsyncResult( - async () => await getTokenDecimals(tokenContract), + async () => await fetchErc20Decimals(tokenContract), [tokenContract], ); diff --git a/ui/pages/confirmations/components/confirm/row/dataTree.tsx b/ui/pages/confirmations/components/confirm/row/dataTree.tsx index f728b9d5dfa9..aebd1c702aa6 100644 --- a/ui/pages/confirmations/components/confirm/row/dataTree.tsx +++ b/ui/pages/confirmations/components/confirm/row/dataTree.tsx @@ -1,3 +1,4 @@ +import { Hex } from '@metamask/utils'; import React, { memo } from 'react'; import { @@ -6,9 +7,8 @@ import { PRIMARY_TYPES_PERMIT, } from '../../../../../../shared/constants/signatures'; import { isValidHexAddress } from '../../../../../../shared/modules/hexstring-utils'; -import { sanitizeString } from '../../../../../helpers/utils/util'; -import { getTokenStandardAndDetails } from '../../../../../store/actions'; +import { sanitizeString } from '../../../../../helpers/utils/util'; import { Box } from '../../../../../components/component-library'; import { BlockSize } from '../../../../../helpers/constants/design-system'; import { useAsyncResult } from '../../../../../hooks/useAsyncResult'; @@ -19,6 +19,7 @@ import { ConfirmInfoRowText, ConfirmInfoRowTextTokenUnits, } from '../../../../../components/app/confirm/info/row'; +import { fetchErc20Decimals } from '../../../utils/token'; type ValueType = string | Record | TreeData[]; @@ -68,15 +69,12 @@ const getTokenDecimalsOfDataTree = async ( } const tokenContract = (dataTreeData as Record).token - ?.value as string; - if (!tokenContract) { + ?.value as Hex; + if (!tokenContract || !isValidHexAddress(tokenContract)) { return undefined; } - const tokenDetails = await getTokenStandardAndDetails(tokenContract); - const tokenDecimals = tokenDetails?.decimals; - - return parseInt(tokenDecimals ?? '0', 10); + return await fetchErc20Decimals(tokenContract); }; export const DataTree = ({ From eff052573a4409ba3065ce329e301e859fed443d Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:20:59 +0400 Subject: [PATCH 04/17] refactor: memoize fetchErc20Decimals --- ui/pages/confirmations/utils/token.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index 1977d46ec6b6..aa6b924e7576 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -1,9 +1,10 @@ +import { memoize } from 'lodash'; import { Hex } from '@metamask/utils'; import { getTokenStandardAndDetails } from '../../../store/actions'; import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; // Fetches the decimals for the given token address. -export async function fetchErc20Decimals(address: Hex): Promise { +export const fetchErc20Decimals = memoize(async (address: Hex): Promise => { try { const { decimals: decStr } = await getTokenStandardAndDetails(address); if (!decStr) { @@ -19,4 +20,4 @@ export async function fetchErc20Decimals(address: Hex): Promise { } catch { return ERC20_DEFAULT_DECIMALS; } -} \ No newline at end of file +}) \ No newline at end of file From a83c8af07187e3d97117975063f33a56356b7e09 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:22:07 +0400 Subject: [PATCH 05/17] fix: lint add EOF line --- ui/pages/confirmations/utils/token.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index aa6b924e7576..f0206439dfc3 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -20,4 +20,4 @@ export const fetchErc20Decimals = memoize(async (address: Hex): Promise } catch { return ERC20_DEFAULT_DECIMALS; } -}) \ No newline at end of file +}) From 557d8a429732b469c3bcc007ffb12878d35a8827 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:09:39 +0400 Subject: [PATCH 06/17] test: memoized fetchErc20Decimals util --- ui/pages/confirmations/utils/token.test.ts | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 ui/pages/confirmations/utils/token.test.ts diff --git a/ui/pages/confirmations/utils/token.test.ts b/ui/pages/confirmations/utils/token.test.ts new file mode 100644 index 000000000000..e24db97f424b --- /dev/null +++ b/ui/pages/confirmations/utils/token.test.ts @@ -0,0 +1,46 @@ +import { getTokenStandardAndDetails } from '../../../store/actions'; +import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; +import { fetchErc20Decimals } from './token'; + +const MOCK_ADDRESS = '0x514910771af9ca656af840dff83e8264ecf986ca'; +const MOCK_DECIMALS = 36; + +jest.mock('../../../store/actions', () => ({ + getTokenStandardAndDetails: jest.fn(), +})); + +describe('fetchErc20Decimals', () => { + afterEach(() => { + jest.clearAllMocks(); + + /** Reset memoized function for each test */ + fetchErc20Decimals?.cache?.clear?.(); + }); + + it(`should return the default number ${ERC20_DEFAULT_DECIMALS} is no decimals were found from details`, async () => { + (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({}); + const decimals = await fetchErc20Decimals(MOCK_ADDRESS); + + expect(decimals).toBe(ERC20_DEFAULT_DECIMALS); + }); + + it('should return the decimals for a given token address', async () => { + (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({decimals: MOCK_DECIMALS}); + const decimals = await fetchErc20Decimals(MOCK_ADDRESS); + + expect(decimals).toBe(MOCK_DECIMALS); + }); + + it('should memoize the result for the same token addresses', async () => { + (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({decimals: MOCK_DECIMALS}); + + const firstCallResult = await fetchErc20Decimals(MOCK_ADDRESS); + const secondCallResult = await fetchErc20Decimals(MOCK_ADDRESS); + + expect(firstCallResult).toBe(secondCallResult); + expect(getTokenStandardAndDetails).toHaveBeenCalledTimes(1); + + await fetchErc20Decimals('0xDifferentAddress'); + expect(getTokenStandardAndDetails).toHaveBeenCalledTimes(2); + }); +}); \ No newline at end of file From fb228becc236dc8ce1c87c3dc9112cb5e1e843ca Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:15:27 +0400 Subject: [PATCH 07/17] test:fix: fetchErc20Decimals test phrasing --- ui/pages/confirmations/utils/token.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/pages/confirmations/utils/token.test.ts b/ui/pages/confirmations/utils/token.test.ts index e24db97f424b..1c2f43c2d696 100644 --- a/ui/pages/confirmations/utils/token.test.ts +++ b/ui/pages/confirmations/utils/token.test.ts @@ -11,13 +11,13 @@ jest.mock('../../../store/actions', () => ({ describe('fetchErc20Decimals', () => { afterEach(() => { - jest.clearAllMocks(); + // jest.clearAllMocks(); /** Reset memoized function for each test */ - fetchErc20Decimals?.cache?.clear?.(); + // fetchErc20Decimals?.cache?.clear?.(); }); - it(`should return the default number ${ERC20_DEFAULT_DECIMALS} is no decimals were found from details`, async () => { + it(`should return the default number, ${ERC20_DEFAULT_DECIMALS}, if no decimals were found from details`, async () => { (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({}); const decimals = await fetchErc20Decimals(MOCK_ADDRESS); From 282a8a65a43ef01b8613b701653c5ff3f369e303 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:34:23 +0400 Subject: [PATCH 08/17] fix:test: uncomment needed afterEach code --- ui/pages/confirmations/utils/token.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/utils/token.test.ts b/ui/pages/confirmations/utils/token.test.ts index 1c2f43c2d696..4a5d2a7b39f4 100644 --- a/ui/pages/confirmations/utils/token.test.ts +++ b/ui/pages/confirmations/utils/token.test.ts @@ -11,10 +11,10 @@ jest.mock('../../../store/actions', () => ({ describe('fetchErc20Decimals', () => { afterEach(() => { - // jest.clearAllMocks(); + jest.clearAllMocks(); /** Reset memoized function for each test */ - // fetchErc20Decimals?.cache?.clear?.(); + fetchErc20Decimals?.cache?.clear?.(); }); it(`should return the default number, ${ERC20_DEFAULT_DECIMALS}, if no decimals were found from details`, async () => { From 6f9b3c3cc4e39626c04dfae046775710faa34d53 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:39:02 +0400 Subject: [PATCH 09/17] fix: yarn lint:fix --- ui/pages/confirmations/utils/token.test.ts | 10 +++++-- ui/pages/confirmations/utils/token.ts | 32 ++++++++++++---------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/ui/pages/confirmations/utils/token.test.ts b/ui/pages/confirmations/utils/token.test.ts index 4a5d2a7b39f4..e9dbb172cdb4 100644 --- a/ui/pages/confirmations/utils/token.test.ts +++ b/ui/pages/confirmations/utils/token.test.ts @@ -25,14 +25,18 @@ describe('fetchErc20Decimals', () => { }); it('should return the decimals for a given token address', async () => { - (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({decimals: MOCK_DECIMALS}); + (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({ + decimals: MOCK_DECIMALS, + }); const decimals = await fetchErc20Decimals(MOCK_ADDRESS); expect(decimals).toBe(MOCK_DECIMALS); }); it('should memoize the result for the same token addresses', async () => { - (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({decimals: MOCK_DECIMALS}); + (getTokenStandardAndDetails as jest.Mock).mockResolvedValue({ + decimals: MOCK_DECIMALS, + }); const firstCallResult = await fetchErc20Decimals(MOCK_ADDRESS); const secondCallResult = await fetchErc20Decimals(MOCK_ADDRESS); @@ -43,4 +47,4 @@ describe('fetchErc20Decimals', () => { await fetchErc20Decimals('0xDifferentAddress'); expect(getTokenStandardAndDetails).toHaveBeenCalledTimes(2); }); -}); \ No newline at end of file +}); diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index f0206439dfc3..b4ec4fc05e0b 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -4,20 +4,22 @@ import { getTokenStandardAndDetails } from '../../../store/actions'; import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; // Fetches the decimals for the given token address. -export const fetchErc20Decimals = memoize(async (address: Hex): Promise => { - try { - const { decimals: decStr } = await getTokenStandardAndDetails(address); - if (!decStr) { - return ERC20_DEFAULT_DECIMALS; - } - for (const radix of [10, 16]) { - const parsedDec = parseInt(decStr, radix); - if (isFinite(parsedDec)) { - return parsedDec; +export const fetchErc20Decimals = memoize( + async (address: Hex): Promise => { + try { + const { decimals: decStr } = await getTokenStandardAndDetails(address); + if (!decStr) { + return ERC20_DEFAULT_DECIMALS; + } + for (const radix of [10, 16]) { + const parsedDec = parseInt(decStr, radix); + if (isFinite(parsedDec)) { + return parsedDec; + } } + return ERC20_DEFAULT_DECIMALS; + } catch { + return ERC20_DEFAULT_DECIMALS; } - return ERC20_DEFAULT_DECIMALS; - } catch { - return ERC20_DEFAULT_DECIMALS; - } -}) + }, +); From 68fa1c574b61f8aa11883c71998f9c4c3d7c8b20 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:50:32 +0400 Subject: [PATCH 10/17] fix:test: useBalanceChanges memoized fetchErc20Decimals --- .../components/simulation-details/useBalanceChanges.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts index 64d9632c75a7..1849a9934d72 100644 --- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts +++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts @@ -9,6 +9,7 @@ import { TokenStandard } from '../../../../../shared/constants/transaction'; import { getConversionRate } from '../../../../ducks/metamask/metamask'; import { getTokenStandardAndDetails } from '../../../../store/actions'; import { fetchTokenExchangeRates } from '../../../../helpers/utils/util'; +import { fetchErc20Decimals } from '../../utils/token'; import { useBalanceChanges } from './useBalanceChanges'; import { FIAT_UNAVAILABLE } from './types'; @@ -87,6 +88,9 @@ describe('useBalanceChanges', () => { [ERC20_TOKEN_ADDRESS_1_MOCK]: ERC20_TO_FIAT_RATE_1_MOCK, [ERC20_TOKEN_ADDRESS_2_MOCK]: ERC20_TO_FIAT_RATE_2_MOCK, }); + + /** Reset memoized function for each test */ + fetchErc20Decimals?.cache?.clear?.(); }); describe('pending states', () => { From 7c4afafe0b9297ebbf52e893c21e27df13c5ef37 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 17:51:24 +0400 Subject: [PATCH 11/17] fix:test: mv useBalanceChanges memoized clear cache --- .../components/simulation-details/useBalanceChanges.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts index 1849a9934d72..10e4cca518b7 100644 --- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts +++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.test.ts @@ -88,7 +88,9 @@ describe('useBalanceChanges', () => { [ERC20_TOKEN_ADDRESS_1_MOCK]: ERC20_TO_FIAT_RATE_1_MOCK, [ERC20_TOKEN_ADDRESS_2_MOCK]: ERC20_TO_FIAT_RATE_2_MOCK, }); + }); + afterEach(() => { /** Reset memoized function for each test */ fetchErc20Decimals?.cache?.clear?.(); }); From 595975ef72e270ef2b36ba2651801fa131f02566 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:16:29 +0400 Subject: [PATCH 12/17] fix: allow string with hex token addresses - we currently have a patch with custom non-hex string --- .../value-display/value-display.tsx | 19 ++++++++++++++++--- ui/pages/confirmations/utils/token.ts | 9 +++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx index d35373077676..25fad3020103 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx @@ -29,11 +29,24 @@ import { import Name from '../../../../../../../../components/app/name/name'; import { fetchErc20Decimals } from '../../../../../../utils/token'; -const PermitSimulationValueDisplay: React.FC<{ +type PermitSimulationValueDisplayParams = { + /** The primaryType of the typed sign message */ primaryType?: string; - tokenContract: Hex; + + /** + * The ethereum token contract address. It is expected to be in hex format. + * We currently accept strings since we have a patch that accepts a custom string + * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} + */ + tokenContract: Hex | string; + + /** The token amount */ value: number | string; -}> = ({ primaryType, tokenContract, value }) => { +}; + +const PermitSimulationValueDisplay: React.FC< + PermitSimulationValueDisplayParams +> = ({ primaryType, tokenContract, value }) => { const exchangeRate = useTokenExchangeRate(tokenContract); const { value: tokenDecimals } = useAsyncResult( diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index b4ec4fc05e0b..c19a4d65c722 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -3,9 +3,14 @@ import { Hex } from '@metamask/utils'; import { getTokenStandardAndDetails } from '../../../store/actions'; import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; -// Fetches the decimals for the given token address. +/** + * Fetches the decimals for the given token address. + * @param {Hex | string} address - The ethereum token contract address. It is expected to be in hex format. + * We currently accept strings since we have a patch that accepts a custom string + * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} + */ export const fetchErc20Decimals = memoize( - async (address: Hex): Promise => { + async (address: Hex | string): Promise => { try { const { decimals: decStr } = await getTokenStandardAndDetails(address); if (!decStr) { From 6ab6f3b9eb646d47a2b5a8b29cae9af323454ccb Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:35:51 +0400 Subject: [PATCH 13/17] fix:test: memoize fetchErc20Decimals for confirm test --- ui/pages/confirmations/confirm/confirm.test.tsx | 4 ++++ ui/pages/confirmations/utils/token.test.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/pages/confirmations/confirm/confirm.test.tsx b/ui/pages/confirmations/confirm/confirm.test.tsx index 0b10976ab48c..dbf4dab7dfaf 100644 --- a/ui/pages/confirmations/confirm/confirm.test.tsx +++ b/ui/pages/confirmations/confirm/confirm.test.tsx @@ -18,6 +18,7 @@ import { import { renderWithConfirmContextProvider } from '../../../../test/lib/confirmations/render-helpers'; import * as actions from '../../../store/actions'; import { SignatureRequestType } from '../types/confirm'; +import { fetchErc20Decimals } from '../utils/token'; import Confirm from './confirm'; jest.mock('react-router-dom', () => ({ @@ -32,6 +33,9 @@ const middleware = [thunk]; describe('Confirm', () => { afterEach(() => { jest.resetAllMocks(); + + /** Reset memoized function using getTokenStandardAndDetails for each test */ + fetchErc20Decimals?.cache?.clear?.(); }); it('should render', () => { diff --git a/ui/pages/confirmations/utils/token.test.ts b/ui/pages/confirmations/utils/token.test.ts index e9dbb172cdb4..e71813713d79 100644 --- a/ui/pages/confirmations/utils/token.test.ts +++ b/ui/pages/confirmations/utils/token.test.ts @@ -13,7 +13,7 @@ describe('fetchErc20Decimals', () => { afterEach(() => { jest.clearAllMocks(); - /** Reset memoized function for each test */ + /** Reset memoized function using getTokenStandardAndDetails for each test */ fetchErc20Decimals?.cache?.clear?.(); }); From 09a9fee1e6471cbf0634125325d8f44d24adffd9 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:57:53 +0400 Subject: [PATCH 14/17] fix: lint utils/token comment --- ui/pages/confirmations/utils/token.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index c19a4d65c722..fe7e7d77f154 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -5,9 +5,10 @@ import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; /** * Fetches the decimals for the given token address. + * * @param {Hex | string} address - The ethereum token contract address. It is expected to be in hex format. - * We currently accept strings since we have a patch that accepts a custom string - * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} + * We currently accept strings since we have a patch that accepts a custom string + * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} */ export const fetchErc20Decimals = memoize( async (address: Hex | string): Promise => { From 913a79a912a3820d8bd886f1c6471ab04c53a064 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:56:56 +0800 Subject: [PATCH 15/17] refactor: rm new utils/token.ts --- .../components/simulation-details/useBalanceChanges.ts | 3 +-- ui/pages/confirmations/utils/token.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts index e53e5979a2b6..2a198d76ea36 100644 --- a/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts +++ b/ui/pages/confirmations/components/simulation-details/useBalanceChanges.ts @@ -13,8 +13,7 @@ import { TokenStandard } from '../../../../../shared/constants/transaction'; import { getConversionRate } from '../../../../ducks/metamask/metamask'; import { getCurrentChainId, getCurrentCurrency } from '../../../../selectors'; import { fetchTokenExchangeRates } from '../../../../helpers/utils/util'; -import { ERC20_DEFAULT_DECIMALS } from '../../constants/token'; -import { fetchErc20Decimals } from '../../utils/token'; +import { ERC20_DEFAULT_DECIMALS, fetchErc20Decimals } from '../../utils/token'; import { BalanceChange, diff --git a/ui/pages/confirmations/utils/token.ts b/ui/pages/confirmations/utils/token.ts index fe7e7d77f154..1f94280129a9 100644 --- a/ui/pages/confirmations/utils/token.ts +++ b/ui/pages/confirmations/utils/token.ts @@ -1,7 +1,8 @@ import { memoize } from 'lodash'; import { Hex } from '@metamask/utils'; import { getTokenStandardAndDetails } from '../../../store/actions'; -import { ERC20_DEFAULT_DECIMALS } from '../constants/token'; + +export const ERC20_DEFAULT_DECIMALS = 18; /** * Fetches the decimals for the given token address. From 4f8e366109ffb41c4ba5e547c0555d91882d572d Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:01:28 +0800 Subject: [PATCH 16/17] fix: cherry-pick PermitSimulationValueDisplay code --- .../value-display/value-display.tsx | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx index 25fad3020103..d0cd9c529d0e 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { NameType } from '@metamask/name-controller'; -import { Hex } from '@metamask/utils'; import { captureException } from '@sentry/browser'; +import { getTokenStandardAndDetails } from '../../../../../../../../store/actions'; import { shortenString } from '../../../../../../../../helpers/utils/util'; import { calcTokenAmount } from '../../../../../../../../../shared/lib/transactions-controller-utils'; @@ -27,30 +27,23 @@ import { TextAlign, } from '../../../../../../../../helpers/constants/design-system'; import Name from '../../../../../../../../components/app/name/name'; -import { fetchErc20Decimals } from '../../../../../../utils/token'; -type PermitSimulationValueDisplayParams = { - /** The primaryType of the typed sign message */ - primaryType?: string; - - /** - * The ethereum token contract address. It is expected to be in hex format. - * We currently accept strings since we have a patch that accepts a custom string - * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} - */ - tokenContract: Hex | string; +const getTokenDecimals = async (tokenContract: string) => { + const tokenDetails = await getTokenStandardAndDetails(tokenContract); + const tokenDecimals = tokenDetails?.decimals; - /** The token amount */ - value: number | string; + return parseInt(tokenDecimals ?? '0', 10); }; -const PermitSimulationValueDisplay: React.FC< - PermitSimulationValueDisplayParams -> = ({ primaryType, tokenContract, value }) => { +const PermitSimulationValueDisplay: React.FC<{ + primaryType?: string; + tokenContract: string; + value: number | string; +}> = ({ primaryType, tokenContract, value }) => { const exchangeRate = useTokenExchangeRate(tokenContract); const { value: tokenDecimals } = useAsyncResult( - async () => await fetchErc20Decimals(tokenContract), + async () => await getTokenDecimals(tokenContract), [tokenContract], ); From 99cfb205696b218c5c984f5930d44fe97ae24424 Mon Sep 17 00:00:00 2001 From: digiwand <20778143+digiwand@users.noreply.github.com> Date: Wed, 18 Sep 2024 18:26:22 +0800 Subject: [PATCH 17/17] Revert "fix: cherry-pick PermitSimulationValueDisplay code" This reverts commit 4f8e366109ffb41c4ba5e547c0555d91882d572d. --- .../value-display/value-display.tsx | 29 ++++++++++++------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx index d0cd9c529d0e..25fad3020103 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/value-display/value-display.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import { NameType } from '@metamask/name-controller'; +import { Hex } from '@metamask/utils'; import { captureException } from '@sentry/browser'; -import { getTokenStandardAndDetails } from '../../../../../../../../store/actions'; import { shortenString } from '../../../../../../../../helpers/utils/util'; import { calcTokenAmount } from '../../../../../../../../../shared/lib/transactions-controller-utils'; @@ -27,23 +27,30 @@ import { TextAlign, } from '../../../../../../../../helpers/constants/design-system'; import Name from '../../../../../../../../components/app/name/name'; +import { fetchErc20Decimals } from '../../../../../../utils/token'; -const getTokenDecimals = async (tokenContract: string) => { - const tokenDetails = await getTokenStandardAndDetails(tokenContract); - const tokenDecimals = tokenDetails?.decimals; +type PermitSimulationValueDisplayParams = { + /** The primaryType of the typed sign message */ + primaryType?: string; - return parseInt(tokenDecimals ?? '0', 10); -}; + /** + * The ethereum token contract address. It is expected to be in hex format. + * We currently accept strings since we have a patch that accepts a custom string + * {@see .yarn/patches/@metamask-eth-json-rpc-middleware-npm-14.0.1-b6c2ccbe8c.patch} + */ + tokenContract: Hex | string; -const PermitSimulationValueDisplay: React.FC<{ - primaryType?: string; - tokenContract: string; + /** The token amount */ value: number | string; -}> = ({ primaryType, tokenContract, value }) => { +}; + +const PermitSimulationValueDisplay: React.FC< + PermitSimulationValueDisplayParams +> = ({ primaryType, tokenContract, value }) => { const exchangeRate = useTokenExchangeRate(tokenContract); const { value: tokenDecimals } = useAsyncResult( - async () => await getTokenDecimals(tokenContract), + async () => await fetchErc20Decimals(tokenContract), [tokenContract], );