This repository was archived by the owner on Nov 10, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 358
Feature/2397 display guard information in settings #2662
Merged
katspaugh
merged 18 commits into
dev
from
feature/2397-display-guard-information-in-settings
Sep 13, 2021
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
dda9501
Added transaction guard to advanced settings
juampibermani 11e66f6
Merge branch 'dev' into feature/2397-display-guard-information-in-set…
juampibermani f45b4af
Get guard from the unified gateway
juampibermani b0ab537
Fixed tests
juampibermani 2510e78
Added TransactionGuard component
juampibermani 0a0966d
WIP: created component without contract instance
juampibermani b9d1184
Merge branch 'dev' into feature/2397-display-guard-information-in-set…
juampibermani 320187d
Call safe method to set guard tx address
juampibermani 5208e47
Deleted console log
juampibermani c769dfd
Added description to remove guard modal
juampibermani c49f2c0
Update gateway-sdk to v2.1.0
078d761
Fix remove guard function
e77e8dc
Minor fixes
juampibermani cee6eb0
Merge branch 'feature/2397-display-guard-information-in-settings' of …
juampibermani 6819f3c
Replace guard if fetchedSafe has a null guard
juampibermani fae9148
Fixed some tests
juampibermani 8377a06
Fixed test
juampibermani f2af702
Merge branch 'dev' into feature/2397-display-guard-information-in-set…
juampibermani File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import { getGnosisSafeInstanceAt } from 'src/logic/contracts/safeContracts' | ||
| import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' | ||
|
|
||
| export const getSetGuardTxData = (guardAddress: string, safeAddress: string, safeVersion: string): string => { | ||
| const safeInstance = getGnosisSafeInstanceAt(safeAddress, safeVersion) | ||
|
|
||
| return safeInstance.methods.setGuard(guardAddress).encodeABI() | ||
| } | ||
|
|
||
| export const getRemoveGuardTxData = (safeAddress: string, safeVersion: string): string => { | ||
| return getSetGuardTxData(ZERO_ADDRESS, safeAddress, safeVersion) | ||
| } |
191 changes: 191 additions & 0 deletions
191
src/routes/safe/components/Settings/Advanced/RemoveGuardModal.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,191 @@ | ||
| import { EthHashInfo } from '@gnosis.pm/safe-react-components' | ||
| import IconButton from '@material-ui/core/IconButton' | ||
| import Close from '@material-ui/icons/Close' | ||
| import cn from 'classnames' | ||
| import React, { ReactElement, useMemo, useState } from 'react' | ||
| import { useDispatch, useSelector } from 'react-redux' | ||
|
|
||
| import Block from 'src/components/layout/Block' | ||
| import Col from 'src/components/layout/Col' | ||
| import Hairline from 'src/components/layout/Hairline' | ||
| import Paragraph from 'src/components/layout/Paragraph' | ||
| import Row from 'src/components/layout/Row' | ||
| import Modal, { ButtonStatus, Modal as GenericModal } from 'src/components/Modal' | ||
| import { getExplorerInfo } from 'src/config' | ||
| import { createTransaction } from 'src/logic/safe/store/actions/createTransaction' | ||
|
|
||
| import { currentSafe } from 'src/logic/safe/store/selectors' | ||
| import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' | ||
|
|
||
| import { useStyles } from './style' | ||
| import { EstimationStatus, useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas' | ||
| import { useEstimationStatus } from 'src/logic/hooks/useEstimationStatus' | ||
| import { TransactionFees } from 'src/components/TransactionsFees' | ||
| import { TxParametersDetail } from 'src/routes/safe/components/Transactions/helpers/TxParametersDetail' | ||
| import { EditableTxParameters } from 'src/routes/safe/components/Transactions/helpers/EditableTxParameters' | ||
| import { TxParameters } from 'src/routes/safe/container/hooks/useTransactionParameters' | ||
| import { getRemoveGuardTxData } from 'src/logic/safe/utils/guardManager' | ||
| import { Errors, logError } from 'src/logic/exceptions/CodedException' | ||
|
|
||
| interface RemoveGuardModalProps { | ||
| onClose: () => void | ||
| guardAddress: string | ||
| } | ||
|
|
||
| export const RemoveGuardModal = ({ onClose, guardAddress }: RemoveGuardModalProps): ReactElement => { | ||
| const classes = useStyles() | ||
|
|
||
| const { address: safeAddress, currentVersion: safeVersion } = useSelector(currentSafe) | ||
| const dispatch = useDispatch() | ||
| const [manualSafeTxGas, setManualSafeTxGas] = useState(0) | ||
| const [manualGasPrice, setManualGasPrice] = useState<string | undefined>() | ||
| const [manualGasLimit, setManualGasLimit] = useState<string | undefined>() | ||
|
|
||
| const txData = useMemo(() => getRemoveGuardTxData(safeAddress, safeVersion), [safeAddress, safeVersion]) | ||
|
|
||
| const { | ||
| gasCostFormatted, | ||
| txEstimationExecutionStatus, | ||
| isExecution, | ||
| isOffChainSignature, | ||
| isCreation, | ||
| gasLimit, | ||
| gasEstimation, | ||
| gasPriceFormatted, | ||
| } = useEstimateTransactionGas({ | ||
| txData, | ||
| txRecipient: safeAddress, | ||
| txAmount: '0', | ||
| safeTxGas: manualSafeTxGas, | ||
| manualGasPrice, | ||
| manualGasLimit, | ||
| }) | ||
|
|
||
| const [buttonStatus] = useEstimationStatus(txEstimationExecutionStatus) | ||
|
|
||
| const removeTransactionGuard = async (txParameters: TxParameters): Promise<void> => { | ||
| try { | ||
| dispatch( | ||
| createTransaction({ | ||
| safeAddress, | ||
| to: safeAddress, | ||
| valueInWei: '0', | ||
| txData, | ||
| txNonce: txParameters.safeNonce, | ||
| safeTxGas: txParameters.safeTxGas ? Number(txParameters.safeTxGas) : undefined, | ||
| ethParameters: txParameters, | ||
| notifiedTransaction: TX_NOTIFICATION_TYPES.SETTINGS_CHANGE_TX, | ||
| }), | ||
| ) | ||
| } catch (e) { | ||
| logError(Errors._807, `${guardAddress} – ${e.message}`) | ||
| } | ||
| } | ||
|
|
||
| const closeEditModalCallback = (txParameters: TxParameters) => { | ||
| const oldGasPrice = Number(gasPriceFormatted) | ||
| const newGasPrice = Number(txParameters.ethGasPrice) | ||
| const oldSafeTxGas = Number(gasEstimation) | ||
| const newSafeTxGas = Number(txParameters.safeTxGas) | ||
|
|
||
| if (newGasPrice && oldGasPrice !== newGasPrice) { | ||
| setManualGasPrice(txParameters.ethGasPrice) | ||
| } | ||
|
|
||
| if (txParameters.ethGasLimit && gasLimit !== txParameters.ethGasLimit) { | ||
| setManualGasLimit(txParameters.ethGasLimit) | ||
| } | ||
|
|
||
| if (newSafeTxGas && oldSafeTxGas !== newSafeTxGas) { | ||
| setManualSafeTxGas(newSafeTxGas) | ||
| } | ||
| } | ||
|
|
||
| let confirmButtonText = 'Remove' | ||
| if (ButtonStatus.LOADING === buttonStatus) { | ||
| confirmButtonText = txEstimationExecutionStatus === EstimationStatus.LOADING ? 'Estimating' : 'Removing' | ||
| } | ||
|
|
||
| return ( | ||
| <Modal | ||
| description="Remove the selected Transaction Guard" | ||
| handleClose={onClose} | ||
| paperClassName="modal" | ||
| title="Remove Transaction Guard" | ||
| open | ||
| > | ||
| <EditableTxParameters | ||
| isOffChainSignature={isOffChainSignature} | ||
| isExecution={isExecution} | ||
| ethGasLimit={gasLimit} | ||
| ethGasPrice={gasPriceFormatted} | ||
| safeTxGas={gasEstimation.toString()} | ||
| closeEditModalCallback={closeEditModalCallback} | ||
| > | ||
| {(txParameters, toggleEditMode) => { | ||
| return ( | ||
| <> | ||
| <Row align="center" className={classes.modalHeading} grow> | ||
| <Paragraph className={classes.modalManage} noMargin weight="bolder"> | ||
| Remove Transaction Guard | ||
| </Paragraph> | ||
| <IconButton disableRipple onClick={onClose}> | ||
| <Close className={classes.modalClose} /> | ||
| </IconButton> | ||
| </Row> | ||
| <Hairline /> | ||
| <Block> | ||
| <Row className={classes.modalOwner}> | ||
| <Col align="center" xs={1}> | ||
| <EthHashInfo | ||
| hash={guardAddress} | ||
| showCopyBtn | ||
| showAvatar | ||
| explorerUrl={getExplorerInfo(guardAddress)} | ||
| /> | ||
| </Col> | ||
| </Row> | ||
| <Row className={classes.modalDescription}> | ||
| <Paragraph noMargin size="lg"> | ||
| Once the transaction guard has been removed, checks by the transaction guard will not be conducted | ||
| before or after any subsequent transactions. | ||
| </Paragraph> | ||
| </Row> | ||
| </Block> | ||
| <Block className={classes.accordionContainer}> | ||
| {/* Tx Parameters */} | ||
| <TxParametersDetail | ||
| txParameters={txParameters} | ||
| onEdit={toggleEditMode} | ||
| isTransactionCreation={isCreation} | ||
| isTransactionExecution={isExecution} | ||
| isOffChainSignature={isOffChainSignature} | ||
| /> | ||
| </Block> | ||
| <Row className={cn(classes.modalDescription, classes.gasCostsContainer)}> | ||
| <TransactionFees | ||
| gasCostFormatted={gasCostFormatted} | ||
| isExecution={isExecution} | ||
| isCreation={isCreation} | ||
| isOffChainSignature={isOffChainSignature} | ||
| txEstimationExecutionStatus={txEstimationExecutionStatus} | ||
| /> | ||
| </Row> | ||
| <GenericModal.Footer withoutBorder={buttonStatus !== ButtonStatus.LOADING}> | ||
| <GenericModal.Footer.Buttons | ||
| cancelButtonProps={{ onClick: onClose }} | ||
| confirmButtonProps={{ | ||
| color: 'error', | ||
| onClick: () => removeTransactionGuard(txParameters), | ||
| status: buttonStatus, | ||
| text: confirmButtonText, | ||
| }} | ||
| /> | ||
| </GenericModal.Footer> | ||
| </> | ||
| ) | ||
| }} | ||
| </EditableTxParameters> | ||
| </Modal> | ||
| ) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
src/routes/safe/components/Settings/Advanced/TransactionGuard.tsx
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| import { Icon, EthHashInfo } from '@gnosis.pm/safe-react-components' | ||
| import TableContainer from '@material-ui/core/TableContainer' | ||
| import cn from 'classnames' | ||
| import React from 'react' | ||
| import { useSelector } from 'react-redux' | ||
|
|
||
| import { generateColumns } from './dataFetcher' | ||
| import { RemoveGuardModal } from './RemoveGuardModal' | ||
| import { useStyles } from './style' | ||
|
juampibermani marked this conversation as resolved.
|
||
|
|
||
| import ButtonHelper from 'src/components/ButtonHelper' | ||
| import { grantedSelector } from 'src/routes/safe/container/selector' | ||
| import Table from 'src/components/Table' | ||
| import { TableCell, TableRow } from 'src/components/layout/Table' | ||
| import Block from 'src/components/layout/Block' | ||
| import Row from 'src/components/layout/Row' | ||
| import { getExplorerInfo } from 'src/config' | ||
|
|
||
| const REMOVE_GUARD_BTN_TEST_ID = 'remove-guard-btn' | ||
| const GUARDS_ROW_TEST_ID = 'guards-row' | ||
|
|
||
| interface TransactionGuardProps { | ||
| address: string | ||
| } | ||
|
|
||
| export const TransactionGuard = ({ address }: TransactionGuardProps): React.ReactElement => { | ||
| const classes = useStyles() | ||
|
|
||
| const columns = generateColumns() | ||
| const autoColumns = columns.filter(({ custom }) => !custom) | ||
|
|
||
| const granted = useSelector(grantedSelector) | ||
|
|
||
| const [viewRemoveGuardModal, setViewRemoveGuardModal] = React.useState(false) | ||
| const hideRemoveGuardModal = () => setViewRemoveGuardModal(false) | ||
|
|
||
| const triggerRemoveSelectedGuard = (): void => { | ||
| setViewRemoveGuardModal(true) | ||
| } | ||
|
|
||
| return ( | ||
| <> | ||
|
mmv08 marked this conversation as resolved.
|
||
| <TableContainer> | ||
| <Table columns={columns} data={[address]} defaultFixed disablePagination label="Modules" noBorder> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it was written on the ticket, but we don't really need a table there. It makes things complicated. There's only one transaction guard per safe, so it will always use 1 row. This is not required, but you can think about how we can remove it if you want. |
||
| {(sortedData) => | ||
| sortedData.map((row, index) => ( | ||
| <TableRow | ||
| className={cn(classes.hide, index >= 3 && index === sortedData.size - 1 && classes.noBorderBottom)} | ||
| data-testid={GUARDS_ROW_TEST_ID} | ||
| key={index} | ||
| tabIndex={-1} | ||
| > | ||
| {autoColumns.map((column, index) => { | ||
| const columnId = column.id | ||
| return ( | ||
| <React.Fragment key={`${columnId}-${index}`}> | ||
| <TableCell align={column.align} component="td" key={columnId}> | ||
| <Block justify="left"> | ||
| <EthHashInfo hash={row} showCopyBtn showAvatar explorerUrl={getExplorerInfo(row)} /> | ||
| </Block> | ||
| </TableCell> | ||
| <TableCell component="td"> | ||
| <Row align="end" className={classes.actions}> | ||
| {granted && ( | ||
| <ButtonHelper onClick={triggerRemoveSelectedGuard} data-testid={REMOVE_GUARD_BTN_TEST_ID}> | ||
| <Icon size="sm" type="delete" color="error" tooltip="Remove module" /> | ||
| </ButtonHelper> | ||
| )} | ||
| </Row> | ||
| </TableCell> | ||
| </React.Fragment> | ||
| ) | ||
| })} | ||
| </TableRow> | ||
| )) | ||
| } | ||
| </Table> | ||
| </TableContainer> | ||
| {viewRemoveGuardModal && address && <RemoveGuardModal onClose={hideRemoveGuardModal} guardAddress={address} />} | ||
| </> | ||
| ) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a lot of code duplication from the Review modal. For this PR it's fine but we should definitely think of a way to reuse the same code for tx popups.