Skip to content
This repository was archived by the owner on Nov 10, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5ee9ef7
[Address Book] - Add Import/Export Buttons (#2278)
matextrem May 10, 2021
839c947
[Address Book V2] - Export address book (#2284)
matextrem May 17, 2021
7b00ee1
[Address book v2] Address book update events (#2293)
May 17, 2021
b59dd8a
Merge branch 'development' into address-book-v2
May 18, 2021
28afa59
[Address Book V2] Import address book (#2290)
juampibermani May 21, 2021
019d6cc
[Address Book v2] Make the address book global (#2296)
fernandomg May 26, 2021
dd3d09e
Merge branch 'development' into chore/address-book-v2-conflict-resolu…
fernandomg May 26, 2021
51c05e9
fix runtime issue with `addressBookName` not being provided
fernandomg May 26, 2021
82519b8
add back `loadedViaUrl` flag (#2337)
fernandomg May 27, 2021
2308c1f
[Address Book v2] Fix AB v2 migration (#2345)
katspaugh May 27, 2021
0d915a6
Export - Add loading state when click on download button (#2325)
matextrem May 27, 2021
e58b6d6
[Address Book v2] 1603 Use addressbook over known addresses (#2352)
Jun 1, 2021
fc0c450
[AddressBook v2] - Avoid using `checksumAddress` inside reducer (#2355)
fernandomg Jun 1, 2021
94bee4f
[Address Book v2] - Prevent name validation in AB reducer (#2356)
fernandomg Jun 1, 2021
9242d80
Use the same link in the import and export modals (#2380)
katspaugh Jun 2, 2021
5bc38ff
[Address Book v2] - Avoid deleting addressBook entry when deleting a …
fernandomg Jun 2, 2021
c5207f7
Feature/2317 update import export global ab (#2370)
juampibermani Jun 2, 2021
548d6d2
Merge branch 'development' of github.com:gnosis/safe-react into addre…
katspaugh Jun 3, 2021
e66040d
[Address Book v2] Allow empty owner names when loading a safe (#2390)
Jun 3, 2021
50a7a49
keep safes with no name for the list of safes (#2387)
fernandomg Jun 3, 2021
2d532f3
Set default order by name in address book (#2391)
Jun 3, 2021
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
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@
"@gnosis.pm/safe-apps-sdk": "3.0.0-alpha.5",
"@gnosis.pm/safe-apps-sdk-v1": "npm:@gnosis.pm/safe-apps-sdk@0.4.2",
"@gnosis.pm/safe-contracts": "1.1.1-dev.2",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#4864ebb",
"@gnosis.pm/safe-react-components": "https://github.com/gnosis/safe-react-components.git#0e4fcd6",
"@gnosis.pm/util-contracts": "2.0.6",
"@ledgerhq/hw-transport-node-hid-singleton": "5.51.1",
"@material-ui/core": "^4.11.0",
Expand Down Expand Up @@ -214,13 +214,15 @@
"react-ga": "3.3.0",
"react-hot-loader": "4.13.0",
"react-intersection-observer": "^8.31.0",
"react-papaparse": "^3.14.0",
"react-qr-reader": "^2.2.1",
"react-redux": "7.2.3",
"react-router-dom": "5.2.0",
"react-scripts": "^4.0.1",
"react-window": "^1.8.6",
"redux": "4.0.5",
"redux-actions": "^2.6.5",
"redux-localstorage-simple": "^2.4.0",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"semver": "^7.3.2",
Expand Down
13 changes: 4 additions & 9 deletions src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,11 @@ import { getNetworkId } from 'src/config'
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
import { networkSelector } from 'src/logic/wallets/store/selectors'
import { SAFELIST_ADDRESS, WELCOME_ADDRESS } from 'src/routes/routes'
import {
safeTotalFiatBalanceSelector,
safeNameSelector,
safeParamAddressFromStateSelector,
safeLoadedViaUrlSelector,
} from 'src/logic/safe/store/selectors'
import { safeTotalFiatBalanceSelector, safeParamAddressFromStateSelector } from 'src/logic/safe/store/selectors'
import { currentCurrencySelector } from 'src/logic/currencyValues/store/selectors'
import Modal from 'src/components/Modal'
import SendModal from 'src/routes/safe/components/Balances/SendModal'
import { useSafeName } from 'src/logic/addressBook/hooks/useSafeName'
import { useLoadSafe } from 'src/logic/safe/hooks/useLoadSafe'
import { useSafeScheduledUpdates } from 'src/logic/safe/hooks/useSafeScheduledUpdates'
import useSafeActions from 'src/logic/safe/hooks/useSafeActions'
Expand Down Expand Up @@ -72,14 +68,13 @@ const App: React.FC = ({ children }) => {
const matchSafe = useRouteMatch({ path: `${SAFELIST_ADDRESS}`, strict: false })
const history = useHistory()
const safeAddress = useSelector(safeParamAddressFromStateSelector)
const safeName = useSelector(safeNameSelector) ?? ''
const safeName = useSafeName(safeAddress)
const { safeActionsState, onShow, onHide, showSendFunds, hideSendFunds } = useSafeActions()
const currentSafeBalance = useSelector(safeTotalFiatBalanceSelector)
const currentCurrency = useSelector(currentCurrencySelector)
const granted = useSelector(grantedSelector)
const sidebarItems = useSidebarItems()
const isSafeLoadedViaUrl = useSelector(safeLoadedViaUrlSelector)
const safeLoaded = useLoadSafe(safeAddress, isSafeLoadedViaUrl)
const safeLoaded = useLoadSafe(safeAddress)
useSafeScheduledUpdates(safeLoaded, safeAddress)

const sendFunds = safeActionsState.sendFunds
Expand Down
2 changes: 1 addition & 1 deletion src/components/AppLayout/Sidebar/useSidebarItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const useSidebarItems = (): ListItemType[] => {
href: `${matchSafeWithAddress?.url}/transactions`,
},
{
label: 'AddressBook',
label: 'ADDRESS BOOK',
icon: <ListIcon type="addressBook" />,
selected: matchSafeWithAction?.params.safeAction === 'address-book',
href: `${matchSafeWithAddress?.url}/address-book`,
Expand Down
16 changes: 9 additions & 7 deletions src/components/SafeListSidebar/SafeList/AddressWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from 'react'
import styled from 'styled-components'
import { ButtonLink, EthHashInfo, Text } from '@gnosis.pm/safe-react-components'
import { makeStyles } from '@material-ui/core/styles'
import React, { ReactElement } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components'

import { safeNameSelector } from 'src/logic/safe/store/selectors'
import { formatAmount } from 'src/logic/tokens/utils/formatAmount'
import { sameAddress } from 'src/logic/wallets/ethAddresses'
import DefaultBadge from './DefaultBadge'
import { SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { DefaultSafe } from 'src/routes/safe/store/reducer/types/safe'
import setDefaultSafe from 'src/logic/safe/store/actions/setDefaultSafe'
import { makeStyles } from '@material-ui/core/styles'
import { getNetworkInfo } from 'src/config'
import { useDispatch } from 'react-redux'

const StyledButtonLink = styled(ButtonLink)`
visibility: hidden;
Expand Down Expand Up @@ -51,18 +53,18 @@ type Props = {

const { nativeCoin } = getNetworkInfo()

export const AddressWrapper = (props: Props): React.ReactElement => {
export const AddressWrapper = ({ safe, defaultSafe }: Props): ReactElement => {
const classes = useStyles()
const { safe, defaultSafe } = props
const dispatch = useDispatch()
const safeName = useSelector((state) => safeNameSelector(state, safe.address))

const setDefaultSafeAction = (safeAddress: string) => {
dispatch(setDefaultSafe(safeAddress))
}

return (
<div className={classes.wrapper}>
<EthHashInfo hash={safe.address} name={safe.name} showAvatar shortenHash={4} />
<EthHashInfo hash={safe.address} name={safeName} showAvatar shortenHash={4} />

<div className={classes.addressDetails}>
<Text size="xl">{`${formatAmount(safe.ethBalance)} ${nativeCoin.name}`}</Text>
Expand Down
2 changes: 1 addition & 1 deletion src/components/SafeListSidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type Props = {
export const SafeListSidebar = ({ children }: Props): ReactElement => {
const [isOpen, setIsOpen] = useState(false)
const [filter, setFilter] = useState('')
const safes = useSelector(sortedSafeListSelector).filter((safe) => !safe.loadedViaUrl)
const safes = useSelector(sortedSafeListSelector)
const defaultSafe = useSelector(defaultSafeSelector)
const currentSafe = useSelector(safeParamAddressFromStateSelector)

Expand Down
9 changes: 6 additions & 3 deletions src/components/SafeListSidebar/selectors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { createSelector } from 'reselect'

import { safesListSelector } from 'src/logic/safe/store/selectors'
import { safesListWithAddressBookNameSelector } from 'src/logic/safe/store/selectors'

export const sortedSafeListSelector = createSelector(safesListSelector, (safes) =>
safes.sort((a, b) => (a.name > b.name ? 1 : -1)),
/**
* Sort safe list by the name in the address book
*/
export const sortedSafeListSelector = createSelector([safesListWithAddressBookNameSelector], (safes) =>
safes.sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1)),
)
23 changes: 23 additions & 0 deletions src/components/forms/validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
addressIsNotCurrentSafe,
OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR,
mustBeHexData,
validAddressBookName,
} from 'src/components/forms/validator'

describe('Forms > Validators', () => {
Expand Down Expand Up @@ -249,4 +250,26 @@ describe('Forms > Validators', () => {
expect(differentFrom('a')('a')).toEqual(getDifferentFromErrMsg('a'))
})
})

describe('validAddressBookName validator', () => {
it('Returns error for an empty string', () => {
expect(validAddressBookName('')).toBe('Should be 1 to 50 symbols')
})
it('Returns error for a name longer than 50 chars', () => {
expect(validAddressBookName('abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabc')).toBe(
'Should be 1 to 50 symbols',
)
})
it('Returns error for a blacklisted name', () => {
const blacklistedErrorMessage = 'Name should not include: UNKNOWN, OWNER #, MY WALLET'

expect(validAddressBookName('unknown')).toBe(blacklistedErrorMessage)
expect(validAddressBookName('unknown a')).toBe(blacklistedErrorMessage)
expect(validAddressBookName('owner #1')).toBe(blacklistedErrorMessage)
expect(validAddressBookName('My Wallet')).toBe(blacklistedErrorMessage)
})
it('Returns undefined for a non-blacklisted name', () => {
expect(validAddressBookName('A valid name')).toBeUndefined()
})
})
})
29 changes: 22 additions & 7 deletions src/components/forms/validator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { List } from 'immutable'
import memoize from 'lodash.memoize'

import { sameAddress } from 'src/logic/wallets/ethAddresses'
import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { isFeatureEnabled } from 'src/config'
import { FEATURES } from 'src/config/networks/network.d'
import { isValidAddress } from 'src/utils/isValidAddress'
import { ADDRESS_BOOK_INVALID_NAMES, isValidAddressBookName } from 'src/logic/addressBook/utils'

type ValidatorReturnType = string | undefined
export type GenericValidatorType = (...args: unknown[]) => ValidatorReturnType
Expand Down Expand Up @@ -74,9 +75,7 @@ export const mustBeHexData = (data: string): ValidatorReturnType => {
export const mustBeAddressHash = memoize(
(address: string): ValidatorReturnType => {
const errorMessage = 'Must be a valid address'
const startsWith0x = address?.startsWith('0x')
const isAddress = getWeb3().utils.isAddress(address)
return startsWith0x && isAddress ? undefined : errorMessage
return isValidAddress(address) ? undefined : errorMessage
},
)

Expand All @@ -101,8 +100,12 @@ export const mustBeEthereumContractAddress = memoize(
},
)

export const minMaxLength = (minLen: number, maxLen: number) => (value: string): ValidatorReturnType =>
value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`
export const minMaxLength = (minLen: number, maxLen: number) => (value: string): ValidatorReturnType => {
const testValue = value || ''
return testValue.length >= +minLen && testValue.length <= +maxLen
? undefined
: `Should be ${minLen} to ${maxLen} symbols`
}

export const minMaxDecimalsLength = (minLen: number, maxLen: number) => (value: string): ValidatorReturnType => {
const decimals = value.split('.')[1] || '0'
Expand All @@ -113,7 +116,7 @@ export const minMaxDecimalsLength = (minLen: number, maxLen: number) => (value:
export const ADDRESS_REPEATED_ERROR = 'Address already introduced'
export const OWNER_ADDRESS_IS_SAFE_ADDRESS_ERROR = 'Cannot use Safe itself as owner.'

export const uniqueAddress = (addresses: string[] | List<string> = []) => (address?: string): string | undefined => {
export const uniqueAddress = (addresses: string[] = []) => (address?: string): string | undefined => {
const addressExists = addresses.some((addressFromList) => sameAddress(addressFromList, address))
return addressExists ? ADDRESS_REPEATED_ERROR : undefined
}
Expand All @@ -136,3 +139,15 @@ export const differentFrom = (diffValue: number | string) => (value: string): Va
}

export const noErrorsOn = (name: string, errors: Record<string, unknown>): boolean => errors[name] === undefined

export const validAddressBookName = (name: string): string | undefined => {
const lengthError = minMaxLength(1, 50)(name)

if (lengthError === undefined) {
return isValidAddressBookName(name)
? undefined
: `Name should not include: ${ADDRESS_BOOK_INVALID_NAMES.join(', ')}`
}

return lengthError
}
4 changes: 2 additions & 2 deletions src/config/networks/network.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type Token = {
}

export enum ETHEREUM_NETWORK {
UNKNOWN = 0,
MAINNET = 1,
MORDEN = 2,
ROPSTEN = 3,
Expand All @@ -42,9 +43,8 @@ export enum ETHEREUM_NETWORK {
KOVAN = 42,
XDAI = 100,
ENERGY_WEB_CHAIN = 246,
VOLTA = 73799,
UNKNOWN = 0,
LOCAL = 4447,
VOLTA = 73799,
}

export type NetworkSettings = {
Expand Down
10 changes: 10 additions & 0 deletions src/logic/addressBook/hooks/useSafeName.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useSelector } from 'react-redux'

import { getNameFromAddressBook } from 'src/logic/addressBook/utils'
import { addressBookSelector } from 'src/logic/addressBook/store/selectors'

export const useSafeName = (safeAddress: string): string => {
const addressBook = useSelector(addressBookSelector)

return getNameFromAddressBook(addressBook, safeAddress) || ''
}
21 changes: 16 additions & 5 deletions src/logic/addressBook/model/addressBook.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
import { ETHEREUM_NETWORK } from 'src/config/networks/network.d'
import { getNetworkId } from 'src/config'

export const ADDRESS_BOOK_DEFAULT_NAME = 'UNKNOWN'

export type AddressBookEntry = {
address: string
name: string
address: string // the contact address
name: string // human-readable name
chainId: ETHEREUM_NETWORK // see https://chainid.network
}

const networkId = getNetworkId()

export const makeAddressBookEntry = ({
address = '',
name = '',
address,
name,
chainId = networkId,
}: {
address: string
name?: string
name: string
chainId?: number
}): AddressBookEntry => ({
address,
name,
chainId,
})

export type AddressBookState = AddressBookEntry[]
22 changes: 0 additions & 22 deletions src/logic/addressBook/store/actions/addAddressBookEntry.ts

This file was deleted.

This file was deleted.

17 changes: 17 additions & 0 deletions src/logic/addressBook/store/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { createAction } from 'redux-actions'

import { AddressBookEntry, AddressBookState } from 'src/logic/addressBook/model/addressBook'

// following the suggested naming convention at
// https://redux.js.org/style-guide/style-guide#write-action-types-as-domaineventname
export enum ADDRESS_BOOK_ACTIONS {
ADD_OR_UPDATE = 'addressBook/addOrUpdate',
REMOVE = 'addressBook/remove',
IMPORT = 'addressBook/import',
SAFE_LOAD = 'addressBook/safeLoad',
}

export const addressBookAddOrUpdate = createAction<AddressBookEntry>(ADDRESS_BOOK_ACTIONS.ADD_OR_UPDATE)
export const addressBookRemove = createAction<AddressBookEntry>(ADDRESS_BOOK_ACTIONS.REMOVE)
export const addressBookSafeLoad = createAction<AddressBookState>(ADDRESS_BOOK_ACTIONS.SAFE_LOAD)
export const addressBookImport = createAction<AddressBookState>(ADDRESS_BOOK_ACTIONS.IMPORT)
8 changes: 0 additions & 8 deletions src/logic/addressBook/store/actions/loadAddressBook.ts

This file was deleted.

22 changes: 0 additions & 22 deletions src/logic/addressBook/store/actions/loadAddressBookFromStorage.ts

This file was deleted.

7 changes: 0 additions & 7 deletions src/logic/addressBook/store/actions/removeAddressBookEntry.ts

This file was deleted.

8 changes: 0 additions & 8 deletions src/logic/addressBook/store/actions/updateAddressBookEntry.ts

This file was deleted.

Loading