From cd9182cf4ef98a5eae56a4550d300fad2f25b032 Mon Sep 17 00:00:00 2001 From: Fernando <fernando.greco@gmail.com> Date: Mon, 7 Jun 2021 15:47:16 -0300 Subject: [PATCH] [Address Book v2] - Refactor addressBook selectors (#2372) --- .../addressBook/store/selectors/index.ts | 84 ++++++++++++------- .../utils/__tests__/addressBookUtils.test.ts | 78 +---------------- src/logic/addressBook/utils/index.ts | 61 -------------- src/logic/safe/store/selectors/index.ts | 12 +-- .../load/components/OwnerList/index.tsx | 26 +++--- src/routes/open/components/Layout.tsx | 12 +-- .../SafeOwnersConfirmationsForm/index.tsx | 9 +- .../CreateEditEntryModal/index.tsx | 4 +- .../EllipsisTransactionDetails/index.tsx | 4 +- .../AddressBook/ExportEntriesModal/index.tsx | 5 +- .../safe/components/AddressBook/index.tsx | 6 +- .../screens/AddressBookInput/index.tsx | 6 +- .../ContractInteraction/Review/index.tsx | 6 +- .../screens/SendCollectible/index.tsx | 7 +- .../SendModal/screens/SendFunds/index.tsx | 7 +- .../AddOwnerModal/screens/OwnerForm/index.tsx | 9 +- .../screens/OwnerForm/index.tsx | 10 +-- .../SpendingLimit/FormFields/Beneficiary.tsx | 9 +- .../SpendingLimit/InfoDisplay/AddressInfo.tsx | 4 +- .../Transactions/TxList/OwnerRow.tsx | 4 +- .../TxList/hooks/useKnownAddress.ts | 4 +- 21 files changed, 119 insertions(+), 248 deletions(-) diff --git a/src/logic/addressBook/store/selectors/index.ts b/src/logic/addressBook/store/selectors/index.ts index f28d4d4c..e2fcb6e3 100644 --- a/src/logic/addressBook/store/selectors/index.ts +++ b/src/logic/addressBook/store/selectors/index.ts @@ -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 + }, +) diff --git a/src/logic/addressBook/utils/__tests__/addressBookUtils.test.ts b/src/logic/addressBook/utils/__tests__/addressBookUtils.test.ts index f7f006e0..d1495f36 100644 --- a/src/logic/addressBook/utils/__tests__/addressBookUtils.test.ts +++ b/src/logic/addressBook/utils/__tests__/addressBookUtils.test.ts @@ -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) - }) -}) diff --git a/src/logic/addressBook/utils/index.ts b/src/logic/addressBook/utils/index.ts index c08e462c..8173d08c 100644 --- a/src/logic/addressBook/utils/index.ts +++ b/src/logic/addressBook/utils/index.ts @@ -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 diff --git a/src/logic/safe/store/selectors/index.ts b/src/logic/safe/store/selectors/index.ts index a0ab3178..0cd6c7d4 100644 --- a/src/logic/safe/store/selectors/index.ts +++ b/src/logic/safe/store/selectors/index.ts @@ -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 } diff --git a/src/routes/load/components/OwnerList/index.tsx b/src/routes/load/components/OwnerList/index.tsx index afea0b75..5514571f 100644 --- a/src/routes/load/components/OwnerList/index.tsx +++ b/src/routes/load/components/OwnerList/index.tsx @@ -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}> diff --git a/src/routes/open/components/Layout.tsx b/src/routes/open/components/Layout.tsx index 9ae2b4e3..26f5f6b6 100644 --- a/src/routes/open/components/Layout.tsx +++ b/src/routes/open/components/Layout.tsx @@ -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(), diff --git a/src/routes/open/components/SafeOwnersConfirmationsForm/index.tsx b/src/routes/open/components/SafeOwnersConfirmationsForm/index.tsx index 4b4a7704..a6b0aab0 100644 --- a/src/routes/open/components/SafeOwnersConfirmationsForm/index.tsx +++ b/src/routes/open/components/SafeOwnersConfirmationsForm/index.tsx @@ -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) diff --git a/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx b/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx index fe3bc4dd..1d22f4ff 100644 --- a/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx +++ b/src/routes/safe/components/AddressBook/CreateEditEntryModal/index.tsx @@ -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 ( diff --git a/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx b/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx index 43eeff44..595c0391 100644 --- a/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx +++ b/src/routes/safe/components/AddressBook/EllipsisTransactionDetails/index.tsx @@ -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) diff --git a/src/routes/safe/components/AddressBook/ExportEntriesModal/index.tsx b/src/routes/safe/components/AddressBook/ExportEntriesModal/index.tsx index 7360e853..647c7e83 100644 --- a/src/routes/safe/components/AddressBook/ExportEntriesModal/index.tsx +++ b/src/routes/safe/components/AddressBook/ExportEntriesModal/index.tsx @@ -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>('') diff --git a/src/routes/safe/components/AddressBook/index.tsx b/src/routes/safe/components/AddressBook/index.tsx index 79b7cf44..5f96809f 100644 --- a/src/routes/safe/components/AddressBook/index.tsx +++ b/src/routes/safe/components/AddressBook/index.tsx @@ -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) diff --git a/src/routes/safe/components/Balances/SendModal/screens/AddressBookInput/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/AddressBookInput/index.tsx index cbd1cd6a..cc46757d 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/AddressBookInput/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/AddressBookInput/index.tsx @@ -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>('') diff --git a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx index 53bb3999..4b0da32b 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ContractInteraction/Review/index.tsx @@ -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 diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendCollectible/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/SendCollectible/index.tsx index f904a903..820bec8c 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendCollectible/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendCollectible/index.tsx @@ -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 ?? '', diff --git a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx index e3f19a03..609f9603 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx +++ b/src/routes/safe/components/Balances/SendModal/screens/SendFunds/index.tsx @@ -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) 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 5e3b3827..618f7d17 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 @@ -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) } 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 72e1bd84..77b124ac 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 @@ -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) } diff --git a/src/routes/safe/components/Settings/SpendingLimit/FormFields/Beneficiary.tsx b/src/routes/safe/components/Settings/SpendingLimit/FormFields/Beneficiary.tsx index a3aa27bc..0c140520 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/FormFields/Beneficiary.tsx +++ b/src/routes/safe/components/Settings/SpendingLimit/FormFields/Beneficiary.tsx @@ -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) diff --git a/src/routes/safe/components/Settings/SpendingLimit/InfoDisplay/AddressInfo.tsx b/src/routes/safe/components/Settings/SpendingLimit/InfoDisplay/AddressInfo.tsx index b2cb638f..4e2ab775 100644 --- a/src/routes/safe/components/Settings/SpendingLimit/InfoDisplay/AddressInfo.tsx +++ b/src/routes/safe/components/Settings/SpendingLimit/InfoDisplay/AddressInfo.tsx @@ -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 ( diff --git a/src/routes/safe/components/Transactions/TxList/OwnerRow.tsx b/src/routes/safe/components/Transactions/TxList/OwnerRow.tsx index b60fae86..6cc3b07e 100644 --- a/src/routes/safe/components/Transactions/TxList/OwnerRow.tsx +++ b/src/routes/safe/components/Transactions/TxList/OwnerRow.tsx @@ -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 diff --git a/src/routes/safe/components/Transactions/TxList/hooks/useKnownAddress.ts b/src/routes/safe/components/Transactions/TxList/hooks/useKnownAddress.ts index 1a08832b..2c2ecd7f 100644 --- a/src/routes/safe/components/Transactions/TxList/hooks/useKnownAddress.ts +++ b/src/routes/safe/components/Transactions/TxList/hooks/useKnownAddress.ts @@ -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)