#359: Remove separate entry for owners in localStorage (#392)

* Wip

* fetchTransactions fix

* fix p > div > p nesting, fix displaying undefined as currency

* fix duplicate import
This commit is contained in:
Mikhail Mikheev 2020-01-09 11:04:41 +04:00 committed by GitHub
parent 9b32cc9dc1
commit f1d1b78531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 75 additions and 114 deletions

View File

@ -2,7 +2,7 @@
import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import Block from '~/components/layout/Block'
import Paragraph from '~/components/layout/Paragraph'
import Span from '~/components/layout/Span'
import CopyBtn from '~/components/CopyBtn'
import EtherscanBtn from '~/components/EtherscanBtn'
import { shortVersionOf } from '~/logic/wallets/ethAddresses'
@ -19,9 +19,9 @@ const EtherscanLink = ({
type, value, cut, classes,
}: EtherscanLinkProps) => (
<Block className={classes.etherscanLink}>
<Paragraph size="md" noMargin>
<Span size="md">
{cut ? shortVersionOf(value, cut) : value}
</Paragraph>
</Span>
<CopyBtn content={value} />
<EtherscanBtn type={type} value={value} />
</Block>

View File

@ -1,11 +1,8 @@
// @flow
import { List, Map } from 'immutable'
import { type Owner } from '~/routes/safe/store/models/owner'
import { loadFromStorage, saveToStorage, removeFromStorage } from '~/utils/storage'
import { loadFromStorage, saveToStorage } from '~/utils/storage'
export const SAFES_KEY = 'SAFES'
export const TX_KEY = 'TX'
export const OWNERS_KEY = 'OWNERS'
export const DEFAULT_SAFE_KEY = 'DEFAULT_SAFE'
export const getSafeName = async (safeAddress: string) => {
@ -26,19 +23,9 @@ export const saveSafes = async (safes: Object) => {
}
}
export const setOwners = async (safeAddress: string, owners: List<Owner>) => {
try {
const ownersAsMap = Map(owners.map((owner: Owner) => [owner.address.toLowerCase(), owner.name]))
await saveToStorage(`${OWNERS_KEY}-${safeAddress}`, ownersAsMap)
} catch (err) {
console.error('Error storing owners in localstorage', err)
}
}
export const getOwners = async (safeAddress: string): Promise<Map<string, string>> => {
const data: Object = await loadFromStorage(`${OWNERS_KEY}-${safeAddress}`)
return data ? Map(data) : Map()
export const getLocalSafe = async (safeAddress: string) => {
const storedSafes = (await loadFromStorage(SAFES_KEY)) || {}
return storedSafes[safeAddress]
}
export const getDefaultSafe = async (): Promise<string> => {
@ -55,12 +42,3 @@ export const saveDefaultSafe = async (safeAddress: string): Promise<void> => {
console.error('Error saving default Safe to storage: ', err)
}
}
export const removeOwners = async (safeAddress: string): Promise<void> => {
try {
await removeFromStorage(`${OWNERS_KEY}-${safeAddress}`)
} catch (err) {
// eslint-disable-next-line
console.error('Error removing owners from localstorage: ', err)
}
}

View File

@ -29,6 +29,10 @@ const getTokenPriceInCurrency = (
currencySelected: typeof AVAILABLE_CURRENCIES,
currencyValues: List<BalanceCurrencyType>,
): string => {
if (!currencySelected) {
return ''
}
// eslint-disable-next-line no-restricted-syntax
for (const tokenPriceIterator of currencyValues) {
const {
@ -115,6 +119,7 @@ export const generateColumns = () => {
label: 'Value',
custom: false,
static: true,
disablePadding: false,
style: {
fontSize: '11px',
color: '#5d6d74',

View File

@ -4,7 +4,6 @@ import { makeStyles } from '@material-ui/core/styles'
import type { IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
import Bold from '~/components/layout/Bold'
import EtherscanLink from '~/components/EtherscanLink'
import Paragraph from '~/components/layout/Paragraph'
import Block from '~/components/layout/Block'
import { md, lg } from '~/theme/variables'
import { getIncomingTxAmount } from '~/routes/safe/components/Transactions/TxsTable/columns'
@ -28,7 +27,7 @@ type TransferDescProps = {
}
const TransferDescription = ({ value = '', from }: TransferDescProps) => (
<Paragraph noMargin data-testid={TRANSACTIONS_DESC_INCOMING_TEST_ID}>
<Block data-testid={TRANSACTIONS_DESC_INCOMING_TEST_ID}>
<Bold>
Received
{' '}
@ -38,7 +37,7 @@ const TransferDescription = ({ value = '', from }: TransferDescProps) => (
</Bold>
<br />
<EtherscanLink type="address" value={from} />
</Paragraph>
</Block>
)
const IncomingTxDescription = ({ tx }: Props) => {

View File

@ -1,25 +1,35 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
import { List, Map } from 'immutable'
import { List } from 'immutable'
import { type GlobalState } from '~/store/index'
import { makeOwner } from '~/routes/safe/store/models/owner'
import type { SafeProps } from '~/routes/safe/store/models/safe'
import addSafe from '~/routes/safe/store/actions/addSafe'
import { getOwners, getSafeName, SAFES_KEY } from '~/logic/safe/utils'
import { getSafeName, getLocalSafe } from '~/logic/safe/utils'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import { getBalanceInEtherOf } from '~/logic/wallets/getWeb3'
import { loadFromStorage } from '~/utils/storage'
import { sameAddress } from '~/logic/wallets/ethAddresses'
import removeSafeOwner from '~/routes/safe/store/actions/removeSafeOwner'
import addSafeOwner from '~/routes/safe/store/actions/addSafeOwner'
import updateSafeThreshold from '~/routes/safe/store/actions/updateSafeThreshold'
import { sameAddress } from '~/logic/wallets/ethAddresses'
const buildOwnersFrom = (
safeOwners: string[],
storedOwners: Map<string, string>, // eslint-disable-next-line
localSafe: SafeProps | {}, // eslint-disable-next-line
) => safeOwners.map((ownerAddress: string) => {
const ownerName = storedOwners.get(ownerAddress.toLowerCase()) || 'UNKNOWN'
return makeOwner({ name: ownerName, address: ownerAddress })
if (!localSafe) {
return makeOwner({ name: 'UNKNOWN', address: ownerAddress })
}
const storedOwner = localSafe.owners.find(({ address }) => sameAddress(address, ownerAddress))
if (!storedOwner) {
return makeOwner({ name: 'UNKNOWN', address: ownerAddress })
}
return makeOwner({
name: storedOwner.name || 'UNKNOWN',
address: ownerAddress,
})
})
export const buildSafe = async (safeAddress: string, safeName: string) => {
@ -28,7 +38,12 @@ export const buildSafe = async (safeAddress: string, safeName: string) => {
const threshold = Number(await gnosisSafe.getThreshold())
const nonce = Number(await gnosisSafe.nonce())
const owners = List(buildOwnersFrom(await gnosisSafe.getOwners(), await getOwners(safeAddress)))
const owners = List(
buildOwnersFrom(
await gnosisSafe.getOwners(),
await getLocalSafe(safeAddress),
),
)
const safe: SafeProps = {
address: safeAddress,
@ -42,14 +57,14 @@ export const buildSafe = async (safeAddress: string, safeName: string) => {
return safe
}
const getLocalSafe = async (safeAddress: string) => {
const storedSafes = (await loadFromStorage(SAFES_KEY)) || {}
return storedSafes[safeAddress]
}
export const checkAndUpdateSafe = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
export const checkAndUpdateSafe = (safeAddress: string) => async (
dispatch: ReduxDispatch<*>,
) => {
// Check if the owner's safe did change and update them
const [gnosisSafe, localSafe] = await Promise.all([getGnosisSafeInstanceAt(safeAddress), getLocalSafe(safeAddress)])
const [gnosisSafe, localSafe] = await Promise.all([
getGnosisSafeInstanceAt(safeAddress),
getLocalSafe(safeAddress),
])
const remoteOwners = await gnosisSafe.getOwners()
// Converts from [ { address, ownerName} ] to address array
@ -59,8 +74,9 @@ export const checkAndUpdateSafe = (safeAddress: string) => async (dispatch: Redu
const threshold = await gnosisSafe.getThreshold()
localSafe.threshold = threshold.toNumber()
dispatch(updateSafeThreshold({ safeAddress, threshold: threshold.toNumber() }))
dispatch(
updateSafeThreshold({ safeAddress, threshold: threshold.toNumber() }),
)
// If the remote owners does not contain a local address, we remove that local owner
localOwners.forEach((localAddress) => {
const remoteOwnerIndex = remoteOwners.findIndex((remoteAddress) => sameAddress(remoteAddress, localAddress))
@ -73,13 +89,21 @@ export const checkAndUpdateSafe = (safeAddress: string) => async (dispatch: Redu
remoteOwners.forEach((remoteAddress) => {
const localOwnerIndex = localOwners.findIndex((localAddress) => sameAddress(remoteAddress, localAddress))
if (localOwnerIndex === -1) {
dispatch(addSafeOwner({ safeAddress, ownerAddress: remoteAddress, ownerName: 'UNKNOWN' }))
dispatch(
addSafeOwner({
safeAddress,
ownerAddress: remoteAddress,
ownerName: 'UNKNOWN',
}),
)
}
})
}
// eslint-disable-next-line consistent-return
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
export default (safeAddress: string) => async (
dispatch: ReduxDispatch<GlobalState>,
) => {
try {
const safeName = (await getSafeName(safeAddress)) || 'LOADED SAFE'
const safeProps: SafeProps = await buildSafe(safeAddress, safeName)
@ -87,7 +111,7 @@ export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalSta
dispatch(addSafe(safeProps))
} catch (err) {
// eslint-disable-next-line
console.error('Error while updating Safe information: ', err)
console.error("Error while updating Safe information: ", err)
return Promise.resolve()
}

View File

@ -3,23 +3,23 @@ import { List, Map } from 'immutable'
import axios from 'axios'
import bn from 'bignumber.js'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { type GlobalState } from '~/store'
import { makeOwner } from '~/routes/safe/store/models/owner'
import { makeTransaction, type Transaction } from '~/routes/safe/store/models/transaction'
import { makeIncomingTransaction, type IncomingTransaction } from '~/routes/safe/store/models/incomingTransaction'
import { makeConfirmation } from '~/routes/safe/store/models/confirmation'
import { buildTxServiceUrl, type TxServiceType } from '~/logic/safe/transactions/txHistory'
import { buildIncomingTxServiceUrl } from '~/logic/safe/transactions/incomingTxHistory'
import { getOwners } from '~/logic/safe/utils'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { sameAddress, ZERO_ADDRESS } from '~/logic/wallets/ethAddresses'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getLocalSafe } from '~/logic/safe/utils'
import { addTransactions } from './addTransactions'
import { addIncomingTransactions } from './addIncomingTransactions'
import { getHumanFriendlyToken } from '~/logic/tokens/store/actions/fetchTokens'
import { isTokenTransfer } from '~/logic/tokens/utils/tokenHelpers'
import { decodeParamsFromSafeMethod } from '~/logic/contracts/methodIds'
import { ALTERNATIVE_TOKEN_ABI } from '~/logic/tokens/utils/alternativeAbi'
import { ZERO_ADDRESS, sameAddress } from '~/logic/wallets/ethAddresses'
let web3
@ -64,10 +64,19 @@ export const buildTransactionFrom = async (
safeAddress: string,
tx: TxServiceModel,
) => {
const storedOwners = await getOwners(safeAddress)
const { owners } = await getLocalSafe(safeAddress)
const confirmations = List(
tx.confirmations.map((conf: ConfirmationServiceModel) => {
const ownerName = storedOwners.get(conf.owner.toLowerCase()) || 'UNKNOWN'
let ownerName = 'UNKNOWN'
if (owners) {
const storedOwner = owners.find((owner) => sameAddress(conf.owner, owner.address))
if (storedOwner) {
ownerName = storedOwner.name
}
}
return makeConfirmation({
owner: makeOwner({ address: conf.owner, name: ownerName }),

View File

@ -1,5 +1,5 @@
// @flow
import type { AnyAction, Store } from 'redux'
import type { Action, Store } from 'redux'
import { List } from 'immutable'
import { ADD_SAFE } from '~/routes/safe/store/actions/addSafe'
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
@ -10,15 +10,12 @@ import { REPLACE_SAFE_OWNER } from '~/routes/safe/store/actions/replaceSafeOwner
import { EDIT_SAFE_OWNER } from '~/routes/safe/store/actions/editSafeOwner'
import { type GlobalState } from '~/store/'
import {
removeOwners,
saveDefaultSafe,
saveSafes,
setOwners,
} from '~/logic/safe/utils'
import { getActiveTokensAddressesForAllSafes, safesMapSelector } from '~/routes/safe/store/selectors'
import { tokensSelector } from '~/logic/tokens/store/selectors'
import type { Token } from '~/logic/tokens/store/model/token'
import { makeOwner } from '~/routes/safe/store/models/owner'
import { saveActiveTokens } from '~/logic/tokens/utils/tokensStorage'
import { ACTIVATE_TOKEN_FOR_ALL_SAFES } from '~/routes/safe/store/actions/activateTokenForAllSafes'
import { SET_DEFAULT_SAFE } from '~/routes/safe/store/actions/setDefaultSafe'
@ -50,7 +47,7 @@ const recalculateActiveTokens = (state: GlobalState): void => {
saveActiveTokens(activeTokens)
}
const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => async (action: AnyAction) => {
const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => async (action: Action<*>) => {
const handledAction = next(action)
if (watchedActions.includes(action.type)) {
@ -63,64 +60,13 @@ const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => asyn
recalculateActiveTokens(state)
break
}
case ADD_SAFE: {
const { safe } = action.payload
setOwners(safe.address, safe.owners)
break
}
case UPDATE_SAFE: {
const { safeAddress, owners, activeTokens } = action.payload
if (safeAddress && owners) {
setOwners(safeAddress, owners)
}
const { activeTokens } = action.payload
if (activeTokens) {
recalculateActiveTokens(state)
}
break
}
case REMOVE_SAFE: {
const { safeAddress } = action.payload
await removeOwners(safeAddress)
break
}
case ADD_SAFE_OWNER: {
const { safeAddress, ownerAddress, ownerName } = action.payload
const { owners } = safes.get(safeAddress)
setOwners(safeAddress, owners.push(makeOwner({ address: ownerAddress, name: ownerName })))
break
}
case REMOVE_SAFE_OWNER: {
const { safeAddress, ownerAddress } = action.payload
const { owners } = safes.get(safeAddress)
setOwners(
safeAddress,
owners.filter((o) => o.address.toLowerCase() !== ownerAddress.toLowerCase()),
)
break
}
case REPLACE_SAFE_OWNER: {
const {
safeAddress, ownerAddress, ownerName, oldOwnerAddress,
} = action.payload
const { owners } = safes.get(safeAddress)
setOwners(
safeAddress,
owners
.filter((o) => o.address.toLowerCase() !== oldOwnerAddress.toLowerCase())
.push(makeOwner({ address: ownerAddress, name: ownerName })),
)
break
}
case EDIT_SAFE_OWNER: {
const { safeAddress, ownerAddress, ownerName } = action.payload
const { owners } = safes.get(safeAddress)
const ownerToUpdateIndex = owners.findIndex((o) => o.address.toLowerCase() === ownerAddress.toLowerCase())
setOwners(
safeAddress,
owners.update(ownerToUpdateIndex, (owner) => owner.set('name', ownerName)),
)
break
}
case SET_DEFAULT_SAFE: {
if (action.payload) {
saveDefaultSafe(action.payload)