From 2acd0e17bf1a5a9af2ee5594df650c8817fe54a2 Mon Sep 17 00:00:00 2001 From: mmv Date: Thu, 15 Aug 2019 18:42:51 +0400 Subject: [PATCH] Resolve ENS name onChange, add ENS support to load safe route --- src/components/forms/AddressInput/index.jsx | 27 +++++++++++++------ src/components/forms/validator.js | 24 ++--------------- .../load/components/DetailsForm/index.jsx | 21 +++++++++------ src/routes/load/components/Layout.jsx | 18 ++++++++++--- .../load/components/OwnerList/index.jsx | 8 +++--- src/routes/open/components/Layout.jsx | 4 +-- .../SafeOwnersConfirmationsForm/index.jsx | 8 +++--- .../SendModal/screens/SendFunds/index.jsx | 14 ++++------ 8 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/components/forms/AddressInput/index.jsx b/src/components/forms/AddressInput/index.jsx index 20dc6ee9..71217c95 100644 --- a/src/components/forms/AddressInput/index.jsx +++ b/src/components/forms/AddressInput/index.jsx @@ -1,13 +1,12 @@ // @flow import * as React from 'react' import { Field } from 'react-final-form' +import { OnChange } from 'react-final-form-listeners' import TextField from '~/components/forms/TextField' import { composeValidators, required, mustBeEthereumAddress, - ifElseValidator, - ensResolverHasAddress, } from '~/components/forms/validator' import { getAddressFromENS } from '~/logic/wallets/getWeb3' @@ -22,9 +21,7 @@ type Props = { inputAdornment?: React.Element, } -const isValidEnsName = name => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name) - -const { useState, useEffect } = React +const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name) // an idea for second field was taken from here // https://github.com/final-form/react-final-form-listeners/blob/master/src/OnBlur.js @@ -46,7 +43,7 @@ const AddressInput = ({ type="text" validate={composeValidators( required, - ifElseValidator(isValidEnsName, ensResolverHasAddress, mustBeEthereumAddress), + mustBeEthereumAddress, ...validators, )} inputAdornment={inputAdornment} @@ -55,7 +52,21 @@ const AddressInput = ({ className={className} testId={testId} /> - + {async (value) => { + if (isValidEnsName(value)) { + try { + const resolverAddr = await getAddressFromENS(value) + fieldMutator(resolverAddr) + } catch (err) { + console.error('Failed to resolve address for ENS name: ', err) + } + } + }} + + {/* onBlur - didn't work because of the complex validation + (if you submit before it gets the address, breaks everything) */} + {/* { @@ -82,7 +93,7 @@ const AddressInput = ({ return null }} - /> + /> */} ) diff --git a/src/components/forms/validator.js b/src/components/forms/validator.js index 4ba68677..decf8710 100644 --- a/src/components/forms/validator.js +++ b/src/components/forms/validator.js @@ -1,6 +1,6 @@ // @flow import { type FieldValidator } from 'final-form' -import { getWeb3, getAddressFromENS } from '~/logic/wallets/getWeb3' +import { getWeb3 } from '~/logic/wallets/getWeb3' export const simpleMemoize = (fn: Function) => { let lastArg @@ -61,7 +61,7 @@ export const ok = () => undefined export const mustBeEthereumAddress = simpleMemoize((address: Field) => { const isAddress: boolean = getWeb3().utils.isAddress(address) - return isAddress ? undefined : 'Address should be a valid Ethereum address or ENS domain' + return isAddress ? undefined : 'Address should be a valid Ethereum address or ENS name' }) export const minMaxLength = (minLen: string | number, maxLen: string | number) => (value: string) => (value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`) @@ -90,24 +90,4 @@ export const differentFrom = (diffValue: string) => (value: string) => { return undefined } -export const ensResolverHasAddress = async (value: string) => { - let error - - try { - await getAddressFromENS(value) - } catch { - error = 'Couldn\'t resolve the address' - } - - return error -} - export const noErrorsOn = (name: string, errors: Object) => errors[name] === undefined - -export const ifElseValidator = (ifFunc: Function, thenFunc: Function, elseFunc: Function) => (value: string) => { - if (ifFunc(value)) { - return thenFunc(value) - } - - return elseFunc(value) -} diff --git a/src/routes/load/components/DetailsForm/index.jsx b/src/routes/load/components/DetailsForm/index.jsx index 1f4540da..aabd1320 100644 --- a/src/routes/load/components/DetailsForm/index.jsx +++ b/src/routes/load/components/DetailsForm/index.jsx @@ -5,6 +5,7 @@ import SafeProxy from '@gnosis.pm/safe-contracts/build/contracts/Proxy.json' import InputAdornment from '@material-ui/core/InputAdornment' import CheckCircle from '@material-ui/icons/CheckCircle' import Field from '~/components/forms/Field' +import AddressInput from '~/components/forms/AddressInput' import { composeValidators, required, noErrorsOn, mustBeEthereumAddress, } from '~/components/forms/validator' @@ -19,6 +20,7 @@ import { getSafeMasterContract } from '~/logic/contracts/safeContracts' type Props = { classes: Object, errors: Object, + form: Object, } const styles = () => ({ @@ -80,8 +82,8 @@ export const safeFieldsValidation = async (values: Object) => { return errors } -const Details = ({ classes, errors }: Props) => ( - +const Details = ({ classes, errors, form }: Props) => ( + <> Adding an existing Safe only requires the Safe address. Optionally you can give it a name. In case your @@ -99,9 +101,12 @@ const Details = ({ classes, errors }: Props) => ( /> - { + form.mutators.setValue(FIELD_LOAD_ADDRESS, val) + }} inputAdornment={ noErrorsOn(FIELD_LOAD_ADDRESS, errors) && { endAdornment: ( @@ -117,17 +122,17 @@ const Details = ({ classes, errors }: Props) => ( text="Safe Address" /> - + ) const DetailsForm = withStyles(styles)(Details) -const DetailsPage = () => (controls: React.Node, { errors }: Object) => ( - +const DetailsPage = () => (controls: React.Node, { errors, form }: Object) => ( + <> - + - + ) export default DetailsPage diff --git a/src/routes/load/components/Layout.jsx b/src/routes/load/components/Layout.jsx index 6e9ab43b..d10c0696 100644 --- a/src/routes/load/components/Layout.jsx +++ b/src/routes/load/components/Layout.jsx @@ -29,6 +29,12 @@ const back = () => { history.goBack() } +const formMutators = { + setValue: ([field, value], state, { changeValue }) => { + changeValue(state, field, () => value) + }, +} + const Layout = ({ provider, onLoadSafeSubmit, network, userAddress, }: Props) => { @@ -36,7 +42,7 @@ const Layout = ({ const initialValues = {} return ( - + <> {provider ? ( @@ -45,7 +51,13 @@ const Layout = ({ Load existing Safe - + {DetailsForm} {OwnerList} @@ -56,7 +68,7 @@ const Layout = ({ ) : (
No account detected
)} -
+ ) } diff --git a/src/routes/load/components/OwnerList/index.jsx b/src/routes/load/components/OwnerList/index.jsx index e1cf9303..e3cc3d69 100644 --- a/src/routes/load/components/OwnerList/index.jsx +++ b/src/routes/load/components/OwnerList/index.jsx @@ -118,7 +118,7 @@ const OwnerListComponent = (props: Props) => { }, []) return ( - + <> {`This Safe has ${owners.length} owners. Optional: Provide a name for each owner.`} @@ -159,18 +159,18 @@ const OwnerListComponent = (props: Props) => { ))} - + ) } const OwnerListPage = withStyles(styles)(OwnerListComponent) const OwnerList = ({ updateInitialProps }: Object, network: string) => (controls: React$Node, { values }: Object) => ( - + <> - + ) export default OwnerList diff --git a/src/routes/open/components/Layout.jsx b/src/routes/open/components/Layout.jsx index 26c0f7c0..0e6a30e5 100644 --- a/src/routes/open/components/Layout.jsx +++ b/src/routes/open/components/Layout.jsx @@ -51,7 +51,7 @@ const Layout = ({ const initialValues = initialValuesFrom(userAccount) return ( - + <> {provider ? ( @@ -75,7 +75,7 @@ const Layout = ({ ) : (
No web3 provider detected
)} -
+ ) } diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx index 3978e3f4..0a1b82d9 100644 --- a/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx +++ b/src/routes/open/components/SafeOwnersConfirmationsForm/index.jsx @@ -106,7 +106,7 @@ const SafeOwners = (props: Props) => { } return ( - + <> Specify the owners of the Safe. @@ -212,14 +212,14 @@ owner(s) {qrModalOpen && } - + ) } const SafeOwnersForm = withStyles(styles)(SafeOwners) const SafeOwnersPage = ({ updateInitialProps }: Object) => (controls: React.Node, { values, errors, form }: Object) => ( - + <> (controls: React.Node values={values} /> - + ) export default SafeOwnersPage diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx index 4f574694..890863c9 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.jsx @@ -19,11 +19,7 @@ import Field from '~/components/forms/Field' import TextField from '~/components/forms/TextField' import { type Token } from '~/logic/tokens/store/model/token' import { - composeValidators, - required, - mustBeFloat, - maxValue, - greaterThan, + composeValidators, required, mustBeFloat, maxValue, greaterThan, } from '~/components/forms/validator' import TokenSelectField from '~/routes/safe/components/Balances/SendModal/screens/SendFunds/TokenSelectField' import SafeInfo from '~/routes/safe/components/Balances/SendModal/SafeInfo' @@ -74,7 +70,7 @@ const SendFunds = ({ } return ( - + <> Send Funds @@ -102,7 +98,7 @@ const SendFunds = ({ const { token } = formState.values return ( - + <> - + ) }} - + ) }