diff --git a/src/components/ExecuteCheckbox/index.tsx b/src/components/ExecuteCheckbox/index.tsx index 127e832cec..3cdedee961 100644 --- a/src/components/ExecuteCheckbox/index.tsx +++ b/src/components/ExecuteCheckbox/index.tsx @@ -7,7 +7,7 @@ interface ExecuteCheckboxProps { onChange: (val: boolean) => unknown } -const ExecuteCheckbox = ({ onChange }: ExecuteCheckboxProps): ReactElement | null => { +const ExecuteCheckbox = ({ onChange }: ExecuteCheckboxProps): ReactElement => { const handleChange = (e: React.ChangeEvent): void => { onChange(e.target.checked) } diff --git a/src/components/ReviewInfoText/index.tsx b/src/components/ReviewInfoText/index.tsx index 2d7b57c1bc..c041b2a34b 100644 --- a/src/components/ReviewInfoText/index.tsx +++ b/src/components/ReviewInfoText/index.tsx @@ -9,14 +9,14 @@ import { lg, sm } from 'src/theme/variables' import { TransactionFees } from '../TransactionsFees' import { getRecommendedNonce } from 'src/logic/safe/api/fetchSafeTxGasEstimation' import { extractSafeAddress } from 'src/routes/routes' -import { useEffect, useState } from 'react' +import { ComponentProps, useEffect, useState } from 'react' type CustomReviewInfoTextProps = { safeNonce?: string testId?: string } -type ReviewInfoTextProps = Parameters[0] & CustomReviewInfoTextProps +type ReviewInfoTextProps = ComponentProps & CustomReviewInfoTextProps const ReviewInfoTextWrapper = styled.div` background-color: ${({ theme }) => theme.colors.background}; @@ -27,7 +27,6 @@ export const ReviewInfoText = ({ gasCostFormatted, isCreation, isExecution, - isOffChainSignature, safeNonce: txParamsSafeNonce = '', testId, txEstimationExecutionStatus, @@ -88,7 +87,6 @@ export const ReviewInfoText = ({ gasCostFormatted={gasCostFormatted} isCreation={isCreation} isExecution={isExecution} - isOffChainSignature={isOffChainSignature} txEstimationExecutionStatus={txEstimationExecutionStatus} /> )} diff --git a/src/components/TransactionsFees/index.tsx b/src/components/TransactionsFees/index.tsx index 3bffdb4887..79ca5aef3b 100644 --- a/src/components/TransactionsFees/index.tsx +++ b/src/components/TransactionsFees/index.tsx @@ -3,22 +3,30 @@ import Paragraph from 'src/components/layout/Paragraph' import { getNativeCurrency } from 'src/config' import { TransactionFailText } from 'src/components/TransactionFailText' import { Text } from '@gnosis.pm/safe-react-components' +import useCanTxExecute from 'src/logic/hooks/useCanTxExecute' +import { providerSelector } from 'src/logic/wallets/store/selectors' +import { useSelector } from 'react-redux' +import { currentSafe } from 'src/logic/safe/store/selectors' +import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner' type TransactionFailTextProps = { txEstimationExecutionStatus: EstimationStatus gasCostFormatted?: string isExecution: boolean isCreation: boolean - isOffChainSignature: boolean } export const TransactionFees = ({ gasCostFormatted, isExecution, isCreation, - isOffChainSignature, txEstimationExecutionStatus, }: TransactionFailTextProps): React.ReactElement | null => { + const { currentVersion: safeVersion } = useSelector(currentSafe) + const { smartContractWallet } = useSelector(providerSelector) + const canTxExecute = useCanTxExecute(isExecution) + const isOffChainSignature = checkIfOffChainSignatureIsPossible(canTxExecute, smartContractWallet, safeVersion) + const nativeCurrency = getNativeCurrency() let transactionAction if (txEstimationExecutionStatus === EstimationStatus.LOADING) { diff --git a/src/logic/hooks/__tests__/useCanTxExecute.test.ts b/src/logic/hooks/__tests__/useCanTxExecute.test.ts new file mode 100644 index 0000000000..9b4048cda0 --- /dev/null +++ b/src/logic/hooks/__tests__/useCanTxExecute.test.ts @@ -0,0 +1,191 @@ +import { calculateCanTxExecute } from '../useCanTxExecute' + +describe('useCanTxExecute tests', () => { + describe('calculateCanTxExecute tests', () => { + beforeEach(() => { + threshold = 1 + isExecution = false + currentSafeNonce = 8 + recommendedNonce = 8 + txConfirmations = 0 + preApprovingOwner = '' + manualSafeNonce = recommendedNonce + }) + // to be overriden as necessary + let threshold + let preApprovingOwner + let txConfirmations + let currentSafeNonce + let recommendedNonce + let isExecution + let manualSafeNonce + it(`should return true if isExecution`, () => { + // given + isExecution = true + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + isExecution, + ) + + // then + expect(result).toBe(true) + }) + it(`should return true if single owner and edited nonce is same as safeNonce`, () => { + // given + threshold = 1 + currentSafeNonce = 8 + recommendedNonce = 12 + manualSafeNonce = 8 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + undefined, + manualSafeNonce, + ) + + // then + expect(result).toBe(true) + }) + it(`should return false if single owner and edited nonce is different than safeNonce`, () => { + // given + threshold = 1 + currentSafeNonce = 8 + recommendedNonce = 8 + manualSafeNonce = 20 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + undefined, + manualSafeNonce, + ) + + // then + expect(result).toBe(false) + }) + it(`should return true if single owner and recommendedNonce is same as safeNonce`, () => { + // given + threshold = 1 + currentSafeNonce = 8 + recommendedNonce = 8 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + ) + + // then + expect(result).toBe(true) + }) + it(`should return false if single owner and recommendedNonce is greater than safeNonce and no edited nonce`, () => { + // given + threshold = 1 + currentSafeNonce = 8 + recommendedNonce = 11 + manualSafeNonce = undefined + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + undefined, + manualSafeNonce, + ) + + // then + expect(result).toBe(false) + }) + it(`should return false if single owner and recommendedNonce is different than safeNonce`, () => { + // given + threshold = 1 + currentSafeNonce = 8 + recommendedNonce = 12 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + ) + + // then + expect(result).toBe(false) + }) + it(`should return true if the safe threshold is reached for the transaction`, () => { + // given + threshold = 3 + txConfirmations = 3 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + ) + + // then + expect(result).toBe(true) + }) + it(`should return false if the number of confirmations does not meet the threshold and there is no preApprovingOwner`, () => { + // given + threshold = 5 + txConfirmations = 4 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + ) + + // then + expect(result).toBe(false) + }) + it(`should return true if the number of confirmations is one bellow the threshold but there is a preApprovingOwner`, () => { + // given + threshold = 5 + preApprovingOwner = '0x29B1b813b6e84654Ca698ef5d7808E154364900B' + txConfirmations = 4 + + // when + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + ) + + // then + expect(result).toBe(true) + }) + }) +}) diff --git a/src/logic/hooks/__tests__/useEstimateTransactionGas.test.ts b/src/logic/hooks/__tests__/useEstimateTransactionGas.test.ts index d7a613d7f3..5429e98497 100644 --- a/src/logic/hooks/__tests__/useEstimateTransactionGas.test.ts +++ b/src/logic/hooks/__tests__/useEstimateTransactionGas.test.ts @@ -1,77 +1,5 @@ -import { - checkIfTxIsApproveAndExecution, - checkIfTxIsCreation, - checkIfTxIsExecution, -} from 'src/logic/hooks/useEstimateTransactionGas' +import { checkIfTxIsApproveAndExecution, checkIfTxIsCreation } from 'src/logic/hooks/useEstimateTransactionGas' -describe('checkIfTxIsExecution', () => { - const mockedEthAccount = '0x29B1b813b6e84654Ca698ef5d7808E154364900B' - it(`should return true if the safe threshold is 1`, () => { - // given - const threshold = 1 - const preApprovingOwner = undefined - const transactionConfirmations = 0 - const transactionType = '' - - // when - const result = checkIfTxIsExecution(threshold, preApprovingOwner, transactionConfirmations, transactionType) - - // then - expect(result).toBe(true) - }) - it(`should return true if the safe threshold is reached for the transaction`, () => { - // given - const threshold = 3 - const preApprovingOwner = mockedEthAccount - const transactionConfirmations = 3 - const transactionType = '' - - // when - const result = checkIfTxIsExecution(threshold, preApprovingOwner, transactionConfirmations, transactionType) - - // then - expect(result).toBe(true) - }) - it(`should return true if the transaction is spendingLimit`, () => { - // given - const threshold = 5 - const preApprovingOwner = undefined - const transactionConfirmations = 0 - const transactionType = 'spendingLimit' - - // when - const result = checkIfTxIsExecution(threshold, preApprovingOwner, transactionConfirmations, transactionType) - - // then - expect(result).toBe(true) - }) - it(`should return true if the number of confirmations is one bellow the threshold but there is a preApprovingOwner`, () => { - // given - const threshold = 5 - const preApprovingOwner = mockedEthAccount - const transactionConfirmations = 4 - const transactionType = undefined - - // when - const result = checkIfTxIsExecution(threshold, preApprovingOwner, transactionConfirmations, transactionType) - - // then - expect(result).toBe(true) - }) - it(`should return false if the number of confirmations is one bellow the threshold and there is no preApprovingOwner`, () => { - // given - const threshold = 5 - const preApprovingOwner = undefined - const transactionConfirmations = 4 - const transactionType = undefined - - // when - const result = checkIfTxIsExecution(threshold, preApprovingOwner, transactionConfirmations, transactionType) - - // then - expect(result).toBe(false) - }) -}) describe('checkIfTxIsCreation', () => { it(`should return true if there are no confirmations for the transaction and the transaction is not spendingLimit`, () => { // given diff --git a/src/logic/hooks/useCanTxExecute.tsx b/src/logic/hooks/useCanTxExecute.tsx new file mode 100644 index 0000000000..2a48320a55 --- /dev/null +++ b/src/logic/hooks/useCanTxExecute.tsx @@ -0,0 +1,76 @@ +import { useEffect, useState } from 'react' +import { useSelector } from 'react-redux' +import { extractSafeAddress } from 'src/routes/routes' +import { currentSafe } from '../safe/store/selectors' +import useGetRecommendedNonce from './useGetRecommendedNonce' + +export const calculateCanTxExecute = ( + currentSafeNonce: number, + preApprovingOwner: string, + threshold: number, + txConfirmations: number, + recommendedNonce?: number, + isExecution?: boolean, // when executing from the TxList + manualSafeNonce?: number, +): boolean => { + if (isExecution) return true + + // Single owner + if (threshold === 1) { + // nonce was changed manually to be executed + if (manualSafeNonce) { + return manualSafeNonce === currentSafeNonce + } + // is next tx + return recommendedNonce === currentSafeNonce + } + + if (txConfirmations >= threshold) { + return true + } + + // When having a preApprovingOwner it is needed one less confirmation to execute the tx + if (preApprovingOwner && txConfirmations) { + return txConfirmations + 1 === threshold + } + + return false +} + +type UseCanTxExecuteType = ( + isExecution?: boolean, + manualSafeNonce?: number, + preApprovingOwner?: string, + txConfirmations?: number, +) => boolean + +const useCanTxExecute: UseCanTxExecuteType = ( + isExecution = false, + manualSafeNonce, + preApprovingOwner = '', + txConfirmations = 0, +) => { + const [canTxExecute, setCanTxExecute] = useState(false) + const { threshold } = useSelector(currentSafe) + + const safeAddress = extractSafeAddress() + const recommendedNonce = useGetRecommendedNonce(safeAddress) + const { nonce: currentSafeNonce } = useSelector(currentSafe) + + useEffect(() => { + const result = calculateCanTxExecute( + currentSafeNonce, + preApprovingOwner, + threshold, + txConfirmations, + recommendedNonce, + isExecution, + manualSafeNonce, + ) + setCanTxExecute(result) + }, [currentSafeNonce, preApprovingOwner, recommendedNonce, threshold, txConfirmations, isExecution, manualSafeNonce]) + + return canTxExecute +} + +export default useCanTxExecute diff --git a/src/logic/hooks/useEstimateTransactionGas.tsx b/src/logic/hooks/useEstimateTransactionGas.tsx index f305b52509..b5d5d20ee2 100644 --- a/src/logic/hooks/useEstimateTransactionGas.tsx +++ b/src/logic/hooks/useEstimateTransactionGas.tsx @@ -19,6 +19,7 @@ import { Confirmation } from 'src/logic/safe/store/models/types/confirmation' import { checkIfOffChainSignatureIsPossible } from 'src/logic/safe/safeTxSigner' import { ZERO_ADDRESS } from 'src/logic/wallets/ethAddresses' import { sameString } from 'src/utils/strings' +import useCanTxExecute from './useCanTxExecute' export enum EstimationStatus { LOADING = 'LOADING', @@ -26,27 +27,6 @@ export enum EstimationStatus { SUCCESS = 'SUCCESS', } -export const checkIfTxIsExecution = ( - threshold: number, - preApprovingOwner?: string, - txConfirmations?: number, - txType?: string, -): boolean => { - if ( - threshold === 1 || - sameString(txType, 'spendingLimit') || - (txConfirmations !== undefined && txConfirmations >= threshold) - ) { - return true - } - - if (preApprovingOwner && txConfirmations) { - return txConfirmations + 1 === threshold - } - - return false -} - export const checkIfTxIsApproveAndExecution = ( threshold: number, txConfirmations: number, @@ -78,6 +58,8 @@ type UseEstimateTransactionGasProps = { txType?: string manualGasPrice?: string manualGasLimit?: string + manualSafeNonce?: number // Edited nonce + isExecution?: boolean // If called from the TransactionList "next transaction" } export type TransactionGasEstimationResult = { @@ -88,7 +70,6 @@ export type TransactionGasEstimationResult = { gasPrice: string // Current price of gas unit gasPriceFormatted: string // Current gas price formatted gasLimit: string // Minimum gas requited to execute the Tx - isExecution: boolean // Returns true if the user will execute the tx or false if it just signs it isCreation: boolean // Returns true if the transaction is a creation transaction isOffChainSignature: boolean // Returns true if offChainSignature is available } @@ -97,7 +78,6 @@ const getDefaultGasEstimation = ( txEstimationExecutionStatus: EstimationStatus, gasPrice: string, gasPriceFormatted: string, - isExecution = false, isCreation = false, isOffChainSignature = false, ): TransactionGasEstimationResult => { @@ -109,7 +89,6 @@ const getDefaultGasEstimation = ( gasPrice, gasPriceFormatted, gasLimit: '0', - isExecution, isCreation, isOffChainSignature, } @@ -126,6 +105,8 @@ export const useEstimateTransactionGas = ({ txType, manualGasPrice, manualGasLimit, + manualSafeNonce, + isExecution, }: UseEstimateTransactionGasProps): TransactionGasEstimationResult => { const [gasEstimation, setGasEstimation] = useState( getDefaultGasEstimation(EstimationStatus.LOADING, '0', '0'), @@ -133,19 +114,19 @@ export const useEstimateTransactionGas = ({ const nativeCurrency = getNativeCurrency() const { address: safeAddress = '', threshold = 1, currentVersion: safeVersion = '' } = useSelector(currentSafe) ?? {} const { account: from, smartContractWallet, name: providerName } = useSelector(providerSelector) + + const canTxExecute = useCanTxExecute(isExecution, manualSafeNonce, preApprovingOwner, txConfirmations?.size) + useEffect(() => { const estimateGas = async () => { if (!txData.length) { return } - const isExecution = checkIfTxIsExecution(Number(threshold), preApprovingOwner, txConfirmations?.size, txType) - const isOffChainSignature = checkIfOffChainSignatureIsPossible(isExecution, smartContractWallet, safeVersion) + const isOffChainSignature = checkIfOffChainSignatureIsPossible(canTxExecute, smartContractWallet, safeVersion) const isCreation = checkIfTxIsCreation(txConfirmations?.size || 0, txType) if (isOffChainSignature && !isCreation) { - setGasEstimation( - getDefaultGasEstimation(EstimationStatus.SUCCESS, '1', '1', isExecution, isCreation, isOffChainSignature), - ) + setGasEstimation(getDefaultGasEstimation(EstimationStatus.SUCCESS, '1', '1', isCreation, isOffChainSignature)) return } const approvalAndExecution = checkIfTxIsApproveAndExecution( @@ -174,7 +155,7 @@ export const useEstimateTransactionGas = ({ ) } - if (isExecution || approvalAndExecution) { + if (canTxExecute || approvalAndExecution) { ethGasLimitEstimation = await estimateTransactionGasLimit({ safeAddress, safeVersion, @@ -182,8 +163,7 @@ export const useEstimateTransactionGas = ({ txData, txAmount: txAmount || '0', txConfirmations, - isExecution, - isOffChainSignature, + isExecution: canTxExecute, operation: operation || Operation.CALL, from, safeTxGas: safeTxGasEstimation, @@ -198,7 +178,7 @@ export const useEstimateTransactionGas = ({ const gasCost = fromTokenUnit(estimatedGasCosts, nativeCurrency.decimals) const gasCostFormatted = formatAmount(gasCost) - if (isExecution) { + if (canTxExecute) { transactionCallSuccess = await checkTransactionExecution({ safeAddress, safeVersion, @@ -227,7 +207,6 @@ export const useEstimateTransactionGas = ({ gasPrice, gasPriceFormatted, gasLimit, - isExecution, isCreation, isOffChainSignature, }) @@ -257,6 +236,8 @@ export const useEstimateTransactionGas = ({ providerName, manualGasPrice, manualGasLimit, + manualSafeNonce, + canTxExecute, ]) return gasEstimation diff --git a/src/logic/hooks/useGetRecommendedNonce.tsx b/src/logic/hooks/useGetRecommendedNonce.tsx new file mode 100644 index 0000000000..af08fd512b --- /dev/null +++ b/src/logic/hooks/useGetRecommendedNonce.tsx @@ -0,0 +1,40 @@ +import { SafeTransactionEstimation } from '@gnosis.pm/safe-react-gateway-sdk' +import { useEffect, useState } from 'react' +import { useSelector } from 'react-redux' +import { getRecommendedNonce } from '../safe/api/fetchSafeTxGasEstimation' +import { getLastTxNonce } from '../safe/store/selectors/gatewayTransactions' + +type UseGetRecommendedNonce = (safeAddress: string) => number | undefined + +const useGetRecommendedNonce: UseGetRecommendedNonce = (safeAddress) => { + const lastTxNonce = useSelector(getLastTxNonce) + const storeNextNonce = lastTxNonce ? lastTxNonce + 1 : undefined + + const [recommendedNonce, setRecommendedNonce] = useState(storeNextNonce) + + useEffect(() => { + let isCurrent = true + + const fetchRecommendedNonce = async () => { + let recommendedNonce: SafeTransactionEstimation['recommendedNonce'] + try { + recommendedNonce = await getRecommendedNonce(safeAddress) + } catch (e) { + return + } + + if (isCurrent) { + setRecommendedNonce(recommendedNonce) + } + } + fetchRecommendedNonce() + + return () => { + isCurrent = false + } + }, [lastTxNonce, safeAddress]) + + return recommendedNonce +} + +export default useGetRecommendedNonce diff --git a/src/logic/safe/transactions/gas.ts b/src/logic/safe/transactions/gas.ts index eb0a76f26b..0f613d7545 100644 --- a/src/logic/safe/transactions/gas.ts +++ b/src/logic/safe/transactions/gas.ts @@ -74,7 +74,6 @@ export const estimateTransactionGasLimit = async ({ safeTxGas, from, isExecution, - isOffChainSignature = false, approvalAndExecution, }: TransactionEstimationProps): Promise => { if (!from) { @@ -107,7 +106,6 @@ export const estimateTransactionGasLimit = async ({ txAmount, txRecipient, from, - isOffChainSignature, }) } @@ -195,7 +193,6 @@ type TransactionApprovalEstimationProps = { txData: string operation: number from: string - isOffChainSignature: boolean } export const estimateGasForTransactionApproval = async ({ @@ -206,12 +203,7 @@ export const estimateGasForTransactionApproval = async ({ txData, operation, from, - isOffChainSignature, }: TransactionApprovalEstimationProps): Promise => { - if (isOffChainSignature) { - return 0 - } - const safeInstance = getGnosisSafeInstanceAt(safeAddress, safeVersion) const nonce = await safeInstance.methods.nonce().call() diff --git a/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx b/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx index 1d53f50c2e..bdd5d5df1f 100644 --- a/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx +++ b/src/routes/safe/components/Apps/components/ConfirmTxModal/ReviewConfirm.tsx @@ -31,6 +31,7 @@ import { ReviewInfoText } from 'src/components/ReviewInfoText' import { ConfirmTxModalProps, DecodedTxDetail } from '.' import { grantedSelector } from 'src/routes/safe/container/selector' import ExecuteCheckbox from 'src/components/ExecuteCheckbox' +import useCanTxExecute from 'src/logic/hooks/useCanTxExecute' const Container = styled.div` max-width: 480px; @@ -102,6 +103,7 @@ export const ReviewConfirm = ({ const [manualSafeTxGas, setManualSafeTxGas] = useState('0') const [manualGasPrice, setManualGasPrice] = useState() const [manualGasLimit, setManualGasLimit] = useState() + const [manualSafeNonce, setManualSafeNonce] = useState() const { gasLimit, @@ -109,7 +111,6 @@ export const ReviewConfirm = ({ gasEstimation, isOffChainSignature, isCreation, - isExecution, gasCostFormatted, txEstimationExecutionStatus, } = useEstimateTransactionGas({ @@ -120,11 +121,13 @@ export const ReviewConfirm = ({ safeTxGas: manualSafeTxGas, manualGasPrice, manualGasLimit, + manualSafeNonce, }) const [buttonStatus, setButtonStatus] = useEstimationStatus(txEstimationExecutionStatus) - const [executionApproved, setExecutionApproved] = useState(true) - const doExecute = isExecution && executionApproved + const [shouldExecute, setShouldExecute] = useState(true) + const canTxExecute = useCanTxExecute(false, manualSafeNonce) + const willExecute = canTxExecute && shouldExecute // Decode tx data. useEffect(() => { @@ -158,7 +161,7 @@ export const ReviewConfirm = ({ safeTxGas: txParameters.safeTxGas, ethParameters: txParameters, notifiedTransaction: TX_NOTIFICATION_TYPES.STANDARD_TX, - delayExecution: !executionApproved, + delayExecution: !shouldExecute, }, handleUserConfirmation, onReject, @@ -173,6 +176,7 @@ export const ReviewConfirm = ({ const newGasPrice = txParameters.ethGasPrice const oldSafeTxGas = gasEstimation const newSafeTxGas = txParameters.safeTxGas + const newSafeNonce = txParameters.safeNonce if (newGasPrice && oldGasPrice !== newGasPrice) { setManualGasPrice(txParameters.ethGasPrice) @@ -185,6 +189,11 @@ export const ReviewConfirm = ({ if (newSafeTxGas && oldSafeTxGas !== newSafeTxGas) { setManualSafeTxGas(newSafeTxGas) } + + if (newSafeNonce) { + const newSafeNonceNumber = parseInt(newSafeNonce, 10) + setManualSafeNonce(newSafeNonceNumber) + } } return ( @@ -194,7 +203,7 @@ export const ReviewConfirm = ({ safeTxGas={Math.max(parseInt(gasEstimation), params?.safeTxGas || 0).toString()} closeEditModalCallback={closeEditModalCallback} isOffChainSignature={isOffChainSignature} - isExecution={doExecute} + isExecution={willExecute} > {(txParameters, toggleEditMode) => (