From eb97907fe5e02ce1ed9194cbbfe3941072832740 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 19 Dec 2024 00:57:31 +0000 Subject: [PATCH 1/8] Skip decode if toggle disabled Add useTokenTransactionData hook. Remove all core usages of decode data. --- test/data/confirmations/token-approve.ts | 4 +- .../info/__snapshots__/info.test.tsx.snap | 304 +++++++++++++++- .../approve-details.test.tsx.snap | 336 +++++++++++++----- .../approve-details/approve-details.test.tsx | 22 +- .../approve-details/approve-details.tsx | 18 +- .../use-approve-token-simulation.test.ts | 173 ++------- .../hooks/use-approve-token-simulation.ts | 34 +- .../info/hooks/use-token-values.test.ts | 98 ++--- .../confirm/info/hooks/use-token-values.ts | 70 +--- .../info/hooks/useDecodedTransactionData.ts | 12 +- .../info/hooks/useTokenTransactionData.ts | 14 + .../native-transfer.test.tsx.snap | 94 +++++ .../nft-token-transfer.test.tsx.snap | 94 +++++ .../set-approval-for-all-info.test.tsx.snap | 100 +++++- .../set-approval-for-all-info.test.tsx | 5 - .../set-approval-for-all-info.tsx | 17 +- .../__snapshots__/send-heading.test.tsx.snap | 58 ++- .../shared/send-heading/send-heading.test.tsx | 6 + .../info/shared/send-heading/send-heading.tsx | 6 - .../token-transfer.test.tsx.snap | 158 +++++--- .../token-transfer/token-transfer.test.tsx | 8 +- .../transaction-flow-section.test.tsx | 45 +-- .../transaction-flow-section.tsx | 15 +- .../components/confirm/info/utils.test.ts | 33 +- .../components/confirm/info/utils.ts | 12 +- .../components/confirm/title/title.tsx | 27 +- 26 files changed, 1147 insertions(+), 616 deletions(-) create mode 100644 ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.ts diff --git a/test/data/confirmations/token-approve.ts b/test/data/confirmations/token-approve.ts index c77d59101a99..f10a2c9c92d3 100644 --- a/test/data/confirmations/token-approve.ts +++ b/test/data/confirmations/token-approve.ts @@ -9,14 +9,16 @@ import { export const genUnapprovedApproveConfirmation = ({ address = CONTRACT_INTERACTION_SENDER_ADDRESS, chainId = CHAIN_ID, + amountHex = '0000000000000000000000000000000000000000000000000000000000000001', }: { address?: Hex; chainId?: string; + amountHex?: string; } = {}) => ({ ...genUnapprovedContractInteractionConfirmation({ chainId }), txParams: { from: address, - data: '0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', + data: `0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b${amountHex}`, gas: '0x16a92', to: '0x076146c765189d51be3160a2140cf80bfc73ad68', value: '0x0', diff --git a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap index 2ff281c5186e..480ef57d7097 100644 --- a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap @@ -2,10 +2,208 @@ exports[`Info renders info section for approve request 1`] = `
+
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+
+

+ You're giving someone else permission to withdraw NFTs from your account. +

+
+
+
+
+
+

+ Withdraw +

+
+
+
+
+
+

+ #1 +

+
+
+
+ +

+ 0x07614...3ad68 +

+
+
+
+
+
+
+
+
+
+

+ Spender +

+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+
+
+
+

+ Permission for +

+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
renders component for approve details 1`] = ` data-testid="confirmation__approve-details" >
-
-

+

+
- Data -

+ +
+
+
- - - - - - + + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+
+
+
+

+ Request from +

+
+
- - - +
+
+
+

+ metamask.github.io +

+
@@ -83,70 +157,144 @@ exports[` renders component for approve details for setApprova data-testid="confirmation__approve-details" >
-
-

+

+
- Data -

+ +
+
+
- - - - - - + + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+
+
+
+

+ Request from +

+
+
- - - +
+
+
+

+ metamask.github.io +

+
diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx index daec14c166af..df6147914304 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.test.tsx @@ -1,15 +1,29 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import mockState from '../../../../../../../../test/data/mock-state.json'; import { renderWithConfirmContextProvider } from '../../../../../../../../test/lib/confirmations/render-helpers'; +import { genUnapprovedApproveConfirmation } from '../../../../../../../../test/data/confirmations/token-approve'; +import { getMockConfirmStateForTransaction } from '../../../../../../../../test/data/confirmations/helper'; import { ApproveDetails } from './approve-details'; +jest.mock( + '../../../../../../../components/app/alert-system/contexts/alertMetricsContext.tsx', + () => ({ + useAlertMetrics: () => ({ + trackInlineAlertClicked: jest.fn(), + trackAlertRender: jest.fn(), + trackAlertActionClicked: jest.fn(), + }), + }), +); + describe('', () => { const middleware = [thunk]; it('renders component for approve details', () => { - const state = mockState; + const state = getMockConfirmStateForTransaction( + genUnapprovedApproveConfirmation(), + ); const mockStore = configureMockStore(middleware)(state); const { container } = renderWithConfirmContextProvider( , @@ -19,7 +33,9 @@ describe('', () => { }); it('renders component for approve details for setApprovalForAll', () => { - const state = mockState; + const state = getMockConfirmStateForTransaction( + genUnapprovedApproveConfirmation(), + ); const mockStore = configureMockStore(middleware)(state); const { container } = renderWithConfirmContextProvider( , diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx index e46b581220a4..ed56623feb31 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx @@ -11,8 +11,6 @@ import { useI18nContext } from '../../../../../../../hooks/useI18nContext'; import { useConfirmContext } from '../../../../../context/confirm'; import { selectConfirmationAdvancedDetailsOpen } from '../../../../../selectors/preferences'; import { SigningInWithRow } from '../../shared/sign-in-with-row/sign-in-with-row'; -import { useDecodedTransactionData } from '../../hooks/useDecodedTransactionData'; -import { Container } from '../../shared/transaction-data/transaction-data'; import { MethodDataRow, OriginRow, @@ -20,6 +18,7 @@ import { } from '../../shared/transaction-details/transaction-details'; import { getIsRevokeSetApprovalForAll } from '../../utils'; import { useIsNFT } from '../hooks/use-is-nft'; +import { useTokenTransactionData } from '../../hooks/useTokenTransactionData'; const Spender = ({ isSetApprovalForAll = false, @@ -32,23 +31,16 @@ const Spender = ({ useConfirmContext(); const { isNFT } = useIsNFT(transactionMeta); + const parsedTransactionData = useTokenTransactionData(); - const decodedResponse = useDecodedTransactionData(); - - const { value, pending } = decodedResponse; - - if (pending) { - return ; - } - - if (!value) { + if (!parsedTransactionData) { return null; } - const spender = value.data[0].params[0].value; + const spender = parsedTransactionData.args?._spender; const { chainId } = transactionMeta; - if (getIsRevokeSetApprovalForAll(value)) { + if (getIsRevokeSetApprovalForAll(parsedTransactionData)) { return null; } diff --git a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.test.ts b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.test.ts index e0a5a8165dfb..26ca44587ce4 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.test.ts +++ b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.test.ts @@ -1,11 +1,7 @@ import { TransactionMeta } from '@metamask/transaction-controller'; -import { - CONTRACT_INTERACTION_SENDER_ADDRESS, - genUnapprovedContractInteractionConfirmation, -} from '../../../../../../../../test/data/confirmations/contract-interaction'; -import mockState from '../../../../../../../../test/data/mock-state.json'; -import { renderHookWithProvider } from '../../../../../../../../test/lib/render-helpers'; -import { useDecodedTransactionData } from '../../hooks/useDecodedTransactionData'; +import { renderHookWithConfirmContextProvider } from '../../../../../../../../test/lib/confirmations/render-helpers'; +import { genUnapprovedApproveConfirmation } from '../../../../../../../../test/data/confirmations/token-approve'; +import { getMockConfirmStateForTransaction } from '../../../../../../../../test/data/confirmations/helper'; import { useApproveTokenSimulation } from './use-approve-token-simulation'; import { useIsNFT } from './use-is-nft'; @@ -14,11 +10,6 @@ jest.mock('./use-is-nft', () => ({ useIsNFT: jest.fn(), })); -jest.mock('../../hooks/useDecodedTransactionData', () => ({ - ...jest.requireActual('../../hooks/useDecodedTransactionData'), - useDecodedTransactionData: jest.fn(), -})); - describe('useApproveTokenSimulation', () => { beforeEach(() => { jest.resetAllMocks(); @@ -27,40 +18,16 @@ describe('useApproveTokenSimulation', () => { it('returns the token id for NFT', async () => { const useIsNFTMock = jest.fn().mockImplementation(() => ({ isNFT: true })); - const useDecodedTransactionDataMock = jest.fn().mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: 'approve', - params: [ - { - type: 'address', - value: '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', - }, - { - type: 'uint256', - value: 70000, - }, - ], - }, - ], - source: 'FourByte', - }, - })); - (useIsNFT as jest.Mock).mockImplementation(useIsNFTMock); - (useDecodedTransactionData as jest.Mock).mockImplementation( - useDecodedTransactionDataMock, - ); - const transactionMeta = genUnapprovedContractInteractionConfirmation({ - address: CONTRACT_INTERACTION_SENDER_ADDRESS, + const transactionMeta = genUnapprovedApproveConfirmation({ + amountHex: + '0000000000000000000000000000000000000000000000000000000000011170', }) as TransactionMeta; - const { result } = renderHookWithProvider( + const { result } = renderHookWithConfirmContextProvider( () => useApproveTokenSimulation(transactionMeta, '4'), - mockState, + getMockConfirmStateForTransaction(transactionMeta), ); expect(result.current).toMatchInlineSnapshot(` @@ -70,22 +37,8 @@ describe('useApproveTokenSimulation', () => { "pending": undefined, "spendingCap": "#7", "value": { - "data": [ - { - "name": "approve", - "params": [ - { - "type": "address", - "value": "0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4", - }, - { - "type": "uint256", - "value": 70000, - }, - ], - }, - ], - "source": "FourByte", + "hex": "0x011170", + "type": "BigNumber", }, } `); @@ -94,40 +47,16 @@ describe('useApproveTokenSimulation', () => { it('returns "UNLIMITED MESSAGE" token amount for fungible tokens approvals equal or over the total number of tokens in circulation', async () => { const useIsNFTMock = jest.fn().mockImplementation(() => ({ isNFT: false })); - const useDecodedTransactionDataMock = jest.fn().mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: 'approve', - params: [ - { - type: 'address', - value: '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', - }, - { - type: 'uint256', - value: 10 ** 15, - }, - ], - }, - ], - source: 'FourByte', - }, - })); - (useIsNFT as jest.Mock).mockImplementation(useIsNFTMock); - (useDecodedTransactionData as jest.Mock).mockImplementation( - useDecodedTransactionDataMock, - ); - const transactionMeta = genUnapprovedContractInteractionConfirmation({ - address: CONTRACT_INTERACTION_SENDER_ADDRESS, + const transactionMeta = genUnapprovedApproveConfirmation({ + amountHex: + '00000000000000000000000000000000000000000000000000038D7EA4C68000', }) as TransactionMeta; - const { result } = renderHookWithProvider( + const { result } = renderHookWithConfirmContextProvider( () => useApproveTokenSimulation(transactionMeta, '0'), - mockState, + getMockConfirmStateForTransaction(transactionMeta), ); expect(result.current).toMatchInlineSnapshot(` @@ -137,22 +66,8 @@ describe('useApproveTokenSimulation', () => { "pending": undefined, "spendingCap": "1000000000000000", "value": { - "data": [ - { - "name": "approve", - "params": [ - { - "type": "address", - "value": "0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4", - }, - { - "type": "uint256", - "value": 1000000000000000, - }, - ], - }, - ], - "source": "FourByte", + "hex": "0x038d7ea4c68000", + "type": "BigNumber", }, } `); @@ -161,40 +76,14 @@ describe('useApproveTokenSimulation', () => { it('returns correct small decimal number token amount for fungible tokens', async () => { const useIsNFTMock = jest.fn().mockImplementation(() => ({ isNFT: false })); - const useDecodedTransactionDataMock = jest.fn().mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: 'approve', - params: [ - { - type: 'address', - value: '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', - }, - { - type: 'uint256', - value: 10 ** 5, - }, - ], - }, - ], - source: 'FourByte', - }, - })); - (useIsNFT as jest.Mock).mockImplementation(useIsNFTMock); - (useDecodedTransactionData as jest.Mock).mockImplementation( - useDecodedTransactionDataMock, - ); - const transactionMeta = genUnapprovedContractInteractionConfirmation({ - address: CONTRACT_INTERACTION_SENDER_ADDRESS, - }) as TransactionMeta; + const transactionMeta = + genUnapprovedApproveConfirmation() as TransactionMeta; - const { result } = renderHookWithProvider( + const { result } = renderHookWithConfirmContextProvider( () => useApproveTokenSimulation(transactionMeta, '18'), - mockState, + getMockConfirmStateForTransaction(transactionMeta), ); expect(result.current).toMatchInlineSnapshot(` @@ -202,24 +91,10 @@ describe('useApproveTokenSimulation', () => { "formattedSpendingCap": "<0.000001", "isUnlimitedSpendingCap": false, "pending": undefined, - "spendingCap": "0.0000000000001", + "spendingCap": "0.000000000000000001", "value": { - "data": [ - { - "name": "approve", - "params": [ - { - "type": "address", - "value": "0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4", - }, - { - "type": "uint256", - "value": 100000, - }, - ], - }, - ], - "source": "FourByte", + "hex": "0x01", + "type": "BigNumber", }, } `); diff --git a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts index acd470ba8822..ca884c04b1f4 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts +++ b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts @@ -1,13 +1,11 @@ import { TransactionMeta } from '@metamask/transaction-controller'; -import { isHexString } from '@metamask/utils'; import { BigNumber } from 'bignumber.js'; -import { isBoolean } from 'lodash'; import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { calcTokenAmount } from '../../../../../../../../shared/lib/transactions-controller-utils'; import { getIntlLocale } from '../../../../../../../ducks/locale/locale'; import { formatAmount } from '../../../../simulation-details/formatAmount'; -import { useDecodedTransactionData } from '../../hooks/useDecodedTransactionData'; +import { useTokenTransactionData } from '../../hooks/useTokenTransactionData'; import { useIsNFT } from './use-is-nft'; const UNLIMITED_THRESHOLD = 10 ** 15; @@ -22,31 +20,13 @@ export const useApproveTokenSimulation = ( ) => { const locale = useSelector(getIntlLocale); const { isNFT, pending: isNFTPending } = useIsNFT(transactionMeta); - const decodedResponse = useDecodedTransactionData(); - const { value, pending } = decodedResponse; + const parsedTransactionData = useTokenTransactionData(); - const decodedSpendingCap = useMemo(() => { - if (!value) { - return '0'; - } - - const paramIndex = value.data[0].params.findIndex( - (param) => - param.value !== undefined && - !isHexString(param.value) && - param.value.length === undefined && - !isBoolean(param.value), - ); - if (paramIndex === -1) { - return '0'; - } - - return calcTokenAmount( - value.data[0].params[paramIndex].value, - Number(decimals), - ).toFixed(); - }, [value, decimals]); + const value = + (parsedTransactionData?.args?._value as BigNumber | undefined) ?? + new BigNumber(0); + const decodedSpendingCap = calcTokenAmount(value, Number(decimals)).toFixed(); const tokenPrefix = isNFT ? '#' : ''; const formattedSpendingCap = useMemo(() => { @@ -70,6 +50,6 @@ export const useApproveTokenSimulation = ( spendingCap, formattedSpendingCap, value, - pending: pending || isNFTPending, + pending: isNFTPending, }; }; diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts index f7f9dd25d4b8..0198b2fc27cb 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts @@ -1,31 +1,23 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import { Numeric } from '../../../../../../../shared/modules/Numeric'; -import { genUnapprovedTokenTransferConfirmation } from '../../../../../../../test/data/confirmations/token-transfer'; -import mockState from '../../../../../../../test/data/mock-state.json'; import { renderHookWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; import useTokenExchangeRate from '../../../../../../components/app/currency-input/hooks/useTokenExchangeRate'; import { useAssetDetails } from '../../../../hooks/useAssetDetails'; +import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; +import { genUnapprovedApproveConfirmation } from '../../../../../../../test/data/confirmations/token-approve'; import { useTokenValues } from './use-token-values'; -import { useDecodedTransactionData } from './useDecodedTransactionData'; jest.mock('../../../../hooks/useAssetDetails', () => ({ ...jest.requireActual('../../../../hooks/useAssetDetails'), useAssetDetails: jest.fn(), })); -jest.mock('./useDecodedTransactionData', () => ({ - ...jest.requireActual('./useDecodedTransactionData'), - useDecodedTransactionData: jest.fn(), -})); - jest.mock( '../../../../../../components/app/currency-input/hooks/useTokenExchangeRate', - () => jest.fn(), ); describe('useTokenValues', () => { const useAssetDetailsMock = jest.mocked(useAssetDetails); - const useDecodedTransactionDataMock = jest.mocked(useDecodedTransactionData); const useTokenExchangeRateMock = jest.mocked(useTokenExchangeRate); beforeEach(() => { @@ -34,97 +26,51 @@ describe('useTokenValues', () => { it('returns native and fiat balances', async () => { (useAssetDetailsMock as jest.Mock).mockImplementation(() => ({ - decimals: '10', - })); - (useDecodedTransactionDataMock as jest.Mock).mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: 'transfer', - params: [ - { - type: 'address', - value: '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', - }, - { - type: 'uint256', - value: 70000000000, - }, - ], - }, - ], - source: 'FourByte', - }, + decimals: '4', })); - (useTokenExchangeRateMock as jest.Mock).mockResolvedValue( - new Numeric(0.91, 10), - ); - const transactionMeta = genUnapprovedTokenTransferConfirmation( - {}, - ) as TransactionMeta; + useTokenExchangeRateMock.mockReturnValue(new Numeric(0.91, 10)); + + const transactionMeta = genUnapprovedApproveConfirmation({ + amountHex: + '0000000000000000000000000000000000000000000000000000000000011170', + }) as TransactionMeta; - const { result, waitForNextUpdate } = renderHookWithConfirmContextProvider( + const { result } = renderHookWithConfirmContextProvider( () => useTokenValues(transactionMeta), - mockState, + getMockConfirmStateForTransaction(transactionMeta), ); - await waitForNextUpdate(); - expect(result.current).toEqual({ decodedTransferValue: '7', displayTransferValue: '7', fiatDisplayValue: '$6.37', fiatValue: 6.37, - pending: false, }); }); it('returns undefined fiat balance if no token rate is returned', async () => { (useAssetDetailsMock as jest.Mock).mockImplementation(() => ({ - decimals: '10', - })); - (useDecodedTransactionDataMock as jest.Mock).mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: 'transfer', - params: [ - { - type: 'address', - value: '0x9bc5baF874d2DA8D216aE9f137804184EE5AfEF4', - }, - { - type: 'uint256', - value: 70000000000, - }, - ], - }, - ], - source: 'FourByte', - }, + decimals: '4', })); - (useTokenExchangeRateMock as jest.Mock).mockResolvedValue(null); - const transactionMeta = genUnapprovedTokenTransferConfirmation( - {}, - ) as TransactionMeta; + useTokenExchangeRateMock.mockReturnValue(undefined); - const { result, waitForNextUpdate } = renderHookWithConfirmContextProvider( + const transactionMeta = genUnapprovedApproveConfirmation({ + amountHex: + '0000000000000000000000000000000000000000000000000000000000011170', + }) as TransactionMeta; + + const { result } = renderHookWithConfirmContextProvider( () => useTokenValues(transactionMeta), - mockState, + getMockConfirmStateForTransaction(transactionMeta), ); - await waitForNextUpdate(); - expect(result.current).toEqual({ decodedTransferValue: '7', displayTransferValue: '7', - fiatDisplayValue: null, - fiatValue: null, - pending: false, + fiatDisplayValue: undefined, + fiatValue: undefined, }); }); }); diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts index b53e2842e5e7..c9a61c87b4f3 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts @@ -1,19 +1,20 @@ import { TransactionMeta } from '@metamask/transaction-controller'; -import { isHexString } from '@metamask/utils'; import { BigNumber } from 'bignumber.js'; -import { isBoolean } from 'lodash'; -import { useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; import { calcTokenAmount } from '../../../../../../../shared/lib/transactions-controller-utils'; -import { Numeric } from '../../../../../../../shared/modules/Numeric'; import useTokenExchangeRate from '../../../../../../components/app/currency-input/hooks/useTokenExchangeRate'; import { getIntlLocale } from '../../../../../../ducks/locale/locale'; import { useFiatFormatter } from '../../../../../../hooks/useFiatFormatter'; import { useAssetDetails } from '../../../../hooks/useAssetDetails'; import { formatAmount } from '../../../simulation-details/formatAmount'; -import { useDecodedTransactionData } from './useDecodedTransactionData'; +import { useTokenTransactionData } from './useTokenTransactionData'; export const useTokenValues = (transactionMeta: TransactionMeta) => { + const locale = useSelector(getIntlLocale); + const parsedTransactionData = useTokenTransactionData(); + const exchangeRate = useTokenExchangeRate(transactionMeta?.txParams?.to); + const fiatFormatter = useFiatFormatter(); + const { decimals } = useAssetDetails( transactionMeta.txParams.to, transactionMeta.txParams.from, @@ -21,65 +22,23 @@ export const useTokenValues = (transactionMeta: TransactionMeta) => { transactionMeta.chainId, ); - const decodedResponse = useDecodedTransactionData(); - const { value, pending } = decodedResponse; - - const { decodedTransferValue, isDecodedTransferValuePending } = - useMemo(() => { - if (!value) { - return { - decodedTransferValue: '0', - isDecodedTransferValuePending: false, - }; - } - - if (!decimals) { - return { - decodedTransferValue: '0', - isDecodedTransferValuePending: true, - }; - } - - const paramIndex = value.data[0].params.findIndex( - (param) => - param.value !== undefined && - !isHexString(param.value) && - param.value.length === undefined && - !isBoolean(param.value), - ); - if (paramIndex === -1) { - return { - decodedTransferValue: '0', - isDecodedTransferValuePending: false, - }; - } + const value = + (parsedTransactionData?.args?._value as BigNumber | undefined) ?? + new BigNumber(0); - return { - decodedTransferValue: calcTokenAmount( - value.data[0].params[paramIndex].value, - decimals, - ).toFixed(), - isDecodedTransferValuePending: false, - }; - }, [value, decimals]); - - const [exchangeRate, setExchangeRate] = useState(); - const fetchExchangeRate = async () => { - const result = await useTokenExchangeRate(transactionMeta?.txParams?.to); - - setExchangeRate(result); - }; - fetchExchangeRate(); + const decodedTransferValue = calcTokenAmount( + value, + Number(decimals), + ).toFixed(); const fiatValue = exchangeRate && decodedTransferValue && exchangeRate.times(decodedTransferValue, 10).toNumber(); - const fiatFormatter = useFiatFormatter(); + const fiatDisplayValue = fiatValue && fiatFormatter(fiatValue, { shorten: true }); - const locale = useSelector(getIntlLocale); const displayTransferValue = formatAmount( locale, new BigNumber(decodedTransferValue), @@ -90,6 +49,5 @@ export const useTokenValues = (transactionMeta: TransactionMeta) => { displayTransferValue, fiatDisplayValue, fiatValue, - pending: pending || isDecodedTransferValuePending, }; }; diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.ts b/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.ts index 5276e02eaad1..3486f16ed864 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.ts @@ -1,6 +1,7 @@ import { Hex } from '@metamask/utils'; import { TransactionMeta } from '@metamask/transaction-controller'; +import { useSelector } from 'react-redux'; import { AsyncResult, useAsyncResult, @@ -9,11 +10,13 @@ import { decodeTransactionData } from '../../../../../../store/actions'; import { DecodedTransactionDataResponse } from '../../../../../../../shared/types/transaction-decode'; import { useConfirmContext } from '../../../../context/confirm'; import { hasTransactionData } from '../../../../../../../shared/modules/transaction.utils'; +import { use4ByteResolutionSelector } from '../../../../../../selectors'; export function useDecodedTransactionData( transactionTypeFilter?: string, ): AsyncResult { const { currentConfirmation } = useConfirmContext(); + const isDecodeEnabled = useSelector(use4ByteResolutionSelector); const currentTransactionType = currentConfirmation?.type; const chainId = currentConfirmation?.chainId as Hex; @@ -23,6 +26,7 @@ export function useDecodedTransactionData( return useAsyncResult(async () => { if ( + !isDecodeEnabled || !hasTransactionData(transactionData) || !transactionTo || (transactionTypeFilter && @@ -36,5 +40,11 @@ export function useDecodedTransactionData( chainId, contractAddress, }); - }, [transactionData, transactionTo, chainId, contractAddress]); + }, [ + isDecodeEnabled, + transactionData, + transactionTo, + chainId, + contractAddress, + ]); } diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.ts new file mode 100644 index 000000000000..c7ca2af1c19c --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.ts @@ -0,0 +1,14 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { useConfirmContext } from '../../../../context/confirm'; +import { parseStandardTokenTransactionData } from '../../../../../../../shared/modules/transaction.utils'; + +export function useTokenTransactionData() { + const { currentConfirmation } = useConfirmContext(); + const transactionData = currentConfirmation?.txParams?.data; + + if (!transactionData) { + return undefined; + } + + return parseStandardTokenTransactionData(transactionData); +} diff --git a/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap index 4fe5c3f41bbd..67a073fd8003 100644 --- a/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap @@ -16,6 +16,100 @@ exports[`NativeTransferInfo renders correctly 1`] = ` 0 ETH
+
+
+
+
+
+

+ From +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+ +
+
diff --git a/ui/pages/confirmations/components/confirm/info/nft-token-transfer/__snapshots__/nft-token-transfer.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/nft-token-transfer/__snapshots__/nft-token-transfer.test.tsx.snap index 5ce090406606..49e781cf0594 100644 --- a/ui/pages/confirmations/components/confirm/info/nft-token-transfer/__snapshots__/nft-token-transfer.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/nft-token-transfer/__snapshots__/nft-token-transfer.test.tsx.snap @@ -44,6 +44,100 @@ exports[`NFTTokenTransferInfo renders correctly 1`] = ` #undefined

+
+
+
+
+
+

+ From +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+ +
+
diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap index a3f8724e7561..034bb47c38cb 100644 --- a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/__snapshots__/set-approval-for-all-info.test.tsx.snap @@ -110,6 +110,102 @@ exports[` renders component for approve request 1`] = ` class="mm-box mm-box--margin-bottom-4 mm-box--padding-2 mm-box--background-color-background-default mm-box--rounded-md" data-testid="confirmation__approve-details" > +
+
+
+

+ Permission for +

+
+
+ +
+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
renders component for approve request 1`] = `

renders component for approve request 1`] = `

', () => { mockStore, ); - await waitFor(() => { - expect(screen.getByText('Data')).toBeInTheDocument(); - }); - expect(container).toMatchSnapshot(); }); diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx index 6902a6da9b1f..42312f899955 100644 --- a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx @@ -2,11 +2,10 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import React from 'react'; import { useConfirmContext } from '../../../../context/confirm'; import { ApproveDetails } from '../approve/approve-details/approve-details'; -import { useDecodedTransactionData } from '../hooks/useDecodedTransactionData'; import { AdvancedDetails } from '../shared/advanced-details/advanced-details'; -import { ConfirmLoader } from '../shared/confirm-loader/confirm-loader'; import { GasFeesSection } from '../shared/gas-fees-section/gas-fees-section'; import { getIsRevokeSetApprovalForAll } from '../utils'; +import { useTokenTransactionData } from '../hooks/useTokenTransactionData'; import { RevokeSetApprovalForAllStaticSimulation } from './revoke-set-approval-for-all-static-simulation/revoke-set-approval-for-all-static-simulation'; import { SetApprovalForAllStaticSimulation } from './set-approval-for-all-static-simulation/set-approval-for-all-static-simulation'; @@ -14,22 +13,18 @@ const SetApprovalForAllInfo = () => { const { currentConfirmation: transactionMeta } = useConfirmContext(); - const decodedResponse = useDecodedTransactionData(); + const parsedTransactionData = useTokenTransactionData(); - const { value, pending } = decodedResponse; + const spender = parsedTransactionData?.args?._spender; - const isRevokeSetApprovalForAll = getIsRevokeSetApprovalForAll(value); - - const spender = value?.data[0].params[0].value; + const isRevokeSetApprovalForAll = getIsRevokeSetApprovalForAll( + parsedTransactionData, + ); if (!transactionMeta?.txParams) { return null; } - if (pending) { - return ; - } - return ( <> {isRevokeSetApprovalForAll ? ( diff --git a/ui/pages/confirmations/components/confirm/info/shared/send-heading/__snapshots__/send-heading.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/shared/send-heading/__snapshots__/send-heading.test.tsx.snap index fdc069a399dc..a2dd153305ed 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/send-heading/__snapshots__/send-heading.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/shared/send-heading/__snapshots__/send-heading.test.tsx.snap @@ -3,47 +3,29 @@ exports[` renders component 1`] = `
- - - +
+
- - - - - - +

+ <0.000001 Unknown +

+
+
`; diff --git a/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.test.tsx b/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.test.tsx index 613930f9901d..40a9842c9491 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.test.tsx @@ -5,6 +5,12 @@ import { getMockTokenTransferConfirmState } from '../../../../../../../../test/d import { renderWithConfirmContextProvider } from '../../../../../../../../test/lib/confirmations/render-helpers'; import SendHeading from './send-heading'; +jest.mock('../../../../../hooks/useAssetDetails', () => ({ + useAssetDetails: jest.fn(() => ({ + decimals: 18, + })), +})); + describe('', () => { const middleware = [thunk]; const state = getMockTokenTransferConfirmState({}); diff --git a/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.tsx b/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.tsx index cbba12835073..4e7f86e0ac8b 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/send-heading/send-heading.tsx @@ -24,7 +24,6 @@ import { useConfirmContext } from '../../../../../context/confirm'; import { useTokenValues } from '../../hooks/use-token-values'; import { useSendingValueMetric } from '../../hooks/useSendingValueMetric'; import { useTokenDetails } from '../../hooks/useTokenDetails'; -import { ConfirmLoader } from '../confirm-loader/confirm-loader'; const SendHeading = () => { const t = useI18nContext(); @@ -36,7 +35,6 @@ const SendHeading = () => { displayTransferValue, fiatDisplayValue, fiatValue, - pending, } = useTokenValues(transactionMeta); type TestNetChainId = (typeof TEST_CHAINS)[number]; @@ -89,10 +87,6 @@ const SendHeading = () => { useSendingValueMetric({ transactionMeta, fiatValue }); - if (pending) { - return ; - } - return (
- - - +
+
- - - + <0.000001 Unknown + +
+
+
+
+
+
- - - +
+
+

+ From +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+ +
({ }), })); +jest.mock('../../../../hooks/useAssetDetails', () => ({ + useAssetDetails: jest.fn(() => ({ + decimals: 18, + })), +})); + describe('TokenTransferInfo', () => { it('renders correctly', () => { const state = getMockTokenTransferConfirmState({}); - const mockStore = configureMockStore([])(state); + const mockStore = configureMockStore()(state); const { container } = renderWithConfirmContextProvider( , mockStore, diff --git a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.test.tsx b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.test.tsx index bdc6ed30678a..866dd3c2805f 100644 --- a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.test.tsx @@ -1,51 +1,38 @@ import { TransactionType } from '@metamask/transaction-controller'; import React from 'react'; import configureMockStore from 'redux-mock-store'; +import { TransactionDescription } from '@ethersproject/abi'; import { getMockTokenTransferConfirmState } from '../../../../../../../test/data/confirmations/helper'; import { renderWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; -import { useDecodedTransactionData } from '../hooks/useDecodedTransactionData'; +import { useTokenTransactionData } from '../hooks/useTokenTransactionData'; import { TransactionFlowSection } from './transaction-flow-section'; -jest.mock('../hooks/useDecodedTransactionData', () => ({ - ...jest.requireActual('../hooks/useDecodedTransactionData'), - useDecodedTransactionData: jest.fn(), -})); +jest.mock('../hooks/useTokenTransactionData'); jest.mock( '../../../../../../components/app/alert-system/contexts/alertMetricsContext.tsx', () => ({ - useAlertMetrics: jest.fn(() => ({ + useAlertMetrics: () => ({ trackInlineAlertClicked: jest.fn(), trackAlertRender: jest.fn(), trackAlertActionClicked: jest.fn(), - })), + }), }), ); describe('', () => { - const useDecodedTransactionDataMock = jest.fn().mockImplementation(() => ({ - pending: false, - value: { - data: [ - { - name: TransactionType.tokenMethodTransfer, - params: [ - { - name: 'dst', - type: 'address', - value: '0x6B175474E89094C44Da98b954EedeAC495271d0F', - }, - { name: 'wad', type: 'uint256', value: 0 }, - ], - }, - ], - source: 'Sourcify', - }, - })); + const useTokenTransactionDataMock = jest.mocked(useTokenTransactionData); - (useDecodedTransactionData as jest.Mock).mockImplementation( - useDecodedTransactionDataMock, - ); + beforeEach(() => { + jest.resetAllMocks(); + + useTokenTransactionDataMock.mockReturnValue({ + name: TransactionType.tokenMethodTransfer, + args: { + _to: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + }, + } as unknown as TransactionDescription); + }); it('renders correctly', () => { const state = getMockTokenTransferConfirmState({}); diff --git a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx index b874999d3956..fe9b9f319c9f 100644 --- a/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx +++ b/ui/pages/confirmations/components/confirm/info/token-transfer/transaction-flow-section.tsx @@ -22,27 +22,20 @@ import { ConfirmInfoAlertRow } from '../../../../../../components/app/confirm/in import { RowAlertKey } from '../../../../../../components/app/confirm/info/row/constants'; import { useI18nContext } from '../../../../../../hooks/useI18nContext'; import { useConfirmContext } from '../../../../context/confirm'; -import { useDecodedTransactionData } from '../hooks/useDecodedTransactionData'; +import { useTokenTransactionData } from '../hooks/useTokenTransactionData'; export const TransactionFlowSection = () => { const t = useI18nContext(); + const { currentConfirmation: transactionMeta } = useConfirmContext(); - const { value, pending } = useDecodedTransactionData(); + const parsedTransactionData = useTokenTransactionData(); - const addresses = value?.data[0].params.filter( - (param) => param.type === 'address', - ); const recipientAddress = transactionMeta.type === TransactionType.simpleSend ? transactionMeta.txParams.to - : // sometimes there's more than one address, in which case we want the last one - addresses?.[addresses.length - 1].value; - - if (pending) { - return null; - } + : parsedTransactionData?.args?._to; const { chainId } = transactionMeta; diff --git a/ui/pages/confirmations/components/confirm/info/utils.test.ts b/ui/pages/confirmations/components/confirm/info/utils.test.ts index 9c12b9127811..b9752da7f1a8 100644 --- a/ui/pages/confirmations/components/confirm/info/utils.test.ts +++ b/ui/pages/confirmations/components/confirm/info/utils.test.ts @@ -1,6 +1,6 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import { toHex } from '@metamask/controller-utils'; -import { DecodedTransactionDataSource } from '../../../../../../shared/types/transaction-decode'; +import { TransactionDescription } from '@ethersproject/abi'; import { getIsRevokeSetApprovalForAll, hasValueAndNativeBalanceMismatch, @@ -9,33 +9,22 @@ import { describe('getIsRevokeSetApprovalForAll', () => { it('returns false if no data is passed as an argument', () => { const testValue = { - data: [], - source: DecodedTransactionDataSource.FourByte, - }; + args: {}, + } as TransactionDescription; + const actual = getIsRevokeSetApprovalForAll(testValue); expect(actual).toEqual(false); }); - it('returns true if no setApprovalForAll decoded tx is passed as an argument', () => { + it('returns true if setApprovalForAll decoded tx is passed as an argument', () => { const testValue = { - data: [ - { - name: 'setApprovalForAll', - params: [ - { - type: 'address', - value: '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', - }, - { - type: 'boolean', - value: false, - }, - ], - }, - ], - source: DecodedTransactionDataSource.FourByte, - }; + name: 'setApprovalForAll', + args: { + _approved: false, + }, + } as unknown as TransactionDescription; + const actual = getIsRevokeSetApprovalForAll(testValue); expect(actual).toEqual(true); diff --git a/ui/pages/confirmations/components/confirm/info/utils.ts b/ui/pages/confirmations/components/confirm/info/utils.ts index 1af918aea74e..f0f2f6fbeade 100644 --- a/ui/pages/confirmations/components/confirm/info/utils.ts +++ b/ui/pages/confirmations/components/confirm/info/utils.ts @@ -2,7 +2,7 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import type { Hex } from '@metamask/utils'; import { remove0x } from '@metamask/utils'; import { BN } from 'bn.js'; -import { DecodedTransactionDataResponse } from '../../../../../../shared/types/transaction-decode'; +import { TransactionDescription } from '@ethersproject/abi'; import { BackgroundColor, TextColor, @@ -11,13 +11,11 @@ import { const VALUE_COMPARISON_PERCENT_THRESHOLD = 5; export function getIsRevokeSetApprovalForAll( - value: DecodedTransactionDataResponse | undefined, + value: TransactionDescription | undefined, ): boolean { - const isRevokeSetApprovalForAll = - value?.data?.[0]?.name === 'setApprovalForAll' && - value?.data?.[0]?.params?.[1]?.value === false; - - return isRevokeSetApprovalForAll; + return ( + value?.name === 'setApprovalForAll' && value?.args?._approved === false + ); } export const getAmountColors = (credit?: boolean, debit?: boolean) => { diff --git a/ui/pages/confirmations/components/confirm/title/title.tsx b/ui/pages/confirmations/components/confirm/title/title.tsx index e8148912cac1..7be6c59be50d 100644 --- a/ui/pages/confirmations/components/confirm/title/title.tsx +++ b/ui/pages/confirmations/components/confirm/title/title.tsx @@ -20,8 +20,8 @@ import { Confirmation, SignatureRequestType } from '../../../types/confirm'; import { isSIWESignatureRequest } from '../../../utils'; import { useTypedSignSignatureInfo } from '../../../hooks/useTypedSignSignatureInfo'; import { useIsNFT } from '../info/approve/hooks/use-is-nft'; -import { useDecodedTransactionData } from '../info/hooks/useDecodedTransactionData'; import { getIsRevokeSetApprovalForAll } from '../info/utils'; +import { useTokenTransactionData } from '../info/hooks/useTokenTransactionData'; import { useCurrentSpendingCap } from './hooks/useCurrentSpendingCap'; function ConfirmBannerAlert({ ownerId }: { ownerId: string }) { @@ -173,19 +173,12 @@ const ConfirmTitle: React.FC = memo(() => { const { customSpendingCap, pending: spendingCapPending } = useCurrentSpendingCap(currentConfirmation); - let isRevokeSetApprovalForAll = false; - let revokePending = false; - const decodedResponse = useDecodedTransactionData( - TransactionType.tokenMethodSetApprovalForAll, - ); - if ( - currentConfirmation?.type === TransactionType.tokenMethodSetApprovalForAll - ) { - isRevokeSetApprovalForAll = getIsRevokeSetApprovalForAll( - decodedResponse.value, - ); - revokePending = decodedResponse.pending; - } + const parsedTransactionData = useTokenTransactionData(); + + const isRevokeSetApprovalForAll = + currentConfirmation?.type === + TransactionType.tokenMethodSetApprovalForAll && + getIsRevokeSetApprovalForAll(parsedTransactionData); const title = useMemo( () => @@ -195,7 +188,7 @@ const ConfirmTitle: React.FC = memo(() => { isNFT, customSpendingCap, isRevokeSetApprovalForAll, - spendingCapPending || revokePending, + spendingCapPending, primaryType, tokenStandard, ), @@ -205,7 +198,6 @@ const ConfirmTitle: React.FC = memo(() => { customSpendingCap, isRevokeSetApprovalForAll, spendingCapPending, - revokePending, primaryType, tokenStandard, ], @@ -219,7 +211,7 @@ const ConfirmTitle: React.FC = memo(() => { isNFT, customSpendingCap, isRevokeSetApprovalForAll, - spendingCapPending || revokePending, + spendingCapPending, primaryType, tokenStandard, ), @@ -229,7 +221,6 @@ const ConfirmTitle: React.FC = memo(() => { customSpendingCap, isRevokeSetApprovalForAll, spendingCapPending, - revokePending, primaryType, tokenStandard, ], From ef12db5372957a7b22306ee7b272772fb435174d Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 19 Dec 2024 11:06:40 +0000 Subject: [PATCH 2/8] Add unit tests for useTokenTransactionData Fix integration tests. --- .../confirmations/set-approval-for-all.ts | 2 +- test/data/confirmations/token-transfer.ts | 7 +- .../transactions/increase-allowance.test.tsx | 6 +- .../set-approval-for-all.test.tsx | 2 +- .../approve-details/approve-details.tsx | 6 +- .../confirm/info/approve/approve.test.tsx | 7 +- .../hooks/use-approve-token-simulation.ts | 9 ++- .../info/hooks/use-token-values.test.ts | 6 +- .../confirm/info/hooks/use-token-values.ts | 14 ++-- .../hooks/useTokenTransactionData.test.ts | 81 +++++++++++++++++++ .../native-transfer.test.tsx.snap | 81 +++++++++++++++++++ .../nft-token-transfer.test.tsx.snap | 81 +++++++++++++++++++ .../token-transfer.test.tsx.snap | 81 +++++++++++++++++++ 13 files changed, 359 insertions(+), 24 deletions(-) create mode 100644 ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts diff --git a/test/data/confirmations/set-approval-for-all.ts b/test/data/confirmations/set-approval-for-all.ts index ca997f6212af..95b134eb0938 100644 --- a/test/data/confirmations/set-approval-for-all.ts +++ b/test/data/confirmations/set-approval-for-all.ts @@ -16,7 +16,7 @@ export const genUnapprovedSetApprovalForAllConfirmation = ({ ...genUnapprovedContractInteractionConfirmation({ chainId }), txParams: { from: address, - data: '0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', + data: '0xa22cb4650000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', gas: '0x16a92', to: '0x076146c765189d51be3160a2140cf80bfc73ad68', value: '0x0', diff --git a/test/data/confirmations/token-transfer.ts b/test/data/confirmations/token-transfer.ts index 22d0cb2d00b4..9228373bdf3e 100644 --- a/test/data/confirmations/token-transfer.ts +++ b/test/data/confirmations/token-transfer.ts @@ -6,19 +6,24 @@ import { genUnapprovedContractInteractionConfirmation, } from './contract-interaction'; +export const TRANSFER_FROM_TRANSACTION_DATA = + '0x23b872dd0000000000000000000000002e0D7E8c45221FcA00d74a3609A0f7097035d09B0000000000000000000000002e0D7E8c45221FcA00d74a3609A0f7097035d09C0000000000000000000000000000000000000000000000000000000000000123'; + export const genUnapprovedTokenTransferConfirmation = ({ address = CONTRACT_INTERACTION_SENDER_ADDRESS, chainId = CHAIN_ID, isWalletInitiatedConfirmation = false, + amountHex = '0000000000000000000000000000000000000000000000000000000000000001', }: { address?: Hex; chainId?: string; isWalletInitiatedConfirmation?: boolean; + amountHex?: string; } = {}) => ({ ...genUnapprovedContractInteractionConfirmation({ chainId }), txParams: { from: address, - data: '0x095ea7b30000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000001', + data: `0xa9059cbb0000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b${amountHex}`, gas: '0x16a92', to: '0x076146c765189d51be3160a2140cf80bfc73ad68', value: '0x0', diff --git a/test/integration/confirmations/transactions/increase-allowance.test.tsx b/test/integration/confirmations/transactions/increase-allowance.test.tsx index 810477d3a3a5..b6f72adeb7ac 100644 --- a/test/integration/confirmations/transactions/increase-allowance.test.tsx +++ b/test/integration/confirmations/transactions/increase-allowance.test.tsx @@ -198,7 +198,7 @@ describe('ERC20 increaseAllowance Confirmation', () => { 'simulation-token-value', ); expect(simulationSection).toContainElement(spendingCapValue); - expect(spendingCapValue).toHaveTextContent('1'); + expect(spendingCapValue).toHaveTextContent('30,000'); expect(simulationSection).toHaveTextContent('0x07614...3ad68'); }); @@ -225,7 +225,7 @@ describe('ERC20 increaseAllowance Confirmation', () => { expect(approveDetails).toContainElement(approveDetailsSpender); expect(approveDetailsSpender).toHaveTextContent(tEn('spender') as string); - expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); + expect(approveDetailsSpender).toHaveTextContent('0x9bc5b...AfEF4'); const spenderTooltip = await screen.findByTestId( 'confirmation__approve-spender-tooltip', ); @@ -286,7 +286,7 @@ describe('ERC20 increaseAllowance Confirmation', () => { ); expect(spendingCapSection).toContainElement(spendingCapGroup); expect(spendingCapGroup).toHaveTextContent(tEn('spendingCap') as string); - expect(spendingCapGroup).toHaveTextContent('1'); + expect(spendingCapGroup).toHaveTextContent('30,000'); const spendingCapGroupTooltip = await screen.findByTestId( 'confirmation__approve-spending-cap-group-tooltip', diff --git a/test/integration/confirmations/transactions/set-approval-for-all.test.tsx b/test/integration/confirmations/transactions/set-approval-for-all.test.tsx index ebe680983a6c..51cb991ac3b2 100644 --- a/test/integration/confirmations/transactions/set-approval-for-all.test.tsx +++ b/test/integration/confirmations/transactions/set-approval-for-all.test.tsx @@ -231,7 +231,7 @@ describe('ERC721 setApprovalForAll Confirmation', () => { expect(approveDetailsSpender).toHaveTextContent( tEn('permissionFor') as string, ); - expect(approveDetailsSpender).toHaveTextContent('0x2e0D7...5d09B'); + expect(approveDetailsSpender).toHaveTextContent('0x9bc5b...AfEF4'); const spenderTooltip = await screen.findByTestId( 'confirmation__approve-spender-tooltip', ); diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx index ed56623feb31..1d552db45930 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve-details/approve-details.tsx @@ -37,7 +37,11 @@ const Spender = ({ return null; } - const spender = parsedTransactionData.args?._spender; + const spender = + parsedTransactionData.args?._spender ?? // ERC-20 - approve + parsedTransactionData.args?._operator ?? // ERC-721 - setApprovalForAll + parsedTransactionData.args?.spender; // Fiat Token V2 - increaseAllowance + const { chainId } = transactionMeta; if (getIsRevokeSetApprovalForAll(parsedTransactionData)) { diff --git a/ui/pages/confirmations/components/confirm/info/approve/approve.test.tsx b/ui/pages/confirmations/components/confirm/info/approve/approve.test.tsx index 914e276369f5..bf26a6e1abc0 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/approve.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/approve/approve.test.tsx @@ -1,8 +1,9 @@ import React from 'react'; import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; -import { getMockApproveConfirmState } from '../../../../../../../test/data/confirmations/helper'; +import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; import { renderWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; +import { genUnapprovedApproveConfirmation } from '../../../../../../../test/data/confirmations/token-approve'; import ApproveInfo from './approve'; jest.mock('../../../../../../store/actions', () => ({ @@ -72,7 +73,9 @@ describe('', () => { const middleware = [thunk]; it('renders component for approve request', async () => { - const state = getMockApproveConfirmState(); + const state = getMockConfirmStateForTransaction( + genUnapprovedApproveConfirmation(), + ); const mockStore = configureMockStore(middleware)(state); diff --git a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts index ca884c04b1f4..7430f0dc36e4 100644 --- a/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts +++ b/ui/pages/confirmations/components/confirm/info/approve/hooks/use-approve-token-simulation.ts @@ -20,12 +20,13 @@ export const useApproveTokenSimulation = ( ) => { const locale = useSelector(getIntlLocale); const { isNFT, pending: isNFTPending } = useIsNFT(transactionMeta); - const parsedTransactionData = useTokenTransactionData(); + const { args: parsedArgs } = useTokenTransactionData() ?? {}; - const value = - (parsedTransactionData?.args?._value as BigNumber | undefined) ?? - new BigNumber(0); + const parsedValue = + parsedArgs?._value ?? // ERC-20 - approve + parsedArgs?.increment; // Fiat Token V2 - increaseAllowance + const value = parsedValue ?? new BigNumber(0); const decodedSpendingCap = calcTokenAmount(value, Number(decimals)).toFixed(); const tokenPrefix = isNFT ? '#' : ''; diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts index 0198b2fc27cb..43be106de1f2 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.test.ts @@ -4,7 +4,7 @@ import { renderHookWithConfirmContextProvider } from '../../../../../../../test/ import useTokenExchangeRate from '../../../../../../components/app/currency-input/hooks/useTokenExchangeRate'; import { useAssetDetails } from '../../../../hooks/useAssetDetails'; import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; -import { genUnapprovedApproveConfirmation } from '../../../../../../../test/data/confirmations/token-approve'; +import { genUnapprovedTokenTransferConfirmation } from '../../../../../../../test/data/confirmations/token-transfer'; import { useTokenValues } from './use-token-values'; jest.mock('../../../../hooks/useAssetDetails', () => ({ @@ -31,7 +31,7 @@ describe('useTokenValues', () => { useTokenExchangeRateMock.mockReturnValue(new Numeric(0.91, 10)); - const transactionMeta = genUnapprovedApproveConfirmation({ + const transactionMeta = genUnapprovedTokenTransferConfirmation({ amountHex: '0000000000000000000000000000000000000000000000000000000000011170', }) as TransactionMeta; @@ -56,7 +56,7 @@ describe('useTokenValues', () => { useTokenExchangeRateMock.mockReturnValue(undefined); - const transactionMeta = genUnapprovedApproveConfirmation({ + const transactionMeta = genUnapprovedTokenTransferConfirmation({ amountHex: '0000000000000000000000000000000000000000000000000000000000011170', }) as TransactionMeta; diff --git a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts index c9a61c87b4f3..b38dfd2be8ce 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/use-token-values.ts @@ -22,14 +22,12 @@ export const useTokenValues = (transactionMeta: TransactionMeta) => { transactionMeta.chainId, ); - const value = - (parsedTransactionData?.args?._value as BigNumber | undefined) ?? - new BigNumber(0); - - const decodedTransferValue = calcTokenAmount( - value, - Number(decimals), - ).toFixed(); + const value = parsedTransactionData?.args?._value as BigNumber | undefined; + + const decodedTransferValue = + decimals !== undefined && value + ? calcTokenAmount(value, Number(decimals)).toFixed() + : '0'; const fiatValue = exchangeRate && diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts new file mode 100644 index 000000000000..6189db3777e4 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts @@ -0,0 +1,81 @@ +import { Hex } from '@metamask/utils'; +import { genUnapprovedContractInteractionConfirmation } from '../../../../../../../test/data/confirmations/contract-interaction'; +import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; +import { + genUnapprovedTokenTransferConfirmation, + TRANSFER_FROM_TRANSACTION_DATA, +} from '../../../../../../../test/data/confirmations/token-transfer'; +import { renderHookWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; +import { useTokenTransactionData } from './useTokenTransactionData'; +import { TransactionDescription } from '@ethersproject/abi'; +import { genUnapprovedApproveConfirmation } from '../../../../../../../test/data/confirmations/token-approve'; +import { genUnapprovedSetApprovalForAllConfirmation } from '../../../../../../../test/data/confirmations/set-approval-for-all'; + +function runHook(transactionData: string) { + const transaction = genUnapprovedContractInteractionConfirmation({ + txData: transactionData as Hex, + }); + + const state = getMockConfirmStateForTransaction(transaction); + + const { result } = renderHookWithConfirmContextProvider( + useTokenTransactionData, + state, + ); + + return result.current as TransactionDescription; +} + +describe('useTokenTransactionData', () => { + it('parses transfer transaction', () => { + const transactionData = + genUnapprovedTokenTransferConfirmation().txParams.data; + + const result = runHook(transactionData); + + expect(result.name).toBe('transfer'); + expect(result.args._to).toBe('0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B'); + expect(result.args._value.toHexString()).toBe('0x01'); + }); + + it('parses transferFrom transaction', () => { + const result = runHook(TRANSFER_FROM_TRANSACTION_DATA); + + expect(result.name).toBe('transferFrom'); + expect(result.args._from).toBe( + '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + ); + expect(result.args._to).toBe('0x2e0d7E8c45221fCa00d74A3609A0F7097035D09c'); + expect(result.args._value.toHexString()).toEqual('0x0123'); + }); + + it('parses approve transaction', () => { + const transactionData = genUnapprovedApproveConfirmation().txParams.data; + + const result = runHook(transactionData); + + expect(result.name).toBe('approve'); + expect(result.args._spender).toBe( + '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + ); + expect(result.args._value.toHexString()).toBe('0x01'); + }); + + it('parses setApprovalForAll transaction', () => { + const transactionData = + genUnapprovedSetApprovalForAllConfirmation().txParams.data; + + const result = runHook(transactionData); + + expect(result.name).toBe('setApprovalForAll'); + expect(result.args._operator).toBe( + '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + ); + expect(result.args._approved).toBe(true); + }); + + it('returns undefined if no transaction data', () => { + const result = runHook(undefined as never); + expect(result).toBeUndefined(); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap index 67a073fd8003..bd992e954422 100644 --- a/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/native-transfer/__snapshots__/native-transfer.test.tsx.snap @@ -108,6 +108,87 @@ exports[`NativeTransferInfo renders correctly 1`] = ` class="mm-box mm-icon mm-icon--size-md mm-box--display-inline-block mm-box--color-icon-muted" style="mask-image: url('./images/icons/arrow-right.svg');" /> +
+
+
+

+ To +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+
+
+
+

+ To +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
+
+
+
+

+ To +

+
+
+
+
+
+
+
+
+ + + + + +
+
+
+

+ 0x2e0D7...5d09B +

+
+
+
+
Date: Thu, 19 Dec 2024 11:38:38 +0000 Subject: [PATCH 3/8] Add additional unit tests Fix linting. --- .../confirmations/set-approval-for-all.ts | 3 +++ .../hooks/useDecodedTransactionData.test.ts | 26 +++++++++++++++++++ .../hooks/useTokenTransactionData.test.ts | 19 +++++++++++--- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/test/data/confirmations/set-approval-for-all.ts b/test/data/confirmations/set-approval-for-all.ts index 95b134eb0938..ec1889a7b16b 100644 --- a/test/data/confirmations/set-approval-for-all.ts +++ b/test/data/confirmations/set-approval-for-all.ts @@ -6,6 +6,9 @@ import { genUnapprovedContractInteractionConfirmation, } from './contract-interaction'; +export const INCREASE_ALLOWANCE_TRANSACTION_DATA = + '0x395093510000000000000000000000002e0d7e8c45221fca00d74a3609a0f7097035d09b0000000000000000000000000000000000000000000000000000000000000123'; + export const genUnapprovedSetApprovalForAllConfirmation = ({ address = CONTRACT_INTERACTION_SENDER_ADDRESS, chainId = CHAIN_ID, diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.test.ts index 32a711abf754..c12ce7025cb5 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.test.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useDecodedTransactionData.test.ts @@ -76,6 +76,32 @@ describe('useDecodedTransactionData', () => { expect(result).toStrictEqual({ pending: false, value: undefined }); }); + it('returns undefined if decode disabled', async () => { + decodeTransactionDataMock.mockResolvedValue(TRANSACTION_DECODE_SOURCIFY); + + const result = await runHook( + getMockConfirmStateForTransaction( + { + id: '123', + chainId: CHAIN_ID_MOCK, + type: TransactionType.contractInteraction, + status: TransactionStatus.unapproved, + txParams: { + data: TRANSACTION_DATA_UNISWAP, + to: CONTRACT_ADDRESS_MOCK, + } as TransactionParams, + }, + { + metamask: { + use4ByteResolution: false, + }, + }, + ), + ); + + expect(result).toStrictEqual({ pending: false, value: undefined }); + }); + it('returns the decoded data', async () => { decodeTransactionDataMock.mockResolvedValue(TRANSACTION_DECODE_SOURCIFY); diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts index 6189db3777e4..f73372d9391f 100644 --- a/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTokenTransactionData.test.ts @@ -1,4 +1,5 @@ import { Hex } from '@metamask/utils'; +import { TransactionDescription } from '@ethersproject/abi'; import { genUnapprovedContractInteractionConfirmation } from '../../../../../../../test/data/confirmations/contract-interaction'; import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; import { @@ -6,10 +7,12 @@ import { TRANSFER_FROM_TRANSACTION_DATA, } from '../../../../../../../test/data/confirmations/token-transfer'; import { renderHookWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; -import { useTokenTransactionData } from './useTokenTransactionData'; -import { TransactionDescription } from '@ethersproject/abi'; import { genUnapprovedApproveConfirmation } from '../../../../../../../test/data/confirmations/token-approve'; -import { genUnapprovedSetApprovalForAllConfirmation } from '../../../../../../../test/data/confirmations/set-approval-for-all'; +import { + genUnapprovedSetApprovalForAllConfirmation, + INCREASE_ALLOWANCE_TRANSACTION_DATA, +} from '../../../../../../../test/data/confirmations/set-approval-for-all'; +import { useTokenTransactionData } from './useTokenTransactionData'; function runHook(transactionData: string) { const transaction = genUnapprovedContractInteractionConfirmation({ @@ -74,6 +77,16 @@ describe('useTokenTransactionData', () => { expect(result.args._approved).toBe(true); }); + it('parses increaseAllowance transaction', () => { + const result = runHook(INCREASE_ALLOWANCE_TRANSACTION_DATA); + + expect(result.name).toBe('increaseAllowance'); + expect(result.args.spender).toBe( + '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B', + ); + expect(result.args.increment.toHexString()).toBe('0x0123'); + }); + it('returns undefined if no transaction data', () => { const result = runHook(undefined as never); expect(result).toBeUndefined(); From dc50b2d1be8dcf459a406efbfefd7f2ed630183b Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 19 Dec 2024 12:41:28 +0000 Subject: [PATCH 4/8] Fix E2E test --- .../set-approval-for-all-info/set-approval-for-all-info.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx index 42312f899955..e2371d09454d 100644 --- a/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx +++ b/ui/pages/confirmations/components/confirm/info/set-approval-for-all-info/set-approval-for-all-info.tsx @@ -15,7 +15,7 @@ const SetApprovalForAllInfo = () => { const parsedTransactionData = useTokenTransactionData(); - const spender = parsedTransactionData?.args?._spender; + const spender = parsedTransactionData?.args?._operator; const isRevokeSetApprovalForAll = getIsRevokeSetApprovalForAll( parsedTransactionData, From 96785717643b1afd0fcba8de84179ca7f67c9e58 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 19 Dec 2024 14:59:04 +0000 Subject: [PATCH 5/8] Fix unit and integration tests --- .../confirmations/transactions/increase-allowance.test.tsx | 4 ++-- .../components/confirm/info/__snapshots__/info.test.tsx.snap | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/integration/confirmations/transactions/increase-allowance.test.tsx b/test/integration/confirmations/transactions/increase-allowance.test.tsx index 024c2ba492d4..083c8b3a72dd 100644 --- a/test/integration/confirmations/transactions/increase-allowance.test.tsx +++ b/test/integration/confirmations/transactions/increase-allowance.test.tsx @@ -213,7 +213,7 @@ describe('ERC20 increaseAllowance Confirmation', () => { 'simulation-token-value', ); expect(simulationSection).toContainElement(spendingCapValue); - expect(spendingCapValue).toHaveTextContent('30,000'); + expect(spendingCapValue).toHaveTextContent('3'); expect(simulationSection).toHaveTextContent('0x07614...3ad68'); }); @@ -301,7 +301,7 @@ describe('ERC20 increaseAllowance Confirmation', () => { ); expect(spendingCapSection).toContainElement(spendingCapGroup); expect(spendingCapGroup).toHaveTextContent(tEn('spendingCap') as string); - expect(spendingCapGroup).toHaveTextContent('30,000'); + expect(spendingCapGroup).toHaveTextContent('3'); const spendingCapGroupTooltip = await screen.findByTestId( 'confirmation__approve-spending-cap-group-tooltip', diff --git a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap index 880450cbf3f5..8dfed1275f0a 100644 --- a/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/__snapshots__/info.test.tsx.snap @@ -80,7 +80,7 @@ exports[`Info renders info section for approve request 1`] = ` class="mm-box mm-text mm-text--body-md mm-text--text-align-center mm-box--padding-inline-2 mm-box--align-items-center mm-box--color-text-default mm-box--background-color-background-alternative mm-box--rounded-xl" data-testid="simulation-token-value" > - #1 + #0.0001

Date: Thu, 19 Dec 2024 15:51:44 +0000 Subject: [PATCH 6/8] Update copy --- app/_locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 7ddf609b48f0..8d57ceefe493 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -6636,7 +6636,7 @@ "message": "Decode smart contracts" }, "use4ByteResolutionDescription": { - "message": "To improve user experience, we customize the activity tab with messages based on the smart contracts you interact with. MetaMask uses a service called 4byte.directory to decode data and show you a version of a smart contract that's easier to read. This helps reduce your chances of approving malicious smart contract actions, but can result in your IP address being shared." + "message": "We use 4byte.directory and Sourcify services to decode and display more readable transaction data. This helps you understand the outcome of pending and past transactions, but can result in your IP address being shared." }, "useMultiAccountBalanceChecker": { "message": "Batch account balance requests" From 3644b3e52d0200d8a716eb2fdc1512d016c39f95 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 19 Dec 2024 19:50:53 +0000 Subject: [PATCH 7/8] Fix unit test --- .../security-tab/__snapshots__/security-tab.test.js.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap b/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap index 3b1837d55ef2..491ed613b1e5 100644 --- a/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap +++ b/ui/pages/settings/security-tab/__snapshots__/security-tab.test.js.snap @@ -390,7 +390,7 @@ exports[`Security Tab should match snapshot 1`] = `
- To improve user experience, we customize the activity tab with messages based on the smart contracts you interact with. MetaMask uses a service called 4byte.directory to decode data and show you a version of a smart contract that's easier to read. This helps reduce your chances of approving malicious smart contract actions, but can result in your IP address being shared. + We use 4byte.directory and Sourcify services to decode and display more readable transaction data. This helps you understand the outcome of pending and past transactions, but can result in your IP address being shared.
Date: Fri, 20 Dec 2024 09:42:59 +0000 Subject: [PATCH 8/8] Update translation key --- app/_locales/de/messages.json | 3 --- app/_locales/el/messages.json | 3 --- app/_locales/en/messages.json | 6 +++--- app/_locales/es/messages.json | 3 --- app/_locales/fr/messages.json | 3 --- app/_locales/hi/messages.json | 3 --- app/_locales/id/messages.json | 3 --- app/_locales/ja/messages.json | 3 --- app/_locales/ko/messages.json | 3 --- app/_locales/pt/messages.json | 3 --- app/_locales/ru/messages.json | 3 --- app/_locales/tl/messages.json | 3 --- app/_locales/tr/messages.json | 3 --- app/_locales/vi/messages.json | 3 --- app/_locales/zh_CN/messages.json | 3 --- ui/helpers/constants/settings.js | 2 +- .../onboarding-flow/privacy-settings/privacy-settings.js | 2 +- ui/pages/settings/security-tab/security-tab.component.js | 2 +- 18 files changed, 6 insertions(+), 48 deletions(-) diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 04c45bd81348..0bcd6ecf5972 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Smart Contracts dekodieren" }, - "use4ByteResolutionDescription": { - "message": "Um das Benutzererlebnis zu verbessern, passen wir die Aktivitätsregisterkarte mit Nachrichten an, die auf den Smart Contracts basieren, mit denen Sie interagieren. MetaMask verwendet einen Dienst namens 4byte.directory, um Daten zu entschlüsseln und Ihnen eine Version eines Smart Contracts anzuzeigen, die leichter zu lesen ist. Dies trägt dazu bei, die Wahrscheinlichkeit zu verringern, dass Sie bösartige Smart-Contract-Aktionen genehmigen, kann aber dazu führen, dass Ihre IP-Adresse weitergegeben wird." - }, "useMultiAccountBalanceChecker": { "message": "Kontoguthaben-Anfragen sammeln" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 24da4df88460..ec50350850a7 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Αποκωδικοποίηση έξυπνων συμβολαίων" }, - "use4ByteResolutionDescription": { - "message": "Για να βελτιώσουμε την εμπειρία του χρήστη, προσαρμόζουμε την καρτέλα δραστηριότητας με μηνύματα που βασίζονται στα έξυπνα συμβόλαια με τα οποία αλληλεπιδράτε. Το MetaMask χρησιμοποιεί μια υπηρεσία που ονομάζεται 4byte.directory για την αποκωδικοποίηση δεδομένων και την εμφάνιση μιας έκδοσης ενός έξυπνου συμβολαίου που είναι πιο ευανάγνωστο. Αυτό συμβάλλει στη μείωση των πιθανοτήτων σας να εγκρίνετε κακόβουλες ενέργειες έξυπνων συμβολαίων, αλλά μπορεί να έχει ως αποτέλεσμα την κοινοποίηση της διεύθυνσης IP σας." - }, "useMultiAccountBalanceChecker": { "message": "Μαζικά αιτήματα υπολοίπου λογαριασμού" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 3f29d98231db..491172333f93 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -6269,6 +6269,9 @@ "message": "To: $1", "description": "$1 is the address to include in the To label. It is typically shortened first using shortenAddress" }, + "toggleDecodeDescription": { + "message": "We use 4byte.directory and Sourcify services to decode and display more readable transaction data. This helps you understand the outcome of pending and past transactions, but can result in your IP address being shared." + }, "toggleRequestQueueDescription": { "message": "This allows you to select a network for each site instead of a single selected network for all sites. This feature will prevent you from switching networks manually, which may break your user experience on certain sites." }, @@ -6632,9 +6635,6 @@ "use4ByteResolution": { "message": "Decode smart contracts" }, - "use4ByteResolutionDescription": { - "message": "We use 4byte.directory and Sourcify services to decode and display more readable transaction data. This helps you understand the outcome of pending and past transactions, but can result in your IP address being shared." - }, "useMultiAccountBalanceChecker": { "message": "Batch account balance requests" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 0f24f5bc5b1a..c39e7f394fc7 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Decodificar contratos inteligentes" }, - "use4ByteResolutionDescription": { - "message": "Para mejorar la experiencia del usuario, personalizamos la pestaña de actividad con mensajes basados en los contratos inteligentes con los que interactúa. MetaMask usa un servicio llamado 4byte.directory para decodificar datos y mostrarle una versión de un contrato inteligente que es más fácil de leer. Esto ayuda a reducir sus posibilidades de aprobar acciones de contratos inteligentes maliciosos, pero puede resultar en que se comparta su dirección IP." - }, "useMultiAccountBalanceChecker": { "message": "Solicitudes de saldo de cuenta por lotes" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index ce615bddd591..8a2386b774f9 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Décoder les contrats intelligents" }, - "use4ByteResolutionDescription": { - "message": "Pour améliorer l’expérience utilisateur, nous personnalisons les messages qui s’affichent dans l’onglet d’activité en fonction des contrats intelligents avec lesquels vous interagissez. MetaMask utilise un service appelé 4byte.directory pour décoder les données et vous montrer une version plus facile à lire des contrats intelligents. Ainsi vous aurez moins de chances d’approuver l’exécution de contrats intelligents malveillants, mais cela peut nécessiter le partage de votre adresse IP." - }, "useMultiAccountBalanceChecker": { "message": "Demandes d’informations concernant le solde de plusieurs comptes" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 05488711d94f..a4e1b61b13fc 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "स्मार्ट कॉन्ट्रैक्ट्स को डीकोड करें" }, - "use4ByteResolutionDescription": { - "message": "यूज़र के अनुभव को बेहतर बनाने के लिए, आपके द्वारा इंटरैक्ट किए गए स्मार्ट कॉन्ट्रैक्ट्स के आधार पर हम एक्टिविटी टैब को मैसेज के साथ कस्टमाइज़ करते हैं। डेटा को डीकोड करने और आसानी से पढ़े जा सकने वाले स्मार्ट कॉन्ट्रैक्ट्स का एक वर्शन आपको दिखाने के लिए MetaMask एक सर्विस इस्तेमाल करता है जिसका नाम 4byte.directory है। इससे आपके द्वारा बुरी नीयत वाले स्मार्ट कॉन्ट्रैक्ट एक्शन को मंजूरी देने की संभावनाओं को कम करने में मदद मिलती है। हालांकि, इसमें आपका IP एड्रेस शेयर होने का खतरा हो सकता है।" - }, "useMultiAccountBalanceChecker": { "message": "अकाउंट के बैलेंस के रिक्वेस्ट्स को बैच करें" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index c918a6cc0fb0..1540aeca6b7c 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Uraikan kode kontrak cerdas" }, - "use4ByteResolutionDescription": { - "message": "Untuk meningkatkan pengalaman pengguna, kami menyesuaikan tab aktivitas dengan pesan berdasarkan kontrak cerdas yang berinteraksi dengan Anda. MetaMask menggunakan layanan yang disebut 4byte.directory untuk menguraikan kode data dan menampilkan versi kontrak cerdas yang lebih mudah dibaca. Ini membantu mengurangi peluang Anda untuk menyetujui tindakan kontrak cerdas yang berbahaya, tetapi dapat menyebabkan alamat IP Anda tersebar." - }, "useMultiAccountBalanceChecker": { "message": "Kelompokkan permintaan saldo akun" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index ead0da87b7b8..c0f0c006a764 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "スマートコントラクトのデコード" }, - "use4ByteResolutionDescription": { - "message": "ユーザーエクスペリエンスの向上のため、ユーザーがやり取りするスマートコントラクトに応じたメッセージで、アクティビティタブをカスタマイズします。MetaMaskは、4byte.directoryと呼ばれるサービスを利用してデータをデコードし、より読みやすいバージョンのスマートコントラクトを表示します。これにより、悪質なスマートコントラクトの操作を承認する可能性は減りますが、IPアドレスが公開されます。" - }, "useMultiAccountBalanceChecker": { "message": "アカウント残高の一括リクエスト" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index f22491040b4f..c6aef67d8d14 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "스마트 계약 디코딩" }, - "use4ByteResolutionDescription": { - "message": "인터렉션하는 스마트 계약에 따라 메시지를 이용하여 활동 탭을 사용자 맞춤하여 사용자 경험을 개선합니다. MetaMask는 4byte.directory라는 서비스를 통해 데이터를 디코딩하여 스마트 계약을 읽기 쉬운 버전으로 보여 줍니다. 이는 악의적인 스마트 계약을 승인할 가능성을 줄이는 데 도움이 되지만 IP 주소가 공유될 수 있습니다." - }, "useMultiAccountBalanceChecker": { "message": "일괄 계정 잔액 요청" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 50bf0a7d9996..20ef4cd6b2a3 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Decodificar contratos inteligentes" }, - "use4ByteResolutionDescription": { - "message": "Para melhorar a experiência do usuário, personalizamos a guia de atividades com mensagens baseadas nos contratos inteligentes com os quais você interage. A MetaMask usa um serviço chamado 4byte.directory para decodificar os dados e exibir a você uma versão de um contrato inteligente que é mais fácil de ler. Isso ajuda a reduzir suas chances de aprovar ações de contratos inteligentes mal-intencionados, mas pode resultar no compartilhamento do seu endereço IP." - }, "useMultiAccountBalanceChecker": { "message": "Agrupar solicitações de saldo de contas" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index b1445befdd17..166cb43adb7d 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Расшифровать смарт-контракты" }, - "use4ByteResolutionDescription": { - "message": "Чтобы улучшить взаимодействие с пользователем, мы настраиваем вкладку действий, добавляя сообщения на основе смарт-контрактов, с которыми вы взаимодействуете. MetaMask использует службу под названием 4byte.directory для декодирования данных и показа версии смарт-контакта, которую легче читать. Это помогает снизить шансы того, что вы одобрите вредоносные действия смарт-контракта, но может привести к раскрытию вашего IP-адреса." - }, "useMultiAccountBalanceChecker": { "message": "Пакетные запросы баланса счета" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 327be7838680..9ec0374617a0 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "I-decode ang mga smart na kontrata" }, - "use4ByteResolutionDescription": { - "message": "Upang mapabuti ang karanasan ng user, kino-customize namin ang tab ng mga aktibidad gamit ang mga mensahe ayon sa mga smart na kontrata kung saan ka nakikipag-ugnayan. Gumagamit ang MetaMask ng serbisyong tinatawag na 4byte.directory para i-decode ang datos at ipakita sa iyo ang bersyon ng smart na kontrata na mas madaling basahin. Tumutulong ito na bawasan ang pagkakataon na aprubahan mo ang mga mapaminsalang aksyon sa smart na kontrata, ngunit maaaring magresulta sa pagbabahagi ng iyong IP address." - }, "useMultiAccountBalanceChecker": { "message": "Maramihang kahilingan sa balanse ng account" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 35ec9700e7d0..e4b47c473c46 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Akıllı sözleşmelerin şifresini çöz" }, - "use4ByteResolutionDescription": { - "message": "Kullanıcı deneyiminizi iyileştirmek amacıyla aktivite sekmesini etkileşimde bulunduğunuz akıllı sözleşmelere bağlı mesajlarla kişiselleştiririz. MetaMask, verileri çözmek ve size okunması daha kolay olan bir akıllı sözleşme sürümü göstermek için 4byte.directory adlı bir hizmet kullanır. Böylece kötü amaçlı akıllı sözleşme eylemlerini onaylama ihtimalinizi düşürmeye yardımcı olur ancak IP adresinizin paylaşılmasına neden olabilir." - }, "useMultiAccountBalanceChecker": { "message": "Toplu hesap bakiyesi talepleri" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 21b187998966..c72503787264 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "Giải mã hợp đồng thông minh" }, - "use4ByteResolutionDescription": { - "message": "Để cải thiện trải nghiệm người dùng, chúng tôi sẽ tùy chỉnh thẻ hoạt động bằng các thông báo dựa trên các hợp đồng thông minh mà bạn tương tác. MetaMask sử dụng một dịch vụ có tên là 4byte.directory để giải mã dữ liệu và cho bạn thấy một phiên bản hợp đồng thông minh dễ đọc hơn. Điều này giúp giảm nguy cơ chấp thuận các hành động hợp đồng thông minh độc hại, nhưng có thể khiến địa chỉ IP của bạn bị chia sẻ." - }, "useMultiAccountBalanceChecker": { "message": "Xử lý hàng loạt yêu cầu số dư tài khoản" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index 635753750343..54f86c50ec0e 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -6338,9 +6338,6 @@ "use4ByteResolution": { "message": "对智能合约进行解码" }, - "use4ByteResolutionDescription": { - "message": "为了改善用户体验,我们根据与您交互的智能合约消息,自定义活动选项卡。MetaMask 使用名为 4byte.directory 的服务来对数据进行解码,并向您显示更方便阅读的智能合约版本。这有助于减少您批准恶意智能合约操作的机会,但可能导致您的 IP 地址被共享。" - }, "useMultiAccountBalanceChecker": { "message": "账户余额分批请求" }, diff --git a/ui/helpers/constants/settings.js b/ui/helpers/constants/settings.js index 232bcdae5aff..adb3102da571 100644 --- a/ui/helpers/constants/settings.js +++ b/ui/helpers/constants/settings.js @@ -212,7 +212,7 @@ const SETTINGS_CONSTANTS = [ { tabMessage: (t) => t('securityAndPrivacy'), sectionMessage: (t) => t('use4ByteResolution'), - descriptionMessage: (t) => t('use4ByteResolutionDescription'), + descriptionMessage: (t) => t('toggleDecodeDescription'), route: `${SECURITY_ROUTE}#decode-smart-contracts`, icon: 'fa fa-lock', }, diff --git a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js index 163091e41958..b7c4e07aa9d6 100644 --- a/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js +++ b/ui/pages/onboarding-flow/privacy-settings/privacy-settings.js @@ -721,7 +721,7 @@ export default function PrivacySettings() { value={turnOn4ByteResolution} setValue={setTurnOn4ByteResolution} title={t('use4ByteResolution')} - description={t('use4ByteResolutionDescription')} + description={t('toggleDecodeDescription')} /> {t('use4ByteResolution')}
- {t('use4ByteResolutionDescription')} + {t('toggleDecodeDescription')}