Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

feat: Add ENS Reverse Lookup to Create/Load Safe process #3262

Merged
merged 25 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a5855ee
feat: Add ENS Reverse Lookup to Load Safe process
usame-algan Jan 10, 2022
a6847e5
build: Add ens domain to provider info
usame-algan Jan 11, 2022
d67909a
feat: Add ens reverse lookup function
usame-algan Jan 11, 2022
442fff1
fix: ENS Lookup only on account change
usame-algan Jan 11, 2022
47e4d0f
chore: Cleanup code + add types
iamacook Jan 12, 2022
d94080c
fix: Tweak logic + add return type
iamacook Jan 12, 2022
8e8dc68
chore: Remove empty string constant
iamacook Jan 12, 2022
2f1d876
fix: Compare against ChainId
iamacook Jan 13, 2022
70d30d5
feat: Add ENS Reverse Lookup to Load Safe process
usame-algan Jan 10, 2022
ec0faee
Merge branch 'safe-creation-reverse-ens-lookup' of github.com:gnosis/…
usame-algan Jan 13, 2022
4aae8f8
chore: Replace reverse ens lookup function from core sdk
usame-algan Jan 13, 2022
c282e51
feat: Add reverse ENS Lookup to create safe process
usame-algan Jan 14, 2022
800c363
chore: Add typing, extract getOwnerName
usame-algan Jan 17, 2022
3962480
refactor: use getOwnerName for load safe review step
usame-algan Jan 17, 2022
5ad3945
chore: jest spy on ens getResolver to fix failing tests
usame-algan Jan 17, 2022
938da79
fix: Don't use typed value as placeholder for owner name
usame-algan Jan 17, 2022
b14bf08
fix: try catch ens resolver
usame-algan Jan 17, 2022
1e9aeb4
build: Use ENS domain part for safe creation and loading
usame-algan Jan 18, 2022
6863634
chore: Rename getDomainPart util function
usame-algan Jan 18, 2022
33ee89c
Merge branch 'dev' into safe-creation-reverse-ens-lookup
usame-algan Jan 18, 2022
9db6155
fix: Move initial ENS fetch, fetch ENS when adding new owners
usame-algan Jan 20, 2022
591b911
refactor: use absolute import paths
usame-algan Jan 20, 2022
6beb294
refactor: Use absolute paths for imports
usame-algan Jan 20, 2022
967df77
fix: Get ENS if new owner is imported with qr code
usame-algan Jan 21, 2022
8cbb27e
Merge remote-tracking branch 'origin/dev' into safe-creation-reverse-…
usame-algan Jan 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/logic/wallets/getWeb3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export const reverseENSLookup = async (address: string): Promise<string> => {
return verifiedAddress === address ? name : ''
}

export const removeTld = (name: string): string => name.replace(/\.[^.]+$/, '')

export const getContentFromENS = (name: string): Promise<ContentHash> => web3.eth.ens.getContenthash(name)

export const isTxPendingError = (err: Error): boolean => {
Expand Down
1 change: 1 addition & 0 deletions src/routes/CreateSafePage/CreateSafePage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const estimateGasForDeployingSafeSpy = jest.spyOn(safeContracts, 'estimateGasFor
const calculateGasPriceSpy = jest.spyOn(ethTransactions, 'calculateGasPrice')

const getENSAddressSpy = jest.spyOn(getWeb3ReadOnly().eth.ens, 'getAddress')
jest.spyOn(getWeb3ReadOnly().eth.ens, 'getResolver')

jest.mock('src/logic/contracts/safeContracts', () => {
// Require the original module to not be mocked...
Expand Down
8 changes: 5 additions & 3 deletions src/routes/CreateSafePage/CreateSafePage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactElement, useState, useEffect } from 'react'
import { ReactElement, useEffect, useState } from 'react'
import IconButton from '@material-ui/core/IconButton'
import ChevronLeft from '@material-ui/icons/ChevronLeft'
import styled from 'styled-components'
Expand All @@ -12,7 +12,7 @@ import Block from 'src/components/layout/Block'
import Row from 'src/components/layout/Row'
import Heading from 'src/components/layout/Heading'
import { history } from 'src/routes/routes'
import { sm, secondary } from 'src/theme/variables'
import { secondary, sm } from 'src/theme/variables'
import StepperForm, { StepFormElement } from 'src/components/StepperForm/StepperForm'
import NameNewSafeStep, { nameNewSafeStepLabel } from './steps/NameNewSafeStep'
import {
Expand All @@ -22,6 +22,7 @@ import {
FIELD_MAX_OWNER_NUMBER,
FIELD_NEW_SAFE_PROXY_SALT,
FIELD_NEW_SAFE_THRESHOLD,
FIELD_SAFE_OWNER_ENS_LIST,
FIELD_SAFE_OWNERS_LIST,
SAFE_PENDING_CREATION_STORAGE_KEY,
} from './fields/createSafeFields'
Expand Down Expand Up @@ -145,7 +146,7 @@ function getInitialValues(userAddress, addressBook, location, suggestedSafeName)

// we set the owner names
const ownersNamesFromUrl = Array.isArray(ownernames) ? ownernames : [ownernames]
const userAddressName = [addressBook[userAddress]?.name || 'My Wallet']
const userAddressName = [addressBook[userAddress]?.name || '']
const ownerNames = isOwnersPresentInTheUrl ? ownersNamesFromUrl : userAddressName

const thresholdFromURl = Number(threshold)
Expand All @@ -160,6 +161,7 @@ function getInitialValues(userAddress, addressBook, location, suggestedSafeName)
nameFieldName: `owner-name-${index}`,
addressFieldName: `owner-address-${index}`,
})),
[FIELD_SAFE_OWNER_ENS_LIST]: {},
// we set owners address values as owner-address-${index} format in the form state
...owners.reduce(
(ownerAddressFields, ownerAddress, index) => ({
Expand Down
12 changes: 7 additions & 5 deletions src/routes/CreateSafePage/components/SafeCreationProcess.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
FIELD_CREATE_CUSTOM_SAFE_NAME,
FIELD_NEW_SAFE_PROXY_SALT,
FIELD_NEW_SAFE_GAS_PRICE,
FIELD_SAFE_OWNER_ENS_LIST,
} from '../fields/createSafeFields'
import { getSafeInfo } from 'src/logic/safe/utils/safeInformation'
import { buildSafe } from 'src/logic/safe/store/actions/fetchSafe'
Expand Down Expand Up @@ -172,13 +173,14 @@ function SafeCreationProcess(): ReactElement {
const owners = createSafeFormValues[FIELD_SAFE_OWNERS_LIST]

// we update the address book with the owners and the new safe
const ownersAddressBookEntry = owners.map(({ nameFieldName, addressFieldName }) =>
makeAddressBookEntry({
const ownersAddressBookEntry = owners.map(({ nameFieldName, addressFieldName }) => {
const ownerAddress = createSafeFormValues[addressFieldName]
return makeAddressBookEntry({
address: createSafeFormValues[addressFieldName],
name: createSafeFormValues[nameFieldName],
name: createSafeFormValues[nameFieldName] || createSafeFormValues[FIELD_SAFE_OWNER_ENS_LIST][ownerAddress],
chainId,
}),
)
})
})
const safeAddressBookEntry = makeAddressBookEntry({ address: newSafeAddress, name: safeName, chainId })
await dispatch(addressBookSafeLoad([...ownersAddressBookEntry, safeAddressBookEntry]))

Expand Down
2 changes: 2 additions & 0 deletions src/routes/CreateSafePage/fields/createSafeFields.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const FIELD_CREATE_CUSTOM_SAFE_NAME = 'customSafeName'
export const FIELD_CREATE_SUGGESTED_SAFE_NAME = 'suggestedSafeName'
export const FIELD_SAFE_OWNERS_LIST = 'owners'
export const FIELD_SAFE_OWNER_ENS_LIST = 'safeOwnerENSList'
export const FIELD_NEW_SAFE_THRESHOLD = 'newSafeThreshold'
export const FIELD_MAX_OWNER_NUMBER = 'maxOwnerNumber'
export const FIELD_NEW_SAFE_PROXY_SALT = 'safeCreationSalt'
Expand All @@ -18,6 +19,7 @@ export type CreateSafeFormValues = {
[FIELD_CREATE_CUSTOM_SAFE_NAME]?: string
[FIELD_NEW_SAFE_THRESHOLD]: number
[FIELD_SAFE_OWNERS_LIST]: Array<OwnerFieldItem>
[FIELD_SAFE_OWNER_ENS_LIST]: Record<string, string>
[FIELD_MAX_OWNER_NUMBER]: number
[FIELD_NEW_SAFE_PROXY_SALT]: number
[FIELD_NEW_SAFE_GAS_LIMIT]: number
Expand Down
46 changes: 43 additions & 3 deletions src/routes/CreateSafePage/steps/NameNewSafeStep.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ReactElement, useEffect } from 'react'
import { ReactElement, useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import { useForm } from 'react-final-form'
import styled from 'styled-components'
Expand All @@ -10,13 +10,20 @@ import Paragraph from 'src/components/layout/Paragraph'
import Field from 'src/components/forms/Field'
import TextField from 'src/components/forms/TextField'
import { providerNameSelector } from 'src/logic/wallets/store/selectors'
import { FIELD_CREATE_CUSTOM_SAFE_NAME, FIELD_CREATE_SUGGESTED_SAFE_NAME } from '../fields/createSafeFields'
import {
FIELD_CREATE_CUSTOM_SAFE_NAME,
FIELD_CREATE_SUGGESTED_SAFE_NAME,
FIELD_SAFE_OWNER_ENS_LIST,
FIELD_SAFE_OWNERS_LIST,
} from '../fields/createSafeFields'
import { useStepper } from 'src/components/Stepper/stepperContext'
import NetworkLabel from 'src/components/NetworkLabel/NetworkLabel'
import { removeTld, reverseENSLookup } from '../../../logic/wallets/getWeb3'

export const nameNewSafeStepLabel = 'Name'

function NameNewSafeStep(): ReactElement {
const [ownersWithENSName, setOwnersWithENSName] = useState<Record<string, string>>({})
const provider = useSelector(providerNameSelector)

const { setCurrentStep } = useStepper()
Expand All @@ -28,9 +35,42 @@ function NameNewSafeStep(): ReactElement {
}, [provider, setCurrentStep])

const createNewSafeForm = useForm()

const formValues = createNewSafeForm.getState().values

useEffect(() => {
const getInitialOwnerENSNames = async () => {
const formValues = createNewSafeForm.getState().values
const owners = formValues[FIELD_SAFE_OWNERS_LIST]
const ownersWithENSName = await Promise.all(
owners.map(async ({ addressFieldName }) => {
const address = formValues[addressFieldName]
const ensName = await reverseENSLookup(address)
const ensDomain = removeTld(ensName)
return {
address,
name: ensDomain,
}
}),
)

const ownersWithENSNameRecord = ownersWithENSName.reduce<Record<string, string>>((acc, { address, name }) => {
return {
...acc,
[address]: name,
}
}, {})

setOwnersWithENSName(ownersWithENSNameRecord)
}
getInitialOwnerENSNames()
}, [createNewSafeForm])

useEffect(() => {
if (ownersWithENSName) {
createNewSafeForm.change(FIELD_SAFE_OWNER_ENS_LIST, ownersWithENSName)
}
}, [ownersWithENSName, createNewSafeForm])
katspaugh marked this conversation as resolved.
Show resolved Hide resolved

return (
<BlockWithPadding data-testid={'create-safe-name-step'}>
<Block margin="md">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ import {
required,
THRESHOLD_ERROR,
} from 'src/components/forms/validator'
import { FIELD_MAX_OWNER_NUMBER, FIELD_NEW_SAFE_THRESHOLD, FIELD_SAFE_OWNERS_LIST } from '../fields/createSafeFields'
import {
FIELD_MAX_OWNER_NUMBER,
FIELD_NEW_SAFE_THRESHOLD,
FIELD_SAFE_OWNER_ENS_LIST,
FIELD_SAFE_OWNERS_LIST,
} from '../fields/createSafeFields'
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
import NetworkLabel from 'src/components/NetworkLabel/NetworkLabel'
import { removeTld, reverseENSLookup } from '../../../logic/wallets/getWeb3'
katspaugh marked this conversation as resolved.
Show resolved Hide resolved

export const ownersAndConfirmationsNewSafeStepLabel = 'Owners and Confirmations'

Expand All @@ -53,6 +59,7 @@ function OwnersAndConfirmationsNewSafeStep(): ReactElement {
const formErrors = createSafeForm.getState().errors || {}

const owners = createSafeFormValues[FIELD_SAFE_OWNERS_LIST]
const ownersWithENSName = createSafeFormValues[FIELD_SAFE_OWNER_ENS_LIST]
const threshold = createSafeFormValues[FIELD_NEW_SAFE_THRESHOLD]
const maxOwnerNumber = createSafeFormValues[FIELD_MAX_OWNER_NUMBER]

Expand All @@ -68,11 +75,13 @@ function OwnersAndConfirmationsNewSafeStep(): ReactElement {

function onClickRemoveOwner({ addressFieldName }) {
const ownersUpdated = owners.filter((owner) => owner.addressFieldName !== addressFieldName)

createSafeForm.change(FIELD_SAFE_OWNERS_LIST, ownersUpdated)
createSafeForm.change(addressFieldName, undefined)

const hasToUpdateThreshold = threshold > ownersUpdated.length
const updatedMaxOwnerNumbers = maxOwnerNumber - 1
createSafeForm.change(FIELD_MAX_OWNER_NUMBER, updatedMaxOwnerNumbers)

const hasToUpdateThreshold = threshold > ownersUpdated.length
if (hasToUpdateThreshold) {
createSafeForm.change(FIELD_NEW_SAFE_THRESHOLD, threshold - 1)
}
Expand Down Expand Up @@ -113,7 +122,9 @@ function OwnersAndConfirmationsNewSafeStep(): ReactElement {
<RowHeader>
{owners.map(({ nameFieldName, addressFieldName }) => {
const hasOwnerAddressError = formErrors[addressFieldName]
const ownerAddress = createSafeFormValues[addressFieldName]
const showDeleteIcon = addressFieldName !== 'owner-address-0' // we hide de delete icon for the first owner
const ownerName = ownersWithENSName[ownerAddress] || 'Owner Name'

const handleScan = (address: string, closeQrModal: () => void): void => {
createSafeForm.change(addressFieldName, address)
Expand All @@ -126,7 +137,7 @@ function OwnersAndConfirmationsNewSafeStep(): ReactElement {
<OwnerNameField
component={TextField}
name={nameFieldName}
placeholder="Owner Name"
placeholder={ownerName}
text="Owner Name"
type="text"
validate={minMaxLength(0, 50)}
Expand All @@ -135,7 +146,13 @@ function OwnersAndConfirmationsNewSafeStep(): ReactElement {
</Col>
<Col xs={7}>
<AddressInput
fieldMutator={(address) => {
fieldMutator={async (address) => {
const ensName = await reverseENSLookup(address)
const ensDomain = removeTld(ensName)
const newOwnersWithENSName: Record<string, string> = Object.assign(ownersWithENSName, {
[address]: ensDomain,
})
createSafeForm.change(FIELD_SAFE_OWNER_ENS_LIST, newOwnersWithENSName)
createSafeForm.change(addressFieldName, address)
const addressName = addressBook[address]?.name
if (addressName) {
Expand Down
4 changes: 3 additions & 1 deletion src/routes/CreateSafePage/steps/ReviewNewSafeStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
FIELD_NEW_SAFE_GAS_PRICE,
FIELD_NEW_SAFE_PROXY_SALT,
FIELD_NEW_SAFE_THRESHOLD,
FIELD_SAFE_OWNER_ENS_LIST,
FIELD_SAFE_OWNERS_LIST,
} from '../fields/createSafeFields'
import { getExplorerInfo, getNativeCurrency } from 'src/config'
Expand Down Expand Up @@ -46,6 +47,7 @@ function ReviewNewSafeStep(): ReactElement | null {
const safeName = createSafeFormValues[FIELD_CREATE_CUSTOM_SAFE_NAME] || defaultSafeValue
const threshold = createSafeFormValues[FIELD_NEW_SAFE_THRESHOLD]
const owners = createSafeFormValues[FIELD_SAFE_OWNERS_LIST]
const ownersWithENSName = createSafeFormValues[FIELD_SAFE_OWNER_ENS_LIST]
const numberOfOwners = owners.length
const safeCreationSalt = createSafeFormValues[FIELD_NEW_SAFE_PROXY_SALT]
const ownerAddresses = owners.map(({ addressFieldName }) => createSafeFormValues[addressFieldName])
Expand Down Expand Up @@ -110,8 +112,8 @@ function ReviewNewSafeStep(): ReactElement | null {
</TitleContainer>
<Hairline />
{owners.map(({ nameFieldName, addressFieldName }) => {
const ownerName = createSafeFormValues[nameFieldName]
const ownerAddress = createSafeFormValues[addressFieldName]
const ownerName = createSafeFormValues[nameFieldName] || ownersWithENSName[ownerAddress]
return (
<React.Fragment key={`owner-${addressFieldName}`}>
<OwnersAddressesContainer>
Expand Down
1 change: 1 addition & 0 deletions src/routes/LoadSafePage/LoadSafePage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as safeVersion from 'src/logic/safe/utils/safeVersion'
import { GATEWAY_URL } from 'src/utils/constants'

const getENSAddressSpy = jest.spyOn(getWeb3ReadOnly().eth.ens, 'getAddress')
jest.spyOn(getWeb3ReadOnly().eth.ens, 'getResolver')

jest.spyOn(safeVersion, 'getSafeVersionInfo').mockImplementation(async () => ({
current: '1.3.0',
Expand Down
9 changes: 5 additions & 4 deletions src/routes/LoadSafePage/LoadSafePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ import {
FIELD_LOAD_IS_LOADING_SAFE_ADDRESS,
FIELD_LOAD_SAFE_ADDRESS,
FIELD_LOAD_SUGGESTED_SAFE_NAME,
FIELD_SAFE_OWNER_ENS_LIST,
FIELD_SAFE_OWNER_LIST,
LoadSafeFormValues,
} from './fields/loadFields'
import { extractPrefixedSafeAddress, generateSafeRoute, LOAD_SPECIFIC_SAFE_ROUTE, SAFE_ROUTES } from '../routes'
import { getShortName } from 'src/config'
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
import { getLoadSafeName } from './fields/utils'
import { getLoadSafeName, getOwnerName } from './fields/utils'
import { currentChainId } from 'src/logic/config/store/selectors'

function Load(): ReactElement {
Expand All @@ -54,6 +55,7 @@ function Load(): ReactElement {
[FIELD_LOAD_SAFE_ADDRESS]: safeAddress,
[FIELD_LOAD_IS_LOADING_SAFE_ADDRESS]: false,
[FIELD_SAFE_OWNER_LIST]: [],
[FIELD_SAFE_OWNER_ENS_LIST]: {},
}
setInitialFormValues(initialValues)
}, [safeAddress, safeRandomName])
Expand All @@ -63,11 +65,10 @@ function Load(): ReactElement {

const ownerEntries = ownerList
.map((owner) => {
const ownerFieldName = `owner-address-${owner.address}`
const ownerNameValue = values[ownerFieldName]
const ownerName = getOwnerName(values, owner.address)
return {
...owner,
name: ownerNameValue,
name: ownerName,
}
})
.filter((owner) => !!owner.name)
Expand Down
2 changes: 2 additions & 0 deletions src/routes/LoadSafePage/fields/loadFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const FIELD_LOAD_SUGGESTED_SAFE_NAME = 'suggestedSafeName'
export const FIELD_LOAD_SAFE_ADDRESS = 'safeAddress'
export const FIELD_LOAD_IS_LOADING_SAFE_ADDRESS = 'isLoadingSafeAddress'
export const FIELD_SAFE_OWNER_LIST = 'safeOwnerList'
export const FIELD_SAFE_OWNER_ENS_LIST = 'safeOwnerENSList'
export const FIELD_SAFE_THRESHOLD = 'safeThreshold'

export type OwnerFieldListItem = {
Expand All @@ -16,5 +17,6 @@ export type LoadSafeFormValues = {
[FIELD_LOAD_SAFE_ADDRESS]?: string
[FIELD_LOAD_IS_LOADING_SAFE_ADDRESS]: boolean
[FIELD_SAFE_OWNER_LIST]: Array<OwnerFieldListItem>
[FIELD_SAFE_OWNER_ENS_LIST]: Record<string, string>
[FIELD_SAFE_THRESHOLD]?: number
}
6 changes: 6 additions & 0 deletions src/routes/LoadSafePage/fields/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
FIELD_LOAD_CUSTOM_SAFE_NAME,
FIELD_LOAD_SAFE_ADDRESS,
FIELD_LOAD_SUGGESTED_SAFE_NAME,
FIELD_SAFE_OWNER_ENS_LIST,
LoadSafeFormValues,
} from './loadFields'

Expand All @@ -17,3 +18,8 @@ export function getLoadSafeName(formValues: LoadSafeFormValues, addressBook: Add
formValues[FIELD_LOAD_SUGGESTED_SAFE_NAME]
)
}

export function getOwnerName(formValues: LoadSafeFormValues, address: string): string {
const ownerFieldName = `owner-address-${address}`
return formValues[ownerFieldName] || formValues[FIELD_SAFE_OWNER_ENS_LIST][address]
}
Loading