From dc5a72b85a6dfe6d90f589e02a5b04aa5beb95ed Mon Sep 17 00:00:00 2001 From: Danil Kovtonyuk Date: Fri, 27 May 2022 00:04:27 +1000 Subject: [PATCH] fix: calculate optimism l1 fee --- abis/OvmGasPriceOracle.abi.json | 151 ++++++++++++++++++++++++++ components/withdraw/WithdrawTotal.vue | 5 +- constants/variables.js | 5 + networkConfig.js | 1 + store/application.js | 24 +++- store/gasPrices.js | 59 +++++++++- 6 files changed, 235 insertions(+), 10 deletions(-) create mode 100644 abis/OvmGasPriceOracle.abi.json diff --git a/abis/OvmGasPriceOracle.abi.json b/abis/OvmGasPriceOracle.abi.json new file mode 100644 index 0000000..8f239ad --- /dev/null +++ b/abis/OvmGasPriceOracle.abi.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/components/withdraw/WithdrawTotal.vue b/components/withdraw/WithdrawTotal.vue index c6bcd5f..f14d213 100644 --- a/components/withdraw/WithdrawTotal.vue +++ b/components/withdraw/WithdrawTotal.vue @@ -17,7 +17,7 @@
{{ $t('networkFee') }} - {{ networkFeeInEth }} {{ networkCurrency }} + {{ toDecimals(networkFee, null, 6) }} {{ networkCurrency }}
{{ $t('relayerFee') }} @@ -76,9 +76,6 @@ export default { ...mapGetters('token', ['toDecimals', 'fromDecimals']), ...mapGetters('application', ['networkFee']), ...mapGetters('price', ['tokenRate']), - networkFeeInEth() { - return fromWei(this.networkFee) - }, relayerFee() { const { amount } = this.selectedStatistic const total = toBN(this.fromDecimals(amount.toString())) diff --git a/constants/variables.js b/constants/variables.js index 5b96108..e2868b0 100644 --- a/constants/variables.js +++ b/constants/variables.js @@ -87,3 +87,8 @@ export const trees = { PARTS_COUNT: 4, LEVELS: 20 // const from contract } + +export const DUMMY_NONCE = '0x1111111111111111111111111111111111111111111111111111111111111111' + +export const DUMMY_WITHDRAW_DATA = + '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111' diff --git a/networkConfig.js b/networkConfig.js index 2811513..3364c47 100644 --- a/networkConfig.js +++ b/networkConfig.js @@ -249,6 +249,7 @@ export default { deployedBlock: 2243689, multicall: '0x35A6Cdb2C9AD4a45112df4a04147EB07dFA01aB7', echoContractAccount: '0xa75BF2815618872f155b7C4B0C81bF990f5245E4', + ovmGasPriceOracleContract: '0x420000000000000000000000000000000000000F', rpcUrls: { Alchemy: { name: 'Alchemy', diff --git a/store/application.js b/store/application.js index 7529ffb..3475410 100644 --- a/store/application.js +++ b/store/application.js @@ -148,19 +148,18 @@ const getters = { currentContract: (state, getters) => (params) => { return getters.tornadoProxyContract(params) }, - withdrawGas: (state, getters, rootState, rootGetters) => { - const netId = rootGetters['metamask/netId'] + withdrawGas: (state, getters) => { let action = ACTION.WITHDRAW_WITH_EXTRA if (getters.hasEnabledLightProxy) { action = ACTION.WITHDRAW } - if (Number(netId) === 10) { + if (getters.isOptimismConnected) { action = ACTION.OP_WITHDRAW } - if (Number(netId) === 42161) { + if (getters.isArbitrumConnected) { action = ACTION.ARB_WITHDRAW } @@ -169,7 +168,14 @@ const getters = { networkFee: (state, getters, rootState, rootGetters) => { const gasPrice = rootGetters['gasPrices/fastGasPrice'] - return toBN(gasPrice).mul(toBN(getters.withdrawGas)) + const networkFee = toBN(gasPrice).mul(toBN(getters.withdrawGas)) + + if (getters.isOptimismConnected) { + const l1Fee = rootGetters['gasPrices/l1Fee'] + return networkFee.add(toBN(l1Fee)) + } + + return networkFee }, relayerFee: (state, getters, rootState, rootGetters) => { const { currency, amount } = rootState.application.selectedStatistic @@ -245,6 +251,14 @@ const getters = { }, hasEnabledLightProxy: (state, getters, rootState, rootGetters) => { return Boolean(rootGetters['metamask/networkConfig']['tornado-proxy-light.contract.tornadocash.eth']) + }, + isOptimismConnected: (state, getters, rootState, rootGetters) => { + const netId = rootGetters['metamask/netId'] + return Number(netId) === 10 + }, + isArbitrumConnected: (state, getters, rootState, rootGetters) => { + const netId = rootGetters['metamask/netId'] + return Number(netId) === 42161 } } diff --git a/store/gasPrices.js b/store/gasPrices.js index cc76e86..025e7cb 100644 --- a/store/gasPrices.js +++ b/store/gasPrices.js @@ -1,7 +1,13 @@ /* eslint-disable no-console */ +import Web3 from 'web3' import { GasPriceOracle } from 'gas-price-oracle' +import { serialize } from '@ethersproject/transactions' import { toHex, toWei, toBN, fromWei } from 'web3-utils' +import networkConfig from '@/networkConfig' +import OvmGasPriceOracleABI from '@/abis/OvmGasPriceOracle.abi.json' +import { DUMMY_NONCE, DUMMY_WITHDRAW_DATA } from '@/constants/variables' + export const state = () => { return { oracle: { @@ -31,11 +37,26 @@ export const state = () => { maxFeePerGas: 9, maxPriorityFeePerGas: 1 } - } + }, + l1Fee: '0' } } export const getters = { + ovmGasPriceOracleContract: (state, getters, rootState) => ({ netId }) => { + const config = networkConfig[`netId${netId}`] + const { url } = rootState.settings[`netId${netId}`].rpc + const address = config.ovmGasPriceOracleContract + if (address) { + const web3 = new Web3(url) + return new web3.eth.Contract(OvmGasPriceOracleABI, address) + } + + return null + }, + l1Fee: (state) => { + return state.l1Fee + }, oracle: (state, getters, rootState, rootGetters) => { const netId = Number(rootGetters['metamask/netId']) const { gasPrices } = rootGetters['metamask/networkConfig'] @@ -108,6 +129,9 @@ export const mutations = { this._vm.$set(state.eip, 'fast', fast) this._vm.$set(state.eip, 'standard', standard) this._vm.$set(state.eip, 'low', low) + }, + SAVE_L1_FEE(state, l1Fee) { + state.l1Fee = l1Fee } } @@ -124,6 +148,8 @@ export const actions = { commit('SAVE_ORACLE_GAS_PRICES', gas) } + await dispatch('fetchL1Fee') + setTimeout(() => dispatch('fetchGasPrice'), 1000 * pollInterval) } catch (e) { console.error('fetchGasPrice', e) @@ -187,5 +213,36 @@ export const actions = { setDefault({ commit, rootGetters }) { const { gasPrices } = rootGetters['metamask/networkConfig'] commit('SAVE_ORACLE_GAS_PRICES', gasPrices) + }, + async fetchL1Fee({ commit, getters, dispatch, rootGetters }) { + const netId = rootGetters['metamask/netId'] + const isOptimismConnected = rootGetters['application/isOptimismConnected'] + + const oracleInstance = getters.ovmGasPriceOracleContract({ netId }) + + if (isOptimismConnected && oracleInstance) { + try { + const gasLimit = rootGetters['application/withdrawGas'] + const tornadoProxyInstance = rootGetters['application/tornadoProxyContract']({ netId }) + + const gasPrice = getters.fastGasPrice + + const tx = serialize({ + type: 0, + gasLimit, + gasPrice, + chainId: netId, + nonce: DUMMY_NONCE, + data: DUMMY_WITHDRAW_DATA, + to: tornadoProxyInstance._address + }) + + const l1Fee = await oracleInstance.methods.getL1Fee(tx).call() + + commit('SAVE_L1_FEE', l1Fee) + } catch (err) { + console.error('fetchL1Fee has error:', err.message) + } + } } }