(Feature) Types for safe (#1274)

* Types

* Types

* Fix SetDefaultSafe return type

* Remove unused files

Co-authored-by: Daniel Sanchez <daniel.sanchez@gnosis.pm>
Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com>
This commit is contained in:
Agustin Pane 2020-08-27 07:10:02 -03:00 committed by GitHub
parent 5573383c48
commit 9fdfd7448c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 70 additions and 66 deletions

View File

@ -6,9 +6,13 @@ import { makeOwner } from 'src/logic/safe/store/models/owner'
import { safesListSelector } from 'src/logic/safe/store/selectors' import { safesListSelector } from 'src/logic/safe/store/selectors'
import { Dispatch } from 'redux'
import { AppReduxState } from 'src/store'
import { SafeOwner, SafeRecordProps } from 'src/logic/safe/store/models/safe'
export const ADD_SAFE = 'ADD_SAFE' export const ADD_SAFE = 'ADD_SAFE'
export const buildOwnersFrom = (names, addresses) => { export const buildOwnersFrom = (names: string[], addresses: string[]): List<SafeOwner> => {
const owners = names.map((name, index) => makeOwner({ name, address: addresses[index] })) const owners = names.map((name, index) => makeOwner({ name, address: addresses[index] }))
return List(owners) return List(owners)
@ -18,7 +22,7 @@ export const addSafe = createAction(ADD_SAFE, (safe) => ({
safe, safe,
})) }))
const saveSafe = (safe: any) => (dispatch, getState) => { const saveSafe = (safe: SafeRecordProps) => (dispatch: Dispatch, getState: () => AppReduxState): void => {
const state = getState() const state = getState()
const safeList = safesListSelector(state) const safeList = safesListSelector(state)

View File

@ -1,5 +1,5 @@
import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json' import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json'
import { List } from 'immutable' import { List, Set, Map } from 'immutable'
import generateBatchRequests from 'src/logic/contracts/generateBatchRequests' import generateBatchRequests from 'src/logic/contracts/generateBatchRequests'
import { getLocalSafe, getSafeName } from 'src/logic/safe/utils' import { getLocalSafe, getSafeName } from 'src/logic/safe/utils'
@ -13,16 +13,15 @@ import updateSafe from 'src/logic/safe/store/actions/updateSafe'
import { makeOwner } from 'src/logic/safe/store/models/owner' import { makeOwner } from 'src/logic/safe/store/models/owner'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { ModulePair, SafeOwner } from 'src/logic/safe/store/models/safe' import { ModulePair, SafeOwner, SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { Dispatch } from 'redux' import { Action, Dispatch } from 'redux'
import { SENTINEL_ADDRESS } from 'src/logic/contracts/safeContracts' import { SENTINEL_ADDRESS } from 'src/logic/contracts/safeContracts'
import { AppReduxState } from 'src/store'
const buildOwnersFrom = ( const buildOwnersFrom = (safeOwners: string[], localSafe: SafeRecordProps): List<SafeOwner> => {
safeOwners, const ownersList = safeOwners.map((ownerAddress) => {
localSafe, // eslint-disable-next-line
) =>
safeOwners.map((ownerAddress) => {
const convertedAdd = checksumAddress(ownerAddress) const convertedAdd = checksumAddress(ownerAddress)
if (!localSafe) { if (!localSafe) {
return makeOwner({ name: 'UNKNOWN', address: convertedAdd }) return makeOwner({ name: 'UNKNOWN', address: convertedAdd })
} }
@ -38,6 +37,9 @@ const buildOwnersFrom = (
}) })
}) })
return List(ownersList)
}
const buildModulesLinkedList = (modules: string[] | undefined, nextModule: string): Array<ModulePair> | null => { const buildModulesLinkedList = (modules: string[] | undefined, nextModule: string): Array<ModulePair> | null => {
if (modules?.length) { if (modules?.length) {
return modules.map((moduleAddress, index, modules) => { return modules.map((moduleAddress, index, modules) => {
@ -48,7 +50,11 @@ const buildModulesLinkedList = (modules: string[] | undefined, nextModule: strin
return null return null
} }
export const buildSafe = async (safeAdd: string, safeName: string, latestMasterContractVersion?: any) => { export const buildSafe = async (
safeAdd: string,
safeName: string,
latestMasterContractVersion?: string,
): Promise<SafeRecordProps> => {
const safeAddress = checksumAddress(safeAdd) const safeAddress = checksumAddress(safeAdd)
const safeParams = ['getThreshold', 'nonce', 'VERSION', 'getOwners'] const safeParams = ['getThreshold', 'nonce', 'VERSION', 'getOwners']
@ -57,18 +63,18 @@ export const buildSafe = async (safeAdd: string, safeName: string, latestMasterC
abi: GnosisSafeSol.abi, abi: GnosisSafeSol.abi,
address: safeAddress, address: safeAddress,
methods: safeParams, methods: safeParams,
} as any), }),
getLocalSafe(safeAddress), getLocalSafe(safeAddress),
getBalanceInEtherOf(safeAddress), getBalanceInEtherOf(safeAddress),
]) ])
const threshold = Number(thresholdStr) const threshold = Number(thresholdStr)
const nonce = Number(nonceStr) const nonce = Number(nonceStr)
const owners = List<SafeOwner>(buildOwnersFrom(remoteOwners, localSafe)) const owners = buildOwnersFrom(remoteOwners, localSafe)
const needsUpdate = safeNeedsUpdate(currentVersion, latestMasterContractVersion) const needsUpdate = safeNeedsUpdate(currentVersion, latestMasterContractVersion)
const featuresEnabled = enabledFeatures(currentVersion) const featuresEnabled = enabledFeatures(currentVersion)
const safe = { return {
address: safeAddress, address: safeAddress,
name: safeName, name: safeName,
threshold, threshold,
@ -78,9 +84,14 @@ export const buildSafe = async (safeAdd: string, safeName: string, latestMasterC
currentVersion, currentVersion,
needsUpdate, needsUpdate,
featuresEnabled, featuresEnabled,
balances: Map(),
latestIncomingTxBlock: null,
activeAssets: Set(),
activeTokens: Set(),
blacklistedAssets: Set(),
blacklistedTokens: Set(),
modules: null,
} }
return safe
} }
export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch): Promise<void> => { export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch): Promise<void> => {
@ -98,7 +109,7 @@ export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch
abi: GnosisSafeSol.abi, abi: GnosisSafeSol.abi,
address: safeAddress, address: safeAddress,
methods: safeParams, methods: safeParams,
} as any), }),
getLocalSafe(safeAddress), getLocalSafe(safeAddress),
]) ])
@ -139,8 +150,10 @@ export const checkAndUpdateSafe = (safeAdd: string) => async (dispatch: Dispatch
} }
} }
// eslint-disable-next-line consistent-return export default (safeAdd: string) => async (
export default (safeAdd: string) => async (dispatch, getState) => { dispatch: Dispatch<any>,
getState: () => AppReduxState,
): Promise<Action | void> => {
try { try {
const safeAddress = checksumAddress(safeAdd) const safeAddress = checksumAddress(safeAdd)
const safeName = (await getSafeName(safeAddress)) || 'LOADED SAFE' const safeName = (await getSafeName(safeAddress)) || 'LOADED SAFE'

View File

@ -3,8 +3,9 @@ import setDefaultSafe from './setDefaultSafe'
import { getDefaultSafe } from 'src/logic/safe/utils' import { getDefaultSafe } from 'src/logic/safe/utils'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { Dispatch } from 'redux'
const loadDefaultSafe = () => async (dispatch) => { const loadDefaultSafe = () => async (dispatch: Dispatch): Promise<void> => {
try { try {
const defaultSafe = await getDefaultSafe() const defaultSafe = await getDefaultSafe()
const checksumed = defaultSafe && defaultSafe.length > 0 ? checksumAddress(defaultSafe) : defaultSafe const checksumed = defaultSafe && defaultSafe.length > 0 ? checksumAddress(defaultSafe) : defaultSafe

View File

@ -5,8 +5,9 @@ import { SAFES_KEY } from 'src/logic/safe/utils'
import { buildSafe } from 'src/logic/safe/store/reducer/safe' import { buildSafe } from 'src/logic/safe/store/reducer/safe'
import { loadFromStorage } from 'src/utils/storage' import { loadFromStorage } from 'src/utils/storage'
import { Dispatch } from 'redux'
const loadSafesFromStorage = () => async (dispatch) => { const loadSafesFromStorage = () => async (dispatch: Dispatch): Promise<void> => {
try { try {
const safes = await loadFromStorage(SAFES_KEY) const safes = await loadFromStorage(SAFES_KEY)

View File

@ -1,8 +1,9 @@
import { createAction } from 'redux-actions' import { createAction } from 'redux-actions'
import { AnyAction } from 'redux'
export const SET_DEFAULT_SAFE = 'SET_DEFAULT_SAFE' export const SET_DEFAULT_SAFE = 'SET_DEFAULT_SAFE'
export type SetDefaultSafe = (safe: string) => void export type SetDefaultSafe = (safe: string) => AnyAction
const setDefaultSafe: SetDefaultSafe = createAction(SET_DEFAULT_SAFE) const setDefaultSafe: SetDefaultSafe = createAction(SET_DEFAULT_SAFE)

View File

@ -12,14 +12,14 @@ import { SET_DEFAULT_SAFE } from 'src/logic/safe/store/actions/setDefaultSafe'
import { SET_LATEST_MASTER_CONTRACT_VERSION } from 'src/logic/safe/store/actions/setLatestMasterContractVersion' import { SET_LATEST_MASTER_CONTRACT_VERSION } from 'src/logic/safe/store/actions/setLatestMasterContractVersion'
import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe' import { UPDATE_SAFE } from 'src/logic/safe/store/actions/updateSafe'
import { makeOwner } from 'src/logic/safe/store/models/owner' import { makeOwner } from 'src/logic/safe/store/models/owner'
import makeSafe from 'src/logic/safe/store/models/safe' import makeSafe, { SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { SafeReducerMap } from 'src/routes/safe/store/reducer/types/safe' import { SafeReducerMap } from 'src/routes/safe/store/reducer/types/safe'
export const SAFE_REDUCER_ID = 'safes' export const SAFE_REDUCER_ID = 'safes'
export const DEFAULT_SAFE_INITIAL_STATE = 'NOT_ASKED' export const DEFAULT_SAFE_INITIAL_STATE = 'NOT_ASKED'
export const buildSafe = (storedSafe) => { export const buildSafe = (storedSafe: SafeRecordProps): SafeRecordProps => {
const names = storedSafe.owners.map((owner) => owner.name) const names = storedSafe.owners.map((owner) => owner.name)
const addresses = storedSafe.owners.map((owner) => checksumAddress(owner.address)) const addresses = storedSafe.owners.map((owner) => checksumAddress(owner.address))
const owners = buildOwnersFrom(Array.from(names), Array.from(addresses)) const owners = buildOwnersFrom(Array.from(names), Array.from(addresses))
@ -29,7 +29,7 @@ export const buildSafe = (storedSafe) => {
const blacklistedAssets = Set(storedSafe.blacklistedAssets) const blacklistedAssets = Set(storedSafe.blacklistedAssets)
const balances = Map(storedSafe.balances) const balances = Map(storedSafe.balances)
const safe = { return {
...storedSafe, ...storedSafe,
owners, owners,
balances, balances,
@ -37,9 +37,9 @@ export const buildSafe = (storedSafe) => {
blacklistedTokens, blacklistedTokens,
activeAssets, activeAssets,
blacklistedAssets, blacklistedAssets,
latestIncomingTxBlock: null,
modules: null,
} }
return safe
} }
export default handleActions( export default handleActions(

View File

@ -1,10 +1,11 @@
import { loadFromStorage, saveToStorage } from 'src/utils/storage' import { loadFromStorage, saveToStorage } from 'src/utils/storage'
import { SafeRecordProps } from 'src/logic/safe/store/models/safe'
export const SAFES_KEY = 'SAFES' export const SAFES_KEY = 'SAFES'
export const TX_KEY = 'TX' export const TX_KEY = 'TX'
export const DEFAULT_SAFE_KEY = 'DEFAULT_SAFE' export const DEFAULT_SAFE_KEY = 'DEFAULT_SAFE'
export const getSafeName = async (safeAddress) => { export const getSafeName = async (safeAddress: string): Promise<string | undefined> => {
const safes = await loadFromStorage(SAFES_KEY) const safes = await loadFromStorage(SAFES_KEY)
if (!safes) { if (!safes) {
return undefined return undefined
@ -22,9 +23,9 @@ export const saveSafes = async (safes) => {
} }
} }
export const getLocalSafe = async (safeAddress) => { export const getLocalSafe = async (safeAddress: string): Promise<SafeRecordProps | null> => {
const storedSafes = (await loadFromStorage(SAFES_KEY)) || {} const storedSafes = (await loadFromStorage(SAFES_KEY)) || {}
return storedSafes[safeAddress] return storedSafes[safeAddress] || null
} }
export const getDefaultSafe = async (): Promise<string> => { export const getDefaultSafe = async (): Promise<string> => {
@ -33,7 +34,7 @@ export const getDefaultSafe = async (): Promise<string> => {
return defaultSafe || '' return defaultSafe || ''
} }
export const saveDefaultSafe = async (safeAddress) => { export const saveDefaultSafe = async (safeAddress: string): Promise<void> => {
try { try {
await saveToStorage(DEFAULT_SAFE_KEY, safeAddress) await saveToStorage(DEFAULT_SAFE_KEY, safeAddress)
} catch (err) { } catch (err) {

View File

@ -1,12 +1,9 @@
import * as React from 'react' import * as React from 'react'
import { connect } from 'react-redux' import { useDispatch, useSelector } from 'react-redux'
import Layout from '../components/Layout' import Layout from 'src/routes/load/components/Layout'
import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME } from '../components/fields' import { FIELD_LOAD_ADDRESS, FIELD_LOAD_NAME } from '../components/fields'
import actions from './actions'
import selector from './selector'
import Page from 'src/components/layout/Page' import Page from 'src/components/layout/Page'
import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts'
import { SAFES_KEY, saveSafes } from 'src/logic/safe/utils' import { SAFES_KEY, saveSafes } from 'src/logic/safe/utils'
@ -15,16 +12,17 @@ import { SAFELIST_ADDRESS } from 'src/routes/routes'
import { buildSafe } from 'src/logic/safe/store/actions/fetchSafe' import { buildSafe } from 'src/logic/safe/store/actions/fetchSafe'
import { history } from 'src/store' import { history } from 'src/store'
import { loadFromStorage } from 'src/utils/storage' import { loadFromStorage } from 'src/utils/storage'
import { Dispatch } from 'redux' import { SafeOwner, SafeRecordProps } from 'src/logic/safe/store/models/safe'
import { SafeOwner } from '../../../logic/safe/store/models/safe'
import { List } from 'immutable' import { List } from 'immutable'
import { checksumAddress } from 'src/utils/checksumAddress' import { checksumAddress } from 'src/utils/checksumAddress'
import { addSafe } from 'src/logic/safe/store/actions/addSafe'
import { networkSelector, providerNameSelector, userAccountSelector } from 'src/logic/wallets/store/selectors'
export const loadSafe = async ( export const loadSafe = async (
safeName: string, safeName: string,
safeAddress: string, safeAddress: string,
owners: List<SafeOwner>, owners: List<SafeOwner>,
addSafe: Dispatch<any>, addSafe: (safe: SafeRecordProps) => void,
): Promise<void> => { ): Promise<void> => {
const safeProps = await buildSafe(safeAddress, safeName) const safeProps = await buildSafe(safeAddress, safeName)
safeProps.owners = owners safeProps.owners = owners
@ -37,20 +35,21 @@ export const loadSafe = async (
await addSafe(safeProps) await addSafe(safeProps)
} }
interface LoadProps {
addSafe: Dispatch<any>
network: string
provider?: string
userAddress: string
}
export interface LoadFormValues { export interface LoadFormValues {
name: string name: string
address: string address: string
threshold: string threshold: string
} }
const Load = ({ addSafe, network, provider, userAddress }: LoadProps): React.ReactElement => { const Load = (): React.ReactElement => {
const dispatch = useDispatch()
const provider = useSelector(providerNameSelector)
const network = useSelector(networkSelector)
const userAddress = useSelector(userAccountSelector)
const addSafeHandler = (safe: SafeRecordProps) => {
dispatch(addSafe(safe))
}
const onLoadSafeSubmit = async (values: LoadFormValues) => { const onLoadSafeSubmit = async (values: LoadFormValues) => {
let safeAddress = values[FIELD_LOAD_ADDRESS] let safeAddress = values[FIELD_LOAD_ADDRESS]
// TODO: review this check. It doesn't seems to be necessary at this point // TODO: review this check. It doesn't seems to be necessary at this point
@ -68,7 +67,7 @@ const Load = ({ addSafe, network, provider, userAddress }: LoadProps): React.Rea
const ownerAddresses = await gnosisSafe.methods.getOwners().call() const ownerAddresses = await gnosisSafe.methods.getOwners().call()
const owners = getOwnersFrom(ownerNames, ownerAddresses.slice().sort()) const owners = getOwnersFrom(ownerNames, ownerAddresses.slice().sort())
await loadSafe(safeName, safeAddress, owners, addSafe) await loadSafe(safeName, safeAddress, owners, addSafeHandler)
const url = `${SAFELIST_ADDRESS}/${safeAddress}/balances` const url = `${SAFELIST_ADDRESS}/${safeAddress}/balances`
history.push(url) history.push(url)
@ -79,9 +78,9 @@ const Load = ({ addSafe, network, provider, userAddress }: LoadProps): React.Rea
return ( return (
<Page> <Page>
<Layout network={network} onLoadSafeSubmit={onLoadSafeSubmit} provider={provider} userAddress={userAddress} /> <Layout onLoadSafeSubmit={onLoadSafeSubmit} network={network} userAddress={userAddress} provider={provider} />
</Page> </Page>
) )
} }
export default connect(selector, actions)(Load) export default Load

View File

@ -1,5 +0,0 @@
import addSafe from 'src/logic/safe/store/actions/addSafe'
export default {
addSafe,
}

View File

@ -1,11 +0,0 @@
import { createStructuredSelector } from 'reselect'
import { networkSelector, providerNameSelector, userAccountSelector } from 'src/logic/wallets/store/selectors'
const structuredSelector = createStructuredSelector({
provider: providerNameSelector,
network: networkSelector,
userAddress: userAccountSelector,
})
export default structuredSelector