Merge pull request #97 from gnosis/83-tokens

83-Tokens progress: Internal refactorings
This commit is contained in:
Mikhail Mikheev 2019-04-08 11:00:25 +04:00 committed by GitHub
commit 5d05861856
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2351 additions and 34538 deletions

32863
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,7 @@
},
"dependencies": {
"@gnosis.pm/util-contracts": "^2.0.0",
"@material-ui/core": "^3.0.1",
"@material-ui/core": "^3.9.3",
"@material-ui/icons": "^3.0.1",
"axios": "^0.18.0",
"bignumber.js": "^8.1.1",
@ -80,7 +80,7 @@
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-final-form": "^4.1.0",
"react-hot-loader": "^4.8.0",
"react-hot-loader": "^4.8.2",
"react-infinite-scroll-component": "^4.5.2",
"react-redux": "^6.0.1",
"react-router-dom": "^4.3.1",
@ -117,10 +117,10 @@
"@babel/preset-flow": "^7.0.0-beta.40",
"@babel/preset-react": "^7.0.0-beta.40",
"@sambego/storybook-state": "^1.0.7",
"@storybook/addon-actions": "^5.0.5",
"@storybook/addon-knobs": "^5.0.5",
"@storybook/addon-links": "^5.0.5",
"@storybook/react": "^5.0.5",
"@storybook/addon-actions": "^5.0.6",
"@storybook/addon-knobs": "^5.0.6",
"@storybook/addon-links": "^5.0.6",
"@storybook/react": "^5.0.6",
"autoprefixer": "^9.4.10",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
@ -132,7 +132,7 @@
"classnames": "^2.2.5",
"css-loader": "^2.1.0",
"detect-port": "^1.2.2",
"eslint": "^5.15.3",
"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-flowtype": "^3.4.2",
"eslint-plugin-import": "^2.9.0",
@ -142,7 +142,7 @@
"ethereumjs-abi": "^0.6.7",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^3.0.1",
"flow-bin": "^0.95.1",
"flow-bin": "0.96.0",
"fs-extra": "^7.0.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.4",
@ -158,9 +158,9 @@
"storybook-host": "^5.0.3",
"storybook-router": "^0.3.3",
"style-loader": "^0.23.1",
"truffle": "^5.0.9",
"truffle-contract": "^4.0.10",
"truffle-solidity-loader": "^0.1.9",
"truffle": "^5.0.10",
"truffle-contract": "^4.0.11",
"truffle-solidity-loader": "^0.1.10",
"uglifyjs-webpack-plugin": "^2.1.2",
"webpack": "^4.1.1",
"webpack-bundle-analyzer": "^3.1.0",

View File

@ -5,8 +5,6 @@ import { List } from 'immutable'
import Row from '~/components/layout/Row'
import Table from '@material-ui/core/Table'
import TableBody from '@material-ui/core/TableBody'
import TableRow from '@material-ui/core/TableRow'
import TableCell from '@material-ui/core/TableCell'
import { withStyles } from '@material-ui/core/styles'
import CircularProgress from '@material-ui/core/CircularProgress'
import TablePagination from '@material-ui/core/TablePagination'
@ -136,14 +134,7 @@ class GnoTable<K> extends React.Component<Props<K>, State> {
{!isEmpty && (
<Table aria-labelledby={label} className={classes.root}>
<TableHead columns={columns} order={order} orderBy={orderByParam} onSort={this.onSort} />
<TableBody>
{children(sortedData)}
{emptyRows > 0 && (
<TableRow style={this.getEmptyStyle(emptyRows)}>
<TableCell colSpan={4} />
</TableRow>
)}
</TableBody>
<TableBody>{children(sortedData)}</TableBody>
</Table>
)}
{isEmpty && (

View File

@ -4,5 +4,9 @@ import 'babel-polyfill'
import React from 'react'
import ReactDOM from 'react-dom'
import Root from '~/components/Root'
import { store } from '~/store'
import loadSafesFromStorage from '~/routes/safe/store/actions/loadSafesFromStorage'
store.dispatch(loadSafesFromStorage())
ReactDOM.render(<Root />, document.getElementById('root'))

View File

@ -5,7 +5,7 @@ import { type Operation, submitOperation } from '~/logic/safe/safeTxHistory'
import { getSafeEthereumInstance } from '~/logic/safe/safeFrontendOperations'
import { buildSignaturesFrom } from '~/logic/safe/safeTxSigner'
import { generateMetamaskSignature, generateTxGasEstimateFrom, estimateDataGas } from '~/logic/safe/safeTxSignerEIP712'
import { storeSignature, getSignaturesFrom } from '~/utils/localStorage/signatures'
import { storeSignature, getSignaturesFrom } from '~/utils/storage/signatures'
import { signaturesViaMetamask } from '~/config'
export const approveTransaction = async (

View File

@ -6,7 +6,7 @@ import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Safe } from '~/routes/safe/store/model/safe'
import { getGnosisSafeContract } from '~/logic/contracts/safeContracts'
import { storeSubject } from '~/utils/localStorage/transactions'
import { storeSubject } from '~/utils/storage/transactions'
export const TX_NAME_PARAM = 'txName'
export const TX_DESTINATION_PARAM = 'txDestination'

View File

@ -2,7 +2,7 @@
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { BigNumber } from 'bignumber.js'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getSignaturesFrom } from '~/utils/localStorage/signatures'
import { getSignaturesFrom } from '~/utils/storage/signatures'
const estimateDataGasCosts = (data) => {
const reducer = (accumulator, currentValue) => {

View File

@ -0,0 +1,3 @@
// @flow
export * from './safeStorage'

View File

@ -0,0 +1,43 @@
// @flow
import { type Owner } from '~/routes/safe/store/model/owner'
import { List, Map } from 'immutable'
import { loadFromStorage, saveToStorage } from '~/utils/storage'
export const SAFES_KEY = 'SAFES'
export const TX_KEY = 'TX'
export const OWNERS_KEY = 'OWNERS'
export const getSafeName = async (safeAddress: string) => {
const safes = await loadFromStorage(SAFES_KEY)
if (!safes) {
return undefined
}
const safe = safes[safeAddress]
return safe ? safe.name : undefined
}
export const saveSafes = async (safes: Object) => {
try {
await saveToStorage(SAFES_KEY, safes)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing safe info in localstorage')
}
}
export const setOwners = async (safeAddress: string, owners: List<Owner>) => {
try {
const ownersAsMap = Map(owners.map((owner: Owner) => [owner.get('address').toLowerCase(), owner.get('name')]))
await saveToStorage(`${OWNERS_KEY}-${safeAddress}`, ownersAsMap)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing owners in localstorage')
}
}
export const getOwners = async (safeAddress: string): Map<string, string> => {
const data: Object = await loadFromStorage(`${OWNERS_KEY}-${safeAddress}`)
return data ? Map(data) : Map()
}

View File

@ -1,7 +1,7 @@
// @flow
import { List } from 'immutable'
import { ImmortalDB } from 'immortal-db'
import { type Token, type TokenProps } from '~/logic/tokens/store/model/token'
import { loadFromStorage, saveToStorage } from '~/utils/storage'
export const ACTIVE_TOKENS_KEY = 'ACTIVE_TOKENS'
export const TOKENS_KEY = 'TOKENS'
@ -11,9 +11,8 @@ const getTokensKey = (safeAddress: string) => `${TOKENS_KEY}-${safeAddress}`
export const setActiveTokens = async (safeAddress: string, tokens: List<TokenProps>) => {
try {
const serializedState = JSON.stringify(tokens.toJS())
const key = getActiveTokensKey(safeAddress)
await ImmortalDB.set(key, serializedState)
await saveToStorage(key, tokens.toJS())
} catch (err) {
// eslint-disable-next-line
console.log('Error storing tokens in localstorage')
@ -22,25 +21,24 @@ export const setActiveTokens = async (safeAddress: string, tokens: List<TokenPro
export const getActiveTokens = async (safeAddress: string): Promise<List<TokenProps>> => {
const key = getActiveTokensKey(safeAddress)
const data = await ImmortalDB.get(key)
const data = await loadFromStorage(key)
return data ? List(JSON.parse(data)) : List()
return data ? List(data) : List()
}
export const getTokens = async (safeAddress: string): Promise<List<TokenProps>> => {
const key = getTokensKey(safeAddress)
const data = await ImmortalDB.get(key)
const data = await loadFromStorage(key)
return data ? List(JSON.parse(data)) : List()
return data ? List(data) : List()
}
export const setToken = async (safeAddress: string, token: Token) => {
const data: List<TokenProps> = await getTokens(safeAddress)
try {
const serializedState = JSON.stringify(data.push(token))
const key = getTokensKey(safeAddress)
await ImmortalDB.set(key, serializedState)
await saveToStorage(key, data.push(token))
} catch (err) {
// eslint-disable-next-line
console.log('Error adding token in localstorage')
@ -52,9 +50,8 @@ export const removeTokenFromStorage = async (safeAddress: string, token: Token)
try {
const index = data.indexOf(token)
const serializedState = JSON.stringify(data.remove(index))
const key = getTokensKey(safeAddress)
await ImmortalDB.set(key, serializedState)
await saveToStorage(key, data.remove(index))
} catch (err) {
// eslint-disable-next-line
console.log('Error removing token in localstorage')

View File

@ -3,7 +3,8 @@ import * as React from 'react'
import { connect } from 'react-redux'
import Page from '~/components/layout/Page'
import { buildSafe } from '~/routes/safe/store/actions/fetchSafe'
import { SAFES_KEY, load, saveSafes } from '~/utils/localStorage'
import { SAFES_KEY, saveSafes } from '~/logic/safe/utils'
import { loadFromStorage } from '~/utils/storage'
import { SAFELIST_ADDRESS } from '~/routes/routes'
import { history } from '~/store'
import selector, { type SelectorProps } from './selector'
@ -18,7 +19,7 @@ export const loadSafe = async (safeName: string, safeAddress: string, updateSafe
await updateSafe(safeRecord)
const storedSafes = load(SAFES_KEY) || {}
const storedSafes = await loadFromStorage(SAFES_KEY) || {}
storedSafes[safeAddress] = safeRecord.toJSON()
saveSafes(storedSafes)

View File

@ -5,7 +5,7 @@ import Stepper from '~/components/Stepper'
import { connect } from 'react-redux'
import { type Safe } from '~/routes/safe/store/model/safe'
import { type Owner, makeOwner } from '~/routes/safe/store/model/owner'
import { setOwners } from '~/utils/localStorage'
import { setOwners } from '~/utils/storage'
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
import AddOwnerForm, { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from './AddOwnerForm'
import Review from './Review'

View File

@ -1,8 +1,12 @@
// @flow
import { List } from 'immutable'
import { createAction } from 'redux-actions'
import { type SafeProps } from '~/routes/safe/store/model/safe'
import { type Safe, makeSafe } from '~/routes/safe/store/model/safe'
import { saveSafes, setOwners } from '~/logic/safe/utils'
import { makeOwner, type Owner } from '~/routes/safe/store/model/owner'
import type { Dispatch as ReduxDispatch, GetState } from 'redux'
import { type GlobalState } from '~/store/index'
import { safesMapSelector } from '~/routes/safeList/store/selectors/index'
export const ADD_SAFE = 'ADD_SAFE'
@ -12,18 +16,40 @@ export const buildOwnersFrom = (names: Array<string>, addresses: Array<string>)
return List(owners)
}
const addSafe = createAction(
ADD_SAFE,
(name: string, address: string, threshold: number, ownersName: string[], ownersAddress: string[]): SafeProps => {
const owners: List<Owner> = buildOwnersFrom(ownersName, ownersAddress)
type ActionReturn = {
safe: Safe,
}
return {
address,
name,
threshold,
owners,
}
},
export const addSafe = createAction<string, *, *>(
ADD_SAFE,
(safe: Safe): ActionReturn => ({
safe,
}),
)
export default addSafe
const saveSafe = (
name: string,
address: string,
threshold: number,
ownersName: string[],
ownersAddress: string[],
) => async (dispatch: ReduxDispatch<GlobalState>, getState: GetState<GlobalState>) => {
const owners: List<Owner> = buildOwnersFrom(ownersName, ownersAddress)
const state: GlobalState = getState()
const safe: Safe = makeSafe({
name,
address,
threshold,
owners,
})
const safes = safesMapSelector(state)
const newSafes = safes.set(address, safe)
setOwners(address, owners)
saveSafes(newSafes.toJSON())
dispatch(addSafe(safe))
}
export default saveSafe

View File

@ -3,4 +3,4 @@ import { createAction } from 'redux-actions'
export const ADD_TRANSACTIONS = 'ADD_TRANSACTIONS'
export default createAction(ADD_TRANSACTIONS)
export default createAction<string, *>(ADD_TRANSACTIONS)

View File

@ -5,7 +5,7 @@ import { type GlobalState } from '~/store/index'
import { makeOwner } from '~/routes/safe/store/model/owner'
import { type SafeProps, makeSafe } from '~/routes/safe/store/model/safe'
import updateSafe from '~/routes/safe/store/actions/updateSafe'
import { getOwners, getSafeName } from '~/utils/localStorage'
import { getOwners, getSafeName } from '~/logic/safe/utils'
import { getGnosisSafeContract } from '~/logic/contracts/safeContracts'
import { getWeb3 } from '~/logic/wallets/getWeb3'
@ -16,11 +16,11 @@ const buildOwnersFrom = (safeOwners: string[], storedOwners: Map<string, string>
export const buildSafe = async (safeAddress: string, safeName: string) => {
const web3 = getWeb3()
const GnosisSafe = await getGnosisSafeContract(web3)
const gnosisSafe = await GnosisSafe.at(safeAddress)
const SafeContract = await getGnosisSafeContract(web3)
const gnosisSafe = await SafeContract.at(safeAddress)
const threshold = Number(await gnosisSafe.getThreshold())
const owners = List(buildOwnersFrom(await gnosisSafe.getOwners(), getOwners(safeAddress)))
const owners = List(buildOwnersFrom(await gnosisSafe.getOwners(), await getOwners(safeAddress)))
const safe: SafeProps = {
address: safeAddress,
@ -34,7 +34,7 @@ export const buildSafe = async (safeAddress: string, safeName: string) => {
export default (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const safeName = getSafeName(safeAddress) || 'LOADED SAFE'
const safeName = await getSafeName(safeAddress) || 'LOADED SAFE'
const safeRecord = await buildSafe(safeAddress, safeName)
return dispatch(updateSafe(safeRecord))

View File

@ -6,9 +6,9 @@ import { type GlobalState } from '~/store/index'
import { makeOwner } from '~/routes/safe/store/model/owner'
import { makeTransaction, type Transaction } from '~/routes/safe/store/model/transaction'
import { makeConfirmation } from '~/routes/safe/store/model/confirmation'
import { loadSafeSubjects } from '~/utils/localStorage/transactions'
import { loadSafeSubjects } from '~/utils/storage/transactions'
import { buildTxServiceUrlFrom, type TxServiceType } from '~/logic/safe/safeTxHistory'
import { getOwners } from '~/utils/localStorage'
import { getOwners } from '~/logic/safe/utils'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import addTransactions from './addTransactions'

View File

@ -0,0 +1,25 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { SAFES_KEY } from '~/logic/safe/utils'
import { type SafeProps } from '~/routes/safe/store/model/safe'
import { loadFromStorage } from '~/utils/storage'
import { addSafe } from './addSafe'
import { buildSafe } from '~/routes/safe/store/reducer/safe'
export default () => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const safes: ?{ [string]: SafeProps } = await loadFromStorage(SAFES_KEY)
if (safes) {
Object.values(safes).forEach((safeProps: SafeProps) => {
dispatch(addSafe(buildSafe(safeProps)))
})
}
} catch (err) {
// eslint-disable-next-line
console.error('Error while getting safes from storage:', err)
}
return Promise.resolve()
}

View File

@ -3,6 +3,6 @@ import { createAction } from 'redux-actions'
export const UPDATE_SAFE = 'UPDATE_SAFE'
const updateSafe = createAction(UPDATE_SAFE)
const updateSafe = createAction<string, *>(UPDATE_SAFE)
export default updateSafe

View File

@ -3,6 +3,6 @@ import { createAction } from 'redux-actions'
export const UPDATE_SAFES = 'UPDATE_SAFES'
const updateSafesInBatch = createAction(UPDATE_SAFES)
const updateSafesInBatch = createAction<string, *>(UPDATE_SAFES)
export default updateSafesInBatch

View File

@ -1,13 +1,12 @@
// @flow
import { Map } from 'immutable'
import { handleActions, type ActionType } from 'redux-actions'
import addSafe, { ADD_SAFE, buildOwnersFrom } from '~/routes/safe/store/actions/addSafe'
import { ADD_SAFE, buildOwnersFrom } from '~/routes/safe/store/actions/addSafe'
import { type Safe, type SafeProps, makeSafe } from '~/routes/safe/store/model/safe'
import { type OwnerProps } from '~/routes/safe/store/model/owner'
import {
saveSafes, setOwners, load, SAFES_KEY,
} from '~/utils/localStorage'
import updateSafe, { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
import { loadFromStorage } from '~/utils/storage'
import { SAFES_KEY } from '~/logic/safe/utils'
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
export const SAFE_REDUCER_ID = 'safes'
@ -46,8 +45,8 @@ const buildSafesFrom = (loadedSafes: Object): Map<string, Safe> => {
}
}
export const safesInitialState = (): State => {
const storedSafes = load(SAFES_KEY)
export const safesInitialState = async (): Promise<State> => {
const storedSafes = await loadFromStorage(SAFES_KEY)
const safes = storedSafes ? buildSafesFrom(storedSafes) : Map()
return safes
@ -55,7 +54,7 @@ export const safesInitialState = (): State => {
export default handleActions<State, *>(
{
[UPDATE_SAFE]: (state: State, action: ActionType<typeof updateSafe>): State => {
[UPDATE_SAFE]: (state: State, action: ActionType<Function>): State => {
const safe = action.payload
const safeAddress = safe.get('address')
@ -66,14 +65,10 @@ export default handleActions<State, *>(
return state.set(safeAddress, safe)
},
[ADD_SAFE]: (state: State, action: ActionType<typeof addSafe>): State => {
const safe: Safe = makeSafe(action.payload)
setOwners(safe.get('address'), safe.get('owners'))
[ADD_SAFE]: (state: State, action: ActionType<Function>): State => {
const { safe }: { safe: Safe } = action.payload
const safes = state.set(action.payload.address, safe)
saveSafes(safes.toJSON())
return safes
return state.set(safe.address, safe)
},
},
Map(),

View File

@ -18,4 +18,4 @@ const SafeList = ({ safes, provider }: Props) => (
</Page>
)
export default connect(selector)(SafeList)
export default connect<*, *, *, *>(selector)(SafeList)

View File

@ -6,8 +6,9 @@ import { type Safe } from '~/routes/safe/store/model/safe'
import { userAccountSelector } from '~/logic/wallets/store/selectors'
import { type Owner } from '~/routes/safe/store/model/owner'
import { sameAddress } from '~/logic/wallets/ethAddresses'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
export const safesMapSelector = (state: GlobalState): Map<string, Safe> => state.safes
export const safesMapSelector = (state: GlobalState): Map<string, Safe> => state[SAFE_REDUCER_ID]
const safesListSelector: Selector<GlobalState, {}, List<Safe>> = createSelector(
safesMapSelector,

View File

@ -6,7 +6,7 @@ import {
} from 'redux'
import thunk from 'redux-thunk'
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/logic/wallets/store/reducer/provider'
import safe, { SAFE_REDUCER_ID, type State as SafeState, safesInitialState } from '~/routes/safe/store/reducer/safe'
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
import tokens, { TOKEN_REDUCER_ID, type State as TokensState } from '~/logic/tokens/store/reducer/tokens'
import transactions, {
type State as TransactionsState,
@ -36,10 +36,6 @@ const reducers: Reducer<GlobalState> = combineReducers({
[TRANSACTIONS_REDUCER_ID]: transactions,
})
const initialState = {
[SAFE_REDUCER_ID]: safesInitialState(),
}
export const store: Store<GlobalState> = createStore(reducers, initialState, finalCreateStore)
export const store: Store<GlobalState> = createStore(reducers, finalCreateStore)
export const aNewStore = (localState?: Object): Store<GlobalState> => createStore(reducers, localState, finalCreateStore)

View File

@ -9,7 +9,7 @@ import { safesMapSelector } from '~/routes/safeList/store/selectors'
import { makeOwner, type Owner } from '~/routes/safe/store/model/owner'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { safesInitialState } from '~/routes/safe/store/reducer/safe'
import { setOwners, OWNERS_KEY } from '~/utils/localStorage'
import { setOwners, OWNERS_KEY } from '~/utils/storage'
describe('Safe - redux load safe', () => {
let store
@ -40,7 +40,7 @@ describe('Safe - redux load safe', () => {
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'UNKNOWN', address: accounts[0] })]))
expect(safesInitialState()).toEqual(safes)
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is not present but owners, store and persist it with stored names', async () => {
@ -64,7 +64,7 @@ describe('Safe - redux load safe', () => {
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: ownerName, address: accounts[0] })]))
expect(safesInitialState()).toEqual(safes)
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is present but no owners, store and persist it with default names', async () => {
@ -86,7 +86,7 @@ describe('Safe - redux load safe', () => {
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'UNKNOWN', address: accounts[0] })]))
expect(safesInitialState()).toEqual(safes)
expect(await safesInitialState()).toEqual(safes)
})
it('if safe is present but owners, store and persist it with stored names', async () => {
@ -107,6 +107,6 @@ describe('Safe - redux load safe', () => {
expect(safe.get('address')).toBe(safeAddress)
expect(safe.get('owners')).toEqual(List([makeOwner({ name: 'Adol 1 Eth Account', address: accounts[0] })]))
expect(safesInitialState()).toEqual(safes)
expect(await safesInitialState()).toEqual(safes)
})
})

View File

@ -1,61 +0,0 @@
// @flow
import { List, Map } from 'immutable'
import { type Owner } from '~/routes/safe/store/model/owner'
export const SAFES_KEY = 'SAFES'
export const TX_KEY = 'TX'
export const OWNERS_KEY = 'OWNERS'
export const load = (key: string) => {
try {
const serializedState = localStorage.getItem(key)
if (serializedState === null) {
return undefined
}
if (serializedState === undefined) {
return undefined
}
return JSON.parse(serializedState)
} catch (err) {
return undefined
}
}
export const getSafeName = (safeAddress: string) => {
const safes = load(SAFES_KEY)
if (!safes) {
return undefined
}
const safe = safes[safeAddress]
return safe ? safe.name : undefined
}
export const saveSafes = (safes: Object) => {
try {
const serializedState = JSON.stringify(safes)
localStorage.setItem(SAFES_KEY, serializedState)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing safe info in localstorage')
}
}
export const setOwners = (safeAddress: string, owners: List<Owner>) => {
try {
const ownersAsMap = Map(owners.map((owner: Owner) => [owner.get('address').toLowerCase(), owner.get('name')]))
const serializedState = JSON.stringify(ownersAsMap)
localStorage.setItem(`${OWNERS_KEY}-${safeAddress}`, serializedState)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing owners in localstorage')
}
}
export const getOwners = (safeAddress: string): Map<string, string> => {
const data = load(`${OWNERS_KEY}-${safeAddress}`)
return data ? Map(data) : Map()
}

View File

@ -0,0 +1,32 @@
// @flow
import {
ImmortalStorage, CookieStore, IndexedDbStore, LocalStorageStore, SessionStorageStore,
} from 'immortal-db'
const stores = [CookieStore, IndexedDbStore, LocalStorageStore, SessionStorageStore]
export const storage = new ImmortalStorage(stores)
const PREFIX = 'v1'
export const loadFromStorage = async (key: string): Promise<*> => {
try {
const stringifiedValue = await storage.get(`${PREFIX}__${key}`)
if (stringifiedValue === null || stringifiedValue === undefined) {
return undefined
}
return JSON.parse(stringifiedValue)
} catch (err) {
console.error(`Failed to load ${key} from storage:`, err)
return undefined
}
}
export const saveToStorage = async (key: string, value: *): Promise<*> => {
try {
const stringifiedValue = JSON.stringify(value)
await storage.set(`${PREFIX}__${key}`, stringifiedValue)
} catch (err) {
console.error(`Failed to save ${key} in the storage:`, err)
}
}

View File

@ -1,20 +1,19 @@
// @flow
import { Map } from 'immutable'
import { load } from '~/utils/localStorage'
import { loadFromStorage, saveToStorage } from '~/utils/storage'
const getSignaturesKeyFrom = (safeAddress: string) => `TXS-SIGNATURES-${safeAddress}`
export const storeSignature = (safeAddress: string, nonce: number, signature: string) => {
export const storeSignature = async (safeAddress: string, nonce: number, signature: string) => {
const signaturesKey = getSignaturesKeyFrom(safeAddress)
const subjects = Map(load(signaturesKey)) || Map()
const subjects = Map(await loadFromStorage(signaturesKey)) || Map()
try {
const key = `${nonce}`
const existingSignatures = subjects.get(key)
const signatures = existingSignatures ? existingSignatures + signature : signature
const updatedSubjects = subjects.set(key, signatures)
const serializedState = JSON.stringify(updatedSubjects)
localStorage.setItem(signaturesKey, serializedState)
await saveToStorage(signaturesKey, updatedSubjects)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing signatures in localstorage')
@ -23,7 +22,7 @@ export const storeSignature = (safeAddress: string, nonce: number, signature: st
export const getSignaturesFrom = (safeAddress: string, nonce: number) => {
const key = getSignaturesKeyFrom(safeAddress)
const data: any = load(key)
const data: any = loadFromStorage(key)
const signatures = data ? Map(data) : Map()
const txSigs = signatures.get(String(nonce)) || ''

View File

@ -1,17 +1,16 @@
// @flow
import { Map } from 'immutable'
import { load } from '~/utils/localStorage'
import { loadFromStorage, saveToStorage } from '~/utils/storage'
const getSubjectKeyFrom = (safeAddress: string) => `TXS-SUBJECTS-${safeAddress}`
export const storeSubject = (safeAddress: string, nonce: number, subject: string) => {
export const storeSubject = async (safeAddress: string, nonce: number, subject: string) => {
const key = getSubjectKeyFrom(safeAddress)
const subjects = Map(load(key)) || Map()
const subjects = Map(await loadFromStorage(key)) || Map()
try {
const updatedSubjects = subjects.set(nonce, subject)
const serializedState = JSON.stringify(updatedSubjects)
localStorage.setItem(key, serializedState)
saveToStorage(key, updatedSubjects)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing transaction subject in localstorage')
@ -20,7 +19,7 @@ export const storeSubject = (safeAddress: string, nonce: number, subject: string
export const loadSafeSubjects = (safeAddress: string): Map<string, string> => {
const key = getSubjectKeyFrom(safeAddress)
const data: any = load(key)
const data: any = loadFromStorage(key)
return data ? Map(data) : Map()
}

3651
yarn.lock

File diff suppressed because it is too large Load Diff