Merge pull request #97 from gnosis/83-tokens
83-Tokens progress: Internal refactorings
This commit is contained in:
commit
5d05861856
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
|
@ -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",
|
||||
|
|
|
@ -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 && (
|
||||
|
|
|
@ -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'))
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * from './safeStorage'
|
|
@ -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()
|
||||
}
|
|
@ -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')
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -18,4 +18,4 @@ const SafeList = ({ safes, provider }: Props) => (
|
|||
</Page>
|
||||
)
|
||||
|
||||
export default connect(selector)(SafeList)
|
||||
export default connect<*, *, *, *>(selector)(SafeList)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)) || ''
|
|
@ -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()
|
||||
}
|
Loading…
Reference in New Issue