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:
Mikhail Mikheev 2020-03-31 18:16:29 +04:00 committed by GitHub
parent fad5e10c2e
commit 31a1565637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 175 additions and 169 deletions

View File

@ -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}

View File

@ -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>

View File

@ -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}

View File

@ -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)

View File

@ -1,11 +1,11 @@
/* eslint-disable */ /* eslint-disable */
;(function(global, factory) { ;(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' typeof exports === 'object' && typeof module !== 'undefined'
? factory(exports) ? factory(exports)
: typeof define === 'function' && define.amd : typeof define === 'function' && define.amd
? define(['exports'], factory) ? define(['exports'], factory)
: factory((global.blockies = {})) : factory((global.blockies = {}))
})(this, function(exports) { })(this, function (exports) {
'use strict' 'use strict'
/** /**
@ -40,7 +40,7 @@
return String.fromCharCode(w & 255, (w >> 8) & 255) return String.fromCharCode(w & 255, (w >> 8) & 255)
} }
var PNG = function(width, height, depth) { var PNG = function (width, height, depth) {
this.width = width this.width = width
this.height = height this.height = height
this.depth = depth this.depth = depth
@ -115,14 +115,14 @@
} }
// compute the index into a png for a given pixel // compute the index into a png for a given pixel
this.index = function(x, y) { this.index = function (x, y) {
var i = y * (this.width + 1) + x + 1 var i = y * (this.width + 1) + x + 1
var j = this.idat_offs + 8 + 2 + 5 * Math.floor(i / 0xffff + 1) + i var j = this.idat_offs + 8 + 2 + 5 * Math.floor(i / 0xffff + 1) + i
return j return j
} }
// convert a color and build up the palette // convert a color and build up the palette
this.color = function(red, green, blue, alpha) { this.color = function (red, green, blue, alpha) {
alpha = alpha >= 0 ? alpha : 255 alpha = alpha >= 0 ? alpha : 255
var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue
@ -142,7 +142,7 @@
} }
// output a PNG string, Base64 encoded // output a PNG string, Base64 encoded
this.getBase64 = function() { this.getBase64 = function () {
var s = this.getDump() var s = this.getDump()
var ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' var ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
@ -173,7 +173,7 @@
} }
// output a PNG string // output a PNG string
this.getDump = function() { this.getDump = function () {
// compute adler32 of output pixels + row filter bytes // compute adler32 of output pixels + row filter bytes
var BASE = 65521 /* largest prime smaller than 65536 */ var BASE = 65521 /* largest prime smaller than 65536 */
var NMAX = 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ var NMAX = 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
@ -215,7 +215,7 @@
return '\x89PNG\r\n\x1A\n' + this.buffer.join('') return '\x89PNG\r\n\x1A\n' + this.buffer.join('')
} }
this.fillRect = function(x, y, w, h, color) { this.fillRect = function (x, y, w, h, color) {
for (var i = 0; i < w; i++) { for (var i = 0; i < w; i++) {
for (var j = 0; j < h; j++) { for (var j = 0; j < h; j++) {
this.buffer[this.index(x + i, y + j)] = color this.buffer[this.index(x + i, y + j)] = color

View File

@ -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]
} }

View File

@ -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}

View File

@ -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()

View File

@ -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),

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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,

View File

@ -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) {

View File

@ -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))

View File

@ -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
} }

View File

@ -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,

View File

@ -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,

View File

@ -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],
) )

View File

@ -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>

View File

@ -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))
}) })

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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'

View File

@ -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) => {

View File

@ -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)

View File

@ -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)
}) })
}) })

View File

@ -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))

View File

@ -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))

View File

@ -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) {

View File

@ -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={

View File

@ -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={

View File

@ -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
} }

View File

@ -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> => {

View File

@ -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 {

View File

@ -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)
} }

View File

@ -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)
} }

View File

@ -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)

View File

@ -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,

View File

@ -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)
} }

View File

@ -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),

View File

@ -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',

View File

@ -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)
} }

View File

@ -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}>

View File

@ -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

View File

@ -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} />

View File

@ -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 (

View File

@ -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)
} }

View File

@ -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} />

View File

@ -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)
} }

View File

@ -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)

View File

@ -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
} }

View File

@ -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}

View File

@ -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,
})) }))

View File

@ -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 (
<> <>

View File

@ -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}>

View File

@ -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)
} }

View File

@ -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 }))

View File

@ -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)

View File

@ -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)
} }

View File

@ -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}>

View File

@ -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

View File

@ -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)

View File

@ -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 (
<> <>

View File

@ -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}>

View File

@ -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)

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -69,7 +69,7 @@ class Settings extends React.Component<Props, State> {
} }
} }
handleChange = menuOptionIndex => () => { handleChange = (menuOptionIndex) => () => {
this.setState({ menuOptionIndex }) this.setState({ menuOptionIndex })
} }

View File

@ -114,7 +114,7 @@ const ApproveTxModal = ({
} }
}, [approveAndExecute]) }, [approveAndExecute])
const handleExecuteCheckbox = () => setApproveAndExecute(prevApproveAndExecute => !prevApproveAndExecute) const handleExecuteCheckbox = () => setApproveAndExecute((prevApproveAndExecute) => !prevApproveAndExecute)
const approveTx = () => { const approveTx = () => {
processTransaction({ processTransaction({

View File

@ -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}

View File

@ -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
}) })

View File

@ -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

View File

@ -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)

View File

@ -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 })

View File

@ -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)))
}) })
} }

View File

@ -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 })

View File

@ -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

View File

@ -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
} }

View File

@ -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))