diff --git a/src/logic/safe/transactions/send.js b/src/logic/safe/transactions/send.js index 0381a7f5..c98bdf94 100644 --- a/src/logic/safe/transactions/send.js +++ b/src/logic/safe/transactions/send.js @@ -1,11 +1,12 @@ // @flow +import GnosisSafeSol from '@gnosis.pm/safe-contracts/build/contracts/GnosisSafe.json' import { getWeb3 } from '~/logic/wallets/getWeb3' import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens' import { EMPTY_DATA } from '~/logic/wallets/ethTransactions' import { isEther } from '~/logic/tokens/utils/tokenHelpers' import { type Token } from '~/logic/tokens/store/model/token' import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts' -import { type Operation, saveTxToHistory } from '~/logic/safe/transactions' +import { type Operation } from '~/logic/safe/transactions' import { ZERO_ADDRESS } from '~/logic/wallets/ethAddresses' import { getErrorMessage } from '~/test/utils/ethereumErrors' @@ -13,7 +14,7 @@ export const CALL = 0 export const TX_TYPE_EXECUTION = 'execution' export const TX_TYPE_CONFIRMATION = 'confirmation' -export const approveTransaction = async ( +export const getApprovalTransaction = async ( safeInstance: any, to: string, valueInWei: number | string, @@ -22,7 +23,7 @@ export const approveTransaction = async ( nonce: number, sender: string, ) => { - const contractTxHash = await safeInstance.getTransactionHash( + const txHash = await safeInstance.getTransactionHash( to, valueInWei, data, @@ -37,24 +38,23 @@ export const approveTransaction = async ( from: sender, }, ) - const receipt = await safeInstance.approveHash(contractTxHash, { from: sender }) - await saveTxToHistory( - safeInstance, - to, - valueInWei, - data, - operation, - nonce, - receipt.tx, // tx hash, - sender, - TX_TYPE_CONFIRMATION, - ) + try { + const web3 = getWeb3() + const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address) - return receipt + return contract.methods.approveHash(txHash) + } catch (error) { + /* eslint-disable */ + const executeData = safeInstance.contract.methods.approveHash(txHash).encodeABI() + const errMsg = await getErrorMessage(safeInstance.address, 0, executeData, sender) + console.log(`Error executing the TX: ${errMsg}`) + + throw error + } } -export const executeTransaction = async ( +export const getExecutionTransaction = async ( safeInstance: any, to: string, valueInWei: number | string, @@ -75,33 +75,10 @@ export const executeTransaction = async ( } try { - const receipt = await safeInstance.execTransaction( - to, - valueInWei, - data, - operation, - 0, - 0, - 0, - ZERO_ADDRESS, - ZERO_ADDRESS, - sigs, - { from: sender }, - ) + const web3 = getWeb3() + const contract = new web3.eth.Contract(GnosisSafeSol.abi, safeInstance.address) - await saveTxToHistory( - safeInstance, - to, - valueInWei, - data, - operation, - nonce, - receipt.tx, // tx hash, - sender, - TX_TYPE_EXECUTION, - ) - - return receipt + return contract.methods.execTransaction(to, valueInWei, data, operation, 0, 0, 0, ZERO_ADDRESS, ZERO_ADDRESS, sigs) } catch (error) { /* eslint-disable */ const executeDataUsedSignatures = safeInstance.contract.methods diff --git a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/index.jsx b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/index.jsx index 27705bf2..02b9037e 100644 --- a/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/index.jsx +++ b/src/routes/safe/components/Settings/ManageOwners/ReplaceOwnerModal/index.jsx @@ -36,8 +36,6 @@ export const sendReplaceOwner = async ( values: Object, safeAddress: string, ownerAddressToRemove: string, - ownerNameToRemove: string, - ownersOld: List, openSnackbar: Function, createTransaction: Function, replaceSafeOwner: Function, @@ -109,8 +107,6 @@ const ReplaceOwner = ({ values, safeAddress, ownerAddress, - ownerName, - owners, openSnackbar, createTransaction, replaceSafeOwner, diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx index b4123640..70fbfe14 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/index.jsx @@ -13,7 +13,8 @@ export const TRANSACTIONS_DESC_ADD_OWNER_TEST_ID = 'tx-description-add-owner' export const TRANSACTIONS_DESC_REMOVE_OWNER_TEST_ID = 'tx-description-remove-owner' export const TRANSACTIONS_DESC_CHANGE_THRESHOLD_TEST_ID = 'tx-description-change-threshold' export const TRANSACTIONS_DESC_SEND_TEST_ID = 'tx-description-send' -export const TRANSACTIONS_DESC_CUSTOM_TEST_ID = 'tx-description-custom' +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 styles = () => ({ txDataContainer: { @@ -42,6 +43,8 @@ type DescriptionDescProps = { } type CustomDescProps = { + value: string, + recipient: string, data: String, classes: Obeject, } @@ -88,9 +91,24 @@ const SettingsDescription = ({ removedOwner, addedOwner, newThreshold }: Descrip ) -const CustomDescription = ({ data, classes }: CustomDescProps) => ( +const CustomDescription = ({ + data, value = 0, recipient, classes, +}: CustomDescProps) => ( <> - + + + Send + {' '} + {value} + {' '} + ETH + {' '} + to: + +
+ +
+ Data (hex encoded):
{data} @@ -109,7 +127,7 @@ const TxDescription = ({ tx, classes }: Props) => { )} {customTx && ( - + )} {!cancellationTx && !modifySettingsTx && !customTx && ( diff --git a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js index affddad6..a55c986a 100644 --- a/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js +++ b/src/routes/safe/components/Transactions/TxsTable/ExpandedTx/TxDescription/utils.js @@ -23,6 +23,11 @@ export const getTxData = (tx: Transaction): DecodedTxData => { if (tx.isTokenTransfer && tx.decodedParams) { txData.recipient = tx.decodedParams.recipient txData.value = fromWei(toBN(tx.decodedParams.value), 'ether') + } else if (tx.customTx) { + txData.recipient = tx.recipient + txData.value = fromWei(toBN(tx.value), 'ether') + txData.data = tx.data + txData.customTx = true } else if (Number(tx.value) > 0) { txData.recipient = tx.recipient txData.value = fromWei(toBN(tx.value), 'ether') @@ -49,9 +54,6 @@ export const getTxData = (tx: Transaction): DecodedTxData => { } } else if (tx.cancellationTx) { txData.cancellationTx = true - } else if (tx.customTx) { - txData.data = tx.data - txData.customTx = true } return txData diff --git a/src/routes/safe/store/actions/createTransaction.js b/src/routes/safe/store/actions/createTransaction.js index 4d9359c5..9f9f573a 100644 --- a/src/routes/safe/store/actions/createTransaction.js +++ b/src/routes/safe/store/actions/createTransaction.js @@ -6,11 +6,14 @@ import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions' import { type GlobalState } from '~/store' import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts' import { - approveTransaction, - executeTransaction, + getApprovalTransaction, + getExecutionTransaction, CALL, type Notifications, DEFAULT_NOTIFICATIONS, + TX_TYPE_CONFIRMATION, + TX_TYPE_EXECUTION, + saveTxToHistory, } from '~/logic/safe/transactions' const createTransaction = ( @@ -31,18 +34,54 @@ const createTransaction = ( const isExecution = threshold.toNumber() === 1 || shouldExecute let txHash + let tx try { if (isExecution) { - openSnackbar(notifications.BEFORE_EXECUTION_OR_CREATION, 'success') - txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) - openSnackbar(notifications.AFTER_EXECUTION, 'success') + tx = await getExecutionTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) } else { - openSnackbar(notifications.BEFORE_EXECUTION_OR_CREATION, 'success') - txHash = await approveTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) - openSnackbar(notifications.CREATED_MORE_CONFIRMATIONS_NEEDED, 'success') + tx = await getApprovalTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) } + + const sendParams = { + from, + } + + // if not set owner management tests will fail on ganache + if (process.env.NODE_ENV === 'test') { + sendParams.gas = '7000000' + } + + await tx + .send(sendParams) + .once('transactionHash', (hash) => { + txHash = hash + openSnackbar(notifications.BEFORE_EXECUTION_OR_CREATION, 'success') + }) + .on('error', (error) => { + console.error('Tx error: ', error) + }) + .then(async (receipt) => { + await saveTxToHistory( + safeInstance, + to, + valueInWei, + txData, + CALL, + nonce, + receipt.transactionHash, + from, + isExecution ? TX_TYPE_EXECUTION : TX_TYPE_CONFIRMATION, + ) + + return receipt.transactionHash + }) + + openSnackbar( + isExecution ? notifications.AFTER_EXECUTION : notifications.CREATED_MORE_CONFIRMATIONS_NEEDED, + 'success', + ) } catch (err) { - openSnackbar(notifications.ERROR, '') + openSnackbar(notifications.ERROR, 'error') console.error(`Error while creating transaction: ${err}`) } diff --git a/src/routes/safe/store/actions/processTransaction.js b/src/routes/safe/store/actions/processTransaction.js index c30fd27c..010d62ef 100644 --- a/src/routes/safe/store/actions/processTransaction.js +++ b/src/routes/safe/store/actions/processTransaction.js @@ -5,7 +5,14 @@ import { userAccountSelector } from '~/logic/wallets/store/selectors' import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions' import { type GlobalState } from '~/store' import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts' -import { approveTransaction, executeTransaction, CALL } from '~/logic/safe/transactions' +import { + getApprovalTransaction, + getExecutionTransaction, + CALL, + saveTxToHistory, + TX_TYPE_EXECUTION, + TX_TYPE_CONFIRMATION, +} from '~/logic/safe/transactions' // https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures // https://github.com/gnosis/safe-contracts/blob/master/test/gnosisSafeTeamEdition.js#L26 @@ -45,16 +52,52 @@ const processTransaction = ( const sigs = generateSignaturesFromTxConfirmations(tx, approveAndExecute && userAddress) let txHash + let transaction if (shouldExecute) { - openSnackbar('Transaction has been submitted', 'success') - txHash = await executeTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from, sigs) - openSnackbar('Transaction has been confirmed', 'success') + transaction = await getExecutionTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from, sigs) } else { - openSnackbar('Approval transaction has been submitted', 'success') - txHash = await approveTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from) - openSnackbar('Approval transaction has been confirmed', 'success') + transaction = await getApprovalTransaction(safeInstance, tx.recipient, tx.value, tx.data, CALL, nonce, from) } + const sendParams = { + from, + } + + // if not set owner management tests will fail on ganache + if (process.env.NODE_ENV === 'test') { + sendParams.gas = '7000000' + } + + await transaction + .send(sendParams) + .once('transactionHash', (hash) => { + txHash = hash + openSnackbar( + shouldExecute ? 'Transaction has been submitted' : 'Approval transaction has been submitted', + 'success', + ) + }) + .on('error', (error) => { + console.error('Processing transaction error: ', error) + }) + .then(async (receipt) => { + await saveTxToHistory( + safeInstance, + tx.recipient, + tx.value, + tx.data, + CALL, + nonce, + receipt.transactionHash, + from, + shouldExecute ? TX_TYPE_EXECUTION : TX_TYPE_CONFIRMATION, + ) + + return receipt.transactionHash + }) + + openSnackbar(shouldExecute ? 'Transaction has been confirmed' : 'Approval transaction has been confirmed', 'success') + dispatch(fetchTransactions(safeAddress)) return txHash