From 8f16c4f18d663304ef2ea1112ffb4ed9888d2cee Mon Sep 17 00:00:00 2001 From: Agustin Pane Date: Tue, 16 Mar 2021 06:42:42 -0300 Subject: [PATCH] (Feature) - #1991 Prevent that a Safe adds itself as an owner (#2026) * Uses addressIsNotSafe on replaceOwner modal and addNewOwnerModal * Update method name from addressIsNotSafe to addressIsNotCurrentSafe --- src/components/forms/validator.test.ts | 18 ++++++++++++++++++ src/components/forms/validator.ts | 4 ++++ .../AddOwnerModal/screens/OwnerForm/index.tsx | 14 +++++++++++--- .../screens/OwnerForm/index.tsx | 14 +++++++++++--- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/components/forms/validator.test.ts b/src/components/forms/validator.test.ts index 38264deb..cd1918ba 100644 --- a/src/components/forms/validator.test.ts +++ b/src/components/forms/validator.test.ts @@ -10,6 +10,8 @@ import { uniqueAddress, differentFrom, ADDRESS_REPEATED_ERROR, + addressIsNotCurrentSafe, + OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR, } from 'src/components/forms/validator' describe('Forms > Validators', () => { @@ -179,6 +181,22 @@ describe('Forms > Validators', () => { }) }) + describe('addressIsNotSafe validator', () => { + it('Returns undefined if the given `address` it not the given `safeAddress`', async () => { + const address = '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe' + const safeAddress = '0x2D6F2B448b0F711Eb81f2929566504117d67E44F' + + expect(addressIsNotCurrentSafe(safeAddress)(address)).toBeUndefined() + }) + + it('Returns an error message if the given `address` is the same as the `safeAddress`', async () => { + const address = '0x2D6F2B448b0F711Eb81f2929566504117d67E44F' + const safeAddress = '0x2D6F2B448b0F711Eb81f2929566504117d67E44F' + + expect(addressIsNotCurrentSafe(safeAddress)(address)).toEqual(OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR) + }) + }) + describe('differentFrom validator', () => { const getDifferentFromErrMsg = (diffValue: string): string => `Value should be different than ${diffValue}` diff --git a/src/components/forms/validator.ts b/src/components/forms/validator.ts index 09db0431..271c27ba 100644 --- a/src/components/forms/validator.ts +++ b/src/components/forms/validator.ts @@ -92,12 +92,16 @@ export const minMaxLength = (minLen: number, maxLen: number) => (value: string): value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols` export const ADDRESS_REPEATED_ERROR = 'Address already introduced' +export const OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR = 'Cannot use Safe itself as owner.' export const uniqueAddress = (addresses: string[] | List = []) => (address?: string): string | undefined => { const addressExists = addresses.some((addressFromList) => sameAddress(addressFromList, address)) return addressExists ? ADDRESS_REPEATED_ERROR : undefined } +export const addressIsNotCurrentSafe = (safeAddress: string) => (address?: string): string | undefined => + sameAddress(safeAddress, address) ? OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR : undefined + export const composeValidators = (...validators: Validator[]) => (value: unknown): ValidatorReturnType => validators.reduce( (error: string | undefined, validator: GenericValidatorType): ValidatorReturnType => error || validator(value), diff --git a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx index 73083d62..dabe3b40 100644 --- a/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/AddOwnerModal/screens/OwnerForm/index.tsx @@ -11,14 +11,20 @@ import AddressInput from 'src/components/forms/AddressInput' import Field from 'src/components/forms/Field' import GnoForm from 'src/components/forms/GnoForm' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required, uniqueAddress } from 'src/components/forms/validator' +import { + addressIsNotCurrentSafe, + composeValidators, + minMaxLength, + required, + uniqueAddress, +} from 'src/components/forms/validator' import Block from 'src/components/layout/Block' import Button from 'src/components/layout/Button' import Col from 'src/components/layout/Col' import Hairline from 'src/components/layout/Hairline' import Paragraph from 'src/components/layout/Paragraph' import Row from 'src/components/layout/Row' -import { safeOwnersAddressesListSelector } from 'src/logic/safe/store/selectors' +import { safeOwnersAddressesListSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors' export const ADD_OWNER_NAME_INPUT_TEST_ID = 'add-owner-name-input' export const ADD_OWNER_ADDRESS_INPUT_TEST_ID = 'add-owner-address-testid' @@ -43,7 +49,9 @@ export const OwnerForm = ({ onClose, onSubmit }: OwnerFormProps): React.ReactEle onSubmit(values) } const owners = useSelector(safeOwnersAddressesListSelector) + const safeAddress = useSelector(safeParamAddressFromStateSelector) const ownerDoesntExist = uniqueAddress(owners) + const ownerAddressIsNotSafeAddress = addressIsNotCurrentSafe(safeAddress) return ( <> @@ -98,7 +106,7 @@ export const OwnerForm = ({ onClose, onSubmit }: OwnerFormProps): React.ReactEle placeholder="Owner address*" testId={ADD_OWNER_ADDRESS_INPUT_TEST_ID} text="Owner address*" - validators={[ownerDoesntExist]} + validators={[ownerDoesntExist, ownerAddressIsNotSafeAddress]} /> diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx index 035a5e8f..86558e0d 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/screens/OwnerForm/index.tsx @@ -10,7 +10,13 @@ import AddressInput from 'src/components/forms/AddressInput' import Field from 'src/components/forms/Field' import GnoForm from 'src/components/forms/GnoForm' import TextField from 'src/components/forms/TextField' -import { composeValidators, minMaxLength, required, uniqueAddress } from 'src/components/forms/validator' +import { + addressIsNotCurrentSafe, + composeValidators, + minMaxLength, + required, + uniqueAddress, +} from 'src/components/forms/validator' import Identicon from 'src/components/Identicon' import Block from 'src/components/layout/Block' import Button from 'src/components/layout/Button' @@ -19,7 +25,7 @@ import Hairline from 'src/components/layout/Hairline' import Paragraph from 'src/components/layout/Paragraph' import Row from 'src/components/layout/Row' import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper' -import { safeOwnersAddressesListSelector } from 'src/logic/safe/store/selectors' +import { safeOwnersAddressesListSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors' import { styles } from './style' import { getExplorerInfo } from 'src/config' @@ -40,7 +46,9 @@ const OwnerForm = ({ classes, onClose, onSubmit, ownerAddress, ownerName }) => { onSubmit(values) } const owners = useSelector(safeOwnersAddressesListSelector) + const safeAddress = useSelector(safeParamAddressFromStateSelector) const ownerDoesntExist = uniqueAddress(owners) + const ownerAddressIsNotSafeAddress = addressIsNotCurrentSafe(safeAddress) return ( <> @@ -126,7 +134,7 @@ const OwnerForm = ({ classes, onClose, onSubmit, ownerAddress, ownerName }) => { placeholder="Owner address*" testId={REPLACE_OWNER_ADDRESS_INPUT_TEST_ID} text="Owner address*" - validators={[ownerDoesntExist]} + validators={[ownerDoesntExist, ownerAddressIsNotSafeAddress]} />