send transaction for threshold = 1

This commit is contained in:
Mikhail Mikheev 2019-05-24 17:26:38 +04:00
parent 051f26aa76
commit 7a8a69b528
5 changed files with 168 additions and 89 deletions

View File

@ -1,4 +1,5 @@
// @flow // @flow
export * from './gas' export * from './gas'
export * from './send'
export * from './safeBlockchainOperations' export * from './safeBlockchainOperations'
export * from './safeTxSignerEIP712' export * from './safeTxSignerEIP712'

View File

@ -54,89 +54,89 @@ export const approveTransaction = async (
return txHash return txHash
} }
export const executeTransaction = async ( // export const executeTransaction = async (
safeAddress: string, // safeAddress: string,
to: string, // to: string,
valueInWei: number, // valueInWei: number,
data: string, // data: string,
operation: Operation, // operation: Operation,
nonce: number, // nonce: number,
sender: string, // sender: string,
ownersWhoHasSigned: List<string>, // ownersWhoHasSigned: List<string>,
) => { // ) => {
const gasPrice = await calculateGasPrice() // const gasPrice = await calculateGasPrice()
if (signaturesViaMetamask()) { // if (signaturesViaMetamask()) {
const safe = await getSafeEthereumInstance(safeAddress) // const safe = await getSafeEthereumInstance(safeAddress)
const txGasEstimate = await generateTxGasEstimateFrom(safe, safeAddress, data, to, valueInWei, operation) // const txGasEstimate = await generateTxGasEstimateFrom(safe, safeAddress, data, to, valueInWei, operation)
const signature = await generateMetamaskSignature( // const signature = await generateMetamaskSignature(
safe, // safe,
safeAddress, // safeAddress,
sender, // sender,
to, // to,
valueInWei, // valueInWei,
nonce, // nonce,
data, // data,
operation, // operation,
txGasEstimate, // txGasEstimate,
) // )
storeSignature(safeAddress, nonce, signature) // storeSignature(safeAddress, nonce, signature)
const sigs = getSignaturesFrom(safeAddress, nonce) // const sigs = getSignaturesFrom(safeAddress, nonce)
const threshold = await safe.getThreshold() // const threshold = await safe.getThreshold()
const gas = await estimateDataGas( // const gas = await estimateDataGas(
safe, // safe,
to, // to,
valueInWei, // valueInWei,
data, // data,
operation, // operation,
txGasEstimate, // txGasEstimate,
0, // 0,
nonce, // nonce,
Number(threshold), // Number(threshold),
0, // 0,
) // )
const numOwners = await safe.getOwners() // const numOwners = await safe.getOwners()
const gasIncludingRemovingStoreUpfront = gas + txGasEstimate + numOwners.length * 15000 // const gasIncludingRemovingStoreUpfront = gas + txGasEstimate + numOwners.length * 15000
const txReceipt = await safe.execTransaction( // const txReceipt = await safe.execTransaction(
to, // to,
valueInWei, // valueInWei,
data, // data,
operation, // operation,
txGasEstimate, // txGasEstimate,
0, // dataGasEstimate // 0, // dataGasEstimate
0, // gasPrice // 0, // gasPrice
0, // txGasToken // 0, // txGasToken
0, // refundReceiver // 0, // refundReceiver
sigs, // sigs,
{ from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice }, // { from: sender, gas: gasIncludingRemovingStoreUpfront, gasPrice },
) // )
const txHash = txReceipt.tx // const txHash = txReceipt.tx
await checkReceiptStatus(txHash) // 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
} // }
const gnosisSafe = await getSafeEthereumInstance(safeAddress) // const gnosisSafe = await getSafeEthereumInstance(safeAddress)
const signatures = buildSignaturesFrom(ownersWhoHasSigned, sender) // const signatures = buildSignaturesFrom(ownersWhoHasSigned, sender)
const txExecutionData = gnosisSafe.contract.methods // const txExecutionData = gnosisSafe.contract.methods
.execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures) // .execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures)
.encodeABI() // .encodeABI()
const gas = await calculateGasOf(txExecutionData, sender, safeAddress) // const gas = await calculateGasOf(txExecutionData, sender, safeAddress)
const numOwners = await gnosisSafe.getOwners() // const numOwners = await gnosisSafe.getOwners()
const gasIncludingRemovingStoreUpfront = gas + numOwners.length * 15000 // const gasIncludingRemovingStoreUpfront = gas + numOwners.length * 15000
const txReceipt = await gnosisSafe.execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures, { // const txReceipt = await gnosisSafe.execTransaction(to, valueInWei, data, operation, 0, 0, 0, 0, 0, signatures, {
from: sender, // from: sender,
gas: gasIncludingRemovingStoreUpfront, // gas: gasIncludingRemovingStoreUpfront,
gasPrice, // gasPrice,
}) // })
const txHash = txReceipt.tx // const txHash = txReceipt.tx
await checkReceiptStatus(txHash) // 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
} // }

View File

@ -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
}

View File

@ -19,6 +19,7 @@ import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import ArrowDown from '../assets/arrow-down.svg' import ArrowDown from '../assets/arrow-down.svg'
import { secondary } from '~/theme/variables' import { secondary } from '~/theme/variables'
import { styles } from './style' import { styles } from './style'
import { createTransaction } from '~/logic/safe/transactions'
type Props = { type Props = {
onClose: () => void, onClose: () => void,
@ -97,8 +98,18 @@ const ReviewTx = ({
<Button className={classes.button} minWidth={140} onClick={onClickBack}> <Button className={classes.button} minWidth={140} onClick={onClickBack}>
Back Back
</Button> </Button>
<Button type="submit" className={classes.button} variant="contained" minWidth={140} color="primary"> <Button
Review type="submit"
className={classes.button}
onClick={async () => {
await createTransaction(safeAddress, tx.recipientAddress, tx.amount, tx.token)
onClose()
}}
variant="contained"
minWidth={140}
color="primary"
>
SUBMIT
</Button> </Button>
</Row> </Row>
</React.Fragment> </React.Fragment>

View File

@ -13671,7 +13671,7 @@ react-event-listener@^0.6.2:
prop-types "^15.6.0" prop-types "^15.6.0"
warning "^4.0.1" 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" version "2.0.4"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== 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: dependencies:
isexe "^2.0.0" 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: wide-align@^1.1.0:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"