mirror of
https://github.com/status-im/safe-react.git
synced 2025-03-01 01:40:35 +00:00
Fixes: Offchain signatures (#706)
* offchain signatures wip * offchain signing wip * offchain signatures wip * offchain signatures wip * save signatures to the history service * fix eth signer & useEfefct hook * offchain signatures wip * signature check, mainnet testing wip * dep update * disable offchain signing for smart contract wallets * Refactor EIP712 signer * bring back .env.example * Check if save version is >1.1.1 * use canTryoffchainSigning boolean variable, add comment about 4001 error * move semver selector for safe version/offchain signatures to a constant, make use of empty_data for isContractWallet * remove TYPE when sending txs to history service * add eth_signTypedData_v4 signer, dep bump, add missing await * add comments about version check for canTryOffchainSigning variable * hide "please sign notification" * dep bump * dep bump * Check if connected is ledger before trying offchain signatures * minor fixes, temp deployment to test trezor * add hardwareWallet boolean property to wallet model, disable offchain signatures for hw wallets * add personal signer * prettier fixes * offchain signatures fixes
This commit is contained in:
parent
fad5e10c2e
commit
31a1565637
@ -37,7 +37,7 @@ type Props = {
|
|||||||
const List = ({ activeItem, classes, items, onItemClick }: Props) => {
|
const List = ({ activeItem, classes, items, onItemClick }: Props) => {
|
||||||
return (
|
return (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
{items.map(i => (
|
{items.map((i) => (
|
||||||
<Item
|
<Item
|
||||||
className={cn(classes.menuOption, activeItem === i.id && classes.active)}
|
className={cn(classes.menuOption, activeItem === i.id && classes.active)}
|
||||||
key={i.id}
|
key={i.id}
|
||||||
|
@ -160,7 +160,7 @@ const CookiesBanner = () => {
|
|||||||
disabled
|
disabled
|
||||||
label="Necessary"
|
label="Necessary"
|
||||||
name="Necessary"
|
name="Necessary"
|
||||||
onChange={() => setLocalNecessary(prev => !prev)}
|
onChange={() => setLocalNecessary((prev) => !prev)}
|
||||||
value={localNecessary}
|
value={localNecessary}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -169,7 +169,7 @@ const CookiesBanner = () => {
|
|||||||
control={<Checkbox checked={localAnalytics} />}
|
control={<Checkbox checked={localAnalytics} />}
|
||||||
label="Analytics"
|
label="Analytics"
|
||||||
name="Analytics"
|
name="Analytics"
|
||||||
onChange={() => setLocalAnalytics(prev => !prev)}
|
onChange={() => setLocalAnalytics((prev) => !prev)}
|
||||||
value={localAnalytics}
|
value={localAnalytics}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,7 +77,7 @@ const Layout = openHoc(({ classes, clickAway, open, providerDetails, providerInf
|
|||||||
<NetworkLabel />
|
<NetworkLabel />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Provider info={providerInfo} open={open} toggle={toggle}>
|
<Provider info={providerInfo} open={open} toggle={toggle}>
|
||||||
{providerRef => (
|
{(providerRef) => (
|
||||||
<Popper
|
<Popper
|
||||||
anchorEl={providerRef.current}
|
anchorEl={providerRef.current}
|
||||||
className={classes.popper}
|
className={classes.popper}
|
||||||
|
@ -65,6 +65,6 @@ const SafeListHeader = ({ safesCount }: Props) => {
|
|||||||
|
|
||||||
export default connect<Object, Object, ?Function, ?Object>(
|
export default connect<Object, Object, ?Function, ?Object>(
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
state => ({ safesCount: safesCountSelector(state) }),
|
(state) => ({ safesCount: safesCountSelector(state) }),
|
||||||
null,
|
null,
|
||||||
)(SafeListHeader)
|
)(SafeListHeader)
|
||||||
|
@ -45,7 +45,7 @@ class Notifier extends Component<Props> {
|
|||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const { notifications = [], enqueueSnackbar, removeSnackbar } = this.props
|
const { notifications = [], enqueueSnackbar, removeSnackbar } = this.props
|
||||||
|
|
||||||
notifications.forEach(notification => {
|
notifications.forEach((notification) => {
|
||||||
// Do nothing if snackbar is already displayed
|
// Do nothing if snackbar is already displayed
|
||||||
if (this.displayed.includes(notification.key)) {
|
if (this.displayed.includes(notification.key)) {
|
||||||
return
|
return
|
||||||
@ -68,7 +68,7 @@ class Notifier extends Component<Props> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
storeDisplayed = id => {
|
storeDisplayed = (id) => {
|
||||||
this.displayed = [...this.displayed, id]
|
this.displayed = [...this.displayed, id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,10 +72,10 @@ const ScanQRModal = ({ classes, isOpen, onClose, onScan }: Props) => {
|
|||||||
) : (
|
) : (
|
||||||
<QrReader
|
<QrReader
|
||||||
legacyMode={!hasWebcam}
|
legacyMode={!hasWebcam}
|
||||||
onError={err => {
|
onError={(err) => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
}}
|
}}
|
||||||
onScan={data => {
|
onScan={(data) => {
|
||||||
if (data) onScan(data)
|
if (data) onScan(data)
|
||||||
}}
|
}}
|
||||||
ref={scannerRef}
|
ref={scannerRef}
|
||||||
|
@ -79,7 +79,7 @@ const SafeList = ({ currentSafe, defaultSafe, onSafeClick, safes, setDefaultSafe
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<MuiList className={classes.list}>
|
<MuiList className={classes.list}>
|
||||||
{safes.map(safe => (
|
{safes.map((safe) => (
|
||||||
<React.Fragment key={safe.address}>
|
<React.Fragment key={safe.address}>
|
||||||
<Link
|
<Link
|
||||||
data-testid={SIDEBAR_SAFELIST_ROW_TESTID}
|
data-testid={SIDEBAR_SAFELIST_ROW_TESTID}
|
||||||
@ -113,7 +113,7 @@ const SafeList = ({ currentSafe, defaultSafe, onSafeClick, safes, setDefaultSafe
|
|||||||
) : (
|
) : (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
className={classes.makeDefaultBtn}
|
className={classes.makeDefaultBtn}
|
||||||
onClick={e => {
|
onClick={(e) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ const Sidebar = ({ children, currentSafe, defaultSafe, safes, setDefaultSafeActi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toggleSidebar = () => {
|
const toggleSidebar = () => {
|
||||||
setIsOpen(prevIsOpen => !prevIsOpen)
|
setIsOpen((prevIsOpen) => !prevIsOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFilterChange = (value: string) => {
|
const handleFilterChange = (value: string) => {
|
||||||
@ -142,7 +142,7 @@ const Sidebar = ({ children, currentSafe, defaultSafe, safes, setDefaultSafeActi
|
|||||||
|
|
||||||
export default connect<Object, Object, ?Function, ?Object>(
|
export default connect<Object, Object, ?Function, ?Object>(
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
state => ({
|
(state) => ({
|
||||||
safes: sortedSafeListSelector(state),
|
safes: sortedSafeListSelector(state),
|
||||||
defaultSafe: defaultSafeSelector(state),
|
defaultSafe: defaultSafeSelector(state),
|
||||||
currentSafe: safeParamAddressFromStateSelector(state),
|
currentSafe: safeParamAddressFromStateSelector(state),
|
||||||
|
@ -54,7 +54,7 @@ const GnoStepper = (props: Props) => {
|
|||||||
|
|
||||||
const getPageProps = (pages: React.Node): PageProps => React.Children.toArray(pages)[page].props
|
const getPageProps = (pages: React.Node): PageProps => React.Children.toArray(pages)[page].props
|
||||||
|
|
||||||
const updateInitialProps = newInitialProps => {
|
const updateInitialProps = (newInitialProps) => {
|
||||||
setValues(newInitialProps)
|
setValues(newInitialProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ const GnoStepper = (props: Props) => {
|
|||||||
return next(formValues)
|
return next(formValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isLastPage = pageNumber => {
|
const isLastPage = (pageNumber) => {
|
||||||
const { steps } = props
|
const { steps } = props
|
||||||
return pageNumber === steps.length - 1
|
return pageNumber === steps.length - 1
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ export const stableSort = (dataArray: List<any>, cmp: any, fixed: boolean): List
|
|||||||
return a[1] - b[1]
|
return a[1] - b[1]
|
||||||
})
|
})
|
||||||
|
|
||||||
const sortedElems: List<any> = stabilizedThis.map(el => el[0])
|
const sortedElems: List<any> = stabilizedThis.map((el) => el[0])
|
||||||
|
|
||||||
return fixedElems.concat(sortedElems)
|
return fixedElems.concat(sortedElems)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ type Props = {
|
|||||||
disabled?: boolean,
|
disabled?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidEnsName = name => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
||||||
|
|
||||||
// an idea for second field was taken from here
|
// an idea for second field was taken from here
|
||||||
// https://github.com/final-form/react-final-form-listeners/blob/master/src/OnBlur.js
|
// https://github.com/final-form/react-final-form-listeners/blob/master/src/OnBlur.js
|
||||||
@ -52,7 +52,7 @@ const AddressInput = ({
|
|||||||
validate={composeValidators(required, mustBeEthereumAddress, ...validators)}
|
validate={composeValidators(required, mustBeEthereumAddress, ...validators)}
|
||||||
/>
|
/>
|
||||||
<OnChange name={name}>
|
<OnChange name={name}>
|
||||||
{async value => {
|
{async (value) => {
|
||||||
if (isValidEnsName(value)) {
|
if (isValidEnsName(value)) {
|
||||||
try {
|
try {
|
||||||
const resolverAddr = await getAddressFromENS(value)
|
const resolverAddr = await getAddressFromENS(value)
|
||||||
|
@ -80,7 +80,7 @@ const PageFrame = ({ children, classes, currentNetwork }: Props) => {
|
|||||||
|
|
||||||
export default withStyles(notificationStyles)(
|
export default withStyles(notificationStyles)(
|
||||||
connect(
|
connect(
|
||||||
state => ({
|
(state) => ({
|
||||||
currentNetwork: networkSelector(state),
|
currentNetwork: networkSelector(state),
|
||||||
}),
|
}),
|
||||||
null,
|
null,
|
||||||
|
@ -19,7 +19,7 @@ const loadAddressBookFromStorage = () => async (dispatch: ReduxDispatch<GlobalSt
|
|||||||
// Fetch all the current safes, in case that we don't have a safe on the adbk, we add it
|
// Fetch all the current safes, in case that we don't have a safe on the adbk, we add it
|
||||||
const safes = safesListSelector(state)
|
const safes = safesListSelector(state)
|
||||||
const adbkEntries = addressBook.keySeq().toArray()
|
const adbkEntries = addressBook.keySeq().toArray()
|
||||||
safes.forEach(safe => {
|
safes.forEach((safe) => {
|
||||||
const { address } = safe
|
const { address } = safe
|
||||||
const found = adbkEntries.includes(address)
|
const found = adbkEntries.includes(address)
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -47,11 +47,11 @@ export default handleActions<State, *>(
|
|||||||
const { entry } = action.payload
|
const { entry } = action.payload
|
||||||
|
|
||||||
// Adds the entry to all the safes (if it does not already exists)
|
// Adds the entry to all the safes (if it does not already exists)
|
||||||
const newState = state.withMutations(map => {
|
const newState = state.withMutations((map) => {
|
||||||
const adbkMap = map.get('addressBook')
|
const adbkMap = map.get('addressBook')
|
||||||
|
|
||||||
if (adbkMap) {
|
if (adbkMap) {
|
||||||
adbkMap.keySeq().forEach(safeAddress => {
|
adbkMap.keySeq().forEach((safeAddress) => {
|
||||||
const safeAddressBook = state.getIn(['addressBook', safeAddress])
|
const safeAddressBook = state.getIn(['addressBook', safeAddress])
|
||||||
|
|
||||||
if (safeAddressBook) {
|
if (safeAddressBook) {
|
||||||
@ -71,13 +71,13 @@ export default handleActions<State, *>(
|
|||||||
const { entry } = action.payload
|
const { entry } = action.payload
|
||||||
|
|
||||||
// Updates the entry from all the safes
|
// Updates the entry from all the safes
|
||||||
const newState = state.withMutations(map => {
|
const newState = state.withMutations((map) => {
|
||||||
map
|
map
|
||||||
.get('addressBook')
|
.get('addressBook')
|
||||||
.keySeq()
|
.keySeq()
|
||||||
.forEach(safeAddress => {
|
.forEach((safeAddress) => {
|
||||||
const entriesList: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
|
const entriesList: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
|
||||||
const entryIndex = entriesList.findIndex(entryItem => sameAddress(entryItem.address, entry.address))
|
const entryIndex = entriesList.findIndex((entryItem) => sameAddress(entryItem.address, entry.address))
|
||||||
const updatedEntriesList = entriesList.set(entryIndex, entry)
|
const updatedEntriesList = entriesList.set(entryIndex, entry)
|
||||||
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
||||||
})
|
})
|
||||||
@ -88,13 +88,13 @@ export default handleActions<State, *>(
|
|||||||
[REMOVE_ENTRY]: (state: State, action: ActionType<Function>): State => {
|
[REMOVE_ENTRY]: (state: State, action: ActionType<Function>): State => {
|
||||||
const { entryAddress } = action.payload
|
const { entryAddress } = action.payload
|
||||||
// Removes the entry from all the safes
|
// Removes the entry from all the safes
|
||||||
const newState = state.withMutations(map => {
|
const newState = state.withMutations((map) => {
|
||||||
map
|
map
|
||||||
.get('addressBook')
|
.get('addressBook')
|
||||||
.keySeq()
|
.keySeq()
|
||||||
.forEach(safeAddress => {
|
.forEach((safeAddress) => {
|
||||||
const entriesList = state.getIn(['addressBook', safeAddress])
|
const entriesList = state.getIn(['addressBook', safeAddress])
|
||||||
const entryIndex = entriesList.findIndex(entry => sameAddress(entry.address, entryAddress))
|
const entryIndex = entriesList.findIndex((entry) => sameAddress(entry.address, entryAddress))
|
||||||
const updatedEntriesList = entriesList.remove(entryIndex)
|
const updatedEntriesList = entriesList.remove(entryIndex)
|
||||||
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
||||||
})
|
})
|
||||||
@ -105,15 +105,15 @@ export default handleActions<State, *>(
|
|||||||
const { entry, entryAddress } = action.payload
|
const { entry, entryAddress } = action.payload
|
||||||
|
|
||||||
// Adds or Updates the entry to all the safes
|
// Adds or Updates the entry to all the safes
|
||||||
return state.withMutations(map => {
|
return state.withMutations((map) => {
|
||||||
const addressBook = map.get('addressBook')
|
const addressBook = map.get('addressBook')
|
||||||
if (addressBook) {
|
if (addressBook) {
|
||||||
addressBook.keySeq().forEach(safeAddress => {
|
addressBook.keySeq().forEach((safeAddress) => {
|
||||||
const safeAddressBook: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
|
const safeAddressBook: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
|
||||||
const entryIndex = safeAddressBook.findIndex(entryItem => sameAddress(entryItem.address, entryAddress))
|
const entryIndex = safeAddressBook.findIndex((entryItem) => sameAddress(entryItem.address, entryAddress))
|
||||||
|
|
||||||
if (entryIndex !== -1) {
|
if (entryIndex !== -1) {
|
||||||
const updatedEntriesList = safeAddressBook.update(entryIndex, currentEntry => currentEntry.merge(entry))
|
const updatedEntriesList = safeAddressBook.update(entryIndex, (currentEntry) => currentEntry.merge(entry))
|
||||||
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
||||||
} else {
|
} else {
|
||||||
const updatedSafeAdbkList = safeAddressBook.push(makeAddressBookEntry(entry))
|
const updatedSafeAdbkList = safeAddressBook.push(makeAddressBookEntry(entry))
|
||||||
|
@ -41,7 +41,7 @@ export const getNameFromAddressBook = (userAddress: string): string | null => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
const addressBook = useSelector(getAddressBook)
|
const addressBook = useSelector(getAddressBook)
|
||||||
const result = addressBook.filter(addressBookItem => addressBookItem.address === userAddress)
|
const result = addressBook.filter((addressBookItem) => addressBookItem.address === userAddress)
|
||||||
if (result.size > 0) {
|
if (result.size > 0) {
|
||||||
return result.get(0).name
|
return result.get(0).name
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,10 @@ export const saveAddressBook = async (addressBook: AddressBook) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getAddressesListFromAdbk = (addressBook: AddressBook) =>
|
export const getAddressesListFromAdbk = (addressBook: AddressBook) =>
|
||||||
Array.from(addressBook).map(entry => entry.address)
|
Array.from(addressBook).map((entry) => entry.address)
|
||||||
|
|
||||||
const getNameFromAdbk = (addressBook: AddressBook, userAddress: string): string | null => {
|
const getNameFromAdbk = (addressBook: AddressBook, userAddress: string): string | null => {
|
||||||
const entry = addressBook.find(addressBookItem => addressBookItem.address === userAddress)
|
const entry = addressBook.find((addressBookItem) => addressBookItem.address === userAddress)
|
||||||
if (entry) {
|
if (entry) {
|
||||||
return entry.name
|
return entry.name
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ export const getOwnersWithNameFromAddressBook = (addressBook: AddressBook, owner
|
|||||||
if (!ownerList) {
|
if (!ownerList) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const ownersListWithAdbkNames = ownerList.map(owner => {
|
const ownersListWithAdbkNames = ownerList.map((owner) => {
|
||||||
const ownerName = getNameFromAdbk(addressBook, owner.address)
|
const ownerName = getNameFromAdbk(addressBook, owner.address)
|
||||||
return {
|
return {
|
||||||
address: owner.address,
|
address: owner.address,
|
||||||
|
@ -18,8 +18,8 @@ export const fetchCurrencyValues = (safeAddress: string) => async (dispatch: Red
|
|||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const currencyList = List(
|
const currencyList = List(
|
||||||
tokensFetched.data
|
tokensFetched.data
|
||||||
.filter(currencyBalance => currencyBalance.balanceUsd)
|
.filter((currencyBalance) => currencyBalance.balanceUsd)
|
||||||
.map(currencyBalance => {
|
.map((currencyBalance) => {
|
||||||
const { balanceUsd, tokenAddress } = currencyBalance
|
const { balanceUsd, tokenAddress } = currencyBalance
|
||||||
return makeBalanceCurrency({
|
return makeBalanceCurrency({
|
||||||
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
|
currencyName: balanceUsd ? AVAILABLE_CURRENCIES.USD : null,
|
||||||
|
@ -16,7 +16,7 @@ export default handleActions<State, *>(
|
|||||||
[UPDATE_VIEWED_SAFES]: (state: State, action: ActionType<Function>): State => {
|
[UPDATE_VIEWED_SAFES]: (state: State, action: ActionType<Function>): State => {
|
||||||
const safeAddress = action.payload
|
const safeAddress = action.payload
|
||||||
|
|
||||||
const newState = state.updateIn(['viewedSafes'], prev =>
|
const newState = state.updateIn(['viewedSafes'], (prev) =>
|
||||||
prev.includes(safeAddress) ? prev : [...prev, safeAddress],
|
prev.includes(safeAddress) ? prev : [...prev, safeAddress],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ export const showSnackbar = (notification: Notification, enqueueSnackbar: Functi
|
|||||||
enqueueSnackbar(notification.message, {
|
enqueueSnackbar(notification.message, {
|
||||||
...notification.options,
|
...notification.options,
|
||||||
// eslint-disable-next-line react/display-name
|
// eslint-disable-next-line react/display-name
|
||||||
action: key => (
|
action: (key) => (
|
||||||
<IconButton onClick={() => closeSnackbar(key)}>
|
<IconButton onClick={() => closeSnackbar(key)}>
|
||||||
<IconClose />
|
<IconClose />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
@ -23,10 +23,10 @@ export default handleActions<NotificationReducerState, *>(
|
|||||||
const { dismissAll, key } = action.payload
|
const { dismissAll, key } = action.payload
|
||||||
|
|
||||||
if (key) {
|
if (key) {
|
||||||
return state.update(key, prev => prev.set('dismissed', true))
|
return state.update(key, (prev) => prev.set('dismissed', true))
|
||||||
}
|
}
|
||||||
if (dismissAll) {
|
if (dismissAll) {
|
||||||
return state.withMutations(map => {
|
return state.withMutations((map) => {
|
||||||
map.forEach((notification, notificationKey) => {
|
map.forEach((notification, notificationKey) => {
|
||||||
map.set(notificationKey, notification.set('dismissed', true))
|
map.set(notificationKey, notification.set('dismissed', true))
|
||||||
})
|
})
|
||||||
|
@ -23,7 +23,7 @@ export const generateSignaturesFromTxConfirmations = (
|
|||||||
let sigs = '0x'
|
let sigs = '0x'
|
||||||
Object.keys(confirmationsMap)
|
Object.keys(confirmationsMap)
|
||||||
.sort()
|
.sort()
|
||||||
.forEach(addr => {
|
.forEach((addr) => {
|
||||||
const conf = confirmationsMap[addr]
|
const conf = confirmationsMap[addr]
|
||||||
if (conf.signature) {
|
if (conf.signature) {
|
||||||
sigs += conf.signature.slice(2)
|
sigs += conf.signature.slice(2)
|
||||||
|
@ -12,7 +12,7 @@ export const getAwaitingTransactions = (
|
|||||||
return Map({})
|
return Map({})
|
||||||
}
|
}
|
||||||
|
|
||||||
const allAwaitingTransactions = allTransactions.map(safeTransactions => {
|
const allAwaitingTransactions = allTransactions.map((safeTransactions) => {
|
||||||
const nonCancelledTransactions = safeTransactions.filter((transaction: Transaction) => {
|
const nonCancelledTransactions = safeTransactions.filter((transaction: Transaction) => {
|
||||||
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
|
// If transactions are not executed, but there's a transaction with the same nonce EXECUTED later
|
||||||
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
|
// it means that the transaction was cancelled (Replaced) and shouldn't get executed
|
||||||
@ -27,7 +27,7 @@ export const getAwaitingTransactions = (
|
|||||||
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
|
// Then we check if the waiting confirmations are not from the current user, otherwise, filters this
|
||||||
// transaction
|
// transaction
|
||||||
const transactionWaitingUser = transaction.confirmations.filter(
|
const transactionWaitingUser = transaction.confirmations.filter(
|
||||||
confirmation => confirmation.owner && confirmation.owner.address !== userAccount,
|
(confirmation) => confirmation.owner && confirmation.owner.address !== userAccount,
|
||||||
)
|
)
|
||||||
|
|
||||||
return transactionWaitingUser.size > 0
|
return transactionWaitingUser.size > 0
|
||||||
|
@ -5,7 +5,7 @@ import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
|||||||
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
|
||||||
const estimateDataGasCosts = data => {
|
const estimateDataGasCosts = (data) => {
|
||||||
const reducer = (accumulator, currentValue) => {
|
const reducer = (accumulator, currentValue) => {
|
||||||
if (currentValue === EMPTY_DATA) {
|
if (currentValue === EMPTY_DATA) {
|
||||||
return accumulator + 0
|
return accumulator + 0
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
|
||||||
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
|
|
||||||
const ETH_SIGN_NOT_SUPPORTED_ERROR_MSG = 'ETH_SIGN_NOT_SUPPORTED_ERROR_MSG'
|
const ETH_SIGN_NOT_SUPPORTED_ERROR_MSG = 'ETH_SIGN_NOT_SUPPORTED'
|
||||||
|
|
||||||
export const generateEthSignature = async ({
|
export const getEthSigner = async ({
|
||||||
baseGas,
|
baseGas,
|
||||||
data,
|
data,
|
||||||
gasPrice,
|
gasPrice,
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
// import { getEIP712Signer } from './EIP712Signer'
|
import { getEIP712Signer } from './EIP712Signer'
|
||||||
import { generateEthSignature } from './ethSigner'
|
import { getEthSigner } from './ethSigner'
|
||||||
|
|
||||||
// 1. we try to sign via EIP-712 if user's wallet supports it
|
// 1. we try to sign via EIP-712 if user's wallet supports it
|
||||||
// 2. If not, try to use eth_sign (Safe version has to be >1.1.1)
|
// 2. If not, try to use eth_sign (Safe version has to be >1.1.1)
|
||||||
// If eth_sign, doesn't work continue with the regular flow (on-chain signatures, more in createTransaction.js)
|
// If eth_sign, doesn't work continue with the regular flow (on-chain signatures, more in createTransaction.js)
|
||||||
|
|
||||||
const signingFuncs = [generateEthSignature]
|
const signingFuncs = [getEIP712Signer('v3'), getEIP712Signer('v4'), getEIP712Signer(), getEthSigner]
|
||||||
|
|
||||||
export const SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES = '>=1.1.1'
|
export const SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES = '>=1.1.1'
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ export const safeNeedsUpdate = (currentVersion: string, latestVersion: string) =
|
|||||||
return latest ? semverLessThan(current, latest) : false
|
return latest ? semverLessThan(current, latest) : false
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getCurrentSafeVersion = gnosisSafeInstance => gnosisSafeInstance.VERSION()
|
export const getCurrentSafeVersion = (gnosisSafeInstance) => gnosisSafeInstance.VERSION()
|
||||||
|
|
||||||
export const enabledFeatures = (version: string) =>
|
export const enabledFeatures = (version: string) =>
|
||||||
FEATURES.reduce((acc, feature) => {
|
FEATURES.reduce((acc, feature) => {
|
||||||
|
@ -44,7 +44,7 @@ const activateTokensByBalance = (safeAddress: string) => async (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// active tokens by balance, excluding those already blacklisted and the `null` address
|
// active tokens by balance, excluding those already blacklisted and the `null` address
|
||||||
const activeByBalance = addresses.filter(address => address !== null && !blacklistedTokens.includes(address))
|
const activeByBalance = addresses.filter((address) => address !== null && !blacklistedTokens.includes(address))
|
||||||
|
|
||||||
// need to persist those already active tokens, despite its balances
|
// need to persist those already active tokens, despite its balances
|
||||||
const activeTokens = alreadyActiveTokens.toSet().union(activeByBalance)
|
const activeTokens = alreadyActiveTokens.toSet().union(activeByBalance)
|
||||||
|
@ -16,8 +16,8 @@ export default handleActions<State, *>(
|
|||||||
[ADD_TOKENS]: (state: State, action: ActionType<Function>): State => {
|
[ADD_TOKENS]: (state: State, action: ActionType<Function>): State => {
|
||||||
const { tokens } = action.payload
|
const { tokens } = action.payload
|
||||||
|
|
||||||
const newState = state.withMutations(map => {
|
const newState = state.withMutations((map) => {
|
||||||
tokens.forEach(token => {
|
tokens.forEach((token) => {
|
||||||
map.set(token.address, token)
|
map.set(token.address, token)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -44,7 +44,7 @@ export const removeTokenFromStorage = async (safeAddress: string, token: Token)
|
|||||||
|
|
||||||
export const removeFromActiveTokens = async (safeAddress: string, token: Token) => {
|
export const removeFromActiveTokens = async (safeAddress: string, token: Token) => {
|
||||||
const activeTokens = await getActiveTokens()
|
const activeTokens = await getActiveTokens()
|
||||||
const index = activeTokens.findIndex(activeToken => activeToken.name === token.name)
|
const index = activeTokens.findIndex((activeToken) => activeToken.name === token.name)
|
||||||
|
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
await saveActiveTokens(safeAddress, activeTokens.delete(index))
|
await saveActiveTokens(safeAddress, activeTokens.delete(index))
|
||||||
|
@ -49,4 +49,4 @@ export const isUserOwner = (safe: Safe, userAccount: string): boolean => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const isUserOwnerOnAnySafe = (safes: List<Safe>, userAccount: string): boolean =>
|
export const isUserOwnerOnAnySafe = (safes: List<Safe>, userAccount: string): boolean =>
|
||||||
safes.some(safe => isUserOwner(safe, userAccount))
|
safes.some((safe) => isUserOwner(safe, userAccount))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
function transactionDataCheck() {
|
function transactionDataCheck() {
|
||||||
let completed = false
|
let completed = false
|
||||||
return stateAndHelpers => {
|
return (stateAndHelpers) => {
|
||||||
const { wallet } = stateAndHelpers
|
const { wallet } = stateAndHelpers
|
||||||
|
|
||||||
if (wallet && wallet.name === 'Ledger' && !completed) {
|
if (wallet && wallet.name === 'Ledger' && !completed) {
|
||||||
|
@ -104,7 +104,7 @@ const Details = ({ classes, errors, form }: Props) => (
|
|||||||
<Block className={classes.root} margin="lg">
|
<Block className={classes.root} margin="lg">
|
||||||
<AddressInput
|
<AddressInput
|
||||||
component={TextField}
|
component={TextField}
|
||||||
fieldMutator={val => {
|
fieldMutator={(val) => {
|
||||||
form.mutators.setValue(FIELD_LOAD_ADDRESS, val)
|
form.mutators.setValue(FIELD_LOAD_ADDRESS, val)
|
||||||
}}
|
}}
|
||||||
inputAdornment={
|
inputAdornment={
|
||||||
|
@ -74,7 +74,7 @@ const SafeOwners = (props: Props) => {
|
|||||||
const [qrModalOpen, setQrModalOpen] = useState<boolean>(false)
|
const [qrModalOpen, setQrModalOpen] = useState<boolean>(false)
|
||||||
const [scanQrForOwnerName, setScanQrForOwnerName] = useState<string | null>(null)
|
const [scanQrForOwnerName, setScanQrForOwnerName] = useState<string | null>(null)
|
||||||
|
|
||||||
const openQrModal = ownerName => {
|
const openQrModal = (ownerName) => {
|
||||||
setScanQrForOwnerName(ownerName)
|
setScanQrForOwnerName(ownerName)
|
||||||
setQrModalOpen(true)
|
setQrModalOpen(true)
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ const SafeOwners = (props: Props) => {
|
|||||||
setNumOwners(numOwners + 1)
|
setNumOwners(numOwners + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScan = value => {
|
const handleScan = (value) => {
|
||||||
let scannedAddress = value
|
let scannedAddress = value
|
||||||
|
|
||||||
if (scannedAddress.startsWith('ethereum:')) {
|
if (scannedAddress.startsWith('ethereum:')) {
|
||||||
@ -144,7 +144,7 @@ const SafeOwners = (props: Props) => {
|
|||||||
<Col className={classes.ownerAddress} xs={6}>
|
<Col className={classes.ownerAddress} xs={6}>
|
||||||
<AddressInput
|
<AddressInput
|
||||||
component={TextField}
|
component={TextField}
|
||||||
fieldMutator={val => {
|
fieldMutator={(val) => {
|
||||||
form.mutators.setValue(addressName, val)
|
form.mutators.setValue(addressName, val)
|
||||||
}}
|
}}
|
||||||
inputAdornment={
|
inputAdornment={
|
||||||
|
@ -10,7 +10,7 @@ export const getOwnerAddressBy = (index: number) => `owner${index}Address`
|
|||||||
export const getNumOwnersFrom = (values: Object) => {
|
export const getNumOwnersFrom = (values: Object) => {
|
||||||
const accounts = Object.keys(values)
|
const accounts = Object.keys(values)
|
||||||
.sort()
|
.sort()
|
||||||
.filter(key => /^owner\d+Address$/.test(key) && !!values[key])
|
.filter((key) => /^owner\d+Address$/.test(key) && !!values[key])
|
||||||
|
|
||||||
return accounts.length
|
return accounts.length
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,17 @@ import { type Owner, makeOwner } from '~/routes/safe/store/models/owner'
|
|||||||
export const getAccountsFrom = (values: Object): string[] => {
|
export const getAccountsFrom = (values: Object): string[] => {
|
||||||
const accounts = Object.keys(values)
|
const accounts = Object.keys(values)
|
||||||
.sort()
|
.sort()
|
||||||
.filter(key => /^owner\d+Address$/.test(key))
|
.filter((key) => /^owner\d+Address$/.test(key))
|
||||||
|
|
||||||
return accounts.map(account => values[account]).slice(0, values.owners)
|
return accounts.map((account) => values[account]).slice(0, values.owners)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getNamesFrom = (values: Object): string[] => {
|
export const getNamesFrom = (values: Object): string[] => {
|
||||||
const accounts = Object.keys(values)
|
const accounts = Object.keys(values)
|
||||||
.sort()
|
.sort()
|
||||||
.filter(key => /^owner\d+Name$/.test(key))
|
.filter((key) => /^owner\d+Name$/.test(key))
|
||||||
|
|
||||||
return accounts.map(account => values[account]).slice(0, values.owners)
|
return accounts.map((account) => values[account]).slice(0, values.owners)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getOwnersFrom = (names: string[], addresses: string[]): List<Owner> => {
|
export const getOwnersFrom = (names: string[], addresses: string[]): List<Owner> => {
|
||||||
|
@ -43,7 +43,7 @@ const CreateEditEntryModalComponent = ({
|
|||||||
newEntryModalHandler,
|
newEntryModalHandler,
|
||||||
onClose,
|
onClose,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const onFormSubmitted = values => {
|
const onFormSubmitted = (values) => {
|
||||||
if (entryToEdit && !entryToEdit.entry.isNew) {
|
if (entryToEdit && !entryToEdit.entry.isNew) {
|
||||||
editEntryModalHandler(values)
|
editEntryModalHandler(values)
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,7 +26,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DeleteEntryModalComponent = ({ classes, deleteEntryModalHandler, entryToDelete, isOpen, onClose }: Props) => {
|
const DeleteEntryModalComponent = ({ classes, deleteEntryModalHandler, entryToDelete, isOpen, onClose }: Props) => {
|
||||||
const handleDeleteEntrySubmit = values => {
|
const handleDeleteEntrySubmit = (values) => {
|
||||||
deleteEntryModalHandler(values, entryToDelete.index)
|
deleteEntryModalHandler(values, entryToDelete.index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const EllipsisTransactionDetails = ({ address, knownAddress }: EllipsisTransacti
|
|||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const currentSafeAddress = useSelector(safeParamAddressFromStateSelector)
|
const currentSafeAddress = useSelector(safeParamAddressFromStateSelector)
|
||||||
|
|
||||||
const handleClick = event => {
|
const handleClick = (event) => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ type Props = {
|
|||||||
|
|
||||||
const AddressBookTable = ({ classes }: Props) => {
|
const AddressBookTable = ({ classes }: Props) => {
|
||||||
const columns = generateColumns()
|
const columns = generateColumns()
|
||||||
const autoColumns = columns.filter(c => !c.custom)
|
const autoColumns = columns.filter((c) => !c.custom)
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const addressBook = useSelector(getAddressBookListSelector)
|
const addressBook = useSelector(getAddressBookListSelector)
|
||||||
const [selectedEntry, setSelectedEntry] = useState(null)
|
const [selectedEntry, setSelectedEntry] = useState(null)
|
||||||
@ -68,7 +68,7 @@ const AddressBookTable = ({ classes }: Props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (entryAddressToEditOrCreateNew) {
|
if (entryAddressToEditOrCreateNew) {
|
||||||
const key = addressBook.findKey(entry => entry.address === entryAddressToEditOrCreateNew)
|
const key = addressBook.findKey((entry) => entry.address === entryAddressToEditOrCreateNew)
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
// Edit old entry
|
// Edit old entry
|
||||||
const value = addressBook.get(key)
|
const value = addressBook.get(key)
|
||||||
|
@ -48,7 +48,7 @@ const appList = [
|
|||||||
export default appList
|
export default appList
|
||||||
|
|
||||||
export const getAppInfo = (appId: string) => {
|
export const getAppInfo = (appId: string) => {
|
||||||
const res = appList.find(app => app.id === appId.toString())
|
const res = appList.find((app) => app.id === appId.toString())
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return {
|
return {
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -13,7 +13,7 @@ import ButtonLink from '~/components/layout/ButtonLink'
|
|||||||
const StyledIframe = styled.iframe`
|
const StyledIframe = styled.iframe`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: ${props => (props.shouldDisplay ? 'block' : 'none')};
|
display: ${(props) => (props.shouldDisplay ? 'block' : 'none')};
|
||||||
`
|
`
|
||||||
const operations = {
|
const operations = {
|
||||||
SEND_TRANSACTIONS: 'sendTransactions',
|
SEND_TRANSACTIONS: 'sendTransactions',
|
||||||
@ -51,13 +51,13 @@ function Apps({
|
|||||||
const [appIsLoading, setAppIsLoading] = useState(true)
|
const [appIsLoading, setAppIsLoading] = useState(true)
|
||||||
const [iframeEl, setframeEl] = useState(null)
|
const [iframeEl, setframeEl] = useState(null)
|
||||||
|
|
||||||
const getSelectedApp = () => appsList.find(e => e.id === selectedApp)
|
const getSelectedApp = () => appsList.find((e) => e.id === selectedApp)
|
||||||
|
|
||||||
const sendMessageToIframe = (messageId, data) => {
|
const sendMessageToIframe = (messageId, data) => {
|
||||||
iframeEl.contentWindow.postMessage({ messageId, data }, getSelectedApp().url)
|
iframeEl.contentWindow.postMessage({ messageId, data }, getSelectedApp().url)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleIframeMessage = async data => {
|
const handleIframeMessage = async (data) => {
|
||||||
if (!data || !data.messageId) {
|
if (!data || !data.messageId) {
|
||||||
console.warn('iframe: message without messageId')
|
console.warn('iframe: message without messageId')
|
||||||
return
|
return
|
||||||
@ -109,7 +109,7 @@ function Apps({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const iframeRef = useCallback(node => {
|
const iframeRef = useCallback((node) => {
|
||||||
if (node !== null) {
|
if (node !== null) {
|
||||||
setframeEl(node)
|
setframeEl(node)
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ function Apps({
|
|||||||
}
|
}
|
||||||
}, [iframeEl])
|
}, [iframeEl])
|
||||||
|
|
||||||
const onSelectApp = appId => {
|
const onSelectApp = (appId) => {
|
||||||
setAppIsLoading(true)
|
setAppIsLoading(true)
|
||||||
setSelectedApp(appId)
|
setSelectedApp(appId)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ const sendTransactions = (
|
|||||||
const encodeMultiSendCalldata = multiSend.methods
|
const encodeMultiSendCalldata = multiSend.methods
|
||||||
.multiSend(
|
.multiSend(
|
||||||
`0x${txs
|
`0x${txs
|
||||||
.map(tx =>
|
.map((tx) =>
|
||||||
[
|
[
|
||||||
web3.eth.abi.encodeParameter('uint8', 0).slice(-2),
|
web3.eth.abi.encodeParameter('uint8', 0).slice(-2),
|
||||||
web3.eth.abi.encodeParameter('address', tx.to).slice(-40),
|
web3.eth.abi.encodeParameter('address', tx.to).slice(-40),
|
||||||
|
@ -16,7 +16,7 @@ const useStyles = makeStyles({
|
|||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.10)',
|
boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.10)',
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
cursor: props => (props.granted ? 'pointer' : 'default'),
|
cursor: (props) => (props.granted ? 'pointer' : 'default'),
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
flexGrow: '1',
|
flexGrow: '1',
|
||||||
@ -54,7 +54,7 @@ const useStyles = makeStyles({
|
|||||||
zIndex: '5',
|
zIndex: '5',
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
backgroundColor: props => `#${props.backgroundColor}` || '#f0efee',
|
backgroundColor: (props) => `#${props.backgroundColor}` || '#f0efee',
|
||||||
backgroundPosition: '50% 50%',
|
backgroundPosition: '50% 50%',
|
||||||
backgroundRepeat: 'no-repeat',
|
backgroundRepeat: 'no-repeat',
|
||||||
backgroundSize: 'contain',
|
backgroundSize: 'contain',
|
||||||
|
@ -77,17 +77,17 @@ const SendModal = ({ activeScreenType, isOpen, onClose, recipientAddress, select
|
|||||||
|
|
||||||
const scalableModalSize = activeScreen === 'chooseTxType'
|
const scalableModalSize = activeScreen === 'chooseTxType'
|
||||||
|
|
||||||
const handleTxCreation = txInfo => {
|
const handleTxCreation = (txInfo) => {
|
||||||
setActiveScreen('reviewTx')
|
setActiveScreen('reviewTx')
|
||||||
setTx(txInfo)
|
setTx(txInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCustomTxCreation = customTxInfo => {
|
const handleCustomTxCreation = (customTxInfo) => {
|
||||||
setActiveScreen('reviewCustomTx')
|
setActiveScreen('reviewCustomTx')
|
||||||
setTx(customTxInfo)
|
setTx(customTxInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSendCollectible = txInfo => {
|
const handleSendCollectible = (txInfo) => {
|
||||||
setActiveScreen('reviewCollectible')
|
setActiveScreen('reviewCollectible')
|
||||||
setTx(txInfo)
|
setTx(txInfo)
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ const textFieldInputStyle = makeStyles(() => ({
|
|||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const filterAddressBookWithContractAddresses = async addressBook => {
|
const filterAddressBookWithContractAddresses = async (addressBook) => {
|
||||||
const abFlags = await Promise.all(
|
const abFlags = await Promise.all(
|
||||||
addressBook.map(async ({ address }) => {
|
addressBook.map(async ({ address }) => {
|
||||||
return (await mustBeEthereumContractAddress(address)) === undefined
|
return (await mustBeEthereumContractAddress(address)) === undefined
|
||||||
@ -49,7 +49,7 @@ const filterAddressBookWithContractAddresses = async addressBook => {
|
|||||||
return addressBook.filter((adbkEntry, index) => abFlags[index])
|
return addressBook.filter((adbkEntry, index) => abFlags[index])
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidEnsName = name => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
const isValidEnsName = (name) => /^([\w-]+\.)+(eth|test|xyz|luxe)$/.test(name)
|
||||||
|
|
||||||
const AddressBookInput = ({
|
const AddressBookInput = ({
|
||||||
classes,
|
classes,
|
||||||
@ -69,7 +69,7 @@ const AddressBookInput = ({
|
|||||||
|
|
||||||
const [inputAddValue, setInputAddValue] = useState(recipientAddress)
|
const [inputAddValue, setInputAddValue] = useState(recipientAddress)
|
||||||
|
|
||||||
const onAddressInputChanged = async addressValue => {
|
const onAddressInputChanged = async (addressValue) => {
|
||||||
setInputAddValue(addressValue)
|
setInputAddValue(addressValue)
|
||||||
let resolvedAddress = addressValue
|
let resolvedAddress = addressValue
|
||||||
let isValidText
|
let isValidText
|
||||||
@ -92,7 +92,7 @@ const AddressBookInput = ({
|
|||||||
// First removes the entries that are not contracts if the operation is custom tx
|
// First removes the entries that are not contracts if the operation is custom tx
|
||||||
const adbkToFilter = isCustomTx ? await filterAddressBookWithContractAddresses(addressBook) : addressBook
|
const adbkToFilter = isCustomTx ? await filterAddressBookWithContractAddresses(addressBook) : addressBook
|
||||||
// Then Filters the entries based on the input of the user
|
// Then Filters the entries based on the input of the user
|
||||||
const filteredADBK = adbkToFilter.filter(adbkEntry => {
|
const filteredADBK = adbkToFilter.filter((adbkEntry) => {
|
||||||
const { address, name } = adbkEntry
|
const { address, name } = adbkEntry
|
||||||
return (
|
return (
|
||||||
name.toLowerCase().includes(addressValue.toLowerCase()) ||
|
name.toLowerCase().includes(addressValue.toLowerCase()) ||
|
||||||
@ -137,7 +137,7 @@ const AddressBookInput = ({
|
|||||||
closeIcon={null}
|
closeIcon={null}
|
||||||
disableOpenOnFocus
|
disableOpenOnFocus
|
||||||
filterOptions={(optionsArray, { inputValue }) =>
|
filterOptions={(optionsArray, { inputValue }) =>
|
||||||
optionsArray.filter(item => {
|
optionsArray.filter((item) => {
|
||||||
const inputLowerCase = inputValue.toLowerCase()
|
const inputLowerCase = inputValue.toLowerCase()
|
||||||
const foundName = item.name.toLowerCase().includes(inputLowerCase)
|
const foundName = item.name.toLowerCase().includes(inputLowerCase)
|
||||||
const foundAddress = item.address.toLowerCase().includes(inputLowerCase)
|
const foundAddress = item.address.toLowerCase().includes(inputLowerCase)
|
||||||
@ -145,7 +145,7 @@ const AddressBookInput = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
freeSolo
|
freeSolo
|
||||||
getOptionLabel={adbkEntry => adbkEntry.address || ''}
|
getOptionLabel={(adbkEntry) => adbkEntry.address || ''}
|
||||||
id="free-solo-demo"
|
id="free-solo-demo"
|
||||||
onChange={(event, value) => {
|
onChange={(event, value) => {
|
||||||
let address = ''
|
let address = ''
|
||||||
@ -164,7 +164,7 @@ const AddressBookInput = ({
|
|||||||
}}
|
}}
|
||||||
open={!blurred}
|
open={!blurred}
|
||||||
options={adbkList.toArray()}
|
options={adbkList.toArray()}
|
||||||
renderInput={params => (
|
renderInput={(params) => (
|
||||||
<MuiTextField
|
<MuiTextField
|
||||||
{...params}
|
{...params}
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@ -185,7 +185,7 @@ const AddressBookInput = ({
|
|||||||
className: statusClasses,
|
className: statusClasses,
|
||||||
}}
|
}}
|
||||||
label={!isValidForm ? validationText : 'Recipient'}
|
label={!isValidForm ? validationText : 'Recipient'}
|
||||||
onChange={event => {
|
onChange={(event) => {
|
||||||
setInputTouched(true)
|
setInputTouched(true)
|
||||||
onAddressInputChanged(event.target.value)
|
onAddressInputChanged(event.target.value)
|
||||||
}}
|
}}
|
||||||
@ -193,7 +193,7 @@ const AddressBookInput = ({
|
|||||||
variant="filled"
|
variant="filled"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
renderOption={adbkEntry => {
|
renderOption={(adbkEntry) => {
|
||||||
const { address, name } = adbkEntry
|
const { address, name } = adbkEntry
|
||||||
return (
|
return (
|
||||||
<div className={classes.itemOptionList}>
|
<div className={classes.itemOptionList}>
|
||||||
|
@ -53,7 +53,7 @@ const ReviewTx = ({ closeSnackbar, enqueueSnackbar, onClose, onPrev, tx }: Props
|
|||||||
const [gasCosts, setGasCosts] = useState<string>('< 0.001')
|
const [gasCosts, setGasCosts] = useState<string>('< 0.001')
|
||||||
const [data, setData] = useState('')
|
const [data, setData] = useState('')
|
||||||
|
|
||||||
const txToken = tokens.find(token => token.address === tx.token)
|
const txToken = tokens.find((token) => token.address === tx.token)
|
||||||
const isSendingETH = txToken.address === ETH_ADDRESS
|
const isSendingETH = txToken.address === ETH_ADDRESS
|
||||||
const txRecipient = isSendingETH ? tx.recipientAddress : txToken.address
|
const txRecipient = isSendingETH ? tx.recipientAddress : txToken.address
|
||||||
|
|
||||||
|
@ -67,10 +67,10 @@ const CollectibleSelectField = ({ initialValue, tokens }: SelectFieldProps) => {
|
|||||||
disabled={!tokens.length}
|
disabled={!tokens.length}
|
||||||
initialValue={initialValue}
|
initialValue={initialValue}
|
||||||
name="nftTokenId"
|
name="nftTokenId"
|
||||||
renderValue={nftTokenId => <SelectedCollectible tokenId={nftTokenId} tokens={tokens} />}
|
renderValue={(nftTokenId) => <SelectedCollectible tokenId={nftTokenId} tokens={tokens} />}
|
||||||
validate={required}
|
validate={required}
|
||||||
>
|
>
|
||||||
{tokens.map(token => (
|
{tokens.map((token) => (
|
||||||
<MenuItem key={`${token.assetAddress}-${token.tokenId}`} value={token.tokenId}>
|
<MenuItem key={`${token.assetAddress}-${token.tokenId}`} value={token.tokenId}>
|
||||||
<ListItemIcon className={classes.tokenImage}>
|
<ListItemIcon className={classes.tokenImage}>
|
||||||
<Img alt={token.name} height={28} onError={setImageToPlaceholder} src={token.image} />
|
<Img alt={token.name} height={28} onError={setImageToPlaceholder} src={token.image} />
|
||||||
|
@ -69,10 +69,10 @@ const TokenSelectField = ({ assets, initialValue }: SelectFieldProps) => {
|
|||||||
disabled={!assetsAddresses.length}
|
disabled={!assetsAddresses.length}
|
||||||
initialValue={initialValue}
|
initialValue={initialValue}
|
||||||
name="assetAddress"
|
name="assetAddress"
|
||||||
renderValue={assetAddress => <SelectedToken assetAddress={assetAddress} assets={assets} />}
|
renderValue={(assetAddress) => <SelectedToken assetAddress={assetAddress} assets={assets} />}
|
||||||
validate={required}
|
validate={required}
|
||||||
>
|
>
|
||||||
{assetsAddresses.map(assetAddress => {
|
{assetsAddresses.map((assetAddress) => {
|
||||||
const asset = assets[assetAddress]
|
const asset = assets[assetAddress]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -36,7 +36,7 @@ import { sm } from '~/theme/variables'
|
|||||||
type Props = {
|
type Props = {
|
||||||
initialValues: Object,
|
initialValues: Object,
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
onNext: any => void,
|
onNext: (any) => void,
|
||||||
recipientAddress: string,
|
recipientAddress: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ const SendCustomTx = ({ initialValues, onClose, onNext, recipientAddress }: Prop
|
|||||||
shouldDisableSubmitButton = !selectedEntry.address
|
shouldDisableSubmitButton = !selectedEntry.address
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleScan = value => {
|
const handleScan = (value) => {
|
||||||
let scannedAddress = value
|
let scannedAddress = value
|
||||||
|
|
||||||
if (scannedAddress.startsWith('ethereum:')) {
|
if (scannedAddress.startsWith('ethereum:')) {
|
||||||
@ -128,7 +128,7 @@ const SendCustomTx = ({ initialValues, onClose, onNext, recipientAddress }: Prop
|
|||||||
</Row>
|
</Row>
|
||||||
{selectedEntry && selectedEntry.address ? (
|
{selectedEntry && selectedEntry.address ? (
|
||||||
<div
|
<div
|
||||||
onKeyDown={e => {
|
onKeyDown={(e) => {
|
||||||
if (e.keyCode !== 9) {
|
if (e.keyCode !== 9) {
|
||||||
setSelectedEntry(null)
|
setSelectedEntry(null)
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,10 @@ const TokenSelectField = ({ classes, initialValue, isValid, tokens }: SelectFiel
|
|||||||
displayEmpty
|
displayEmpty
|
||||||
initialValue={initialValue}
|
initialValue={initialValue}
|
||||||
name="token"
|
name="token"
|
||||||
renderValue={tokenAddress => <SelectedTokenStyled tokenAddress={tokenAddress} tokens={tokens} />}
|
renderValue={(tokenAddress) => <SelectedTokenStyled tokenAddress={tokenAddress} tokens={tokens} />}
|
||||||
validate={required}
|
validate={required}
|
||||||
>
|
>
|
||||||
{tokens.map(token => (
|
{tokens.map((token) => (
|
||||||
<MenuItem key={token.address} value={token.address}>
|
<MenuItem key={token.address} value={token.address}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<Img alt={token.name} height={28} onError={setImageToPlaceholder} src={token.logoUri} />
|
<Img alt={token.name} height={28} onError={setImageToPlaceholder} src={token.logoUri} />
|
||||||
|
@ -39,7 +39,7 @@ import { sm } from '~/theme/variables'
|
|||||||
type Props = {
|
type Props = {
|
||||||
initialValues: Object,
|
initialValues: Object,
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
onNext: any => void,
|
onNext: (any) => void,
|
||||||
recipientAddress?: string,
|
recipientAddress?: string,
|
||||||
selectedToken: string,
|
selectedToken: string,
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedT
|
|||||||
}
|
}
|
||||||
}, [selectedEntry, pristine])
|
}, [selectedEntry, pristine])
|
||||||
|
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
const submitValues = values
|
const submitValues = values
|
||||||
// If the input wasn't modified, there was no mutation of the recipientAddress
|
// If the input wasn't modified, there was no mutation of the recipientAddress
|
||||||
if (!values.recipientAddress) {
|
if (!values.recipientAddress) {
|
||||||
@ -110,9 +110,9 @@ const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedT
|
|||||||
const formState = args[2]
|
const formState = args[2]
|
||||||
const mutators = args[3]
|
const mutators = args[3]
|
||||||
const { token: tokenAddress } = formState.values
|
const { token: tokenAddress } = formState.values
|
||||||
const selectedTokenRecord = tokens.find(token => token.address === tokenAddress)
|
const selectedTokenRecord = tokens.find((token) => token.address === tokenAddress)
|
||||||
|
|
||||||
const handleScan = value => {
|
const handleScan = (value) => {
|
||||||
let scannedAddress = value
|
let scannedAddress = value
|
||||||
|
|
||||||
if (scannedAddress.startsWith('ethereum:')) {
|
if (scannedAddress.startsWith('ethereum:')) {
|
||||||
@ -142,7 +142,7 @@ const SendFunds = ({ initialValues, onClose, onNext, recipientAddress, selectedT
|
|||||||
</Row>
|
</Row>
|
||||||
{selectedEntry && selectedEntry.address ? (
|
{selectedEntry && selectedEntry.address ? (
|
||||||
<div
|
<div
|
||||||
onKeyDown={e => {
|
onKeyDown={(e) => {
|
||||||
if (e.keyCode !== 9) {
|
if (e.keyCode !== 9) {
|
||||||
setSelectedEntry(null)
|
setSelectedEntry(null)
|
||||||
}
|
}
|
||||||
|
@ -103,12 +103,12 @@ class Tokens extends React.Component<Props, State> {
|
|||||||
this.setState(() => ({ filter: '' }))
|
this.setState(() => ({ filter: '' }))
|
||||||
}
|
}
|
||||||
|
|
||||||
onChangeSearchBar = value => {
|
onChangeSearchBar = (value) => {
|
||||||
this.setState(() => ({ filter: value }))
|
this.setState(() => ({ filter: value }))
|
||||||
}
|
}
|
||||||
|
|
||||||
onSwitch = (token: Token) => () => {
|
onSwitch = (token: Token) => () => {
|
||||||
this.setState(prevState => {
|
this.setState((prevState) => {
|
||||||
const activeTokensAddresses = prevState.activeTokensAddresses.has(token.address)
|
const activeTokensAddresses = prevState.activeTokensAddresses.has(token.address)
|
||||||
? prevState.activeTokensAddresses.remove(token.address)
|
? prevState.activeTokensAddresses.remove(token.address)
|
||||||
: prevState.activeTokensAddresses.add(token.address)
|
: prevState.activeTokensAddresses.add(token.address)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
|
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
|
||||||
|
|
||||||
export const setImageToPlaceholder = e => {
|
export const setImageToPlaceholder = (e) => {
|
||||||
e.target.onerror = null
|
e.target.onerror = null
|
||||||
e.target.src = TokenPlaceholder
|
e.target.src = TokenPlaceholder
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ const DropdownCurrency = () => {
|
|||||||
|
|
||||||
const [searchParams, setSearchParams] = useState('')
|
const [searchParams, setSearchParams] = useState('')
|
||||||
const classes = useDropdownStyles()
|
const classes = useDropdownStyles()
|
||||||
const currenciesListFiltered = currenciesList.filter(currency =>
|
const currenciesListFiltered = currenciesList.filter((currency) =>
|
||||||
currency.toLowerCase().includes(searchParams.toLowerCase()),
|
currency.toLowerCase().includes(searchParams.toLowerCase()),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,14 +83,14 @@ const DropdownCurrency = () => {
|
|||||||
input: classes.inputInput,
|
input: classes.inputInput,
|
||||||
}}
|
}}
|
||||||
inputProps={{ 'aria-label': 'search' }}
|
inputProps={{ 'aria-label': 'search' }}
|
||||||
onChange={event => setSearchParams(event.target.value)}
|
onChange={(event) => setSearchParams(event.target.value)}
|
||||||
placeholder="Search…"
|
placeholder="Search…"
|
||||||
value={searchParams}
|
value={searchParams}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<div className={classes.dropdownItemsScrollWrapper}>
|
<div className={classes.dropdownItemsScrollWrapper}>
|
||||||
{currenciesListFiltered.map(currencyName => (
|
{currenciesListFiltered.map((currencyName) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
className={classes.listItem}
|
className={classes.listItem}
|
||||||
key={currencyName}
|
key={currencyName}
|
||||||
|
@ -97,7 +97,7 @@ const AddOwner = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ownerSubmitted = (newValues: Object) => {
|
const ownerSubmitted = (newValues: Object) => {
|
||||||
setValues(stateValues => ({
|
setValues((stateValues) => ({
|
||||||
...stateValues,
|
...stateValues,
|
||||||
ownerName: newValues.ownerName,
|
ownerName: newValues.ownerName,
|
||||||
ownerAddress: newValues.ownerAddress,
|
ownerAddress: newValues.ownerAddress,
|
||||||
@ -106,7 +106,7 @@ const AddOwner = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const thresholdSubmitted = (newValues: Object) => {
|
const thresholdSubmitted = (newValues: Object) => {
|
||||||
setValues(stateValues => ({
|
setValues((stateValues) => ({
|
||||||
...stateValues,
|
...stateValues,
|
||||||
threshold: newValues.threshold,
|
threshold: newValues.threshold,
|
||||||
}))
|
}))
|
||||||
|
@ -38,10 +38,10 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const OwnerForm = ({ classes, onClose, onSubmit, owners }: Props) => {
|
const OwnerForm = ({ classes, onClose, onSubmit, owners }: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
onSubmit(values)
|
onSubmit(values)
|
||||||
}
|
}
|
||||||
const ownerDoesntExist = uniqueAddress(owners.map(o => o.address))
|
const ownerDoesntExist = uniqueAddress(owners.map((o) => o.address))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -113,7 +113,7 @@ const ReviewAddOwner = ({ classes, onClickBack, onClose, onSubmit, owners, safeA
|
|||||||
</Paragraph>
|
</Paragraph>
|
||||||
</Row>
|
</Row>
|
||||||
<Hairline />
|
<Hairline />
|
||||||
{owners.map(owner => (
|
{owners.map((owner) => (
|
||||||
<React.Fragment key={owner.address}>
|
<React.Fragment key={owner.address}>
|
||||||
<Row className={classes.owner}>
|
<Row className={classes.owner}>
|
||||||
<Col align="center" xs={1}>
|
<Col align="center" xs={1}>
|
||||||
|
@ -32,7 +32,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ThresholdForm = ({ classes, onClickBack, onClose, onSubmit, owners, threshold }: Props) => {
|
const ThresholdForm = ({ classes, onClickBack, onClose, onSubmit, owners, threshold }: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
onSubmit(values)
|
onSubmit(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ const EditOwnerComponent = ({
|
|||||||
selectedOwnerName,
|
selectedOwnerName,
|
||||||
updateAddressBookEntry,
|
updateAddressBookEntry,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
const { ownerName } = values
|
const { ownerName } = values
|
||||||
editSafeOwner({ safeAddress, ownerAddress, ownerName })
|
editSafeOwner({ safeAddress, ownerAddress, ownerName })
|
||||||
updateAddressBookEntry(makeAddressBookEntry({ address: ownerAddress, name: ownerName }))
|
updateAddressBookEntry(makeAddressBookEntry({ address: ownerAddress, name: ownerName }))
|
||||||
|
@ -56,7 +56,9 @@ export const sendRemoveOwner = async (
|
|||||||
) => {
|
) => {
|
||||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const safeOwners = await gnosisSafe.getOwners()
|
const safeOwners = await gnosisSafe.getOwners()
|
||||||
const index = safeOwners.findIndex(ownerAddress => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase())
|
const index = safeOwners.findIndex(
|
||||||
|
(ownerAddress) => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase(),
|
||||||
|
)
|
||||||
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
||||||
const txData = gnosisSafe.contract.methods
|
const txData = gnosisSafe.contract.methods
|
||||||
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
|
.removeOwner(prevAddress, ownerAddressToRemove, values.threshold)
|
||||||
|
@ -28,7 +28,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CheckOwner = ({ classes, onClose, onSubmit, ownerAddress, ownerName }: Props) => {
|
const CheckOwner = ({ classes, onClose, onSubmit, ownerAddress, ownerName }: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
onSubmit(values)
|
onSubmit(values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ const ReviewRemoveOwner = ({
|
|||||||
const { fromWei, toBN } = web3.utils
|
const { fromWei, toBN } = web3.utils
|
||||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const safeOwners = await gnosisSafe.getOwners()
|
const safeOwners = await gnosisSafe.getOwners()
|
||||||
const index = safeOwners.findIndex(owner => owner.toLowerCase() === ownerAddress.toLowerCase())
|
const index = safeOwners.findIndex((owner) => owner.toLowerCase() === ownerAddress.toLowerCase())
|
||||||
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
||||||
const txData = gnosisSafe.contract.methods.removeOwner(prevAddress, ownerAddress, values.threshold).encodeABI()
|
const txData = gnosisSafe.contract.methods.removeOwner(prevAddress, ownerAddress, values.threshold).encodeABI()
|
||||||
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
|
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
|
||||||
@ -125,7 +125,7 @@ const ReviewRemoveOwner = ({
|
|||||||
</Row>
|
</Row>
|
||||||
<Hairline />
|
<Hairline />
|
||||||
{owners.map(
|
{owners.map(
|
||||||
owner =>
|
(owner) =>
|
||||||
owner.address !== ownerAddress && (
|
owner.address !== ownerAddress && (
|
||||||
<React.Fragment key={owner.address}>
|
<React.Fragment key={owner.address}>
|
||||||
<Row className={classes.owner}>
|
<Row className={classes.owner}>
|
||||||
|
@ -32,7 +32,7 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ThresholdForm = ({ classes, onClickBack, onClose, onSubmit, owners, threshold }: Props) => {
|
const ThresholdForm = ({ classes, onClickBack, onClose, onSubmit, owners, threshold }: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
onSubmit(values)
|
onSubmit(values)
|
||||||
}
|
}
|
||||||
const defaultThreshold = threshold > 1 ? threshold - 1 : threshold
|
const defaultThreshold = threshold > 1 ? threshold - 1 : threshold
|
||||||
|
@ -54,7 +54,9 @@ export const sendReplaceOwner = async (
|
|||||||
) => {
|
) => {
|
||||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const safeOwners = await gnosisSafe.getOwners()
|
const safeOwners = await gnosisSafe.getOwners()
|
||||||
const index = safeOwners.findIndex(ownerAddress => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase())
|
const index = safeOwners.findIndex(
|
||||||
|
(ownerAddress) => ownerAddress.toLowerCase() === ownerAddressToRemove.toLowerCase(),
|
||||||
|
)
|
||||||
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
||||||
const txData = gnosisSafe.contract.methods
|
const txData = gnosisSafe.contract.methods
|
||||||
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
|
.swapOwner(prevAddress, ownerAddressToRemove, values.ownerAddress)
|
||||||
|
@ -44,10 +44,10 @@ type Props = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const OwnerForm = ({ classes, onClose, onSubmit, ownerAddress, ownerName, owners }: Props) => {
|
const OwnerForm = ({ classes, onClose, onSubmit, ownerAddress, ownerName, owners }: Props) => {
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
onSubmit(values)
|
onSubmit(values)
|
||||||
}
|
}
|
||||||
const ownerDoesntExist = uniqueAddress(owners.map(o => o.address))
|
const ownerDoesntExist = uniqueAddress(owners.map((o) => o.address))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -61,7 +61,7 @@ const ReviewRemoveOwner = ({
|
|||||||
const { fromWei, toBN } = web3.utils
|
const { fromWei, toBN } = web3.utils
|
||||||
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
const gnosisSafe = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const safeOwners = await gnosisSafe.getOwners()
|
const safeOwners = await gnosisSafe.getOwners()
|
||||||
const index = safeOwners.findIndex(owner => owner.toLowerCase() === ownerAddress.toLowerCase())
|
const index = safeOwners.findIndex((owner) => owner.toLowerCase() === ownerAddress.toLowerCase())
|
||||||
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
const prevAddress = index === 0 ? SENTINEL_ADDRESS : safeOwners[index - 1]
|
||||||
const txData = gnosisSafe.contract.methods.swapOwner(prevAddress, ownerAddress, values.ownerAddress).encodeABI()
|
const txData = gnosisSafe.contract.methods.swapOwner(prevAddress, ownerAddress, values.ownerAddress).encodeABI()
|
||||||
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
|
const estimatedGasCosts = await estimateTxGasCosts(safeAddress, safeAddress, txData)
|
||||||
@ -125,7 +125,7 @@ const ReviewRemoveOwner = ({
|
|||||||
</Row>
|
</Row>
|
||||||
<Hairline />
|
<Hairline />
|
||||||
{owners.map(
|
{owners.map(
|
||||||
owner =>
|
(owner) =>
|
||||||
owner.address !== ownerAddress && (
|
owner.address !== ownerAddress && (
|
||||||
<React.Fragment key={owner.address}>
|
<React.Fragment key={owner.address}>
|
||||||
<Row className={classes.owner}>
|
<Row className={classes.owner}>
|
||||||
|
@ -135,7 +135,7 @@ class ManageOwners extends React.Component<Props, State> {
|
|||||||
} = this.state
|
} = this.state
|
||||||
|
|
||||||
const columns = generateColumns()
|
const columns = generateColumns()
|
||||||
const autoColumns = columns.filter(c => !c.custom)
|
const autoColumns = columns.filter((c) => !c.custom)
|
||||||
const ownersAdbk = getOwnersWithNameFromAddressBook(addressBook, owners)
|
const ownersAdbk = getOwnersWithNameFromAddressBook(addressBook, owners)
|
||||||
const ownerData = getOwnerData(ownersAdbk)
|
const ownerData = getOwnerData(ownersAdbk)
|
||||||
|
|
||||||
|
@ -57,10 +57,10 @@ const SafeDetails = (props: Props) => {
|
|||||||
const [isModalOpen, setModalOpen] = React.useState(false)
|
const [isModalOpen, setModalOpen] = React.useState(false)
|
||||||
|
|
||||||
const toggleModal = () => {
|
const toggleModal = () => {
|
||||||
setModalOpen(prevOpen => !prevOpen)
|
setModalOpen((prevOpen) => !prevOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
updateSafe({ address: safeAddress, name: values.safeName })
|
updateSafe({ address: safeAddress, name: values.safeName })
|
||||||
|
|
||||||
const notification = getNotificationsFromTxType(TX_NOTIFICATION_TYPES.SAFE_NAME_CHANGE_TX)
|
const notification = getNotificationsFromTxType(TX_NOTIFICATION_TYPES.SAFE_NAME_CHANGE_TX)
|
||||||
|
@ -60,7 +60,7 @@ const ChangeThreshold = ({ classes, onChangeThreshold, onClose, owners, safeAddr
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const handleSubmit = values => {
|
const handleSubmit = (values) => {
|
||||||
const newThreshold = values[THRESHOLD_FIELD_NAME]
|
const newThreshold = values[THRESHOLD_FIELD_NAME]
|
||||||
|
|
||||||
onClose()
|
onClose()
|
||||||
|
@ -42,10 +42,10 @@ const ThresholdSettings = ({
|
|||||||
const [isModalOpen, setModalOpen] = useState(false)
|
const [isModalOpen, setModalOpen] = useState(false)
|
||||||
|
|
||||||
const toggleModal = () => {
|
const toggleModal = () => {
|
||||||
setModalOpen(prevOpen => !prevOpen)
|
setModalOpen((prevOpen) => !prevOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onChangeThreshold = async newThreshold => {
|
const onChangeThreshold = async (newThreshold) => {
|
||||||
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
|
||||||
const txData = safeInstance.contract.methods.changeThreshold(newThreshold).encodeABI()
|
const txData = safeInstance.contract.methods.changeThreshold(newThreshold).encodeABI()
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class Settings extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange = menuOptionIndex => () => {
|
handleChange = (menuOptionIndex) => () => {
|
||||||
this.setState({ menuOptionIndex })
|
this.setState({ menuOptionIndex })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ const ApproveTxModal = ({
|
|||||||
}
|
}
|
||||||
}, [approveAndExecute])
|
}, [approveAndExecute])
|
||||||
|
|
||||||
const handleExecuteCheckbox = () => setApproveAndExecute(prevApproveAndExecute => !prevApproveAndExecute)
|
const handleExecuteCheckbox = () => setApproveAndExecute((prevApproveAndExecute) => !prevApproveAndExecute)
|
||||||
|
|
||||||
const approveTx = () => {
|
const approveTx = () => {
|
||||||
processTransaction({
|
processTransaction({
|
||||||
|
@ -42,7 +42,7 @@ const OwnersList = ({
|
|||||||
userAddress,
|
userAddress,
|
||||||
}: ListProps) => (
|
}: ListProps) => (
|
||||||
<>
|
<>
|
||||||
{ownersWhoConfirmed.map(owner => (
|
{ownersWhoConfirmed.map((owner) => (
|
||||||
<OwnerComponent
|
<OwnerComponent
|
||||||
classes={classes}
|
classes={classes}
|
||||||
confirmed
|
confirmed
|
||||||
@ -59,7 +59,7 @@ const OwnersList = ({
|
|||||||
userAddress={userAddress}
|
userAddress={userAddress}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{ownersUnconfirmed.map(owner => (
|
{ownersUnconfirmed.map((owner) => (
|
||||||
<OwnerComponent
|
<OwnerComponent
|
||||||
classes={classes}
|
classes={classes}
|
||||||
executor={executor}
|
executor={executor}
|
||||||
|
@ -40,7 +40,7 @@ function getOwnersConfirmations(tx, userAddress) {
|
|||||||
const ownersWhoConfirmed = []
|
const ownersWhoConfirmed = []
|
||||||
let currentUserAlreadyConfirmed = false
|
let currentUserAlreadyConfirmed = false
|
||||||
|
|
||||||
tx.confirmations.forEach(conf => {
|
tx.confirmations.forEach((conf) => {
|
||||||
if (conf.owner.address === userAddress) {
|
if (conf.owner.address === userAddress) {
|
||||||
currentUserAlreadyConfirmed = true
|
currentUserAlreadyConfirmed = true
|
||||||
}
|
}
|
||||||
@ -55,12 +55,12 @@ function getOwnersConfirmations(tx, userAddress) {
|
|||||||
|
|
||||||
function getPendingOwnersConfirmations(owners, tx, userAddress) {
|
function getPendingOwnersConfirmations(owners, tx, userAddress) {
|
||||||
const ownersUnconfirmed = owners.filter(
|
const ownersUnconfirmed = owners.filter(
|
||||||
owner => tx.confirmations.findIndex(conf => conf.owner.address === owner.address) === -1,
|
(owner) => tx.confirmations.findIndex((conf) => conf.owner.address === owner.address) === -1,
|
||||||
)
|
)
|
||||||
|
|
||||||
let userIsUnconfirmedOwner = false
|
let userIsUnconfirmedOwner = false
|
||||||
|
|
||||||
ownersUnconfirmed.some(owner => {
|
ownersUnconfirmed.some((owner) => {
|
||||||
userIsUnconfirmedOwner = owner.address === userAddress
|
userIsUnconfirmedOwner = owner.address === userAddress
|
||||||
return userIsUnconfirmedOwner
|
return userIsUnconfirmedOwner
|
||||||
})
|
})
|
||||||
|
@ -67,12 +67,12 @@ const TxsTable = ({
|
|||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [expandedTx, setExpandedTx] = useState<string | null>(null)
|
const [expandedTx, setExpandedTx] = useState<string | null>(null)
|
||||||
|
|
||||||
const handleTxExpand = safeTxHash => {
|
const handleTxExpand = (safeTxHash) => {
|
||||||
setExpandedTx(prevTx => (prevTx === safeTxHash ? null : safeTxHash))
|
setExpandedTx((prevTx) => (prevTx === safeTxHash ? null : safeTxHash))
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns = generateColumns()
|
const columns = generateColumns()
|
||||||
const autoColumns = columns.filter(c => !c.custom)
|
const autoColumns = columns.filter((c) => !c.custom)
|
||||||
const filteredData = getTxTableData(transactions, cancellationTransactions)
|
const filteredData = getTxTableData(transactions, cancellationTransactions)
|
||||||
.sort((tx1, tx2) => {
|
.sort((tx1, tx2) => {
|
||||||
// First order by nonce
|
// First order by nonce
|
||||||
|
@ -58,8 +58,8 @@ const getTxStatus = (tx: Transaction, userAddress: string, safe: Safe): Transact
|
|||||||
} else if (!tx.confirmations.size) {
|
} else if (!tx.confirmations.size) {
|
||||||
txStatus = 'pending'
|
txStatus = 'pending'
|
||||||
} else {
|
} else {
|
||||||
const userConfirmed = tx.confirmations.filter(conf => conf.owner.address === userAddress).size === 1
|
const userConfirmed = tx.confirmations.filter((conf) => conf.owner.address === userAddress).size === 1
|
||||||
const userIsSafeOwner = safe.owners.filter(owner => owner.address === userAddress).size === 1
|
const userIsSafeOwner = safe.owners.filter((owner) => owner.address === userAddress).size === 1
|
||||||
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
txStatus = !userConfirmed && userIsSafeOwner ? 'awaiting_your_confirmation' : 'awaiting_confirmations'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ export const extendedSafeTokensSelector: Selector<GlobalState, RouterProps, List
|
|||||||
tokensSelector,
|
tokensSelector,
|
||||||
safeEthAsTokenSelector,
|
safeEthAsTokenSelector,
|
||||||
(safeTokens: List<string>, balances: Map<string, string>, tokensList: Map<string, Token>, ethAsToken: Token) => {
|
(safeTokens: List<string>, balances: Map<string, string>, tokensList: Map<string, Token>, ethAsToken: Token) => {
|
||||||
const extendedTokens = Map().withMutations(map => {
|
const extendedTokens = Map().withMutations((map) => {
|
||||||
safeTokens.forEach((tokenAddress: string) => {
|
safeTokens.forEach((tokenAddress: string) => {
|
||||||
const baseToken = tokensList.get(tokenAddress)
|
const baseToken = tokensList.get(tokenAddress)
|
||||||
const tokenBalance = balances.get(tokenAddress)
|
const tokenBalance = balances.get(tokenAddress)
|
||||||
|
@ -98,13 +98,14 @@ const createTransaction = ({
|
|||||||
try {
|
try {
|
||||||
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
||||||
// theoretically EIP712 should also work for 1.0.0 contracts
|
// theoretically EIP712 should also work for 1.0.0 contracts
|
||||||
// Also, offchain signatures are not working for ledger wallet because of a bug in their library:
|
// Also, offchain signatures are not working for ledger/trezor wallet because of a bug in their library:
|
||||||
// https://github.com/LedgerHQ/ledgerjs/issues/378
|
// https://github.com/LedgerHQ/ledgerjs/issues/378
|
||||||
|
// Couldn't find an issue for trezor but the error is almost the same
|
||||||
const canTryOffchainSigning =
|
const canTryOffchainSigning =
|
||||||
!isExecution &&
|
!isExecution &&
|
||||||
!smartContractWallet &&
|
!smartContractWallet &&
|
||||||
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES) &&
|
!hardwareWallet &&
|
||||||
!hardwareWallet
|
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
|
||||||
if (canTryOffchainSigning) {
|
if (canTryOffchainSigning) {
|
||||||
const signature = await tryOffchainSigning({ ...txArgs, safeAddress })
|
const signature = await tryOffchainSigning({ ...txArgs, safeAddress })
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ const loadSafesFromStorage = () => async (dispatch: ReduxDispatch<GlobalState>)
|
|||||||
const safes: ?{ [key: string]: SafeProps } = await loadFromStorage(SAFES_KEY)
|
const safes: ?{ [key: string]: SafeProps } = await loadFromStorage(SAFES_KEY)
|
||||||
|
|
||||||
if (safes) {
|
if (safes) {
|
||||||
Object.values(safes).forEach(safeProps => {
|
Object.values(safes).forEach((safeProps) => {
|
||||||
dispatch(addSafe(buildSafe(safeProps)))
|
dispatch(addSafe(buildSafe(safeProps)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -83,13 +83,14 @@ const processTransaction = ({
|
|||||||
try {
|
try {
|
||||||
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
// Here we're checking that safe contract version is greater or equal 1.1.1, but
|
||||||
// theoretically EIP712 should also work for 1.0.0 contracts
|
// theoretically EIP712 should also work for 1.0.0 contracts
|
||||||
// Also, offchain signatures are not working for ledger wallet because of a bug in their library:
|
// Also, offchain signatures are not working for ledger/trezor wallet because of a bug in their library:
|
||||||
// https://github.com/LedgerHQ/ledgerjs/issues/378
|
// https://github.com/LedgerHQ/ledgerjs/issues/378
|
||||||
|
// Couldn't find an issue for trezor but the error is almost the same
|
||||||
const canTryOffchainSigning =
|
const canTryOffchainSigning =
|
||||||
!isExecution &&
|
!isExecution &&
|
||||||
!smartContractWallet &&
|
!smartContractWallet &&
|
||||||
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES) &&
|
!hardwareWallet &&
|
||||||
!hardwareWallet
|
semverSatisfies(safeVersion, SAFE_VERSION_FOR_OFFCHAIN_SIGNATURES)
|
||||||
if (canTryOffchainSigning) {
|
if (canTryOffchainSigning) {
|
||||||
const signature = await tryOffchainSigning({ ...txArgs, safeAddress })
|
const signature = await tryOffchainSigning({ ...txArgs, safeAddress })
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ const recalculateActiveTokens = (state: GlobalState): void => {
|
|||||||
const tokens = tokensSelector(state)
|
const tokens = tokensSelector(state)
|
||||||
const activeTokenAddresses = getActiveTokensAddressesForAllSafes(state)
|
const activeTokenAddresses = getActiveTokensAddressesForAllSafes(state)
|
||||||
|
|
||||||
const activeTokens: List<Token> = tokens.withMutations(map => {
|
const activeTokens: List<Token> = tokens.withMutations((map) => {
|
||||||
map.forEach((token: Token) => {
|
map.forEach((token: Token) => {
|
||||||
if (!activeTokenAddresses.has(token.address)) {
|
if (!activeTokenAddresses.has(token.address)) {
|
||||||
map.remove(token.address)
|
map.remove(token.address)
|
||||||
@ -65,7 +65,7 @@ const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => asyn
|
|||||||
const { safe } = action.payload
|
const { safe } = action.payload
|
||||||
const ownersArray = safe.owners.toJS()
|
const ownersArray = safe.owners.toJS()
|
||||||
// Adds the owners to the address book
|
// Adds the owners to the address book
|
||||||
ownersArray.forEach(owner => {
|
ownersArray.forEach((owner) => {
|
||||||
dispatch(addAddressBookEntry(makeAddressBookEntry({ ...owner, isOwner: true })))
|
dispatch(addAddressBookEntry(makeAddressBookEntry({ ...owner, isOwner: true })))
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
@ -39,7 +39,7 @@ export const withTracker = (WrappedComponent, options = {}) => {
|
|||||||
fetchCookiesFromStorage()
|
fetchCookiesFromStorage()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const trackPage = page => {
|
const trackPage = (page) => {
|
||||||
if (!useAnalytics || !analyticsLoaded) {
|
if (!useAnalytics || !analyticsLoaded) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
// @flow
|
// @flow
|
||||||
export const sleep: Function = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
|
export const sleep: Function = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user