From 3bffc0bf0a4e292585f9a609279cd77606242cb7 Mon Sep 17 00:00:00 2001 From: iamacook Date: Wed, 22 Nov 2023 18:50:53 +0100 Subject: [PATCH] fix: add guardian validation + test periods --- .../UpsertRecoveryFlowReview.tsx | 8 +- .../UpsertRecoveryFlowSettings.tsx | 25 ++++++- .../tx-flow/flows/UpsertRecovery/index.tsx | 36 +-------- .../UpsertRecovery/useRecoveryPeriods.ts | 75 +++++++++++++++++++ 4 files changed, 103 insertions(+), 41 deletions(-) create mode 100644 src/components/tx-flow/flows/UpsertRecovery/useRecoveryPeriods.ts diff --git a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowReview.tsx b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowReview.tsx index 5832e4cc70..283f8eef6c 100644 --- a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowReview.tsx +++ b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowReview.tsx @@ -9,10 +9,11 @@ import { getRecoveryUpsertTransactions } from '@/services/recovery/setup' import { useWeb3 } from '@/hooks/wallets/web3' import useSafeInfo from '@/hooks/useSafeInfo' import { SvgIcon, Tooltip, Typography } from '@mui/material' -import { UpsertRecoveryFlowFields, RecoveryDelayPeriods, RecoveryExpirationPeriods } from '.' +import { useRecoveryPeriods } from './useRecoveryPeriods' import { TxDataRow } from '@/components/transactions/TxDetails/Summary/TxDataRow' import InfoIcon from '@/public/images/notifications/info.svg' import EthHashInfo from '@/components/common/EthHashInfo' +import { UpsertRecoveryFlowFields } from '.' import type { UpsertRecoveryFlowProps } from '.' export function UpsertRecoveryFlowReview({ @@ -26,9 +27,10 @@ export function UpsertRecoveryFlowReview({ const { safe, safeAddress } = useSafeInfo() const { setSafeTx, safeTxError, setSafeTxError } = useContext(SafeTxContext) + const periods = useRecoveryPeriods() const guardian = params[UpsertRecoveryFlowFields.guardian] - const delay = RecoveryDelayPeriods.find(({ value }) => value === params[UpsertRecoveryFlowFields.txCooldown])!.label - const expiration = RecoveryExpirationPeriods.find( + const delay = periods.delay.find(({ value }) => value === params[UpsertRecoveryFlowFields.txCooldown])!.label + const expiration = periods.expiration.find( ({ value }) => value === params[UpsertRecoveryFlowFields.txExpiration], )!.label const emailAddress = params[UpsertRecoveryFlowFields.emailAddress] diff --git a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx index 0e7053c7a0..1201652771 100644 --- a/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx +++ b/src/components/tx-flow/flows/UpsertRecovery/UpsertRecoveryFlowSettings.tsx @@ -18,10 +18,13 @@ import type { TextFieldProps } from '@mui/material' import type { ReactElement } from 'react' import TxCard from '../../common/TxCard' -import { UpsertRecoveryFlowFields, RecoveryDelayPeriods, RecoveryExpirationPeriods } from '.' +import { UpsertRecoveryFlowFields } from '.' +import { useRecoveryPeriods } from './useRecoveryPeriods' import AddressBookInput from '@/components/common/AddressBookInput' import CircleCheckIcon from '@/public/images/common/circle-check.svg' import { useDarkMode } from '@/hooks/useDarkMode' +import { sameAddress } from '@/utils/addresses' +import useSafeInfo from '@/hooks/useSafeInfo' import type { UpsertRecoveryFlowProps } from '.' import commonCss from '@/components/tx-flow/common/styles.module.css' @@ -34,15 +37,23 @@ export function UpsertRecoveryFlowSettings({ params: UpsertRecoveryFlowProps onSubmit: (formData: UpsertRecoveryFlowProps) => void }): ReactElement { + const { safeAddress } = useSafeInfo() const [showAdvanced, setShowAdvanced] = useState(params[UpsertRecoveryFlowFields.txExpiration] !== '0') const [understandsRisk, setUnderstandsRisk] = useState(false) const isDarkMode = useDarkMode() + const periods = useRecoveryPeriods() const formMethods = useForm({ defaultValues: params, mode: 'onChange', }) + const validateGuardian = (guardian: string) => { + if (sameAddress(guardian, safeAddress)) { + return 'The Safe Account cannot be a guardian of itself' + } + } + const emailAddress = formMethods.watch(UpsertRecoveryFlowFields.emailAddress) const onShowAdvanced = () => setShowAdvanced((prev) => !prev) @@ -63,7 +74,13 @@ export function UpsertRecoveryFlowSettings({ - +
@@ -80,7 +97,7 @@ export function UpsertRecoveryFlowSettings({ name={UpsertRecoveryFlowFields.txCooldown} render={({ field }) => ( - {RecoveryDelayPeriods.map(({ label, value }, index) => ( + {periods.delay.map(({ label, value }, index) => ( {label} @@ -105,7 +122,7 @@ export function UpsertRecoveryFlowSettings({ shouldUnregister={false} render={({ field }) => ( - {RecoveryExpirationPeriods.map(({ label, value }, index) => ( + {periods.expiration.map(({ label, value }, index) => ( {label} diff --git a/src/components/tx-flow/flows/UpsertRecovery/index.tsx b/src/components/tx-flow/flows/UpsertRecovery/index.tsx index 2950c2ee30..ba5cb0b0b6 100644 --- a/src/components/tx-flow/flows/UpsertRecovery/index.tsx +++ b/src/components/tx-flow/flows/UpsertRecovery/index.tsx @@ -6,41 +6,9 @@ import useTxStepper from '../../useTxStepper' import { UpsertRecoveryFlowReview as UpsertRecoveryFlowReview } from './UpsertRecoveryFlowReview' import { UpsertRecoveryFlowSettings as UpsertRecoveryFlowSettings } from './UpsertRecoveryFlowSettings' import { UpsertRecoveryFlowIntro as UpsertRecoveryFlowIntro } from './UpsertRecoveryFlowIntro' +import { DAY_IN_SECONDS } from './useRecoveryPeriods' import type { RecoveryState } from '@/store/recoverySlice' -const DAY_SECONDS = 60 * 60 * 24 - -export const RecoveryDelayPeriods = [ - { - label: '2 days', - value: `${DAY_SECONDS}`, - }, - { - label: '7 days', - value: `${DAY_SECONDS * 7}`, - }, - { - label: '14 days', - value: `${DAY_SECONDS * 14}`, - }, - { - label: '28 days', - value: `${DAY_SECONDS * 28}`, - }, - { - label: '56 days', - value: `${DAY_SECONDS * 56}`, - }, -] as const - -export const RecoveryExpirationPeriods = [ - { - label: 'Never', - value: '0', - }, - ...RecoveryDelayPeriods, -] as const - const Subtitles = ['How does recovery work?', 'Set up recovery settings', 'Set up account recovery'] export enum UpsertRecoveryFlowFields { @@ -60,7 +28,7 @@ export type UpsertRecoveryFlowProps = { export function UpsertRecoveryFlow({ recovery }: { recovery?: RecoveryState[number] }): ReactElement { const { data, step, nextStep, prevStep } = useTxStepper({ [UpsertRecoveryFlowFields.guardian]: recovery?.guardians?.[0] ?? '', - [UpsertRecoveryFlowFields.txCooldown]: recovery?.txCooldown?.toString() ?? `${DAY_SECONDS * 28}`, // 28 days in seconds + [UpsertRecoveryFlowFields.txCooldown]: recovery?.txCooldown?.toString() ?? `${DAY_IN_SECONDS * 28}`, // 28 days in seconds [UpsertRecoveryFlowFields.txExpiration]: recovery?.txExpiration?.toString() ?? '0', [UpsertRecoveryFlowFields.emailAddress]: '', }) diff --git a/src/components/tx-flow/flows/UpsertRecovery/useRecoveryPeriods.ts b/src/components/tx-flow/flows/UpsertRecovery/useRecoveryPeriods.ts new file mode 100644 index 0000000000..bf6d22212d --- /dev/null +++ b/src/components/tx-flow/flows/UpsertRecovery/useRecoveryPeriods.ts @@ -0,0 +1,75 @@ +import chains from '@/config/chains' +import { useCurrentChain } from '@/hooks/useChains' + +export const DAY_IN_SECONDS = 60 * 60 * 24 + +const DefaultRecoveryDelayPeriods = [ + { + label: '2 days', + value: `${DAY_IN_SECONDS * 2}`, + }, + { + label: '7 days', + value: `${DAY_IN_SECONDS * 7}`, + }, + { + label: '14 days', + value: `${DAY_IN_SECONDS * 14}`, + }, + { + label: '28 days', + value: `${DAY_IN_SECONDS * 28}`, + }, + { + label: '56 days', + value: `${DAY_IN_SECONDS * 56}`, + }, +] + +const DefaultRecoveryExpirationPeriods = [ + { + label: 'Never', + value: '0', + }, + ...DefaultRecoveryDelayPeriods, +] + +const TestRecoveryDelayPeriods = [ + { + label: '1 minute', + value: 60, + }, + { + label: '5 minutes', + value: 60 * 5, + }, + { + label: '1 hour', + value: DAY_IN_SECONDS, + }, + ...DefaultRecoveryDelayPeriods, +] + +const TestRecoveryExpirationPeriods = [ + { + label: 'Never', + value: '0', + }, + ...TestRecoveryDelayPeriods, +] + +export function useRecoveryPeriods() { + const chain = useCurrentChain() + + if (!chain || [chains.gor, chains.sep].includes(chain.chainId)) { + return { + delay: TestRecoveryDelayPeriods, + expiration: TestRecoveryExpirationPeriods, + } + } + + return { + delay: DefaultRecoveryDelayPeriods, + expiration: DefaultRecoveryExpirationPeriods, + } +}