(Fix) - Calculates gas for SpendingLimit transactions (#1773)

* Bug: Use link tag instead of javascript navigation in apps list (#1770)

* Use list instead of programmable navigation

* add declaration for styled-components theme

* (Fix) - Calculates gas for SpendingLimit transactions (#1773)

* Calculates gas for spendingLimit transactions

* Adds TransactionFees component inside UpdateSafeModal

* Fix send collectible gas calculation

Co-authored-by: Mikhail Mikheev <mmvsha73@gmail.com>
This commit is contained in:
Agustin Pane 2021-01-14 08:36:55 -03:00 committed by GitHub
parent 8a774f2e66
commit 10f1891f8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 82 additions and 34 deletions

View File

@ -21,6 +21,7 @@ import { List } from 'immutable'
import { Confirmation } from 'src/logic/safe/store/models/types/confirmation' import { Confirmation } from 'src/logic/safe/store/models/types/confirmation'
import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner' import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner'
import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses'
import { sameString } from 'src/utils/strings'
export enum EstimationStatus { export enum EstimationStatus {
LOADING = 'LOADING', LOADING = 'LOADING',
@ -28,13 +29,19 @@ export enum EstimationStatus {
SUCCESS = 'SUCCESS', SUCCESS = 'SUCCESS',
} }
const checkIfTxIsExecution = (threshold: number, preApprovingOwner?: string, txConfirmations?: number): boolean => const checkIfTxIsExecution = (
txConfirmations === threshold || !!preApprovingOwner || threshold === 1 threshold: number,
preApprovingOwner?: string,
txConfirmations?: number,
txType?: string,
): boolean =>
txConfirmations === threshold || !!preApprovingOwner || threshold === 1 || sameString(txType, 'spendingLimit')
const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number): boolean => const checkIfTxIsApproveAndExecution = (threshold: number, txConfirmations: number, txType?: string): boolean =>
txConfirmations + 1 === threshold txConfirmations + 1 === threshold || sameString(txType, 'spendingLimit')
const checkIfTxIsCreation = (txConfirmations: number): boolean => txConfirmations === 0 const checkIfTxIsCreation = (txConfirmations: number, txType?: string): boolean =>
txConfirmations === 0 && !sameString(txType, 'spendingLimit')
type TransactionEstimationProps = { type TransactionEstimationProps = {
txData: string txData: string
@ -115,6 +122,7 @@ type UseEstimateTransactionGasProps = {
preApprovingOwner?: string preApprovingOwner?: string
operation?: number operation?: number
safeTxGas?: number safeTxGas?: number
txType?: string
} }
type TransactionGasEstimationResult = { type TransactionGasEstimationResult = {
@ -136,6 +144,7 @@ export const useEstimateTransactionGas = ({
preApprovingOwner, preApprovingOwner,
operation, operation,
safeTxGas, safeTxGas,
txType,
}: UseEstimateTransactionGasProps): TransactionGasEstimationResult => { }: UseEstimateTransactionGasProps): TransactionGasEstimationResult => {
const [gasEstimation, setGasEstimation] = useState<TransactionGasEstimationResult>({ const [gasEstimation, setGasEstimation] = useState<TransactionGasEstimationResult>({
txEstimationExecutionStatus: EstimationStatus.LOADING, txEstimationExecutionStatus: EstimationStatus.LOADING,
@ -159,9 +168,9 @@ export const useEstimateTransactionGas = ({
return return
} }
const isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size) const isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size, txType)
const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0) const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0, txType)
const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0) const approvalAndExecution = checkIfTxIsApproveAndExecution(Number(threshold), txConfirmations?.size || 0, txType)
try { try {
const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion) const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion)
@ -235,6 +244,7 @@ export const useEstimateTransactionGas = ({
safeVersion, safeVersion,
smartContractWallet, smartContractWallet,
safeTxGas, safeTxGas,
txType,
]) ])
return gasEstimation return gasEstimation

View File

@ -6,7 +6,6 @@ import {
SAFE_MASTER_COPY_ADDRESS, SAFE_MASTER_COPY_ADDRESS,
getGnosisSafeInstanceAt, getGnosisSafeInstanceAt,
} from 'src/logic/contracts/safeContracts' } from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
import { getWeb3 } from 'src/logic/wallets/getWeb3' import { getWeb3 } from 'src/logic/wallets/getWeb3'
import { MultiSend } from 'src/types/contracts/MultiSend.d' import { MultiSend } from 'src/types/contracts/MultiSend.d'
@ -49,7 +48,7 @@ export const getEncodedMultiSendCallData = (txs: MultiSendTx[], web3: Web3): str
return encodedMultiSendCallData return encodedMultiSendCallData
} }
export const upgradeSafeToLatestVersion = async (safeAddress: string, createTransaction): Promise<void> => { export const getUpgradeSafeTransactionHash = async (safeAddress: string): Promise<string> => {
const safeInstance = await getGnosisSafeInstanceAt(safeAddress) const safeInstance = await getGnosisSafeInstanceAt(safeAddress)
const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI() const fallbackHandlerTxData = safeInstance.methods.setFallbackHandler(DEFAULT_FALLBACK_HANDLER_ADDRESS).encodeABI()
const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI() const updateSafeTxData = safeInstance.methods.changeMasterCopy(SAFE_MASTER_COPY_ADDRESS).encodeABI()
@ -69,17 +68,5 @@ export const upgradeSafeToLatestVersion = async (safeAddress: string, createTran
] ]
const web3 = getWeb3() const web3 = getWeb3()
const encodeMultiSendCallData = getEncodedMultiSendCallData(txs, web3) return getEncodedMultiSendCallData(txs, web3)
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: 0,
txData: encodeMultiSendCallData,
notifiedTransaction: 'STANDARD_TX',
enqueueSnackbar: () => {},
closeSnackbar: () => {},
operation: DELEGATE_CALL,
})
return
} }

View File

@ -64,7 +64,7 @@ const ReviewCollectible = ({ onClose, onPrev, tx }: Props): React.ReactElement =
isCreation, isCreation,
} = useEstimateTransactionGas({ } = useEstimateTransactionGas({
txData: data, txData: data,
txRecipient: tx.recipientAddress, txRecipient: tx.assetAddress,
}) })
useEffect(() => { useEffect(() => {

View File

@ -120,6 +120,7 @@ const ReviewTx = ({ onClose, onPrev, tx }: ReviewTxProps): React.ReactElement =>
} = useEstimateTransactionGas({ } = useEstimateTransactionGas({
txData: data, txData: data,
txRecipient, txRecipient,
txType: tx.txType,
}) })
const submitTx = async () => { const submitTx = async () => {

View File

@ -19,7 +19,7 @@ import enqueueSnackbar from 'src/logic/notifications/store/actions/enqueueSnackb
import { getNotificationsFromTxType, enhanceSnackbarForAction } from 'src/logic/notifications' import { getNotificationsFromTxType, enhanceSnackbarForAction } from 'src/logic/notifications'
import { sameAddress } from 'src/logic/wallets/ethAddresses' import { sameAddress } from 'src/logic/wallets/ethAddresses'
import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions' import { TX_NOTIFICATION_TYPES } from 'src/logic/safe/transactions'
import UpdateSafeModal from 'src/routes/safe/components/Settings/UpdateSafeModal' import { UpdateSafeModal } from 'src/routes/safe/components/Settings/UpdateSafeModal'
import { grantedSelector } from 'src/routes/safe/container/selector' import { grantedSelector } from 'src/routes/safe/container/selector'
import updateSafe from 'src/logic/safe/store/actions/updateSafe' import updateSafe from 'src/logic/safe/store/actions/updateSafe'
import Link from 'src/components/layout/Link' import Link from 'src/components/layout/Link'

View File

@ -1,9 +1,7 @@
import IconButton from '@material-ui/core/IconButton' import IconButton from '@material-ui/core/IconButton'
import Close from '@material-ui/icons/Close' import Close from '@material-ui/icons/Close'
import { withStyles } from '@material-ui/styles' import React, { useEffect, useState } from 'react'
import React from 'react'
import { useDispatch } from 'react-redux' import { useDispatch } from 'react-redux'
import { bindActionCreators } from 'redux'
import { styles } from './style' import { styles } from './style'
@ -13,17 +11,61 @@ import Button from 'src/components/layout/Button'
import Hairline from 'src/components/layout/Hairline' import Hairline from 'src/components/layout/Hairline'
import Paragraph from 'src/components/layout/Paragraph' import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { upgradeSafeToLatestVersion } from 'src/logic/safe/utils/upgradeSafe' import { getUpgradeSafeTransactionHash } from 'src/logic/safe/utils/upgradeSafe'
import createTransaction from 'src/logic/safe/store/actions/createTransaction' import createTransaction from 'src/logic/safe/store/actions/createTransaction'
import { makeStyles } from '@material-ui/core'
import { TransactionFees } from 'src/components/TransactionsFees'
import { useEstimateTransactionGas } from 'src/logic/hooks/useEstimateTransactionGas'
import { MULTI_SEND_ADDRESS } from 'src/logic/contracts/safeContracts'
import { DELEGATE_CALL } from 'src/logic/safe/transactions'
import { EMPTY_DATA } from 'src/logic/wallets/ethTransactions'
const UpdateSafeModal = ({ classes, onClose, safeAddress }) => { const useStyles = makeStyles(styles)
type Props = {
onClose: () => void
safeAddress: string
}
export const UpdateSafeModal = ({ onClose, safeAddress }: Props): React.ReactElement => {
const classes = useStyles()
const dispatch = useDispatch() const dispatch = useDispatch()
const [multiSendCallData, setMultiSendCallData] = useState(EMPTY_DATA)
useEffect(() => {
const calculateUpgradeSafeModal = async () => {
const encodeMultiSendCallData = await getUpgradeSafeTransactionHash(safeAddress)
setMultiSendCallData(encodeMultiSendCallData)
}
calculateUpgradeSafeModal()
}, [safeAddress])
const handleSubmit = async () => { const handleSubmit = async () => {
// Call the update safe method // Call the update safe method
await upgradeSafeToLatestVersion(safeAddress, bindActionCreators(createTransaction, dispatch)) dispatch(
createTransaction({
safeAddress,
to: MULTI_SEND_ADDRESS,
valueInWei: '0',
txData: multiSendCallData,
notifiedTransaction: 'STANDARD_TX',
operation: DELEGATE_CALL,
}),
)
onClose() onClose()
} }
const {
gasCostFormatted,
txEstimationExecutionStatus,
isExecution,
isCreation,
isOffChainSignature,
} = useEstimateTransactionGas({
txData: multiSendCallData,
txRecipient: safeAddress,
})
return ( return (
<> <>
<Row align="center" className={classes.heading} grow> <Row align="center" className={classes.heading} grow>
@ -56,6 +98,15 @@ const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
have to confirm the update in case more than one confirmation is required for this Safe. have to confirm the update in case more than one confirmation is required for this Safe.
</Paragraph> </Paragraph>
</Row> </Row>
<Row>
<TransactionFees
gasCostFormatted={gasCostFormatted}
isExecution={isExecution}
isCreation={isCreation}
isOffChainSignature={isOffChainSignature}
txEstimationExecutionStatus={txEstimationExecutionStatus}
/>
</Row>
</Block> </Block>
<Hairline style={{ position: 'absolute', bottom: 85 }} /> <Hairline style={{ position: 'absolute', bottom: 85 }} />
<Row align="center" className={classes.buttonRow}> <Row align="center" className={classes.buttonRow}>
@ -72,5 +123,3 @@ const UpdateSafeModal = ({ classes, onClose, safeAddress }) => {
</> </>
) )
} }
export default withStyles(styles as any)(UpdateSafeModal)

View File

@ -1,6 +1,7 @@
import { lg, md, secondaryText, sm } from 'src/theme/variables' import { lg, md, secondaryText, sm } from 'src/theme/variables'
import { createStyles } from '@material-ui/core'
export const styles = () => ({ export const styles = createStyles({
heading: { heading: {
padding: `${sm} ${lg}`, padding: `${sm} ${lg}`,
justifyContent: 'space-between', justifyContent: 'space-between',