(Fix) Owner replacement transaction details (#688)
* fix: No threshold change for owners replacement * fix: Extract added owner from addressBook When replacing an owner, the added owner's name was the same as the removed one * fix: Add or Update addressBook entry for the newly added owner * Replace `.then` with `async/await` * Optimize AddressBook entry `name` update * Revert "Optimize AddressBook entry `name` update" This reverts commit 00a75d15 * refactor: AddressBook entry from plain JS object to immutable Record * fix: merge instead of set for the AddressBookEntry record * refactor: addOrUpdateAddressBookEntry redux action changed signature to `addOrUpdateAddressBookEntry(entryAddress, entry)` Where `entry` is an object with only the required fields to be updated
This commit is contained in:
parent
a6b70a1663
commit
f1235738c0
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import type { RecordOf } from 'immutable'
|
import { Record, type RecordFactory, type RecordOf } from 'immutable'
|
||||||
|
|
||||||
export type AddressBookEntry = {
|
export type AddressBookEntry = {
|
||||||
address: string,
|
address: string,
|
||||||
|
@ -11,4 +11,10 @@ export type AddressBookProps = {
|
||||||
addressBook: Map<string, AddressBookEntry>,
|
addressBook: Map<string, AddressBookEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const makeAddressBookEntry: RecordFactory<AddressBookEntry> = Record({
|
||||||
|
address: '',
|
||||||
|
name: '',
|
||||||
|
isOwner: false,
|
||||||
|
})
|
||||||
|
|
||||||
export type AddressBook = RecordOf<AddressBookProps>
|
export type AddressBook = RecordOf<AddressBookProps>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// @flow
|
||||||
|
import { createAction } from 'redux-actions'
|
||||||
|
|
||||||
|
import type { AddressBookEntryType } from '~/logic/addressBook/model/addressBook'
|
||||||
|
|
||||||
|
export const ADD_OR_UPDATE_ENTRY = 'ADD_OR_UPDATE_ENTRY'
|
||||||
|
|
||||||
|
export const addOrUpdateAddressBookEntry = createAction<string, *, *>(
|
||||||
|
ADD_OR_UPDATE_ENTRY,
|
||||||
|
(entryAddress: string, entry: AddressBookEntryType): AddressBookEntryType => ({
|
||||||
|
entryAddress,
|
||||||
|
entry,
|
||||||
|
}),
|
||||||
|
)
|
|
@ -2,13 +2,14 @@
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
|
||||||
import type { AddressBook } from '~/logic/addressBook/model/addressBook'
|
import type { AddressBook } from '~/logic/addressBook/model/addressBook'
|
||||||
|
import { makeAddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
import { updateAddressBookEntry } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
import { updateAddressBookEntry } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
||||||
import { saveAddressBook } from '~/logic/addressBook/utils'
|
import { saveAddressBook } from '~/logic/addressBook/utils'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
|
|
||||||
const saveAndUpdateAddressBook = (addressBook: AddressBook) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
const saveAndUpdateAddressBook = (addressBook: AddressBook) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||||
try {
|
try {
|
||||||
dispatch(updateAddressBookEntry(addressBook))
|
dispatch(updateAddressBookEntry(makeAddressBookEntry(addressBook)))
|
||||||
await saveAddressBook(addressBook)
|
await saveAddressBook(addressBook)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { AnyAction, Store } from 'redux'
|
||||||
|
|
||||||
import type { AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
import type { AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
||||||
import { ADD_ENTRY } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
import { ADD_ENTRY } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
||||||
|
import { ADD_OR_UPDATE_ENTRY } from '~/logic/addressBook/store/actions/addOrUpdateAddressBookEntry'
|
||||||
import { REMOVE_ENTRY } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
import { REMOVE_ENTRY } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
||||||
import { UPDATE_ENTRY } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
import { UPDATE_ENTRY } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
||||||
import { addressBookMapSelector } from '~/logic/addressBook/store/selectors'
|
import { addressBookMapSelector } from '~/logic/addressBook/store/selectors'
|
||||||
|
@ -10,9 +11,9 @@ import { saveAddressBook } from '~/logic/addressBook/utils'
|
||||||
import { enhanceSnackbarForAction, getNotificationsFromTxType } from '~/logic/notifications'
|
import { enhanceSnackbarForAction, getNotificationsFromTxType } from '~/logic/notifications'
|
||||||
import enqueueSnackbar from '~/logic/notifications/store/actions/enqueueSnackbar'
|
import enqueueSnackbar from '~/logic/notifications/store/actions/enqueueSnackbar'
|
||||||
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
||||||
import { type GlobalState } from '~/store/'
|
import { type GlobalState } from '~/store'
|
||||||
|
|
||||||
const watchedActions = [ADD_ENTRY, REMOVE_ENTRY, UPDATE_ENTRY]
|
const watchedActions = [ADD_ENTRY, REMOVE_ENTRY, UPDATE_ENTRY, ADD_OR_UPDATE_ENTRY]
|
||||||
|
|
||||||
const addressBookMiddleware = (store: Store<GlobalState>) => (next: Function) => async (action: AnyAction) => {
|
const addressBookMiddleware = (store: Store<GlobalState>) => (next: Function) => async (action: AnyAction) => {
|
||||||
const handledAction = next(action)
|
const handledAction = next(action)
|
||||||
|
|
|
@ -3,8 +3,10 @@ import { List, Map } from 'immutable'
|
||||||
import { type ActionType, handleActions } from 'redux-actions'
|
import { type ActionType, handleActions } from 'redux-actions'
|
||||||
|
|
||||||
import type { AddressBook, AddressBookEntry, AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
import type { AddressBook, AddressBookEntry, AddressBookProps } from '~/logic/addressBook/model/addressBook'
|
||||||
|
import { makeAddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
import { ADD_ADDRESS_BOOK } from '~/logic/addressBook/store/actions/addAddressBook'
|
import { ADD_ADDRESS_BOOK } from '~/logic/addressBook/store/actions/addAddressBook'
|
||||||
import { ADD_ENTRY } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
import { ADD_ENTRY } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
||||||
|
import { ADD_OR_UPDATE_ENTRY } from '~/logic/addressBook/store/actions/addOrUpdateAddressBookEntry'
|
||||||
import { LOAD_ADDRESS_BOOK } from '~/logic/addressBook/store/actions/loadAddressBook'
|
import { LOAD_ADDRESS_BOOK } from '~/logic/addressBook/store/actions/loadAddressBook'
|
||||||
import { REMOVE_ENTRY } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
import { REMOVE_ENTRY } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
||||||
import { UPDATE_ENTRY } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
import { UPDATE_ENTRY } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
||||||
|
@ -19,7 +21,8 @@ export const buildAddressBook = (storedAdbk: AddressBook): AddressBookProps => {
|
||||||
let addressBookBuilt = Map([])
|
let addressBookBuilt = Map([])
|
||||||
Object.entries(storedAdbk).forEach((adbkProps: Array<string, AddressBookEntry[]>) => {
|
Object.entries(storedAdbk).forEach((adbkProps: Array<string, AddressBookEntry[]>) => {
|
||||||
const safeAddress = adbkProps[0]
|
const safeAddress = adbkProps[0]
|
||||||
const adbkSafeEntries = List(adbkProps[1])
|
const adbkRecords = adbkProps[1].map(makeAddressBookEntry)
|
||||||
|
const adbkSafeEntries = List(adbkRecords)
|
||||||
addressBookBuilt = addressBookBuilt.set(safeAddress, adbkSafeEntries)
|
addressBookBuilt = addressBookBuilt.set(safeAddress, adbkSafeEntries)
|
||||||
})
|
})
|
||||||
return addressBookBuilt
|
return addressBookBuilt
|
||||||
|
@ -98,6 +101,28 @@ export default handleActions<State, *>(
|
||||||
})
|
})
|
||||||
return newState
|
return newState
|
||||||
},
|
},
|
||||||
|
[ADD_OR_UPDATE_ENTRY]: (state: State, action: ActionType<Function>): State => {
|
||||||
|
const { entry, entryAddress } = action.payload
|
||||||
|
|
||||||
|
// Adds or Updates the entry to all the safes
|
||||||
|
return state.withMutations(map => {
|
||||||
|
const addressBook = map.get('addressBook')
|
||||||
|
if (addressBook) {
|
||||||
|
addressBook.keySeq().forEach(safeAddress => {
|
||||||
|
const safeAddressBook: List<AddressBookEntry> = state.getIn(['addressBook', safeAddress])
|
||||||
|
const entryIndex = safeAddressBook.findIndex(entryItem => sameAddress(entryItem.address, entryAddress))
|
||||||
|
|
||||||
|
if (entryIndex !== -1) {
|
||||||
|
const updatedEntriesList = safeAddressBook.update(entryIndex, currentEntry => currentEntry.merge(entry))
|
||||||
|
map.setIn(['addressBook', safeAddress], updatedEntriesList)
|
||||||
|
} else {
|
||||||
|
const updatedSafeAdbkList = safeAddressBook.push(makeAddressBookEntry(entry))
|
||||||
|
map.setIn(['addressBook', safeAddress], updatedSafeAdbkList)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Map(),
|
Map(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import Col from '~/components/layout/Col'
|
||||||
import Img from '~/components/layout/Img'
|
import Img from '~/components/layout/Img'
|
||||||
import Row from '~/components/layout/Row'
|
import Row from '~/components/layout/Row'
|
||||||
import type { AddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
import type { AddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
|
import { makeAddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
import { addAddressBookEntry } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
import { addAddressBookEntry } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
||||||
import { removeAddressBookEntry } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
import { removeAddressBookEntry } from '~/logic/addressBook/store/actions/removeAddressBookEntry'
|
||||||
import { updateAddressBookEntry } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
import { updateAddressBookEntry } from '~/logic/addressBook/store/actions/updateAddressBookEntry'
|
||||||
|
@ -89,13 +90,13 @@ const AddressBookTable = ({ classes }: Props) => {
|
||||||
|
|
||||||
const newEntryModalHandler = (entry: AddressBookEntry) => {
|
const newEntryModalHandler = (entry: AddressBookEntry) => {
|
||||||
setEditCreateEntryModalOpen(false)
|
setEditCreateEntryModalOpen(false)
|
||||||
dispatch(addAddressBookEntry(entry))
|
dispatch(addAddressBookEntry(makeAddressBookEntry(entry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
const editEntryModalHandler = (entry: AddressBookEntry) => {
|
const editEntryModalHandler = (entry: AddressBookEntry) => {
|
||||||
setSelectedEntry(null)
|
setSelectedEntry(null)
|
||||||
setEditCreateEntryModalOpen(false)
|
setEditCreateEntryModalOpen(false)
|
||||||
dispatch(updateAddressBookEntry(entry))
|
dispatch(updateAddressBookEntry(makeAddressBookEntry(entry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteEntryModalHandler = () => {
|
const deleteEntryModalHandler = () => {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import Button from '~/components/layout/Button'
|
||||||
import Hairline from '~/components/layout/Hairline'
|
import Hairline from '~/components/layout/Hairline'
|
||||||
import Paragraph from '~/components/layout/Paragraph'
|
import Paragraph from '~/components/layout/Paragraph'
|
||||||
import Row from '~/components/layout/Row'
|
import Row from '~/components/layout/Row'
|
||||||
|
import { makeAddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
import { getNotificationsFromTxType, showSnackbar } from '~/logic/notifications'
|
import { getNotificationsFromTxType, showSnackbar } from '~/logic/notifications'
|
||||||
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
||||||
import { sm } from '~/theme/variables'
|
import { sm } from '~/theme/variables'
|
||||||
|
@ -55,7 +56,7 @@ const EditOwnerComponent = ({
|
||||||
const handleSubmit = values => {
|
const handleSubmit = values => {
|
||||||
const { ownerName } = values
|
const { ownerName } = values
|
||||||
editSafeOwner({ safeAddress, ownerAddress, ownerName })
|
editSafeOwner({ safeAddress, ownerAddress, ownerName })
|
||||||
updateAddressBookEntry({ address: ownerAddress, name: ownerName })
|
updateAddressBookEntry(makeAddressBookEntry({ address: ownerAddress, name: ownerName }))
|
||||||
const notification = getNotificationsFromTxType(TX_NOTIFICATION_TYPES.OWNER_NAME_CHANGE_TX)
|
const notification = getNotificationsFromTxType(TX_NOTIFICATION_TYPES.OWNER_NAME_CHANGE_TX)
|
||||||
showSnackbar(notification.afterExecution.noMoreConfirmationsNeeded, enqueueSnackbar, closeSnackbar)
|
showSnackbar(notification.afterExecution.noMoreConfirmationsNeeded, enqueueSnackbar, closeSnackbar)
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ type Props = {
|
||||||
address: string,
|
address: string,
|
||||||
showLinks?: boolean,
|
showLinks?: boolean,
|
||||||
knownAddress?: boolean,
|
knownAddress?: boolean,
|
||||||
userName?: boolean,
|
userName?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const OwnerAddressTableCell = (props: Props) => {
|
const OwnerAddressTableCell = (props: Props) => {
|
||||||
|
|
|
@ -3,11 +3,13 @@ import { withStyles } from '@material-ui/core/styles'
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { withSnackbar } from 'notistack'
|
import { withSnackbar } from 'notistack'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useDispatch } from 'react-redux'
|
||||||
|
|
||||||
import OwnerForm from './screens/OwnerForm'
|
import OwnerForm from './screens/OwnerForm'
|
||||||
import ReviewReplaceOwner from './screens/Review'
|
import ReviewReplaceOwner from './screens/Review'
|
||||||
|
|
||||||
import Modal from '~/components/Modal'
|
import Modal from '~/components/Modal'
|
||||||
|
import { addOrUpdateAddressBookEntry } from '~/logic/addressBook/store/actions/addOrUpdateAddressBookEntry'
|
||||||
import { SENTINEL_ADDRESS, getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
import { SENTINEL_ADDRESS, getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
|
||||||
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions'
|
||||||
import { type Owner } from '~/routes/safe/store/models/owner'
|
import { type Owner } from '~/routes/safe/store/models/owner'
|
||||||
|
@ -94,6 +96,7 @@ const ReplaceOwner = ({
|
||||||
safeName,
|
safeName,
|
||||||
threshold,
|
threshold,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const dispatch = useDispatch()
|
||||||
const [activeScreen, setActiveScreen] = useState<ActiveScreen>('checkOwner')
|
const [activeScreen, setActiveScreen] = useState<ActiveScreen>('checkOwner')
|
||||||
const [values, setValues] = useState<Object>({})
|
const [values, setValues] = useState<Object>({})
|
||||||
|
|
||||||
|
@ -114,10 +117,11 @@ const ReplaceOwner = ({
|
||||||
setActiveScreen('reviewReplaceOwner')
|
setActiveScreen('reviewReplaceOwner')
|
||||||
}
|
}
|
||||||
|
|
||||||
const onReplaceOwner = () => {
|
const onReplaceOwner = async () => {
|
||||||
onClose()
|
onClose()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sendReplaceOwner(
|
await sendReplaceOwner(
|
||||||
values,
|
values,
|
||||||
safeAddress,
|
safeAddress,
|
||||||
ownerAddress,
|
ownerAddress,
|
||||||
|
@ -127,6 +131,13 @@ const ReplaceOwner = ({
|
||||||
replaceSafeOwner,
|
replaceSafeOwner,
|
||||||
safe,
|
safe,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
// Needs the `address` field because we need to provide the minimum required values to ADD a new entry
|
||||||
|
// The reducer will update all the addressBooks stored, so we cannot decide what to do beforehand,
|
||||||
|
// thus, we pass the minimum required fields (name and address)
|
||||||
|
addOrUpdateAddressBookEntry(values.ownerAddress, { name: values.ownerName, address: values.ownerAddress }),
|
||||||
|
)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error while removing an owner', error)
|
console.error('Error while removing an owner', error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID = 'tx-description-change
|
||||||
export const TRANSACTIONS_DESC_SEND_TEST_ID = 'tx-description-send'
|
export const TRANSACTIONS_DESC_SEND_TEST_ID = 'tx-description-send'
|
||||||
export const TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID = 'tx-description-custom-value'
|
export const TRANSACTIONS_DESC_CUSTOM_VALUE_TEST_ID = 'tx-description-custom-value'
|
||||||
export const TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID = 'tx-description-custom-data'
|
export const TRANSACTIONS_DESC_CUSTOM_DATA_TEST_ID = 'tx-description-custom-data'
|
||||||
|
export const TRANSACTIONS_DESC_NO_DATA = 'tx-description-no-data'
|
||||||
|
|
||||||
export const styles = () => ({
|
export const styles = () => ({
|
||||||
txDataContainer: {
|
txDataContainer: {
|
||||||
|
@ -52,9 +53,10 @@ type TransferDescProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DescriptionDescProps = {
|
type DescriptionDescProps = {
|
||||||
removedOwner?: string,
|
action: string,
|
||||||
addedOwner?: string,
|
addedOwner?: string,
|
||||||
newThreshold?: string,
|
newThreshold?: string,
|
||||||
|
removedOwner?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
type CustomDescProps = {
|
type CustomDescProps = {
|
||||||
|
@ -78,39 +80,81 @@ const TransferDescription = ({ amount = '', recipient }: TransferDescProps) => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SettingsDescription = ({ addedOwner, newThreshold, removedOwner }: DescriptionDescProps) => {
|
const RemovedOwner = ({ removedOwner }: { removedOwner: string }) => {
|
||||||
const ownerChangedName = removedOwner ? getNameFromAddressBook(removedOwner) : getNameFromAddressBook(addedOwner)
|
const ownerChangedName = getNameFromAddressBook(removedOwner)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
|
||||||
{removedOwner && (
|
<Bold>Remove owner:</Bold>
|
||||||
<Block data-testid={TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID}>
|
{ownerChangedName ? (
|
||||||
<Bold>Remove owner:</Bold>
|
<OwnerAddressTableCell address={removedOwner} knownAddress showLinks userName={ownerChangedName} />
|
||||||
{ownerChangedName ? (
|
) : (
|
||||||
<OwnerAddressTableCell address={removedOwner} knownAddress showLinks userName={ownerChangedName} />
|
<EtherscanLink knownAddress={false} type="address" value={removedOwner} />
|
||||||
) : (
|
|
||||||
<EtherscanLink knownAddress={false} type="address" value={removedOwner} />
|
|
||||||
)}
|
|
||||||
</Block>
|
|
||||||
)}
|
)}
|
||||||
{addedOwner && (
|
</Block>
|
||||||
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
|
)
|
||||||
<Bold>Add owner:</Bold>
|
}
|
||||||
{ownerChangedName ? (
|
|
||||||
<OwnerAddressTableCell address={addedOwner} knownAddress showLinks userName={ownerChangedName} />
|
const AddedOwner = ({ addedOwner }: { addedOwner: string }) => {
|
||||||
) : (
|
const ownerChangedName = getNameFromAddressBook(addedOwner)
|
||||||
<EtherscanLink knownAddress={false} type="address" value={addedOwner} />
|
|
||||||
)}
|
return (
|
||||||
</Block>
|
<Block data-testid={TRANSACTIONS_DESC_ADD_OWNER_TEST_ID}>
|
||||||
|
<Bold>Add owner:</Bold>
|
||||||
|
{ownerChangedName ? (
|
||||||
|
<OwnerAddressTableCell address={addedOwner} knownAddress showLinks userName={ownerChangedName} />
|
||||||
|
) : (
|
||||||
|
<EtherscanLink knownAddress={false} type="address" value={addedOwner} />
|
||||||
)}
|
)}
|
||||||
{newThreshold && (
|
</Block>
|
||||||
<Block data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
|
)
|
||||||
<Bold>Change required confirmations:</Bold>
|
}
|
||||||
<Paragraph noMargin size="md">
|
|
||||||
{newThreshold}
|
const NewThreshold = ({ newThreshold }: { newThreshold: string }) => (
|
||||||
</Paragraph>
|
<Block data-testid={TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID}>
|
||||||
</Block>
|
<Bold>Change required confirmations:</Bold>
|
||||||
)}
|
<Paragraph noMargin size="md">
|
||||||
</>
|
{newThreshold}
|
||||||
|
</Paragraph>
|
||||||
|
</Block>
|
||||||
|
)
|
||||||
|
|
||||||
|
const SettingsDescription = ({ action, addedOwner, newThreshold, removedOwner }: DescriptionDescProps) => {
|
||||||
|
if (action === 'removeOwner' && removedOwner && newThreshold) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RemovedOwner removedOwner={removedOwner} />
|
||||||
|
<NewThreshold newThreshold={newThreshold} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'changedThreshold' && newThreshold) {
|
||||||
|
return <NewThreshold newThreshold={newThreshold} />
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'addOwnerWithThreshold' && addedOwner && newThreshold) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<AddedOwner addedOwner={addedOwner} />
|
||||||
|
<NewThreshold newThreshold={newThreshold} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'swapOwner' && removedOwner && addedOwner) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<RemovedOwner removedOwner={removedOwner} />
|
||||||
|
<AddedOwner addedOwner={addedOwner} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Block data-testid={TRANSACTIONS_DESC_NO_DATA}>
|
||||||
|
<Bold>No data available for current transaction</Bold>
|
||||||
|
</Block>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +209,7 @@ const CustomDescription = ({ amount = 0, classes, data, recipient }: CustomDescP
|
||||||
|
|
||||||
const TxDescription = ({ classes, tx }: Props) => {
|
const TxDescription = ({ classes, tx }: Props) => {
|
||||||
const {
|
const {
|
||||||
|
action,
|
||||||
addedOwner,
|
addedOwner,
|
||||||
cancellationTx,
|
cancellationTx,
|
||||||
creationTx,
|
creationTx,
|
||||||
|
@ -179,8 +224,13 @@ const TxDescription = ({ classes, tx }: Props) => {
|
||||||
const amount = getTxAmount(tx)
|
const amount = getTxAmount(tx)
|
||||||
return (
|
return (
|
||||||
<Block className={classes.txDataContainer}>
|
<Block className={classes.txDataContainer}>
|
||||||
{modifySettingsTx && (
|
{modifySettingsTx && action && (
|
||||||
<SettingsDescription addedOwner={addedOwner} newThreshold={newThreshold} removedOwner={removedOwner} />
|
<SettingsDescription
|
||||||
|
action={action}
|
||||||
|
addedOwner={addedOwner}
|
||||||
|
newThreshold={newThreshold}
|
||||||
|
removedOwner={removedOwner}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{!upgradeTx && customTx && (
|
{!upgradeTx && customTx && (
|
||||||
<CustomDescription amount={amount} classes={classes} data={data} recipient={recipient} />
|
<CustomDescription amount={amount} classes={classes} data={data} recipient={recipient} />
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { getWeb3 } from '~/logic/wallets/getWeb3'
|
||||||
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
import { type Transaction } from '~/routes/safe/store/models/transaction'
|
||||||
|
|
||||||
type DecodedTxData = {
|
type DecodedTxData = {
|
||||||
|
action?: string,
|
||||||
recipient: string,
|
recipient: string,
|
||||||
value?: string,
|
value?: string,
|
||||||
modifySettingsTx?: boolean,
|
modifySettingsTx?: boolean,
|
||||||
|
@ -48,21 +49,20 @@ export const getTxData = (tx: Transaction): DecodedTxData => {
|
||||||
txData.modifySettingsTx = true
|
txData.modifySettingsTx = true
|
||||||
|
|
||||||
if (tx.decodedParams) {
|
if (tx.decodedParams) {
|
||||||
/* eslint-disable */
|
txData.action = tx.decodedParams.methodName
|
||||||
if (tx.decodedParams.methodName === 'removeOwner') {
|
|
||||||
|
if (txData.action === 'removeOwner') {
|
||||||
txData.removedOwner = tx.decodedParams.args[1]
|
txData.removedOwner = tx.decodedParams.args[1]
|
||||||
txData.newThreshold = tx.decodedParams.args[2]
|
txData.newThreshold = tx.decodedParams.args[2]
|
||||||
} else if (tx.decodedParams.methodName === 'changeThreshold') {
|
} else if (txData.action === 'changeThreshold') {
|
||||||
txData.newThreshold = tx.decodedParams.args[0]
|
txData.newThreshold = tx.decodedParams.args[0]
|
||||||
} else if (tx.decodedParams.methodName === 'addOwnerWithThreshold') {
|
} else if (txData.action === 'addOwnerWithThreshold') {
|
||||||
txData.addedOwner = tx.decodedParams.args[0]
|
txData.addedOwner = tx.decodedParams.args[0]
|
||||||
txData.newThreshold = tx.decodedParams.args[1]
|
txData.newThreshold = tx.decodedParams.args[1]
|
||||||
} else if (tx.decodedParams.methodName === 'swapOwner') {
|
} else if (txData.action === 'swapOwner') {
|
||||||
txData.newThreshold = tx.decodedParams.args[0]
|
|
||||||
txData.removedOwner = tx.decodedParams.args[1]
|
txData.removedOwner = tx.decodedParams.args[1]
|
||||||
txData.addedOwner = tx.decodedParams.args[2]
|
txData.addedOwner = tx.decodedParams.args[2]
|
||||||
}
|
}
|
||||||
/* eslint-enable */
|
|
||||||
}
|
}
|
||||||
} else if (tx.cancellationTx) {
|
} else if (tx.cancellationTx) {
|
||||||
txData.cancellationTx = true
|
txData.cancellationTx = true
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import type { Action, Store } from 'redux'
|
import type { Action, Store } from 'redux'
|
||||||
|
|
||||||
|
import { makeAddressBookEntry } from '~/logic/addressBook/model/addressBook'
|
||||||
import { addAddressBookEntry } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
import { addAddressBookEntry } from '~/logic/addressBook/store/actions/addAddressBookEntry'
|
||||||
import { saveDefaultSafe, saveSafes } from '~/logic/safe/utils'
|
import { saveDefaultSafe, saveSafes } from '~/logic/safe/utils'
|
||||||
import type { Token } from '~/logic/tokens/store/model/token'
|
import type { Token } from '~/logic/tokens/store/model/token'
|
||||||
|
@ -65,7 +66,7 @@ const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => asyn
|
||||||
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({ ...owner, isOwner: true }))
|
dispatch(addAddressBookEntry(makeAddressBookEntry({ ...owner, isOwner: true })))
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue