diff --git a/src/logic/safe/transactions/index.js b/src/logic/safe/transactions/index.js index 4f54b80d..21061b39 100644 --- a/src/logic/safe/transactions/index.js +++ b/src/logic/safe/transactions/index.js @@ -1,4 +1,5 @@ // @flow export * from './gas' +export * from './send' export * from './safeBlockchainOperations' export * from './safeTxSignerEIP712' diff --git a/src/logic/safe/transactions/safeBlockchainOperations.js b/src/logic/safe/transactions/safeBlockchainOperations.js index ec6c5c4a..ca5abd5c 100644 --- a/src/logic/safe/transactions/safeBlockchainOperations.js +++ b/src/logic/safe/transactions/safeBlockchainOperations.js @@ -54,89 +54,89 @@ export const approveTransaction = async ( return txHash } -export const executeTransaction = async ( - safeAddress: string, - to: string, - valueInWei: number, - data: string, - operation: Operation, - nonce: number, - sender: string, - ownersWhoHasSigned: List, -) => { - const gasPrice = await calculateGasPrice() +// export const executeTransaction = async ( +// safeAddress: string, +// to: string, +// valueInWei: number, +// data: string, +// operation: Operation, +// nonce: number, +// sender: string, +// ownersWhoHasSigned: List, +// ) => { +// const gasPrice = await calculateGasPrice() - if (signaturesViaMetamask()) { - const safe = await getSafeEthereumInstance(safeAddress) - const txGasEstimate = await generateTxGasEstimateFrom(safe, safeAddress, data, to, valueInWei, operation) - const signature = await generateMetamaskSignature( - safe, - safeAddress, - sender, - to, - valueInWei, - nonce, - data, - operation, - txGasEstimate, - ) - storeSignature(safeAddress, nonce, signature) +// if (signaturesViaMetamask()) { +// const safe = await getSafeEthereumInstance(safeAddress) +// const txGasEstimate = await generateTxGasEstimateFrom(safe, safeAddress, data, to, valueInWei, operation) +// const signature = await generateMetamaskSignature( +// safe, +// safeAddress, +// sender, +// to, +// valueInWei, +// nonce, +// data, +// operation, +// txGasEstimate, +// ) +// storeSignature(safeAddress, nonce, signature) - const sigs = getSignaturesFrom(safeAddress, nonce) - const threshold = await safe.getThreshold() - const gas = await estimateDataGas( - safe, - to, - valueInWei, - data, - operation, - txGasEstimate, - 0, - nonce, - Number(threshold), - 0, - ) - const numOwners = await safe.getOwners() - const gasIncludingRemovingStoreUpfront = gas + txGasEstimate + numOwners.length * 15000 +// const sigs = getSignaturesFrom(safeAddress, nonce) +// const threshold = await safe.getThreshold() +// const gas = await estimateDataGas( +// safe, +// to, +// valueInWei, +// data, +// operation, +// txGasEstimate, +// 0, +// nonce, +// Number(threshold), +// 0, +// ) +// const numOwners = await safe.getOwners() +// const gasIncludingRemovingStoreUpfront = gas + txGasEstimate + numOwners.length * 15000 - const txReceipt = await safe.execTransaction( - to, - valueInWei, - data, - operation, - txGasEstimate, - 0, // dataGasEstimate - 0, // gasPrice - 0, // txGasToken - 0, // refundReceiver - sigs, - { from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice }, - ) +// const txReceipt = await safe.execTransaction( +// to, +// valueInWei, +// data, +// operation, +// txGasEstimate, +// 0, // dataGasEstimate +// 0, // gasPrice +// 0, // txGasToken +// 0, // refundReceiver +// sigs, +// { from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice }, +// ) - const txHash = txReceipt.tx - await checkReceiptStatus(txHash) - // await submitOperation(safeAddress, to, valueInWei, data, operation, nonce, txHash, sender, 'execution') +// const txHash = txReceipt.tx +// await checkReceiptStatus(txHash) +// // await submitOperation(safeAddress, to, valueInWei, data, operation, nonce, txHash, sender, 'execution') - return txHash - } +// return txHash +// } - const gnosisSafe = await getSafeEthereumInstance(safeAddress) - const signatures = buildSignaturesFrom(ownersWhoHasSigned, sender) - const txExecutionData = gnosisSafe.contract.methods - .execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures) - .encodeABI() - const gas = await calculateGasOf(txExecutionData, sender, safeAddress) - const numOwners = await gnosisSafe.getOwners() - const gasIncludingRemovingStoreUpfront = gas + numOwners.length * 15000 - const txReceipt = await gnosisSafe.execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures, { - from: sender, - gas: gasIncludingRemovingStoreUpfront, - gasPrice, - }) - const txHash = txReceipt.tx - await checkReceiptStatus(txHash) +// const gnosisSafe = await getSafeEthereumInstance(safeAddress) +// const signatures = buildSignaturesFrom(ownersWhoHasSigned, sender) +// const txExecutionData = gnosisSafe.contract.methods +// .execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures) +// .encodeABI() +// const gas = await calculateGasOf(txExecutionData, sender, safeAddress) +// const numOwners = await gnosisSafe.getOwners() +// const gasIncludingRemovingStoreUpfront = gas + numOwners.length * 15000 +// const txReceipt = await gnosisSafe.execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures, { +// from: sender, +// gas: gasIncludingRemovingStoreUpfront, +// gasPrice, +// }) +// const txHash = txReceipt.tx +// await checkReceiptStatus(txHash) - await submitOperation(safeAddress, to, valueInWei, data, operation, nonce, txHash, sender, 'execution') +// await submitOperation(safeAddress, to, valueInWei, data, operation, nonce, txHash, sender, 'execution') - return txHash -} +// return txHash +// } diff --git a/src/logic/safe/transactions/send.js b/src/logic/safe/transactions/send.js new file mode 100644 index 00000000..563a8fd5 --- /dev/null +++ b/src/logic/safe/transactions/send.js @@ -0,0 +1,75 @@ +// @flow +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 { getSafeEthereumInstance } from '../safeFrontendOperations' + +const CALL = 0 +const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' + +export const executeTransaction = async ( + safeInstance: any, + to: string, + valueInWei: number, + data: string, + operation: number | string, + nonce: string | number, + sender: string, +) => { + try { + // https://gnosis-safe.readthedocs.io/en/latest/contracts/signatures.html#pre-validated-signatures + const sigs = `0x000000000000000000000000${sender.replace( + '0x', + '', + )}000000000000000000000000000000000000000000000000000000000000000001` + + const tx = await safeInstance.execTransaction( + to, + valueInWei, + data, + CALL, + 0, + 0, + 0, + ZERO_ADDRESS, + ZERO_ADDRESS, + sigs, + { from: sender }, + ) + + return tx + } catch (error) { + // eslint-disable-next-line + console.log('Error calculating tx gas estimation ' + error) + return 0 + } +} + +export const createTransaction = async (safeAddress: string, to: string, valueInEth: string, token: Token) => { + const safeInstance = await getSafeEthereumInstance(safeAddress) + const web3 = getWeb3() + const from = web3.currentProvider.selectedAddress + const threshold = await safeInstance.getThreshold() + const nonce = await safeInstance.nonce() + const valueInWei = web3.utils.toWei(valueInEth, 'ether') + const isExecution = threshold.toNumber() === 1 + + let txData = EMPTY_DATA + if (!isEther(token.symbol)) { + const StandardToken = await getStandardTokenContract() + const sendToken = await StandardToken.at(token.address) + + txData = sendToken.contract.transfer(to, valueInWei).encodeABI() + } + + let txHash + if (isExecution) { + txHash = await executeTransaction(safeInstance, to, valueInWei, txData, CALL, nonce, from) + } else { + // txHash = await approveTransaction(safeAddress, to, valueInWei, txData, CALL, nonce) + } + + return txHash +} diff --git a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx index aa5f1c55..447985c8 100644 --- a/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx +++ b/src/routes/safe/components/Balances/SendModal/screens/ReviewTx/index.jsx @@ -19,6 +19,7 @@ import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils' import ArrowDown from '../assets/arrow-down.svg' import { secondary } from '~/theme/variables' import { styles } from './style' +import { createTransaction } from '~/logic/safe/transactions' type Props = { onClose: () => void, @@ -97,8 +98,18 @@ const ReviewTx = ({ - diff --git a/yarn.lock b/yarn.lock index 6a7177cd..bcaaa370 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13671,7 +13671,7 @@ react-event-listener@^0.6.2: prop-types "^15.6.0" warning "^4.0.1" -react-fast-compare@^2.0.2, react-fast-compare@^2.0.3: +react-fast-compare@^2.0.2: version "2.0.4" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== @@ -18371,14 +18371,6 @@ which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: dependencies: isexe "^2.0.0" -why-did-you-update@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/why-did-you-update/-/why-did-you-update-1.0.6.tgz#2e2c6a04291e715755ecdff1ac8272f721df6f04" - integrity sha512-XVrdHhdrPBDuSW8b/uH6DCb1/0984qv8KElpE8NZiRvWZX8nw49av577+ZyIrxSNesi6r2cQEhpxQTKFFHTj8A== - dependencies: - lodash "^4.17.11" - react-fast-compare "^2.0.3" - wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"