From f5ff18487810d2cd78b3559bc538446b5e9a3b89 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Tue, 18 Jun 2024 14:32:39 +0100 Subject: [PATCH 1/9] Add paymaster row to transaction details Add info section component. Add contract interaction stories. Add paymaster address selector. --- .storybook/images/icons/question.svg | 3 + .../app/confirm/info/row/section.tsx | 23 +++++ .../mmi-signature-mismatch-banner.tsx | 4 +- .../contract-interaction.tsx | 18 +--- .../info/shared/transaction-details.tsx | 40 ++++++++- .../confirmations/confirm/confirm.stories.tsx | 86 +++++++++++++++++-- ui/selectors/account-abstraction.ts | 17 ++++ 7 files changed, 165 insertions(+), 26 deletions(-) create mode 100644 .storybook/images/icons/question.svg create mode 100644 ui/components/app/confirm/info/row/section.tsx diff --git a/.storybook/images/icons/question.svg b/.storybook/images/icons/question.svg new file mode 100644 index 000000000000..a8ba55cd769d --- /dev/null +++ b/.storybook/images/icons/question.svg @@ -0,0 +1,3 @@ + + + diff --git a/ui/components/app/confirm/info/row/section.tsx b/ui/components/app/confirm/info/row/section.tsx new file mode 100644 index 000000000000..5160c727f7f5 --- /dev/null +++ b/ui/components/app/confirm/info/row/section.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Box } from '../../../../component-library'; +import { + BackgroundColor, + BorderRadius, +} from '../../../../../helpers/constants/design-system'; + +export const ConfirmInfoSection = ({ + children, +}: { + children: React.ReactNode | string; +}) => { + return ( + + {children} + + ); +}; diff --git a/ui/components/app/mmi-signature-mismatch-banner/mmi-signature-mismatch-banner.tsx b/ui/components/app/mmi-signature-mismatch-banner/mmi-signature-mismatch-banner.tsx index 3fd8d7449d53..4d1e2a583c61 100644 --- a/ui/components/app/mmi-signature-mismatch-banner/mmi-signature-mismatch-banner.tsx +++ b/ui/components/app/mmi-signature-mismatch-banner/mmi-signature-mismatch-banner.tsx @@ -48,8 +48,8 @@ const MMISignatureMismatchBanner: React.FC = memo(() => { }, [currentConfirmation, allAccounts]); if ( - selectedAccount && - fromAccount && + !selectedAccount || + !fromAccount || selectedAccount.address === fromAccount.address ) { return null; diff --git a/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx b/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx index 0f5af1d92ed7..e421b65636cf 100644 --- a/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx +++ b/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx @@ -9,6 +9,7 @@ import { import { currentConfirmationSelector } from '../../../../../../selectors'; import { SimulationDetails } from '../../../simulation-details'; import { TransactionDetails } from '../shared/transaction-details'; +import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; const ContractInteractionInfo: React.FC = () => { const currentConfirmation = useSelector( @@ -21,25 +22,14 @@ const ContractInteractionInfo: React.FC = () => { return ( <> - + - - - - + + ); }; diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx index b135f0dc3008..0b8117839204 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx @@ -11,6 +11,11 @@ import { import { useI18nContext } from '../../../../../../hooks/useI18nContext'; import { currentConfirmationSelector } from '../../../../selectors'; import { useKnownMethodDataInTransaction } from '../hooks/known-method-data-in-transaction'; +import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; +import { + selectPaymasterAddress, + selectUserOperationMetadata, +} from '../../../../../../selectors/account-abstraction'; const OriginRow = () => { const t = useI18nContext(); @@ -83,12 +88,41 @@ const MethodDataRow = () => { ); }; +const PaymasterRow = () => { + const currentConfirmation = useSelector(currentConfirmationSelector) as + | TransactionMeta + | undefined; + + const { id: userOperationId } = currentConfirmation ?? {}; + const isUserOperation = Boolean(currentConfirmation?.isUserOperation); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const paymasterAddress = useSelector((state: any) => + selectPaymasterAddress(state, userOperationId as string), + ); + + if (!isUserOperation || !paymasterAddress) { + return null; + } + + return ( + + + + + + ); +}; + export const TransactionDetails = () => { return ( <> - - - + + + + + + ); }; diff --git a/ui/pages/confirmations/confirm/confirm.stories.tsx b/ui/pages/confirmations/confirm/confirm.stories.tsx index 3e428eba997f..ec7a810e62a8 100644 --- a/ui/pages/confirmations/confirm/confirm.stories.tsx +++ b/ui/pages/confirmations/confirm/confirm.stories.tsx @@ -1,8 +1,19 @@ import React from 'react'; import { Provider } from 'react-redux'; import { cloneDeep } from 'lodash'; -import { unapprovedPersonalSignMsg, signatureRequestSIWE } from '../../../../test/data/confirmations/personal_sign'; -import { unapprovedTypedSignMsgV1, unapprovedTypedSignMsgV4, permitSignatureMsg } from '../../../../test/data/confirmations/typed_sign'; +import { + unapprovedPersonalSignMsg, + signatureRequestSIWE, +} from '../../../../test/data/confirmations/personal_sign'; +import { + unapprovedTypedSignMsgV1, + unapprovedTypedSignMsgV4, + permitSignatureMsg, +} from '../../../../test/data/confirmations/typed_sign'; +import { + DEPOSIT_METHOD_DATA, + genUnapprovedContractInteractionConfirmation, +} from '../../../../test/data/confirmations/contract-interaction'; import mockState from '../../../../test/data/mock-state.json'; import configureStore from '../../../store/store'; import ConfirmPage from './confirm'; @@ -13,19 +24,21 @@ import ConfirmPage from './confirm'; */ const ConfirmPageStory = { title: 'Pages/Confirm/ConfirmPage', - decorators: [(story) =>
{story()}
], -} + decorators: [ + (story) =>
{story()}
, + ], +}; const ARGS_SIGNATURE = { msgParams: { ...unapprovedPersonalSignMsg.msgParams }, -} +}; const ARG_TYPES_SIGNATURE = { msgParams: { control: 'object', description: '(non-param) overrides currentConfirmation.msgParams', }, -} +}; function SignatureStoryTemplate(args, confirmation) { const mockConfirmation = cloneDeep(confirmation); @@ -38,7 +51,28 @@ function SignatureStoryTemplate(args, confirmation) { metamask: { ...mockState.metamask }, }); - return ; + return ( + + + + ); +} + +function TransactionStoryTemplate(confirmation, additionalState = {}) { + const mockConfirmation = cloneDeep(confirmation); + + const store = configureStore({ + confirm: { + currentConfirmation: mockConfirmation, + }, + metamask: { ...mockState.metamask, ...additionalState }, + }); + + return ( + + + + ); } export const PersonalSignStory = (args) => { @@ -93,4 +127,42 @@ SignTypedDataV4Story.args = { msgParams: unapprovedTypedSignMsgV4.msgParams, }; +export const ContractInteractionStory = () => { + const confirmation = genUnapprovedContractInteractionConfirmation({ + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + txData: DEPOSIT_METHOD_DATA, + }); + + return TransactionStoryTemplate(confirmation); +}; + +ContractInteractionStory.storyName = 'Contract Interaction'; + +export const UserOperationStory = () => { + const confirmation = { + ...genUnapprovedContractInteractionConfirmation({ + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + txData: DEPOSIT_METHOD_DATA, + }), + isUserOperation: true, + }; + + return TransactionStoryTemplate(confirmation, { + preferences: { + ...mockState.metamask.preferences, + petnamesEnabled: true, + }, + userOperations: { + [confirmation.id]: { + userOperation: { + paymasterAndData: + '0x9d6ac51b972544251fcc0f2902e633e3f9bd3f2900000000000000000000000000000000000000000000000000000000666bfd410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003498a76eb88b702e5e52b00fbc16a36baf89ebe3e0dd23170949cffc0a623011383cced660ff67930308c22e5aa746a2d586629ddbd87046a146225bf80e9d6f1b', + }, + }, + }, + }); +}; + +UserOperationStory.storyName = 'User Operation'; + export default ConfirmPageStory; diff --git a/ui/selectors/account-abstraction.ts b/ui/selectors/account-abstraction.ts index a8f420fd7fed..77b191d34b20 100644 --- a/ui/selectors/account-abstraction.ts +++ b/ui/selectors/account-abstraction.ts @@ -39,3 +39,20 @@ export function getIsUsingPaymaster(state: AccountAbstractionState) { return Boolean(paymasterData?.length) && paymasterData !== '0x'; } + +export const selectPaymasterData = createSelector( + selectUserOperationMetadata, + (userOperationMetadata) => { + const paymasterAndData = + userOperationMetadata?.userOperation?.paymasterAndData; + + return paymasterAndData === '0x' ? undefined : paymasterAndData; + }, +); + +export const selectPaymasterAddress = createSelector( + selectPaymasterData, + (paymasterData) => { + return paymasterData?.slice(0, 42); + }, +); From ebc0cfaba10181582a8feab1a110e5d2b96f9ea4 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Tue, 18 Jun 2024 20:16:33 +0100 Subject: [PATCH 2/9] Add stories and tests for section component --- .../row/__snapshots__/section.test.tsx.snap | 21 +++++++ .../app/confirm/info/row/divider.tsx | 2 + .../app/confirm/info/row/section.stories.tsx | 55 +++++++++++++++++++ .../app/confirm/info/row/section.test.tsx | 19 +++++++ .../app/confirm/info/row/section.tsx | 12 ++-- .../contract-interaction.tsx | 7 +-- .../info/personal-sign/personal-sign.tsx | 33 +++-------- .../info/shared/transaction-details.tsx | 5 +- .../info/typed-sign-v1/typed-sign-v1.tsx | 24 ++------ .../permit-simulation/permit-simulation.tsx | 10 +--- .../confirm/info/typed-sign/typed-sign.tsx | 51 +++++------------ .../signature-message/signature-message.tsx | 15 +---- 12 files changed, 139 insertions(+), 115 deletions(-) create mode 100644 ui/components/app/confirm/info/row/__snapshots__/section.test.tsx.snap create mode 100644 ui/components/app/confirm/info/row/section.stories.tsx create mode 100644 ui/components/app/confirm/info/row/section.test.tsx diff --git a/ui/components/app/confirm/info/row/__snapshots__/section.test.tsx.snap b/ui/components/app/confirm/info/row/__snapshots__/section.test.tsx.snap new file mode 100644 index 000000000000..8f48917bd4f3 --- /dev/null +++ b/ui/components/app/confirm/info/row/__snapshots__/section.test.tsx.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ConfirmInfoSection should match snapshot 1`] = ` +
+
+ Test Content +
+
+`; + +exports[`ConfirmInfoSection should match snapshot without padding 1`] = ` +
+
+ Test Content +
+
+`; diff --git a/ui/components/app/confirm/info/row/divider.tsx b/ui/components/app/confirm/info/row/divider.tsx index cc2c1ac70e2a..94fc4bb7062e 100644 --- a/ui/components/app/confirm/info/row/divider.tsx +++ b/ui/components/app/confirm/info/row/divider.tsx @@ -6,6 +6,8 @@ export const ConfirmInfoRowDivider: React.FC = () => { style={{ height: '1px', backgroundColor: 'var(--color-border-muted)', + marginLeft: '-8px', + marginRight: '-8px', }} > ); diff --git a/ui/components/app/confirm/info/row/section.stories.tsx b/ui/components/app/confirm/info/row/section.stories.tsx new file mode 100644 index 000000000000..8ce7be068ffb --- /dev/null +++ b/ui/components/app/confirm/info/row/section.stories.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { ConfirmInfoSection } from './section'; +import { ConfirmInfoRow } from './row'; +import { ConfirmInfoRowText } from './text'; + +const ConfirmInfoSectionStory = { + title: 'Components/App/Confirm/InfoSection', + component: ConfirmInfoSection, + + decorators: [ + (story) => ( +
+ {story()} +
+ ), + ], + + argTypes: { + noPadding: { + control: 'boolean', + }, + }, +}; + +export const DefaultStory = (args) => ( + <> + + + + + + + + + + + + + + + + + +); + +DefaultStory.args = { + noPadding: false, +}; + +export default ConfirmInfoSectionStory; diff --git a/ui/components/app/confirm/info/row/section.test.tsx b/ui/components/app/confirm/info/row/section.test.tsx new file mode 100644 index 000000000000..e9c344caf0cb --- /dev/null +++ b/ui/components/app/confirm/info/row/section.test.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { ConfirmInfoSection } from './section'; + +describe('ConfirmInfoSection', () => { + it('should match snapshot', () => { + const { container } = render( + Test Content, + ); + expect(container).toMatchSnapshot(); + }); + + it('should match snapshot without padding', () => { + const { container } = render( + Test Content, + ); + expect(container).toMatchSnapshot(); + }); +}); diff --git a/ui/components/app/confirm/info/row/section.tsx b/ui/components/app/confirm/info/row/section.tsx index 5160c727f7f5..f49c8103fae4 100644 --- a/ui/components/app/confirm/info/row/section.tsx +++ b/ui/components/app/confirm/info/row/section.tsx @@ -5,16 +5,20 @@ import { BorderRadius, } from '../../../../../helpers/constants/design-system'; +export type ConfirmInfoSectionProps = { + children: React.ReactNode | string; + noPadding?: boolean; +}; + export const ConfirmInfoSection = ({ children, -}: { - children: React.ReactNode | string; -}) => { + noPadding, +}: ConfirmInfoSectionProps) => { return ( {children} diff --git a/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx b/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx index e421b65636cf..86bc508ae6a4 100644 --- a/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx +++ b/ui/pages/confirmations/components/confirm/info/contract-interaction/contract-interaction.tsx @@ -1,11 +1,6 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import React from 'react'; import { useSelector } from 'react-redux'; -import { Box } from '../../../../../../components/component-library'; -import { - BackgroundColor, - BorderRadius, -} from '../../../../../../helpers/constants/design-system'; import { currentConfirmationSelector } from '../../../../../../selectors'; import { SimulationDetails } from '../../../simulation-details'; import { TransactionDetails } from '../shared/transaction-details'; @@ -22,7 +17,7 @@ const ContractInteractionInfo: React.FC = () => { return ( <> - + { @@ -43,26 +39,16 @@ const PersonalSignInfo: React.FC = () => { return ( <> {isSIWE && useTransactionSimulations && ( - + - + )} - + { )} - - + + {isSIWE ? ( ) : ( @@ -98,7 +79,7 @@ const PersonalSignInfo: React.FC = () => { /> )} - + ); }; diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx index 0b8117839204..3c2ce1a82034 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx @@ -12,10 +12,7 @@ import { useI18nContext } from '../../../../../../hooks/useI18nContext'; import { currentConfirmationSelector } from '../../../../selectors'; import { useKnownMethodDataInTransaction } from '../hooks/known-method-data-in-transaction'; import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; -import { - selectPaymasterAddress, - selectUserOperationMetadata, -} from '../../../../../../selectors/account-abstraction'; +import { selectPaymasterAddress } from '../../../../../../selectors/account-abstraction'; const OriginRow = () => { const t = useI18nContext(); diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx index a9b776daa529..a2ed4e554e2f 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign-v1/typed-sign-v1.tsx @@ -7,16 +7,12 @@ import { } from '../../../../../../components/app/confirm/info/row'; import { useI18nContext } from '../../../../../../hooks/useI18nContext'; import { currentConfirmationSelector } from '../../../../../../selectors'; -import { Box } from '../../../../../../components/component-library'; -import { - BackgroundColor, - BorderRadius, -} from '../../../../../../helpers/constants/design-system'; import { SignatureRequestType, TypedSignDataV1Type, } from '../../../../types/confirm'; import { ConfirmInfoRowTypedSignDataV1 } from '../../row/typed-sign-data-v1/typedSignDataV1'; +import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; const TypedSignV1Info: React.FC = () => { const t = useI18nContext(); @@ -30,28 +26,18 @@ const TypedSignV1Info: React.FC = () => { return ( <> - + - - + + - + ); }; diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx index 6aa8ec159ec0..665f9190f4aa 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx @@ -21,6 +21,7 @@ import { import { SignatureRequestType } from '../../../../../types/confirm'; import useTokenExchangeRate from '../../../../../../../components/app/currency-input/hooks/useTokenExchangeRate'; import { IndividualFiatDisplay } from '../../../../simulation-details/fiat-display'; +import { ConfirmInfoSection } from '../../../../../../../components/app/confirm/info/row/section'; const PermitSimulation: React.FC = () => { const t = useI18nContext(); @@ -43,12 +44,7 @@ const PermitSimulation: React.FC = () => { }, [exchangeRate, value]); return ( - + { - + ); }; diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx index 766ef740e952..f6efca236f3a 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.tsx @@ -11,15 +11,11 @@ import { } from '../../../../../../components/app/confirm/info/row'; import { useI18nContext } from '../../../../../../hooks/useI18nContext'; import { currentConfirmationSelector } from '../../../../../../selectors'; -import { Box } from '../../../../../../components/component-library'; -import { - BackgroundColor, - BorderRadius, -} from '../../../../../../helpers/constants/design-system'; import { SignatureRequestType } from '../../../../types/confirm'; import { isPermitSignatureRequest } from '../../../../utils'; import { selectUseTransactionSimulations } from '../../../../selectors/preferences'; import { ConfirmInfoRowTypedSignData } from '../../row/typed-sign-data/typedSignData'; +import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; import { PermitSimulation } from './permit-simulation'; const TypedSignInfo: React.FC = () => { @@ -45,50 +41,31 @@ const TypedSignInfo: React.FC = () => { return ( <> {isPermit && useTransactionSimulations && } - + {isPermit && ( <> - - - - - + + + )} - - - - - + + + {isValidAddress(verifyingContract) && ( - - - - - + + + )} - - + + - + ); }; diff --git a/ui/pages/confirmations/components/confirm/signature-message/signature-message.tsx b/ui/pages/confirmations/components/confirm/signature-message/signature-message.tsx index 5b37a251a8b0..f3a49d7015d9 100644 --- a/ui/pages/confirmations/components/confirm/signature-message/signature-message.tsx +++ b/ui/pages/confirmations/components/confirm/signature-message/signature-message.tsx @@ -1,19 +1,15 @@ import React, { memo } from 'react'; import { useSelector } from 'react-redux'; -import { - BackgroundColor, - BorderRadius, -} from '../../../../../helpers/constants/design-system'; import { hexToText } from '../../../../../helpers/utils/util'; import { useI18nContext } from '../../../../../hooks/useI18nContext'; import { currentConfirmationSelector } from '../../../../../selectors'; -import { Box } from '../../../../../components/component-library'; import { ConfirmInfoRow, ConfirmInfoRowText, } from '../../../../../components/app/confirm/info/row'; import { SignatureRequestType } from '../../../types/confirm'; +import { ConfirmInfoSection } from '../../../../../components/app/confirm/info/row/section'; const SignatureMessage: React.FC = memo(() => { const t = useI18nContext(); @@ -26,18 +22,13 @@ const SignatureMessage: React.FC = memo(() => { } return ( - + - + ); }); From 8fb5c58b921fe785ce16adce0bfbafbdd220125b Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Tue, 18 Jun 2024 21:01:40 +0100 Subject: [PATCH 3/9] Add translations --- app/_locales/en/messages.json | 6 +++ .../confirmations/contract-interaction.ts | 3 ++ .../shared/transaction-details.stories.tsx | 48 +++++++++++++++---- .../info/shared/transaction-details.tsx | 7 ++- .../confirmations/confirm/confirm.stories.tsx | 8 ++-- 5 files changed, 58 insertions(+), 14 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index be8313a1fb4a..9c2a271a79ca 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -900,6 +900,12 @@ "confirmConnectionTitle": { "message": "Confirm connection to $1" }, + "confirmFieldPaymaster": { + "message": "Fee paid by" + }, + "confirmFieldTooltipPaymaster": { + "message": "This is the address of the paymaster smart contract that will provide the gas fee for this user operation." + }, "confirmPassword": { "message": "Confirm password" }, diff --git a/test/data/confirmations/contract-interaction.ts b/test/data/confirmations/contract-interaction.ts index dd0500bbaec2..55bcb4b26ad0 100644 --- a/test/data/confirmations/contract-interaction.ts +++ b/test/data/confirmations/contract-interaction.ts @@ -4,6 +4,9 @@ import { } from '@metamask/transaction-controller'; import { Confirmation } from '../../../ui/pages/confirmations/types/confirm'; +export const PAYMASTER_AND_DATA = + '0x9d6ac51b972544251fcc0f2902e633e3f9bd3f2900000000000000000000000000000000000000000000000000000000666bfd410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003498a76eb88b702e5e52b00fbc16a36baf89ebe3e0dd23170949cffc0a623011383cced660ff67930308c22e5aa746a2d586629ddbd87046a146225bf80e9d6f1b'; + export const CONTRACT_INTERACTION_SENDER_ADDRESS = '0x2e0d7e8c45221fca00d74a3609a0f7097035d09b'; diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.stories.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.stories.tsx index 200f67ba65ef..ee70b2eeaadc 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.stories.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.stories.tsx @@ -1,24 +1,56 @@ import { Meta } from '@storybook/react'; import React from 'react'; import { Provider } from 'react-redux'; -import { genUnapprovedContractInteractionConfirmation } from '../../../../../../../test/data/confirmations/contract-interaction'; +import { + PAYMASTER_AND_DATA, + genUnapprovedContractInteractionConfirmation, +} from '../../../../../../../test/data/confirmations/contract-interaction'; import mockState from '../../../../../../../test/data/mock-state.json'; import configureStore from '../../../../../../store/store'; import { TransactionDetails } from './transaction-details'; -const store = configureStore({ - metamask: { ...mockState.metamask }, - confirm: { - currentConfirmation: genUnapprovedContractInteractionConfirmation(), - }, -}); +function getStore() { + const confirmation = { + ...genUnapprovedContractInteractionConfirmation(), + isUserOperation: true, + }; + + return configureStore({ + metamask: { + ...mockState.metamask, + preferences: { + ...mockState.metamask.preferences, + petnamesEnabled: true, + }, + userOperations: { + [confirmation.id]: { + userOperation: { + paymasterAndData: PAYMASTER_AND_DATA, + }, + }, + }, + }, + confirm: { + currentConfirmation: confirmation, + }, + }); +} const Story = { title: 'Components/App/Confirm/info/TransactionDetails', component: TransactionDetails, decorators: [ (story: () => Meta) => ( - {story()} + +
+ {story()} +
+
), ], }; diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx index 3c2ce1a82034..8b1907ddf1aa 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx @@ -86,6 +86,8 @@ const MethodDataRow = () => { }; const PaymasterRow = () => { + const t = useI18nContext(); + const currentConfirmation = useSelector(currentConfirmationSelector) as | TransactionMeta | undefined; @@ -104,7 +106,10 @@ const PaymasterRow = () => { return ( - + diff --git a/ui/pages/confirmations/confirm/confirm.stories.tsx b/ui/pages/confirmations/confirm/confirm.stories.tsx index ec7a810e62a8..fb7d9630132c 100644 --- a/ui/pages/confirmations/confirm/confirm.stories.tsx +++ b/ui/pages/confirmations/confirm/confirm.stories.tsx @@ -12,6 +12,7 @@ import { } from '../../../../test/data/confirmations/typed_sign'; import { DEPOSIT_METHOD_DATA, + PAYMASTER_AND_DATA, genUnapprovedContractInteractionConfirmation, } from '../../../../test/data/confirmations/contract-interaction'; import mockState from '../../../../test/data/mock-state.json'; @@ -24,9 +25,7 @@ import ConfirmPage from './confirm'; */ const ConfirmPageStory = { title: 'Pages/Confirm/ConfirmPage', - decorators: [ - (story) =>
{story()}
, - ], + decorators: [(story) =>
{story()}
], }; const ARGS_SIGNATURE = { @@ -155,8 +154,7 @@ export const UserOperationStory = () => { userOperations: { [confirmation.id]: { userOperation: { - paymasterAndData: - '0x9d6ac51b972544251fcc0f2902e633e3f9bd3f2900000000000000000000000000000000000000000000000000000000666bfd410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003498a76eb88b702e5e52b00fbc16a36baf89ebe3e0dd23170949cffc0a623011383cced660ff67930308c22e5aa746a2d586629ddbd87046a146225bf80e9d6f1b', + paymasterAndData: PAYMASTER_AND_DATA, }, }, }, From 3ee3667159b2b643af14f23acefdb2f699727bc7 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Wed, 19 Jun 2024 11:53:05 +0100 Subject: [PATCH 4/9] Move paymaster alert to paymaster field --- .../confirm/info/row/alert-row/alert-row.stories.tsx | 8 ++++---- .../app/confirm/info/row/alert-row/alert-row.test.tsx | 6 +++--- .../app/confirm/info/row/alert-row/alert-row.tsx | 6 +++--- .../confirm/info/personal-sign/personal-sign.tsx | 10 +++++----- .../confirm/info/shared/transaction-details.tsx | 8 ++++++-- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ui/components/app/confirm/info/row/alert-row/alert-row.stories.tsx b/ui/components/app/confirm/info/row/alert-row/alert-row.stories.tsx index b3d64ac65651..c6b9a3664375 100644 --- a/ui/components/app/confirm/info/row/alert-row/alert-row.stories.tsx +++ b/ui/components/app/confirm/info/row/alert-row/alert-row.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { ConfirmInfoRowVariant } from '../row'; -import { AlertRow } from './alert-row'; +import { ConfirmInfoAlertRow } from './alert-row'; import configureStore from '../../../../../../store/store'; import { Provider } from 'react-redux'; import { Meta } from '@storybook/react'; @@ -41,7 +41,7 @@ const storeMock = configureStore({ const ConfirmInfoRowStory = { title: 'Components/App/Confirm/AlertRow', - component: AlertRow, + component: ConfirmInfoAlertRow, argTypes: { variant: { control: 'select', @@ -55,9 +55,9 @@ const ConfirmInfoRowStory = { }, }, decorators: [(story) => {story()}], -} as Meta; +} as Meta; -export const DefaultStory = (args) => ; +export const DefaultStory = (args) => ; DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/confirm/info/row/alert-row/alert-row.test.tsx b/ui/components/app/confirm/info/row/alert-row/alert-row.test.tsx index 968c4238509a..f539326a9284 100644 --- a/ui/components/app/confirm/info/row/alert-row/alert-row.test.tsx +++ b/ui/components/app/confirm/info/row/alert-row/alert-row.test.tsx @@ -5,7 +5,7 @@ import { Text } from '../../../../../component-library'; import { renderWithProvider } from '../../../../../../../test/lib/render-helpers'; import { Severity } from '../../../../../../helpers/constants/design-system'; import mockState from '../../../../../../../test/data/mock-state.json'; -import { AlertRow, AlertRowProps } from './alert-row'; +import { ConfirmInfoAlertRow, ConfirmInfoAlertRowProps } from './alert-row'; const onProcessActionMock = jest.fn(); @@ -36,7 +36,7 @@ describe('AlertRow', () => { }, ]; const renderAlertRow = ( - props?: Partial, + props?: Partial, state?: Record, ) => { const STATE_MOCK = { @@ -60,7 +60,7 @@ describe('AlertRow', () => { const mockStore = configureMockStore([])(STATE_MOCK); return renderWithProvider( - value} ownerId={OWNER_ID_NO_ALERT_MOCK} diff --git a/ui/components/app/confirm/info/row/alert-row/alert-row.tsx b/ui/components/app/confirm/info/row/alert-row/alert-row.tsx index ef84818904ad..919f77286233 100644 --- a/ui/components/app/confirm/info/row/alert-row/alert-row.tsx +++ b/ui/components/app/confirm/info/row/alert-row/alert-row.tsx @@ -13,7 +13,7 @@ import { import { Box } from '../../../../../component-library'; import { MultipleAlertModal } from '../../../../alert-system/multiple-alert-modal'; -export type AlertRowProps = ConfirmInfoRowProps & { +export type ConfirmInfoAlertRowProps = ConfirmInfoRowProps & { alertKey: string; ownerId: string; }; @@ -36,12 +36,12 @@ function getAlertTextColors( } } -export const AlertRow = ({ +export const ConfirmInfoAlertRow = ({ alertKey, ownerId, variant, ...rowProperties -}: AlertRowProps) => { +}: ConfirmInfoAlertRowProps) => { const { getFieldAlerts } = useAlerts(ownerId); const fieldAlerts = getFieldAlerts(alertKey); const hasFieldAlert = fieldAlerts.length > 0; diff --git a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx index 75e35e143d54..f94dd25f5fe0 100644 --- a/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx +++ b/ui/pages/confirmations/components/confirm/info/personal-sign/personal-sign.tsx @@ -16,7 +16,7 @@ import { import { SignatureRequestType } from '../../../../types/confirm'; import { selectUseTransactionSimulations } from '../../../../selectors/preferences'; import { isSIWESignatureRequest } from '../../../../utils'; -import { AlertRow } from '../../../../../../components/app/confirm/info/row/alert-row/alert-row'; +import { ConfirmInfoAlertRow } from '../../../../../../components/app/confirm/info/row/alert-row/alert-row'; import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; import { SIWESignInfo } from './siwe-sign'; @@ -49,14 +49,14 @@ const PersonalSignInfo: React.FC = () => { )} - - + {isSIWE && ( @@ -67,7 +67,7 @@ const PersonalSignInfo: React.FC = () => { {isSIWE ? ( ) : ( - { hexToText(currentConfirmation.msgParams?.data), )} /> - + )} diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx index 8b1907ddf1aa..b10f783407cf 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx @@ -13,6 +13,8 @@ import { currentConfirmationSelector } from '../../../../selectors'; import { useKnownMethodDataInTransaction } from '../hooks/known-method-data-in-transaction'; import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; import { selectPaymasterAddress } from '../../../../../../selectors/account-abstraction'; +import { ConfirmInfoAlertRow } from '../../../../../../components/app/confirm/info/row/alert-row/alert-row'; +import { RowAlertKey } from '../../../../../../components/app/confirm/info/row/constants'; const OriginRow = () => { const t = useI18nContext(); @@ -106,12 +108,14 @@ const PaymasterRow = () => { return ( - - + ); }; From dd2f5284bcc5506d00ba9160d49a94c526443b4e Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Wed, 19 Jun 2024 12:31:04 +0100 Subject: [PATCH 5/9] Fix unit tests --- .../info/__snapshots__/info.test.tsx.snap | 2 +- .../row/__snapshots__/divider.test.tsx.snap | 2 +- .../app/confirm/info/row/divider.tsx | 1 + .../info/__snapshots__/info.test.tsx.snap | 156 +++--- .../contract-interaction.test.tsx.snap | 2 +- .../transaction-details.test.tsx.snap | 188 +++---- .../__snapshots__/typed-sign.test.tsx.snap | 468 +++++++++--------- .../__snapshots__/confirm.test.tsx.snap | 182 +++---- 8 files changed, 473 insertions(+), 528 deletions(-) diff --git a/ui/components/app/confirm/info/__snapshots__/info.test.tsx.snap b/ui/components/app/confirm/info/__snapshots__/info.test.tsx.snap index 1054ecabe66a..a257e3ee3fa8 100644 --- a/ui/components/app/confirm/info/__snapshots__/info.test.tsx.snap +++ b/ui/components/app/confirm/info/__snapshots__/info.test.tsx.snap @@ -77,7 +77,7 @@ exports[`ConfirmInfo should match snapshot 1`] = `
`; diff --git a/ui/components/app/confirm/info/row/divider.tsx b/ui/components/app/confirm/info/row/divider.tsx index 94fc4bb7062e..98c09840f4bb 100644 --- a/ui/components/app/confirm/info/row/divider.tsx +++ b/ui/components/app/confirm/info/row/divider.tsx @@ -6,6 +6,7 @@ export const ConfirmInfoRowDivider: React.FC = () => { style={{ height: '1px', backgroundColor: 'var(--color-border-muted)', + // Ignore the padding from the section. marginLeft: '-8px', marginRight: '-8px', }} 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 086498a0f4d8..d9f473782e78 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 @@ -78,122 +78,114 @@ exports[`Info renders info section for personal sign request 1`] = ` exports[`Info renders info section for typed sign request 1`] = `
-
-

+

+
- Request from -

-
-
- -
+
-
+
+

-

- metamask.github.io -

-
+ metamask.github.io +

-
-

- Interacting with -

-
+ Interacting with +

+
+
-

- 0xCcCCc...ccccC -

+

+ 0xCcCCc...ccccC +

diff --git a/ui/pages/confirmations/components/confirm/info/contract-interaction/__snapshots__/contract-interaction.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/contract-interaction/__snapshots__/contract-interaction.test.tsx.snap index cf11076fc92e..2ba4eb76e72e 100644 --- a/ui/pages/confirmations/components/confirm/info/contract-interaction/__snapshots__/contract-interaction.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/contract-interaction/__snapshots__/contract-interaction.test.tsx.snap @@ -5,7 +5,7 @@ exports[` does not render if required data is not pre exports[` renders component for contract interaction request 1`] = `
does not render component for transaction details 1`] = `
`; +exports[` does not render component for transaction details 1`] = ` +
+
+
+`; exports[` renders component for transaction details 1`] = `
-

- Request from -

-
-
- + Request from +

+
+
+ +
-
-
-

- metamask.github.io -

+

+ metamask.github.io +

+
-
-
-

- Interacting with -

-
-
- + Interacting with +

+
+
+ +
-
-
+

+ 0x88AA6...A5125 +

-

- 0x88AA6...A5125 -

diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap index 1d14c6815c89..cf3c57f86829 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/__snapshots__/typed-sign.test.tsx.snap @@ -5,122 +5,114 @@ exports[`TypedSignInfo does not render if required data is not present in the tr exports[`TypedSignInfo renders origin for typed sign data request 1`] = `
-
-

+

+
- Request from -

-
-
- -
+
-
+
+

-

- metamask.github.io -

-
+ metamask.github.io +

-
-

- Interacting with -

-
+ Interacting with +

+
+
-

- 0xCcCCc...ccccC -

+

+ 0xCcCCc...ccccC +

@@ -436,122 +428,114 @@ exports[`TypedSignInfo renders origin for typed sign data request 1`] = ` exports[`TypedSignInfo should render message for typed sign v3 request 1`] = `
-
-

+

+
- Request from -

-
-
- -
+
-
+
+

-

- metamask.github.io -

-
+ metamask.github.io +

-
-

- Interacting with -

-
+ Interacting with +

+
+
-

- 0xCcCCc...ccccC -

+

+ 0xCcCCc...ccccC +

@@ -867,122 +851,114 @@ exports[`TypedSignInfo should render message for typed sign v3 request 1`] = ` exports[`TypedSignInfo should render message for typed sign v4 request 1`] = `
-
-

+

+
- Request from -

-
-
- -
+
-
+
+

-

- metamask.github.io -

-
+ metamask.github.io +

-
-

- Interacting with -

-
+ Interacting with +

+
+
-

- 0xCcCCc...ccccC -

+

+ 0xCcCCc...ccccC +

diff --git a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap index c28f6bec6360..89ac8f62ae1c 100644 --- a/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap +++ b/ui/pages/confirmations/confirm/__snapshots__/confirm.test.tsx.snap @@ -111,19 +111,6 @@ exports[`Confirm matches snapshot for personal signature type 1`] = `
-
- -

- Your selected account (0x0dcd5...3e7bc) is different than the account trying to sign () -

-
-
- -

- Your selected account (0x0dcd5...3e7bc) is different than the account trying to sign () -

-
-
-

+

+
- Request from -

-
-
- -
+
-
+
+

-

- metamask.github.io -

-
+ metamask.github.io +

-
-

- Interacting with -

-
+ Interacting with +

+
+
-

- 0xCcCCc...ccccC -

+

+ 0xCcCCc...ccccC +

From 8310c9719f47525862e4a052e50e54e517ba4947 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 20 Jun 2024 12:22:02 +0100 Subject: [PATCH 6/9] Update tooltip Add missing selector. --- app/_locales/en/messages.json | 2 +- .../confirm/info/shared/transaction-details.tsx | 8 ++------ ui/selectors/account-abstraction.ts | 7 +++++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 9c2a271a79ca..4be283a9f4c4 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -904,7 +904,7 @@ "message": "Fee paid by" }, "confirmFieldTooltipPaymaster": { - "message": "This is the address of the paymaster smart contract that will provide the gas fee for this user operation." + "message": "The fee for this transaction will be paid by the paymaster smart contract." }, "confirmPassword": { "message": "Confirm password" diff --git a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx index b10f783407cf..8b1907ddf1aa 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx +++ b/ui/pages/confirmations/components/confirm/info/shared/transaction-details.tsx @@ -13,8 +13,6 @@ import { currentConfirmationSelector } from '../../../../selectors'; import { useKnownMethodDataInTransaction } from '../hooks/known-method-data-in-transaction'; import { ConfirmInfoSection } from '../../../../../../components/app/confirm/info/row/section'; import { selectPaymasterAddress } from '../../../../../../selectors/account-abstraction'; -import { ConfirmInfoAlertRow } from '../../../../../../components/app/confirm/info/row/alert-row/alert-row'; -import { RowAlertKey } from '../../../../../../components/app/confirm/info/row/constants'; const OriginRow = () => { const t = useI18nContext(); @@ -108,14 +106,12 @@ const PaymasterRow = () => { return ( - - + ); }; diff --git a/ui/selectors/account-abstraction.ts b/ui/selectors/account-abstraction.ts index 77b191d34b20..179f4665bfd6 100644 --- a/ui/selectors/account-abstraction.ts +++ b/ui/selectors/account-abstraction.ts @@ -1,5 +1,6 @@ import { TransactionMeta } from '@metamask/transaction-controller'; import { UserOperationControllerState } from '@metamask/user-operation-controller'; +import { createSelector } from 'reselect'; export type AccountAbstractionState = { confirmTransaction?: { txData?: TransactionMeta }; @@ -10,6 +11,12 @@ export function getUserOperations(state: AccountAbstractionState) { return state.metamask.userOperations || {}; } +export const selectUserOperationMetadata = createSelector( + getUserOperations, + (_state: AccountAbstractionState, userOperationId: string) => userOperationId, + (userOperations, userOperationId) => userOperations[userOperationId], +); + export function getUserOperation(state: AccountAbstractionState) { const currentTransaction = state.confirmTransaction?.txData; From e06b707f8e2a14c308cd867bac395611377bb2b4 Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Thu, 20 Jun 2024 12:41:15 +0100 Subject: [PATCH 7/9] Add storybook icon --- .storybook/images/icons/info.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .storybook/images/icons/info.svg diff --git a/.storybook/images/icons/info.svg b/.storybook/images/icons/info.svg new file mode 100644 index 000000000000..929561d16a83 --- /dev/null +++ b/.storybook/images/icons/info.svg @@ -0,0 +1,3 @@ + + + From 7b636f3f7b1ac2d571869881c6d1d9566e40b08d Mon Sep 17 00:00:00 2001 From: Matthew Walsh Date: Fri, 21 Jun 2024 11:36:12 +0100 Subject: [PATCH 8/9] Fix unit tests and linting --- .../advanced-details.test.tsx.snap | 184 +++++++++--------- .../advanced-details/advanced-details.tsx | 58 ++---- .../confirmations/confirm/stories/utils.tsx | 2 + 3 files changed, 110 insertions(+), 134 deletions(-) diff --git a/ui/pages/confirmations/components/confirm/info/shared/advanced-details/__snapshots__/advanced-details.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/shared/advanced-details/__snapshots__/advanced-details.test.tsx.snap index de531cb73c51..295aa2510d56 100644 --- a/ui/pages/confirmations/components/confirm/info/shared/advanced-details/__snapshots__/advanced-details.test.tsx.snap +++ b/ui/pages/confirmations/components/confirm/info/shared/advanced-details/__snapshots__/advanced-details.test.tsx.snap @@ -3,49 +3,45 @@ exports[` does not render component for advanced transaction details 1`] = `
-
-

+

+
- Nonce -

-
-
- -
+
-
+
+

-

- undefined -

-
+ undefined +

@@ -55,90 +51,86 @@ exports[` does not render component for advanced transaction exports[` renders component for advanced transaction details 1`] = `
-
-

- Nonce -

-
-
- -
-
-
-
-

- 12 -

- +
+
+

+ 12 +

+ +
-
-

- Hex -

-
-
+
+
+

-

- 0xd0e30db0 -

-
+ 0xd0e30db0 +

+
+