diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.test.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.test.ts new file mode 100644 index 000000000000..2f0b709dc00c --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.test.ts @@ -0,0 +1,55 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { useTransferRecipient } from './useTransferRecipient'; +import { renderHookWithConfirmContextProvider } from '../../../../../../../test/lib/confirmations/render-helpers'; +import { getMockConfirmStateForTransaction } from '../../../../../../../test/data/confirmations/helper'; +import { genUnapprovedContractInteractionConfirmation } from '../../../../../../../test/data/confirmations/contract-interaction'; +import { genUnapprovedTokenTransferConfirmation } from '../../../../../../../test/data/confirmations/token-transfer'; + +const ADDRESS_MOCK = '0x2e0D7E8c45221FcA00d74a3609A0f7097035d09B'; + +const TRANSACTION_METADATA_MOCK = + genUnapprovedContractInteractionConfirmation() as TransactionMeta; + +function runHook(transaction?: TransactionMeta) { + const state = transaction + ? getMockConfirmStateForTransaction(transaction) + : {}; + + const { result } = renderHookWithConfirmContextProvider( + useTransferRecipient, + state, + ); + + return result.current as string | undefined; +} + +describe('useTransferRecipient', () => { + it('returns undefined if no transaction', () => { + expect(runHook()).toBeUndefined(); + }); + + it('returns transaction to address if no token data', () => { + expect( + runHook({ + ...TRANSACTION_METADATA_MOCK, + txParams: { + ...TRANSACTION_METADATA_MOCK.txParams, + to: ADDRESS_MOCK, + }, + }), + ).toBe(ADDRESS_MOCK); + }); + + it('returns transaction data to address if token transfer', () => { + expect( + runHook({ + ...TRANSACTION_METADATA_MOCK, + txParams: { + ...TRANSACTION_METADATA_MOCK.txParams, + to: '0x123', + data: genUnapprovedTokenTransferConfirmation().txParams.data, + }, + }), + ).toBe(ADDRESS_MOCK); + }); +}); diff --git a/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.ts b/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.ts new file mode 100644 index 000000000000..9dc69f97ef29 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/hooks/useTransferRecipient.ts @@ -0,0 +1,14 @@ +import { TransactionMeta } from '@metamask/transaction-controller'; +import { useTokenTransactionData } from './useTokenTransactionData'; +import { useConfirmContext } from '../../../../context/confirm'; + +export function useTransferRecipient() { + const { currentConfirmation: transactionMetadata } = + useConfirmContext(); + + const transactionData = useTokenTransactionData(); + const transactionTo = transactionMetadata?.txParams?.to; + const transferTo = transactionData?.args?._to as string | undefined; + + return transferTo || transactionTo; +} 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 fe9b9f319c9f..5ed2b103b809 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 @@ -1,7 +1,4 @@ -import { - TransactionMeta, - TransactionType, -} from '@metamask/transaction-controller'; +import { TransactionMeta } from '@metamask/transaction-controller'; import React from 'react'; import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; import { @@ -22,7 +19,7 @@ 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 { useTokenTransactionData } from '../hooks/useTokenTransactionData'; +import { useTransferRecipient } from '../hooks/useTransferRecipient'; export const TransactionFlowSection = () => { const t = useI18nContext(); @@ -30,13 +27,7 @@ export const TransactionFlowSection = () => { const { currentConfirmation: transactionMeta } = useConfirmContext(); - const parsedTransactionData = useTokenTransactionData(); - - const recipientAddress = - transactionMeta.type === TransactionType.simpleSend - ? transactionMeta.txParams.to - : parsedTransactionData?.args?._to; - + const recipientAddress = useTransferRecipient(); const { chainId } = transactionMeta; return ( diff --git a/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.test.ts b/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.test.ts index 93da09a9674e..c2e54357468e 100644 --- a/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.test.ts +++ b/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.test.ts @@ -1,17 +1,19 @@ -import { ApprovalType } from '@metamask/controller-utils'; import { TransactionMeta, TransactionStatus, TransactionType, } from '@metamask/transaction-controller'; -import { getMockConfirmState } from '../../../../../../test/data/confirmations/helper'; +import { getMockConfirmStateForTransaction } from '../../../../../../test/data/confirmations/helper'; import { renderHookWithConfirmContextProvider } from '../../../../../../test/lib/confirmations/render-helpers'; import { Severity } from '../../../../../helpers/constants/design-system'; import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; +import { genUnapprovedTokenTransferConfirmation } from '../../../../../../test/data/confirmations/token-transfer'; import { useFirstTimeInteractionAlert } from './useFirstTimeInteractionAlert'; -const ACCOUNT_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; +const ACCOUNT_ADDRESS_MOCK = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; +const ACCOUNT_ADDRESS_2_MOCK = '0x2e0d7e8c45221fca00d74a3609a0f7097035d09b'; +const CONTRACT_ADDRESS_MOCK = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7be'; const TRANSACTION_ID_MOCK = '123-456'; const TRANSACTION_META_MOCK = { @@ -21,7 +23,7 @@ const TRANSACTION_META_MOCK = { status: TransactionStatus.unapproved, type: TransactionType.contractInteraction, txParams: { - from: ACCOUNT_ADDRESS, + from: ACCOUNT_ADDRESS_MOCK, }, time: new Date().getTime() - 10000, } as TransactionMeta; @@ -33,28 +35,20 @@ function runHook({ currentConfirmation?: TransactionMeta; internalAccountAddresses?: string[]; } = {}) { - const pendingApprovals = currentConfirmation - ? { - [currentConfirmation.id as string]: { - id: currentConfirmation.id, - type: ApprovalType.Transaction, - }, - } - : {}; - - const transactions = currentConfirmation ? [currentConfirmation] : []; - const internalAccounts = { accounts: internalAccountAddresses?.map((address) => ({ address })) ?? [], }; - const state = getMockConfirmState({ - metamask: { - internalAccounts, - pendingApprovals, - transactions, - }, - }); + const state = currentConfirmation + ? getMockConfirmStateForTransaction( + currentConfirmation as TransactionMeta, + { + metamask: { + internalAccounts, + }, + }, + ) + : {}; const response = renderHookWithConfirmContextProvider( useFirstTimeInteractionAlert, @@ -103,13 +97,31 @@ describe('useFirstTimeInteractionAlert', () => { isFirstTimeInteraction: true, txParams: { ...TRANSACTION_META_MOCK.txParams, - to: ACCOUNT_ADDRESS, + to: ACCOUNT_ADDRESS_2_MOCK, + }, + }; + expect( + runHook({ + currentConfirmation: firstTimeConfirmation, + internalAccountAddresses: [ACCOUNT_ADDRESS_2_MOCK], + }), + ).toEqual([]); + }); + + it('returns no alerts if token transfer recipient is internal account', () => { + const firstTimeConfirmation = { + ...TRANSACTION_META_MOCK, + isFirstTimeInteraction: true, + txParams: { + ...TRANSACTION_META_MOCK.txParams, + to: CONTRACT_ADDRESS_MOCK, + data: genUnapprovedTokenTransferConfirmation().txParams.data, }, }; expect( runHook({ currentConfirmation: firstTimeConfirmation, - internalAccountAddresses: [ACCOUNT_ADDRESS], + internalAccountAddresses: [ACCOUNT_ADDRESS_2_MOCK], }), ).toEqual([]); }); @@ -120,13 +132,13 @@ describe('useFirstTimeInteractionAlert', () => { isFirstTimeInteraction: true, txParams: { ...TRANSACTION_META_MOCK.txParams, - to: ACCOUNT_ADDRESS.toLowerCase(), + to: ACCOUNT_ADDRESS_2_MOCK.toLowerCase(), }, }; expect( runHook({ currentConfirmation: firstTimeConfirmation, - internalAccountAddresses: [ACCOUNT_ADDRESS.toUpperCase()], + internalAccountAddresses: [ACCOUNT_ADDRESS_2_MOCK.toUpperCase()], }), ).toEqual([]); }); diff --git a/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.ts b/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.ts index c74552575667..f83f5d1ce30e 100644 --- a/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.ts +++ b/ui/pages/confirmations/hooks/alerts/transactions/useFirstTimeInteractionAlert.ts @@ -8,14 +8,14 @@ import { Severity } from '../../../../../helpers/constants/design-system'; import { RowAlertKey } from '../../../../../components/app/confirm/info/row/constants'; import { useConfirmContext } from '../../../context/confirm'; import { getInternalAccounts } from '../../../../../selectors'; +import { useTransferRecipient } from '../../../components/confirm/info/hooks/useTransferRecipient'; export function useFirstTimeInteractionAlert(): Alert[] { const t = useI18nContext(); const { currentConfirmation } = useConfirmContext(); const internalAccounts = useSelector(getInternalAccounts); - - const { txParams, isFirstTimeInteraction } = currentConfirmation ?? {}; - const { to } = txParams ?? {}; + const to = useTransferRecipient(); + const { isFirstTimeInteraction } = currentConfirmation ?? {}; const isInternalAccount = internalAccounts.some( (account) => account.address?.toLowerCase() === to?.toLowerCase(),