Skip to content

Commit

Permalink
Hide alert if token transfer recipient is internal account
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewwalsh0 committed Dec 20, 2024
1 parent fde9fa1 commit b349f1f
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -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);
});
});
Original file line number Diff line number Diff line change
@@ -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<TransactionMeta>();

const transactionData = useTokenTransactionData();
const transactionTo = transactionMetadata?.txParams?.to;
const transferTo = transactionData?.args?._to as string | undefined;

return transferTo || transactionTo;
}
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -22,21 +19,15 @@ 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();

const { currentConfirmation: transactionMeta } =
useConfirmContext<TransactionMeta>();

const parsedTransactionData = useTokenTransactionData();

const recipientAddress =
transactionMeta.type === TransactionType.simpleSend
? transactionMeta.txParams.to
: parsedTransactionData?.args?._to;

const recipientAddress = useTransferRecipient();
const { chainId } = transactionMeta;

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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([]);
});
Expand All @@ -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([]);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionMeta>();
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(),
Expand Down

0 comments on commit b349f1f

Please sign in to comment.