proper gas calculation

This commit is contained in:
Alexey 2019-11-15 12:01:59 +03:00
parent 5352bd5a55
commit db35a0cbcc
4 changed files with 46 additions and 31 deletions

View File

@ -3,3 +3,5 @@ RPC_URL=https://kovan.infura.io/v3/a3f4d001c1fc4a359ea70dd27fd9cb51
PRIVATE_KEY= PRIVATE_KEY=
ETH_MIXER_ADDRESS=0x1Cea940cA15a303A0E01B7F8589F39fF34308DB2 ETH_MIXER_ADDRESS=0x1Cea940cA15a303A0E01B7F8589F39fF34308DB2
DAI_MIXER_ADDRESS=0x7ed3fC8042e18db889A0466F49c438bB1410b3c7 DAI_MIXER_ADDRESS=0x7ed3fC8042e18db889A0466F49c438bB1410b3c7
APP_PORT=8000

View File

@ -14,5 +14,6 @@ module.exports = {
} ], } ],
defaultGasPrice: 2, defaultGasPrice: 2,
gasOracleUrls: ['https://www.etherchain.org/api/gasPriceOracle', 'https://gasprice.poa.network/'], gasOracleUrls: ['https://www.etherchain.org/api/gasPriceOracle', 'https://gasprice.poa.network/'],
ethdaiAddress: '0x7Ef645705cb7D401C5CD91a395cfcc3Db3C93689' ethdaiAddress: '0x7Ef645705cb7D401C5CD91a395cfcc3Db3C93689',
port: process.env.APP_PORT
} }

View File

@ -1,6 +1,6 @@
const { numberToHex, toWei, toHex, toBN, toChecksumAddress } = require('web3-utils') const { numberToHex, toWei, toHex, toBN, toChecksumAddress } = require('web3-utils')
const { netId, rpcUrl, privateKey, mixers, defaultGasPrice } = require('./config') const { netId, rpcUrl, privateKey, mixers, defaultGasPrice, port } = require('./config')
const { fetchGasPrice, isValidProof, isValidArgs, fetchDAIprice, isKnownContract } = require('./utils') const { fetchGasPrice, isValidProof, isValidArgs, fetchDAIprice, isKnownContract, isEnoughFee } = require('./utils')
const Web3 = require('web3') const Web3 = require('web3')
const express = require('express') const express = require('express')
@ -70,32 +70,15 @@ app.post('/relay', async (req, resp) => {
toBN(args[5]) toBN(args[5])
] ]
if (currency === 'eth' && !refund.isZero()) {
return resp.status(400).json({ error: 'Cannot send refund for eth currency.' })
}
if (relayer !== web3.eth.defaultAccount) { if (relayer !== web3.eth.defaultAccount) {
console.log('This proof is for different relayer:', relayer) console.log('This proof is for different relayer:', relayer)
return resp.status(400).json({ error: 'Relayer address is invalid' }) return resp.status(400).json({ error: 'Relayer address is invalid' })
} }
const expense = toBN(toWei(gasPrices.fast.toString(), 'gwei')).mul(toBN('1000000'))
let desiredFee
switch (currency) {
case 'eth': {
if (!refund.isZero()) {
return resp.status(400).json({ error: 'Cannot send refund for eth currency.' })
}
desiredFee = expense
break
}
case 'dai': {
desiredFee = expense.add(refund).mul(toBN(ethPriceInDai)).div(toBN(10 ** 18))
break
}
}
if (fee.lt(desiredFee)) {
console.log('Fee is too low')
return resp.status(400).json({ error: 'Fee is too low. Try to resend.' })
}
try { try {
const mixer = new web3.eth.Contract(mixerABI, req.body.contract) const mixer = new web3.eth.Contract(mixerABI, req.body.contract)
const isSpent = await mixer.methods.isSpent(nullifierHash).call() const isSpent = await mixer.methods.isSpent(nullifierHash).call()
@ -106,6 +89,7 @@ app.post('/relay', async (req, resp) => {
if (!isKnownRoot) { if (!isKnownRoot) {
return resp.status(400).json({ error: 'The merkle root is too old or invalid.' }) return resp.status(400).json({ error: 'The merkle root is too old or invalid.' })
} }
const withdrawArgs = [ const withdrawArgs = [
proof, proof,
root, root,
@ -115,14 +99,23 @@ app.post('/relay', async (req, resp) => {
fee.toString(), fee.toString(),
refund.toString() refund.toString()
] ]
const gas = await mixer.methods.withdraw(...withdrawArgs).estimateGas({ let gas = await mixer.methods.withdraw(...withdrawArgs).estimateGas({
from: web3.eth.defaultAccount, from: web3.eth.defaultAccount,
value: refund value: refund
}) })
gas += 50000
const { isEnough, reason } = isEnoughFee({ gas, gasPrices, currency, refund, ethPriceInDai, fee })
if (!isEnough) {
console.log(`Wrong fee: ${reason}`)
return resp.status(400).json({ error: reason })
}
const result = mixer.methods.withdraw(...withdrawArgs).send({ const result = mixer.methods.withdraw(...withdrawArgs).send({
from: web3.eth.defaultAccount, from: web3.eth.defaultAccount,
value: refund, value: refund,
gas: numberToHex(gas + 50000), gas: numberToHex(gas),
gasPrice: toHex(toWei(gasPrices.fast.toString(), 'gwei')), gasPrice: toHex(toWei(gasPrices.fast.toString(), 'gwei')),
// TODO: nonce // TODO: nonce
}) })
@ -139,7 +132,7 @@ app.post('/relay', async (req, resp) => {
} }
}) })
app.listen(8000) app.listen(port || 8000)
if (Number(netId) === 1) { if (Number(netId) === 1) {
fetchGasPrice({ gasPrices }) fetchGasPrice({ gasPrices })
@ -147,7 +140,7 @@ if (Number(netId) === 1) {
console.log('Gas price oracle started.') console.log('Gas price oracle started.')
} }
console.log('Relayer started') console.log('Relayer started on port', port || 8000)
console.log(`relayerAddress: ${web3.eth.defaultAccount}`) console.log(`relayerAddress: ${web3.eth.defaultAccount}`)
console.log(`mixers: ${JSON.stringify(mixers)}`) console.log(`mixers: ${JSON.stringify(mixers)}`)
console.log(`gasPrices: ${JSON.stringify(gasPrices)}`) console.log(`gasPrices: ${JSON.stringify(gasPrices)}`)

View File

@ -1,5 +1,5 @@
const fetch = require('node-fetch') const fetch = require('node-fetch')
const { isHexStrict, hexToNumberString } = require('web3-utils') const { isHexStrict, hexToNumberString, toBN, toWei } = require('web3-utils')
const { gasOracleUrls, ethdaiAddress, mixers } = require('./config') const { gasOracleUrls, ethdaiAddress, mixers } = require('./config')
const oracleABI = require('./abis/ETHDAIOracle.json') const oracleABI = require('./abis/ETHDAIOracle.json')
@ -97,4 +97,23 @@ function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms)) return new Promise(resolve => setTimeout(resolve, ms))
} }
module.exports = { fetchGasPrice, isValidProof, isValidArgs, sleep, fetchDAIprice, isKnownContract } function isEnoughFee({ gas, gasPrices, currency, refund, ethPriceInDai, fee }) {
const expense = toBN(toWei(gasPrices.fast.toString(), 'gwei')).mul(toBN(gas))
let desiredFee
switch (currency) {
case 'eth': {
desiredFee = expense
break
}
case 'dai': {
desiredFee = expense.add(refund).mul(toBN(ethPriceInDai)).div(toBN(10 ** 18))
break
}
}
if (fee.lt(desiredFee)) {
return { isEnough: false, reason: 'Not enough fee' }
}
return { isEnough: true }
}
module.exports = { fetchGasPrice, isValidProof, isValidArgs, sleep, fetchDAIprice, isKnownContract, isEnoughFee }