diff --git a/abis/ovmGasPriceOracleABI.json b/abis/ovmGasPriceOracleABI.json new file mode 100644 index 0000000..8f239ad --- /dev/null +++ b/abis/ovmGasPriceOracleABI.json @@ -0,0 +1,151 @@ +[ + { + "inputs": [{ "internalType": "address", "name": "_owner", "type": "address" }], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "DecimalsUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "GasPriceUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "L1BaseFeeUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "OverheadUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, + { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [{ "indexed": false, "internalType": "uint256", "name": "", "type": "uint256" }], + "name": "ScalarUpdated", + "type": "event" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "gasPrice", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }], + "name": "getL1Fee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "bytes", "name": "_data", "type": "bytes" }], + "name": "getL1GasUsed", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "l1BaseFee", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "overhead", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [{ "internalType": "address", "name": "", "type": "address" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "scalar", + "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_decimals", "type": "uint256" }], + "name": "setDecimals", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_gasPrice", "type": "uint256" }], + "name": "setGasPrice", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_baseFee", "type": "uint256" }], + "name": "setL1BaseFee", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_overhead", "type": "uint256" }], + "name": "setOverhead", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "uint256", "name": "_scalar", "type": "uint256" }], + "name": "setScalar", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/package.json b/package.json index 4f47bea..d67c6de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "relay", - "version": "5.0.0-beta.11", + "version": "5.0.0-beta.12", "description": "Relayer for Tornado.cash privacy solution. https://tornado.cash", "scripts": { "server": "node src/server.js", diff --git a/src/worker.js b/src/worker.js index 691991f..674b463 100644 --- a/src/worker.js +++ b/src/worker.js @@ -1,8 +1,10 @@ const Web3 = require('web3') const { GasPriceOracle } = require('gas-price-oracle') +const { serialize } = require('@ethersproject/transactions') const { toBN, toWei, fromWei, toHex } = require('web3-utils') const { redis } = require('./modules/redis') const proxyLightABI = require('../abis/proxyLightABI.json') +const ovmGasPriceOracleABI = require('../abis/ovmGasPriceOracleABI.json') const { queue } = require('./queue') const { getInstance, fromDecimals, logRelayerError, clearRelayerErrors } = require('./utils') const { jobType, status } = require('./constants') @@ -22,10 +24,12 @@ let currentTx let currentJob let txManager let gasPriceOracle +let tornadoProxyInstance function start() { try { web3 = new Web3(httpRpcUrl) + tornadoProxyInstance = new web3.eth.Contract(proxyLightABI, proxyLight) clearRelayerErrors(redis) const { CONFIRMATIONS, MAX_GAS_PRICE } = process.env const gasPriceOracleConfig = { @@ -72,13 +76,44 @@ function getGasLimit() { return gasLimits[action] } -async function checkTornadoFee({ args, contract }) { - const { amount, decimals } = getInstance(contract) - const fee = toBN(args[4]) +async function getL1Fee({ data, gasPrice }) { + const { address } = web3.eth.accounts.privateKeyToAccount(privateKey) + const nonce = await web3.eth.getTransactionCount(address) + + const ovmGasPriceOracleContract = '0x420000000000000000000000000000000000000F' + const oracleInstance = new web3.eth.Contract(ovmGasPriceOracleABI, ovmGasPriceOracleContract) + + const calldata = tornadoProxyInstance.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI() + + const tx = serialize({ + nonce, + type: 0, + data: calldata, + chainId: netId, + value: data.args[5], + to: tornadoProxyInstance._address, + gasLimit: getGasLimit(), + gasPrice: toHex(gasPrice), + }) + + const l1Fee = await oracleInstance.methods.getL1Fee(tx).call() + + return l1Fee +} + +async function checkTornadoFee({ data }) { + const fee = toBN(data.args[4]) + const { amount, decimals } = getInstance(data.contract) const { fast } = await getGasPrices() + const gasPrice = toWei(fast.toString(), 'gwei') + + let expense = toBN(gasPrice).mul(toBN(getGasLimit())) + if (netId === 10) { + const l1Fee = await getL1Fee({ data, gasPrice }) + expense = expense.add(toBN(l1Fee)) + } - const expense = toBN(toWei(fast.toString(), 'gwei')).mul(toBN(getGasLimit())) const feePercent = toBN(fromDecimals(amount, decimals)) .mul(toBN(parseInt(tornadoServiceFee * 1e10))) .div(toBN(1e10 * 100)) @@ -96,15 +131,13 @@ async function checkTornadoFee({ args, contract }) { } async function getTxObject({ data }) { - const contract = new web3.eth.Contract(proxyLightABI, proxyLight) - - const calldata = contract.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI() + const calldata = tornadoProxyInstance.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI() const { fast } = await getGasPrices() return { value: data.args[5], - to: contract._address, + to: tornadoProxyInstance._address, data: calldata, gasLimit: getGasLimit(), gasPrice: toHex(toWei(fast.toString(), 'gwei')), @@ -128,7 +161,7 @@ async function processJob(job) { } async function submitTx(job) { - await checkTornadoFee(job.data) + await checkTornadoFee(job) currentTx = await txManager.createTx(await getTxObject(job)) try {