[Address Book v2] - Refactor addressBook selectors (#2372)
This commit is contained in:
parent
b9b239e0e3
commit
cd9182cf4e
|
@ -4,20 +4,32 @@ import { getNetworkId } from 'src/config'
|
|||
import { ADDRESS_BOOK_DEFAULT_NAME, AddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { AppReduxState } from 'src/store'
|
||||
import { Overwrite } from 'src/types/helpers'
|
||||
import { checksumAddress } from 'src/utils/checksumAddress'
|
||||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
|
||||
const networkId = getNetworkId()
|
||||
|
||||
export const addressBookSelector = (state: AppReduxState): AppReduxState['addressBook'] => state['addressBook']
|
||||
|
||||
type AddressBookMap = {
|
||||
[chainId: number]: {
|
||||
[address: string]: AddressBookEntry
|
||||
}
|
||||
export const addressBookFromQueryParams = (state: AppReduxState): string | undefined => {
|
||||
return state.router.location?.query?.entryAddress
|
||||
}
|
||||
|
||||
export const addressBookMapSelector = createSelector(
|
||||
[addressBookSelector],
|
||||
(addressBook): AddressBookMap => {
|
||||
export const addressBookState = (state: AppReduxState): AppReduxState['addressBook'] => state['addressBook']
|
||||
|
||||
export const addressBookAddresses = createSelector([addressBookState], (addressBook): string[] => {
|
||||
return addressBook.map(({ address }) => address)
|
||||
})
|
||||
|
||||
type AddressBookMap = {
|
||||
[address: string]: AddressBookEntry
|
||||
}
|
||||
|
||||
type AddressBookMapByChain = {
|
||||
[chainId: number]: AddressBookMap
|
||||
}
|
||||
|
||||
export const addressBookAsMap = createSelector(
|
||||
[addressBookState],
|
||||
(addressBook): AddressBookMapByChain => {
|
||||
const addressBookMap = {}
|
||||
|
||||
addressBook.forEach((entry) => {
|
||||
|
@ -33,33 +45,45 @@ export const addressBookMapSelector = createSelector(
|
|||
},
|
||||
)
|
||||
|
||||
export const addressBookAddressesListSelector = createSelector([addressBookSelector], (addressBook): string[] =>
|
||||
addressBook.map(({ address }) => address),
|
||||
)
|
||||
type GetNameParams = Overwrite<Partial<AddressBookEntry>, { address: string }>
|
||||
|
||||
type GetNameParams = Overwrite<
|
||||
AddressBookEntry,
|
||||
{ chainId?: AddressBookEntry['chainId']; name?: AddressBookEntry['name'] }
|
||||
>
|
||||
|
||||
type GetNameReturnObject = Overwrite<GetNameParams, { chainId: AddressBookEntry['chainId'] }>
|
||||
|
||||
export const getNameFromAddressBookSelector = createSelector(
|
||||
export const addressBookEntryName = createSelector(
|
||||
[
|
||||
addressBookMapSelector,
|
||||
(_, { address, chainId = networkId }: GetNameParams): GetNameReturnObject => ({
|
||||
addressBookAsMap,
|
||||
(_, { address, chainId = networkId }: GetNameParams): { address: string; chainId: number } => ({
|
||||
address,
|
||||
chainId,
|
||||
}),
|
||||
],
|
||||
(addressBook, entry) => addressBook?.[entry.chainId]?.[entry.address]?.name ?? ADDRESS_BOOK_DEFAULT_NAME,
|
||||
(addressBook, { address, chainId }) => {
|
||||
if (isValidAddress(address)) {
|
||||
return addressBook?.[chainId]?.[checksumAddress(address)]?.name ?? ADDRESS_BOOK_DEFAULT_NAME
|
||||
}
|
||||
|
||||
return ADDRESS_BOOK_DEFAULT_NAME
|
||||
},
|
||||
)
|
||||
|
||||
export const addressBookQueryParamsSelector = (state: AppReduxState): string | undefined => {
|
||||
const { location } = state.router
|
||||
/*********************/
|
||||
/* Connected Network */
|
||||
/*********************/
|
||||
|
||||
if (location?.query) {
|
||||
const { entryAddress } = location.query
|
||||
return entryAddress
|
||||
}
|
||||
}
|
||||
export const currentNetworkAddressBook = createSelector(
|
||||
[addressBookState],
|
||||
(addressBook): AppReduxState['addressBook'] => {
|
||||
return addressBook.filter(({ chainId }) => chainId === networkId)
|
||||
},
|
||||
)
|
||||
|
||||
export const currentNetworkAddressBookAsMap = createSelector(
|
||||
[currentNetworkAddressBook],
|
||||
(addressBook): AddressBookMap => {
|
||||
const addressBookMap = {}
|
||||
|
||||
addressBook.forEach((entry) => {
|
||||
addressBookMap[entry.address] = entry
|
||||
})
|
||||
|
||||
return addressBookMap
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,32 +1,4 @@
|
|||
import {
|
||||
checkIfEntryWasDeletedFromAddressBook,
|
||||
getNameFromAddressBook,
|
||||
isValidAddressBookName,
|
||||
} from 'src/logic/addressBook/utils'
|
||||
import { AddressBookEntry, AddressBookState, makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
|
||||
const getMockAddressBookEntry = (address: string, name: string = 'test'): AddressBookEntry =>
|
||||
makeAddressBookEntry({
|
||||
address,
|
||||
name,
|
||||
})
|
||||
|
||||
describe('getNameFromSafeAddressBook', () => {
|
||||
const entry1 = getMockAddressBookEntry('123456', 'test1')
|
||||
const entry2 = getMockAddressBookEntry('78910', 'test2')
|
||||
const entry3 = getMockAddressBookEntry('4781321', 'test3')
|
||||
it('It should returns the user name given a safeAddressBook and an user account', () => {
|
||||
// given
|
||||
const safeAddressBook = [entry1, entry2, entry3]
|
||||
const expectedResult = entry2.name
|
||||
|
||||
// when
|
||||
const result = getNameFromAddressBook(safeAddressBook, entry2.address)
|
||||
|
||||
// then
|
||||
expect(result).toBe(expectedResult)
|
||||
})
|
||||
})
|
||||
import { isValidAddressBookName } from 'src/logic/addressBook/utils'
|
||||
|
||||
describe('isValidAddressBookName', () => {
|
||||
it('It should return false if given a blacklisted name like UNKNOWN', () => {
|
||||
|
@ -78,51 +50,3 @@ describe('isValidAddressBookName', () => {
|
|||
expect(result).toEqual(expectedResult)
|
||||
})
|
||||
})
|
||||
|
||||
describe('checkIfEntryWasDeletedFromAddressBook', () => {
|
||||
const mockAdd1 = '0x696fd93D725d84acfFf6c62a1fe8C94E1c9E934A'
|
||||
const mockAdd2 = '0x2C7aC78b01Be0FC66AD29b684ffAb0C93B381D00'
|
||||
const mockAdd3 = '0x537BD452c3505FC07bA242E437bD29D4E1DC9126'
|
||||
const entry1 = getMockAddressBookEntry(mockAdd1, 'test1')
|
||||
const entry2 = getMockAddressBookEntry(mockAdd2, 'test2')
|
||||
const entry3 = getMockAddressBookEntry(mockAdd3, 'test3')
|
||||
it('It should return true if a given entry was deleted from addressBook', () => {
|
||||
// given
|
||||
const addressBookEntry = entry1
|
||||
const addressBook: AddressBookState = [entry2, entry3]
|
||||
const safeAlreadyLoaded = true
|
||||
const expectedResult = true
|
||||
|
||||
// when
|
||||
const result = checkIfEntryWasDeletedFromAddressBook(addressBookEntry, addressBook, safeAlreadyLoaded)
|
||||
|
||||
// then
|
||||
expect(result).toEqual(expectedResult)
|
||||
})
|
||||
it('It should return false if a given entry was not deleted from addressBook', () => {
|
||||
// given
|
||||
const addressBookEntry = entry1
|
||||
const addressBook: AddressBookState = [entry1, entry2, entry3]
|
||||
const safeAlreadyLoaded = true
|
||||
const expectedResult = false
|
||||
|
||||
// when
|
||||
const result = checkIfEntryWasDeletedFromAddressBook(addressBookEntry, addressBook, safeAlreadyLoaded)
|
||||
|
||||
// then
|
||||
expect(result).toEqual(expectedResult)
|
||||
})
|
||||
it('It should return false if the safe was not already loaded', () => {
|
||||
// given
|
||||
const addressBookEntry = entry1
|
||||
const addressBook: AddressBookState = [entry1, entry2, entry3]
|
||||
const safeAlreadyLoaded = false
|
||||
const expectedResult = false
|
||||
|
||||
// when
|
||||
const result = checkIfEntryWasDeletedFromAddressBook(addressBookEntry, addressBook, safeAlreadyLoaded)
|
||||
|
||||
// then
|
||||
expect(result).toEqual(expectedResult)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { mustBeEthereumContractAddress } from 'src/components/forms/validator'
|
||||
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
|
||||
import { AddressBookEntry, AddressBookState } from 'src/logic/addressBook/model/addressBook'
|
||||
import { sameAddress } from 'src/logic/wallets/ethAddresses'
|
||||
import { AppReduxState } from 'src/store'
|
||||
|
@ -17,22 +16,6 @@ export type OldAddressBookType = {
|
|||
|
||||
export const ADDRESS_BOOK_INVALID_NAMES = ['UNKNOWN', 'OWNER #', 'MY WALLET']
|
||||
|
||||
type GetNameFromAddressBookOptions = {
|
||||
filterOnlyValidName: boolean
|
||||
}
|
||||
|
||||
export const getNameFromAddressBook = (
|
||||
addressBook: AddressBookState,
|
||||
userAddress: string,
|
||||
options?: GetNameFromAddressBookOptions,
|
||||
): string | null => {
|
||||
const entry = addressBook.find((addressBookItem) => addressBookItem.address === userAddress)
|
||||
if (entry) {
|
||||
return options?.filterOnlyValidName ? getValidAddressBookName(entry.name) : entry.name
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export const isValidAddressBookName = (addressBookName: string): boolean => {
|
||||
const hasInvalidName = ADDRESS_BOOK_INVALID_NAMES.find((invalidName) =>
|
||||
addressBookName?.toUpperCase().includes(invalidName),
|
||||
|
@ -40,50 +23,6 @@ export const isValidAddressBookName = (addressBookName: string): boolean => {
|
|||
return !hasInvalidName
|
||||
}
|
||||
|
||||
// TODO: is this really required?
|
||||
export const getValidAddressBookName = (addressBookName: string): string | null => {
|
||||
return isValidAddressBookName(addressBookName) ? addressBookName : null
|
||||
}
|
||||
|
||||
export const formatAddressListToAddressBookNames = (
|
||||
addressBook: AddressBookState,
|
||||
addresses: string[],
|
||||
): AddressBookEntry[] => {
|
||||
if (!addresses.length) {
|
||||
return []
|
||||
}
|
||||
return addresses.map((address) => {
|
||||
const ownerName = getNameFromAddressBook(addressBook, address)
|
||||
return {
|
||||
address: address,
|
||||
name: ownerName || '',
|
||||
chainId: ETHEREUM_NETWORK.UNKNOWN,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* If the safe is not loaded, the owner wasn't deleted
|
||||
* If the safe is already loaded and the owner has a valid name, will return true if the address is not already on the addressBook
|
||||
* @param name
|
||||
* @param address
|
||||
* @param addressBook
|
||||
* @param safeAlreadyLoaded
|
||||
*/
|
||||
export const checkIfEntryWasDeletedFromAddressBook = (
|
||||
{ name, address }: AddressBookEntry,
|
||||
addressBook: AddressBookState,
|
||||
safeAlreadyLoaded: boolean,
|
||||
): boolean => {
|
||||
if (!safeAlreadyLoaded) {
|
||||
return false
|
||||
}
|
||||
|
||||
const addressShouldBeOnTheAddressBook = !!getValidAddressBookName(name)
|
||||
const isAlreadyInAddressBook = !!addressBook.find((entry) => sameAddress(entry.address, address))
|
||||
return addressShouldBeOnTheAddressBook && !isAlreadyInAddressBook
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered list of AddressBookEntries whose addresses are contracts
|
||||
* @param {Array<AddressBookEntry>} addressBook
|
||||
|
|
|
@ -2,9 +2,8 @@ import { List } from 'immutable'
|
|||
import { matchPath } from 'react-router-dom'
|
||||
import { createSelector } from 'reselect'
|
||||
|
||||
import { getNetworkId } from 'src/config'
|
||||
import { AddressBookEntry, makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { addressBookMapSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
|
||||
import makeSafe, { SafeRecord, SafeRecordProps } from 'src/logic/safe/store/models/safe'
|
||||
import { SAFE_REDUCER_ID } from 'src/logic/safe/store/reducer/safe'
|
||||
import { SAFELIST_ADDRESS } from 'src/routes/routes'
|
||||
|
@ -72,23 +71,20 @@ export const currentSafeTotalFiatBalance = createSelector(currentSafe, safeField
|
|||
/*************************/
|
||||
/* With AddressBook Data */
|
||||
/*************************/
|
||||
const chainId = getNetworkId()
|
||||
const baseSafeWithName = { ...baseSafe.toJS(), name: '' }
|
||||
|
||||
export type SafeRecordWithNames = Overwrite<SafeRecordProps, { owners: AddressBookEntry[] }> & { name: string }
|
||||
|
||||
export const safesWithNamesAsList = createSelector(
|
||||
[safesAsList, addressBookMapSelector],
|
||||
[safesAsList, currentNetworkAddressBookAsMap],
|
||||
(safesList, addressBookMap): SafeRecordWithNames[] => {
|
||||
const addressBook = addressBookMap?.[chainId]
|
||||
|
||||
return safesList
|
||||
.map((safeRecord) => {
|
||||
const safe = safeRecord.toObject()
|
||||
const name = addressBook?.[safe.address]?.name ?? ''
|
||||
const name = addressBookMap?.[safe.address]?.name ?? ''
|
||||
|
||||
const owners = safe.owners.map((ownerAddress) => {
|
||||
return addressBook?.[ownerAddress] ?? makeAddressBookEntry({ address: ownerAddress, name: '' })
|
||||
return addressBookMap?.[ownerAddress] ?? makeAddressBookEntry({ address: ownerAddress, name: '' })
|
||||
})
|
||||
|
||||
return { ...safe, name, owners }
|
||||
|
|
|
@ -14,10 +14,9 @@ import Hairline from 'src/components/layout/Hairline'
|
|||
import Paragraph from 'src/components/layout/Paragraph'
|
||||
import Row from 'src/components/layout/Row'
|
||||
import OpenPaper from 'src/components/Stepper/OpenPaper'
|
||||
import { AddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { AddressBookEntry, makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
|
||||
|
||||
import { formatAddressListToAddressBookNames } from 'src/logic/addressBook/utils'
|
||||
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
|
||||
import { FIELD_LOAD_ADDRESS, THRESHOLD } from 'src/routes/load/components/fields'
|
||||
import { getOwnerAddressBy, getOwnerNameBy } from 'src/routes/open/components/fields'
|
||||
|
@ -33,12 +32,6 @@ const calculateSafeValues = (owners, threshold, values) => {
|
|||
return initialValues
|
||||
}
|
||||
|
||||
const useAddressBookForOwnersNames = (ownersList: string[]): AddressBookEntry[] => {
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
|
||||
return formatAddressListToAddressBookNames(addressBook, ownersList)
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
interface OwnerListComponentProps {
|
||||
|
@ -49,8 +42,19 @@ interface OwnerListComponentProps {
|
|||
const OwnerListComponent = ({ values, updateInitialProps }: OwnerListComponentProps): ReactElement => {
|
||||
const [owners, setOwners] = useState<string[]>([])
|
||||
const classes = useStyles()
|
||||
const addressBookMap = useSelector(currentNetworkAddressBookAsMap)
|
||||
const [ownersWithName, setOwnersWithName] = useState<AddressBookEntry[]>([])
|
||||
|
||||
const ownersWithNames = useAddressBookForOwnersNames(owners)
|
||||
useEffect(() => {
|
||||
setOwnersWithName(
|
||||
owners.map((address) =>
|
||||
makeAddressBookEntry({
|
||||
address,
|
||||
name: addressBookMap[address]?.name ?? '',
|
||||
}),
|
||||
),
|
||||
)
|
||||
}, [addressBookMap, owners, ownersWithName])
|
||||
|
||||
useEffect(() => {
|
||||
let isCurrent = true
|
||||
|
@ -91,7 +95,7 @@ const OwnerListComponent = ({ values, updateInitialProps }: OwnerListComponentPr
|
|||
</Row>
|
||||
<Hairline />
|
||||
<Block margin="md" padding="md">
|
||||
{ownersWithNames.map(({ address, name }, index) => {
|
||||
{ownersWithName.map(({ address, name }, index) => {
|
||||
return (
|
||||
<Row className={classes.owner} key={address} data-testid="owner-row">
|
||||
<Col className={classes.ownerName} xs={4}>
|
||||
|
|
|
@ -17,14 +17,15 @@ import {
|
|||
getOwnerAddressBy,
|
||||
getOwnerNameBy,
|
||||
} from 'src/routes/open/components/fields'
|
||||
import { WelcomeLayout } from 'src/routes/welcome/components/index'
|
||||
import { WelcomeLayout } from 'src/routes/welcome/components'
|
||||
import { history } from 'src/store'
|
||||
import { secondary, sm } from 'src/theme/variables'
|
||||
import { providerNameSelector, userAccountSelector } from 'src/logic/wallets/store/selectors'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
import { SafeProps } from 'src/routes/open/container/Open'
|
||||
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
|
||||
import { sameString } from 'src/utils/strings'
|
||||
|
||||
const { useEffect } = React
|
||||
|
||||
|
@ -39,12 +40,11 @@ export type InitialValuesForm = {
|
|||
}
|
||||
|
||||
const useInitialValuesFrom = (userAccount: string, safeProps?: SafeProps): InitialValuesForm => {
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const ownerName = getNameFromAddressBook(addressBook, userAccount, { filterOnlyValidName: true })
|
||||
const ownerName = useSelector((state) => addressBookEntryName(state, { address: userAccount }))
|
||||
|
||||
if (!safeProps) {
|
||||
return {
|
||||
[getOwnerNameBy(0)]: ownerName || 'My Wallet',
|
||||
[getOwnerNameBy(0)]: sameString(ownerName, ADDRESS_BOOK_DEFAULT_NAME) ? 'My Wallet' : ownerName,
|
||||
[getOwnerAddressBy(0)]: userAccount,
|
||||
[FIELD_CONFIRMATIONS]: '1',
|
||||
[FIELD_CREATION_PROXY_SALT]: Date.now(),
|
||||
|
|
|
@ -38,8 +38,7 @@ import {
|
|||
} from 'src/routes/open/components/fields'
|
||||
import { getAccountsFrom } from 'src/routes/open/utils/safeDataExtractor'
|
||||
import { useSelector } from 'react-redux'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
|
||||
const { useState } = React
|
||||
|
||||
|
@ -116,7 +115,7 @@ const SafeOwnersForm = (props): React.ReactElement => {
|
|||
const classes = useStyles()
|
||||
|
||||
const validOwners = getNumOwnersFrom(values)
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const addressBook = useSelector(currentNetworkAddressBook)
|
||||
|
||||
const [numOwners, setNumOwners] = useState(validOwners)
|
||||
const [qrModalOpen, setQrModalOpen] = useState(false)
|
||||
|
@ -206,9 +205,7 @@ const SafeOwnersForm = (props): React.ReactElement => {
|
|||
<Col className={classes.ownerAddress} xs={7}>
|
||||
<StyledAddressInput
|
||||
fieldMutator={(newOwnerAddress) => {
|
||||
const newOwnerName = getNameFromAddressBook(addressBook, newOwnerAddress, {
|
||||
filterOnlyValidName: true,
|
||||
})
|
||||
const newOwnerName = addressBook[newOwnerAddress]?.name
|
||||
form.mutators.setValue(addressName, newOwnerAddress)
|
||||
if (newOwnerName) {
|
||||
form.mutators.setValue(ownerName, newOwnerName)
|
||||
|
|
|
@ -13,7 +13,7 @@ import { composeValidators, required, uniqueAddress, validAddressBookName } from
|
|||
import Block from 'src/components/layout/Block'
|
||||
import Col from 'src/components/layout/Col'
|
||||
import Row from 'src/components/layout/Row'
|
||||
import { addressBookAddressesListSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookAddresses } from 'src/logic/addressBook/store/selectors'
|
||||
import { AddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { Entry } from 'src/routes/safe/components/AddressBook'
|
||||
|
||||
|
@ -54,7 +54,7 @@ export const CreateEditEntryModal = ({
|
|||
}
|
||||
}
|
||||
|
||||
const storedAddresses = useSelector(addressBookAddressesListSelector)
|
||||
const storedAddresses = useSelector(addressBookAddresses)
|
||||
const isUniqueAddress = uniqueAddress(storedAddresses)
|
||||
|
||||
return (
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useDispatch, useSelector } from 'react-redux'
|
|||
|
||||
import { sameString } from 'src/utils/strings'
|
||||
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
|
||||
import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
import { SAFELIST_ADDRESS } from 'src/routes/routes'
|
||||
import { safeAddressFromUrl } from 'src/logic/safe/store/selectors'
|
||||
import { xs } from 'src/theme/variables'
|
||||
|
@ -52,7 +52,7 @@ export const EllipsisTransactionDetails = ({
|
|||
const currentSafeAddress = useSelector(safeAddressFromUrl)
|
||||
const isOwnerConnected = useSelector(grantedSelector)
|
||||
|
||||
const recipientName = useSelector((state) => getNameFromAddressBookSelector(state, { address }))
|
||||
const recipientName = useSelector((state) => addressBookEntryName(state, { address }))
|
||||
// We have to check that the name returned is not UNKNOWN
|
||||
const isStoredInAddressBook = !sameString(recipientName, ADDRESS_BOOK_DEFAULT_NAME)
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ import { enhanceSnackbarForAction, getNotificationsFromTxType } from 'src/logic/
|
|||
import enqueueSnackbar from 'src/logic/notifications/store/actions/enqueueSnackbar'
|
||||
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
|
||||
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { AddressBookState } from 'src/logic/addressBook/model/addressBook'
|
||||
import { addressBookState } from 'src/logic/addressBook/store/selectors'
|
||||
|
||||
import { lg, md, background } from 'src/theme/variables'
|
||||
|
||||
|
@ -57,7 +56,7 @@ const StyledCSVLink = styled(CSVDownloader)`
|
|||
|
||||
export const ExportEntriesModal = ({ isOpen, onClose }: ExportEntriesModalProps): ReactElement => {
|
||||
const dispatch = useDispatch()
|
||||
const addressBook: AddressBookState = useSelector(addressBookSelector)
|
||||
const addressBook = useSelector(addressBookState)
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
const [error, setError] = useState<string | undefined>('')
|
||||
const [csvData, setCsvData] = useState<string>('')
|
||||
|
|
|
@ -19,7 +19,7 @@ import Col from 'src/components/layout/Col'
|
|||
import Row from 'src/components/layout/Row'
|
||||
import { AddressBookEntry, makeAddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { addressBookAddOrUpdate, addressBookImport, addressBookRemove } from 'src/logic/addressBook/store/actions'
|
||||
import { addressBookQueryParamsSelector, addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookFromQueryParams, currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
import { isUserAnOwnerOfAnySafe, sameAddress } from 'src/logic/wallets/ethAddresses'
|
||||
import { CreateEditEntryModal } from 'src/routes/safe/components/AddressBook/CreateEditEntryModal'
|
||||
import { ExportEntriesModal } from 'src/routes/safe/components/AddressBook/ExportEntriesModal'
|
||||
|
@ -72,8 +72,8 @@ const AddressBookTable = (): ReactElement => {
|
|||
const autoColumns = columns.filter(({ custom }) => !custom)
|
||||
const dispatch = useDispatch()
|
||||
const safesList = useSelector(safesAsList)
|
||||
const entryAddressToEditOrCreateNew = useSelector(addressBookQueryParamsSelector)
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const entryAddressToEditOrCreateNew = useSelector(addressBookFromQueryParams)
|
||||
const addressBook = useSelector(currentNetworkAddressBook)
|
||||
const granted = useSelector(grantedSelector)
|
||||
const [selectedEntry, setSelectedEntry] = useState<Entry>(initialEntryState)
|
||||
const [editCreateEntryModalOpen, setEditCreateEntryModalOpen] = useState(false)
|
||||
|
|
|
@ -8,7 +8,7 @@ import { mustBeEthereumAddress, mustBeEthereumContractAddress } from 'src/compon
|
|||
import { getNetworkId, isFeatureEnabled } from 'src/config'
|
||||
import { FEATURES } from 'src/config/networks/network.d'
|
||||
import { AddressBookEntry } from 'src/logic/addressBook/model/addressBook'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
import { filterContractAddressBookEntries, filterAddressEntries } from 'src/logic/addressBook/utils'
|
||||
import { isValidEnsName, isValidCryptoDomainName } from 'src/logic/wallets/ethAddresses'
|
||||
import { getAddressFromDomain } from 'src/logic/wallets/getWeb3'
|
||||
|
@ -172,7 +172,7 @@ const BaseAddressBookInput = ({
|
|||
}
|
||||
|
||||
export const AddressBookInput = (props: AddressBookProps): ReactElement => {
|
||||
const addressBookEntries = useSelector(addressBookSelector)
|
||||
const addressBookEntries = useSelector(currentNetworkAddressBook)
|
||||
const [validationText, setValidationText] = useState<string>('')
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -196,7 +196,7 @@ export const ContractsAddressBookInput = ({
|
|||
setSelectedEntry,
|
||||
...props
|
||||
}: AddressBookProps): ReactElement => {
|
||||
const addressBookEntries = useSelector(addressBookSelector)
|
||||
const addressBookEntries = useSelector(currentNetworkAddressBook)
|
||||
const [filteredEntries, setFilteredEntries] = useState<AddressBookEntry[]>([])
|
||||
const [validationText, setValidationText] = useState<string>('')
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import {
|
|||
getValueFromTxInputs,
|
||||
} from 'src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/utils'
|
||||
import { useEstimateTransactionGas, EstimationStatus } from 'src/logic/hooks/useEstimateTransactionGas'
|
||||
import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
import { useEstimationStatus } from 'src/logic/hooks/useEstimationStatus'
|
||||
import { ButtonStatus, Modal } from 'src/components/Modal'
|
||||
import { TransactionFees } from 'src/components/TransactionsFees'
|
||||
|
@ -61,9 +61,7 @@ const ContractInteractionReview = ({ onClose, onPrev, tx }: Props): React.ReactE
|
|||
const [manualSafeTxGas, setManualSafeTxGas] = useState(0)
|
||||
const [manualGasPrice, setManualGasPrice] = useState<string | undefined>()
|
||||
const [manualGasLimit, setManualGasLimit] = useState<string | undefined>()
|
||||
const addressName = useSelector((state) =>
|
||||
getNameFromAddressBookSelector(state, { address: tx.contractAddress as string }),
|
||||
)
|
||||
const addressName = useSelector((state) => addressBookEntryName(state, { address: tx.contractAddress as string }))
|
||||
|
||||
const [txInfo, setTxInfo] = useState<{
|
||||
txRecipient: string
|
||||
|
|
|
@ -15,8 +15,7 @@ import Row from 'src/components/layout/Row'
|
|||
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
|
||||
import { Modal } from 'src/components/Modal'
|
||||
import WhenFieldChanges from 'src/components/WhenFieldChanges'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
import { nftAssetsSelector, nftTokensSelector } from 'src/logic/collectibles/store/selectors'
|
||||
import { Erc721Transfer } from 'src/logic/safe/store/models/types/gateway'
|
||||
import SafeInfo from 'src/routes/safe/components/Balances/SendModal/SafeInfo'
|
||||
|
@ -70,7 +69,7 @@ const SendCollectible = ({
|
|||
const classes = useStyles()
|
||||
const nftAssets = useSelector(nftAssetsSelector)
|
||||
const nftTokens = useSelector(nftTokensSelector)
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const addressBook = useSelector(currentNetworkAddressBook)
|
||||
const [selectedEntry, setSelectedEntry] = useState<{ address: string; name: string } | null>(() => {
|
||||
const defaultEntry = { address: recipientAddress || '', name: '' }
|
||||
|
||||
|
@ -138,7 +137,7 @@ const SendCollectible = ({
|
|||
if (scannedAddress.startsWith('ethereum:')) {
|
||||
scannedAddress = scannedAddress.replace('ethereum:', '')
|
||||
}
|
||||
const scannedName = addressBook ? getNameFromAddressBook(addressBook, scannedAddress) : ''
|
||||
const scannedName = addressBook[scannedAddress]?.name ?? ''
|
||||
mutators.setRecipient(scannedAddress)
|
||||
setSelectedEntry({
|
||||
name: scannedName ?? '',
|
||||
|
|
|
@ -26,8 +26,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 { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
import { sameAddress } from 'src/logic/wallets/ethAddresses'
|
||||
import { SpendingLimit } from 'src/logic/safe/store/models/safe'
|
||||
import { userAccountSelector } from 'src/logic/wallets/store/selectors'
|
||||
|
@ -98,7 +97,7 @@ const SendFunds = ({
|
|||
}: SendFundsProps): ReactElement => {
|
||||
const classes = useStyles()
|
||||
const tokens = useSelector(extendedSafeTokensSelector)
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const addressBook = useSelector(currentNetworkAddressBook)
|
||||
const { nativeCoin } = getNetworkInfo()
|
||||
const [selectedEntry, setSelectedEntry] = useState<{ address: string; name: string } | null>(() => {
|
||||
const defaultEntry = { address: recipientAddress || '', name: '' }
|
||||
|
@ -212,7 +211,7 @@ const SendFunds = ({
|
|||
if (scannedAddress.startsWith('ethereum:')) {
|
||||
scannedAddress = scannedAddress.replace('ethereum:', '')
|
||||
}
|
||||
const scannedName = addressBook ? getNameFromAddressBook(addressBook, scannedAddress) : ''
|
||||
const scannedName = addressBook[scannedAddress]?.name ?? ''
|
||||
const addressErrorMessage = mustBeEthereumAddress(scannedAddress)
|
||||
if (!addressErrorMessage) {
|
||||
mutators.setRecipient(scannedAddress)
|
||||
|
|
|
@ -8,7 +8,6 @@ import { OnChange } from 'react-final-form-listeners'
|
|||
|
||||
import { styles } from './style'
|
||||
|
||||
import { getNetworkId } from 'src/config'
|
||||
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
|
||||
import AddressInput from 'src/components/forms/AddressInput'
|
||||
import Field from 'src/components/forms/Field'
|
||||
|
@ -26,7 +25,7 @@ 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 { addressBookMapSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
|
||||
import { currentSafe } from 'src/logic/safe/store/selectors'
|
||||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
|
||||
|
@ -51,8 +50,6 @@ const formMutators: Record<
|
|||
|
||||
const useStyles = makeStyles(styles)
|
||||
|
||||
const chainId = getNetworkId()
|
||||
|
||||
type OwnerFormProps = {
|
||||
onClose: () => void
|
||||
onSubmit: (values) => void
|
||||
|
@ -64,7 +61,7 @@ export const OwnerForm = ({ onClose, onSubmit, initialValues }: OwnerFormProps):
|
|||
const handleSubmit = (values) => {
|
||||
onSubmit(values)
|
||||
}
|
||||
const addressBookMap = useSelector(addressBookMapSelector)
|
||||
const addressBookMap = useSelector(currentNetworkAddressBookAsMap)
|
||||
const { address: safeAddress = '', owners = [] } = useSelector(currentSafe) ?? {}
|
||||
const ownerDoesntExist = uniqueAddress(owners)
|
||||
const ownerAddressIsNotSafeAddress = addressIsNotCurrentSafe(safeAddress)
|
||||
|
@ -122,7 +119,7 @@ export const OwnerForm = ({ onClose, onSubmit, initialValues }: OwnerFormProps):
|
|||
<OnChange name="ownerAddress">
|
||||
{async (address: string) => {
|
||||
if (isValidAddress(address)) {
|
||||
const { name: ownerName } = addressBookMap[chainId][address]
|
||||
const ownerName = addressBookMap[address]?.name
|
||||
if (ownerName) {
|
||||
mutators.setOwnerName(ownerName)
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ import Row from 'src/components/layout/Row'
|
|||
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
|
||||
import { Modal } from 'src/components/Modal'
|
||||
import { currentSafe } from 'src/logic/safe/store/selectors'
|
||||
import { addressBookMapSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { currentNetworkAddressBookAsMap } from 'src/logic/addressBook/store/selectors'
|
||||
import { OwnerData } from 'src/routes/safe/components/Settings/ManageOwners/dataFetcher'
|
||||
import { isValidAddress } from 'src/utils/isValidAddress'
|
||||
|
||||
import { useStyles } from './style'
|
||||
import { getExplorerInfo, getNetworkId } from 'src/config'
|
||||
import { getExplorerInfo } from 'src/config'
|
||||
import { EthHashInfo } from '@gnosis.pm/safe-react-components'
|
||||
|
||||
export const REPLACE_OWNER_NAME_INPUT_TEST_ID = 'replace-owner-name-input'
|
||||
|
@ -50,8 +50,6 @@ const formMutators: Record<
|
|||
},
|
||||
}
|
||||
|
||||
const chainId = getNetworkId()
|
||||
|
||||
type NewOwnerProps = {
|
||||
ownerAddress: string
|
||||
ownerName: string
|
||||
|
@ -70,7 +68,7 @@ export const OwnerForm = ({ onClose, onSubmit, owner, initialValues }: OwnerForm
|
|||
const handleSubmit = (values: NewOwnerProps) => {
|
||||
onSubmit(values)
|
||||
}
|
||||
const addressBookMap = useSelector(addressBookMapSelector)
|
||||
const addressBookMap = useSelector(currentNetworkAddressBookAsMap)
|
||||
const { address: safeAddress = '', owners } = useSelector(currentSafe) ?? {}
|
||||
const ownerDoesntExist = uniqueAddress(owners)
|
||||
const ownerAddressIsNotSafeAddress = addressIsNotCurrentSafe(safeAddress)
|
||||
|
@ -149,7 +147,7 @@ export const OwnerForm = ({ onClose, onSubmit, owner, initialValues }: OwnerForm
|
|||
<OnChange name="ownerAddress">
|
||||
{async (address: string) => {
|
||||
if (isValidAddress(address)) {
|
||||
const ownerName = addressBookMap?.[chainId]?.[address]?.name
|
||||
const ownerName = addressBookMap[address]?.name
|
||||
if (ownerName) {
|
||||
mutators.setOwnerName(ownerName)
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@ import styled from 'styled-components'
|
|||
|
||||
import { ScanQRWrapper } from 'src/components/ScanQRModal/ScanQRWrapper'
|
||||
import { getExplorerInfo } from 'src/config'
|
||||
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
|
||||
import { currentNetworkAddressBook } from 'src/logic/addressBook/store/selectors'
|
||||
import { AddressBookInput } from 'src/routes/safe/components/Balances/SendModal/screens/AddressBookInput'
|
||||
import { sameString } from 'src/utils/strings'
|
||||
|
||||
|
@ -40,13 +39,11 @@ const Beneficiary = (): ReactElement => {
|
|||
}
|
||||
}, [mutators, pristine, selectedEntry])
|
||||
|
||||
const addressBook = useSelector(addressBookSelector)
|
||||
const addressBook = useSelector(currentNetworkAddressBook)
|
||||
|
||||
const handleScan = (value, closeQrModal) => {
|
||||
const scannedAddress = value.startsWith('ethereum:') ? value.replace('ethereum:', '') : value
|
||||
const scannedName = addressBook
|
||||
? getNameFromAddressBook(addressBook, scannedAddress, { filterOnlyValidName: true }) ?? ''
|
||||
: ''
|
||||
const scannedName = addressBook[scannedAddress]?.name ?? ''
|
||||
|
||||
mutators?.setBeneficiary?.(scannedAddress)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { ReactElement } from 'react'
|
|||
import { useSelector } from 'react-redux'
|
||||
|
||||
import { getExplorerInfo } from 'src/config'
|
||||
import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
|
||||
import { sameString } from 'src/utils/strings'
|
||||
|
||||
|
@ -15,7 +15,7 @@ interface AddressInfoProps {
|
|||
}
|
||||
|
||||
const AddressInfo = ({ address, title }: AddressInfoProps): ReactElement => {
|
||||
const name = useSelector((state) => getNameFromAddressBookSelector(state, { address }))
|
||||
const name = useSelector((state) => addressBookEntryName(state, { address }))
|
||||
const explorerUrl = getExplorerInfo(address)
|
||||
|
||||
return (
|
||||
|
|
|
@ -3,12 +3,12 @@ import React, { ReactElement } from 'react'
|
|||
import { useSelector } from 'react-redux'
|
||||
|
||||
import { getExplorerInfo } from 'src/config'
|
||||
import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
|
||||
import { sameString } from 'src/utils/strings'
|
||||
|
||||
export const OwnerRow = ({ address }: { address: string }): ReactElement => {
|
||||
const ownerName = useSelector((state) => getNameFromAddressBookSelector(state, { address }))
|
||||
const ownerName = useSelector((state) => addressBookEntryName(state, { address }))
|
||||
|
||||
return (
|
||||
<EthHashInfo
|
||||
|
|
|
@ -2,14 +2,14 @@ import { useSelector } from 'react-redux'
|
|||
|
||||
import { sameString } from 'src/utils/strings'
|
||||
import { ADDRESS_BOOK_DEFAULT_NAME } from 'src/logic/addressBook/model/addressBook'
|
||||
import { getNameFromAddressBookSelector } from 'src/logic/addressBook/store/selectors'
|
||||
import { addressBookEntryName } from 'src/logic/addressBook/store/selectors'
|
||||
|
||||
type AddressInfo = { name: string | undefined; image: string | undefined }
|
||||
|
||||
type UseKnownAddressResponse = AddressInfo & { isAddressBook: boolean }
|
||||
|
||||
export const useKnownAddress = (address: string, addressInfo: AddressInfo): UseKnownAddressResponse => {
|
||||
const recipientName = useSelector((state) => getNameFromAddressBookSelector(state, { address }))
|
||||
const recipientName = useSelector((state) => addressBookEntryName(state, { address }))
|
||||
// We have to check that the name returned is not UNKNOWN
|
||||
const isInAddressBook = !sameString(recipientName, ADDRESS_BOOK_DEFAULT_NAME)
|
||||
|
||||
|
|
Loading…
Reference in New Issue