From 57b9c82a30551ec3798357e9c0bdc66c4f0eff55 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 12 Jun 2024 17:37:31 +0530 Subject: [PATCH] feat: permit signature simulation info (#24862) --- app/_locales/en/messages.json | 3 + .../permit-simulation.test.tsx.snap | 98 +++++++++++++++++++ .../typed-sign/permit-simulation/index.ts | 1 + .../permit-simulation.test.tsx | 21 ++++ .../permit-simulation/permit-simulation.tsx | 82 ++++++++++++++++ .../info/typed-sign/typed-sign.test.tsx | 12 +++ .../confirm/info/typed-sign/typed-sign.tsx | 10 +- 7 files changed, 223 insertions(+), 4 deletions(-) create mode 100644 ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/__snapshots__/permit-simulation.test.tsx.snap create mode 100644 ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/index.ts create mode 100644 ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.test.tsx create mode 100644 ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 44434c77b44a..df4e33085230 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3787,6 +3787,9 @@ "permissionsPageTourTitle": { "message": "Connected sites are now permissions" }, + "permitSimulationDetailInfo": { + "message": "This transaction gives permission to withdraw your tokens" + }, "personalAddressDetected": { "message": "Personal address detected. Input the token contract address." }, diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/__snapshots__/permit-simulation.test.tsx.snap b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/__snapshots__/permit-simulation.test.tsx.snap new file mode 100644 index 000000000000..e96dce4d0201 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/__snapshots__/permit-simulation.test.tsx.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PermitSimulation renders component correctly 1`] = ` +
+
+
+
+

+ Estimated changes +

+
+
+ +
+
+
+
+

+ This transaction gives permission to withdraw your tokens +

+
+
+
+
+

+ Approve spend limit +

+
+
+
+
+

+ 3000 +

+
+
+
+ +

+ 0xCcCCc...ccccC +

+
+
+
+
+
+
+
+
+`; diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/index.ts b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/index.ts new file mode 100644 index 000000000000..20c43d2613ca --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/index.ts @@ -0,0 +1 @@ +export { default as PermitSimulation } from './permit-simulation'; diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.test.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.test.tsx new file mode 100644 index 000000000000..ea0ffcc47bc1 --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.test.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; + +import mockState from '../../../../../../../../test/data/mock-state.json'; +import { renderWithProvider } from '../../../../../../../../test/lib/render-helpers'; +import { permitSignatureMsg } from '../../../../../../../../test/data/confirmations/typed_sign'; +import PermitSimulation from './permit-simulation'; + +describe('PermitSimulation', () => { + it('renders component correctly', () => { + const state = { + ...mockState, + confirm: { + currentConfirmation: permitSignatureMsg, + }, + }; + const mockStore = configureMockStore([])(state); + const { container } = renderWithProvider(, mockStore); + expect(container).toMatchSnapshot(); + }); +}); 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 new file mode 100644 index 000000000000..fe43dd17183a --- /dev/null +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/permit-simulation/permit-simulation.tsx @@ -0,0 +1,82 @@ +import React, { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { NameType } from '@metamask/name-controller'; + +import { Numeric } from '../../../../../../../../shared/modules/Numeric'; +import Name from '../../../../../../../components/app/name/name'; +import { + ConfirmInfoRow, + ConfirmInfoRowText, +} from '../../../../../../../components/app/confirm/info/row'; +import { useI18nContext } from '../../../../../../../hooks/useI18nContext'; +import { currentConfirmationSelector } from '../../../../../../../selectors'; +import { Box, Text } from '../../../../../../../components/component-library'; +import { + BackgroundColor, + BorderRadius, + Display, + TextAlign, +} from '../../../../../../../helpers/constants/design-system'; +import { parseTypedDataMessage } from '../../../../../utils'; +import { SignatureRequestType } from '../../../../../types/confirm'; +import useTokenExchangeRate from '../../../../../../../components/app/currency-input/hooks/useTokenExchangeRate'; +import { IndividualFiatDisplay } from '../../../../simulation-details/fiat-display'; + +const PermitSimulation: React.FC = () => { + const t = useI18nContext(); + const currentConfirmation = useSelector( + currentConfirmationSelector, + ) as SignatureRequestType; + + const { + domain: { verifyingContract }, + message: { value }, + } = parseTypedDataMessage(currentConfirmation.msgParams?.data as string); + + const exchangeRate = useTokenExchangeRate(verifyingContract); + + const fiatValue = useMemo(() => { + if (exchangeRate && value) { + return exchangeRate.times(new Numeric(value, 10)).toNumber(); + } + return undefined; + }, [exchangeRate, value]); + + return ( + + + + + + + + + + {value} + + + + + + {fiatValue && } + + + + + ); +}; + +export default PermitSimulation; diff --git a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx index 1f337f5a9dc2..dc1d093d57bb 100644 --- a/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx +++ b/ui/pages/confirmations/components/confirm/info/typed-sign/typed-sign.test.tsx @@ -64,6 +64,18 @@ describe('TypedSignInfo', () => { expect(container).toMatchSnapshot(); }); + it('display simulation details for permit signature', () => { + const state = { + ...mockState, + confirm: { + currentConfirmation: permitSignatureMsg, + }, + }; + const mockStore = configureMockStore([])(state); + const { getByText } = renderWithProvider(, mockStore); + expect(getByText('Estimated changes')).toBeDefined(); + }); + it('displays "Approving to" for permit signature type', () => { const state = { ...mockState, 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 adf66ae16f9d..ed4cb30f3360 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 @@ -19,6 +19,7 @@ import { EIP712_PRIMARY_TYPE_PERMIT } from '../../../../constants'; import { SignatureRequestType } from '../../../../types/confirm'; import { parseTypedDataMessage } from '../../../../utils'; import { ConfirmInfoRowTypedSignData } from '../../row/typed-sign-data/typedSignData'; +import { PermitSimulation } from './permit-simulation'; const TypedSignInfo: React.FC = () => { const t = useI18nContext(); @@ -31,13 +32,14 @@ const TypedSignInfo: React.FC = () => { } const { - domain, domain: { verifyingContract }, primaryType, + message: { spender }, } = parseTypedDataMessage(currentConfirmation.msgParams.data as string); return ( <> + {primaryType === EIP712_PRIMARY_TYPE_PERMIT && } { <> - + @@ -62,10 +64,10 @@ const TypedSignInfo: React.FC = () => { - {isValidAddress(domain.verifyingContract) && ( + {isValidAddress(verifyingContract) && ( - + )}