diff --git a/src/components/Notifier/index.js b/src/components/Notifier/index.js index c4a9fd10..009afe0a 100644 --- a/src/components/Notifier/index.js +++ b/src/components/Notifier/index.js @@ -1,11 +1,17 @@ // @flow -import React, { Component } from 'react' +import { Component } from 'react' +import { List } from 'immutable' import { connect } from 'react-redux' import { withSnackbar } from 'notistack' -import actions from './actions' +import { type Notification } from '~/logic/notifications/store/models/notification' +import actions, {type Actions } from './actions' import selector from './selector' -class Notifier extends Component { +type Props = Actions & { + notifications: List, +} + +class Notifier extends Component { displayed = [] shouldComponentUpdate({ notifications: newSnacks = [] }) { diff --git a/src/logic/notifications/store/reducer/notifications.js b/src/logic/notifications/store/reducer/notifications.js index c4ae1c2b..d16e0c0c 100644 --- a/src/logic/notifications/store/reducer/notifications.js +++ b/src/logic/notifications/store/reducer/notifications.js @@ -29,7 +29,5 @@ export default handleActions( return state.delete(key) }, }, - Map({ - notifications: Map(), - }), + Map(), ) diff --git a/src/logic/notifications/store/selectors/index.js b/src/logic/notifications/store/selectors/index.js index 2ae6eb96..bf6371fa 100644 --- a/src/logic/notifications/store/selectors/index.js +++ b/src/logic/notifications/store/selectors/index.js @@ -5,7 +5,7 @@ import { type GlobalState } from '~/store' import { NOTIFICATIONS_REDUCER_ID } from '~/logic/notifications/store/reducer/notifications' import { type Notification } from '~/logic/notifications/store/models/notification' -export const notificationsMapSelector = ( +const notificationsMapSelector = ( state: GlobalState, ): Map => state[NOTIFICATIONS_REDUCER_ID] diff --git a/src/logic/safe/transactions/gasNew.js b/src/logic/safe/transactions/gasNew.js index df804488..da8db6a5 100644 --- a/src/logic/safe/transactions/gasNew.js +++ b/src/logic/safe/transactions/gasNew.js @@ -1,16 +1,17 @@ // @flow import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json' +import { List } from 'immutable' +import { type Confirmation } from '~/routes/safe/store/models/confirmation' import { getWeb3, getAccountFrom } from '~/logic/wallets/getWeb3' import { calculateGasOf, calculateGasPrice } from '~/logic/wallets/ethTransactions' import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses' -import { type Transaction } from '~/routes/safe/store/models/transaction' import { CALL } from '.' export const estimateTxGasCosts = async ( safeAddress: string, to: string, data: string, - tx?: Transaction, + confirmations?: List, ): Promise => { try { const web3 = getWeb3() @@ -19,12 +20,12 @@ export const estimateTxGasCosts = async ( const nonce = await safeInstance.methods.nonce().call() const threshold = await safeInstance.methods.getThreshold().call() - const isExecution = (tx && tx.confirmations.size) || threshold === '1' + const isExecution = (confirmations && confirmations.size) || threshold === '1' let txData if (isExecution) { // https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures - const signatures = tx + const signatures = confirmations || `0x000000000000000000000000${from.replace( '0x', '', diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx index b4e12d7d..d470fd98 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/ApproveTxModal/index.jsx @@ -1,5 +1,5 @@ // @flow -import React, { useState } from 'react' +import React, { useState, useEffect } from 'react' import Close from '@material-ui/icons/Close' import IconButton from '@material-ui/core/IconButton' import { withStyles } from '@material-ui/core/styles' @@ -13,6 +13,9 @@ import Row from '~/components/layout/Row' import Bold from '~/components/layout/Bold' import Block from '~/components/layout/Block' import Paragraph from '~/components/layout/Paragraph' +import { getWeb3 } from '~/logic/wallets/getWeb3' +import { estimateTxGasCosts } from '~/logic/safe/transactions/gasNew' +import { formatAmount } from '~/logic/tokens/utils/formatAmount' import { TX_NOTIFICATION_TYPES } from '~/logic/safe/transactions' import { type Transaction } from '~/routes/safe/store/models/transaction' import { styles } from './style' @@ -62,9 +65,32 @@ const ApproveTxModal = ({ closeSnackbar, }: Props) => { const [approveAndExecute, setApproveAndExecute] = useState(true) + const [gasCosts, setGasCosts] = useState('< 0.001') const { title, description } = getModalTitleAndDescription(thresholdReached) const oneConfirmationLeft = tx.confirmations.size + 1 === threshold + useEffect(() => { + let isCurrent = true + + const estimateGas = async () => { + const web3 = getWeb3() + const { fromWei, toBN } = web3.utils + + const estimatedGasCosts = await estimateTxGasCosts(safeAddress, tx.recipient, tx.data, tx.confirmations) + const gasCostsAsEth = fromWei(toBN(estimatedGasCosts), 'ether') + const formattedGasCosts = formatAmount(gasCostsAsEth) + if (isCurrent) { + setGasCosts(formattedGasCosts) + } + } + + estimateGas() + + return () => { + isCurrent = false + } + }, [approveAndExecute]) + const handleExecuteCheckbox = () => setApproveAndExecute((prevApproveAndExecute) => !prevApproveAndExecute) const approveTx = () => { @@ -112,6 +138,11 @@ const ApproveTxModal = ({ )} + + + {`You're about to ${approveAndExecute ? 'execute' : 'approve'} a transaction and will have to confirm it with your currently connected wallet. Make sure you have ${gasCosts} (fee price) ETH in this wallet to fund this confirmation.`} + +