Rename 'gasPrices' scope to 'fees', and use it to estimate all network withdrawal fee

This commit is contained in:
Theo 2023-08-22 09:23:18 -07:00
parent d9ae37ebb2
commit d16449bcf8
11 changed files with 86 additions and 501 deletions

View File

@ -1,181 +0,0 @@
[
{
"inputs": [
{ "internalType": "contract MultiWrapper", "name": "_multiWrapper", "type": "address" },
{ "internalType": "contract IOracle[]", "name": "existingOracles", "type": "address[]" },
{ "internalType": "enum OffchainOracle.OracleType[]", "name": "oracleTypes", "type": "uint8[]" },
{ "internalType": "contract IERC20[]", "name": "existingConnectors", "type": "address[]" },
{ "internalType": "contract IERC20", "name": "wBase", "type": "address" }
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "contract IERC20", "name": "connector", "type": "address" }
],
"name": "ConnectorAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "contract IERC20", "name": "connector", "type": "address" }
],
"name": "ConnectorRemoved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "contract MultiWrapper", "name": "multiWrapper", "type": "address" }
],
"name": "MultiWrapperUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "contract IOracle", "name": "oracle", "type": "address" },
{
"indexed": false,
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleType",
"type": "uint8"
}
],
"name": "OracleAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{ "indexed": false, "internalType": "contract IOracle", "name": "oracle", "type": "address" },
{
"indexed": false,
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleType",
"type": "uint8"
}
],
"name": "OracleRemoved",
"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"
},
{
"inputs": [{ "internalType": "contract IERC20", "name": "connector", "type": "address" }],
"name": "addConnector",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "contract IOracle", "name": "oracle", "type": "address" },
{ "internalType": "enum OffchainOracle.OracleType", "name": "oracleKind", "type": "uint8" }
],
"name": "addOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "connectors",
"outputs": [{ "internalType": "contract IERC20[]", "name": "allConnectors", "type": "address[]" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "contract IERC20", "name": "srcToken", "type": "address" },
{ "internalType": "contract IERC20", "name": "dstToken", "type": "address" },
{ "internalType": "bool", "name": "useWrappers", "type": "bool" }
],
"name": "getRate",
"outputs": [{ "internalType": "uint256", "name": "weightedRate", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{ "internalType": "contract IERC20", "name": "srcToken", "type": "address" },
{ "internalType": "bool", "name": "useSrcWrappers", "type": "bool" }
],
"name": "getRateToEth",
"outputs": [{ "internalType": "uint256", "name": "weightedRate", "type": "uint256" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "multiWrapper",
"outputs": [{ "internalType": "contract MultiWrapper", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "oracles",
"outputs": [
{ "internalType": "contract IOracle[]", "name": "allOracles", "type": "address[]" },
{ "internalType": "enum OffchainOracle.OracleType[]", "name": "oracleTypes", "type": "uint8[]" }
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [{ "internalType": "address", "name": "", "type": "address" }],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [{ "internalType": "contract IERC20", "name": "connector", "type": "address" }],
"name": "removeConnector",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{ "internalType": "contract IOracle", "name": "oracle", "type": "address" },
{ "internalType": "enum OffchainOracle.OracleType", "name": "oracleKind", "type": "uint8" }
],
"name": "removeOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "contract MultiWrapper", "name": "_multiWrapper", "type": "address" }],
"name": "setMultiWrapper",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [{ "internalType": "address", "name": "newOwner", "type": "address" }],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

View File

@ -1,151 +0,0 @@
[
{
"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"
}
]

View File

@ -337,6 +337,7 @@ export default {
})
}
this.$store.dispatch('application/setAndUpdateStatistic', { currency, amount: Number(amount) })
this.$store.dispatch('fees/calculateWithdrawalNetworkFee', {})
if (currency !== this.nativeCurrency) {
this.$store.dispatch('application/setDefaultEthToReceive', { currency })
}

View File

@ -18,7 +18,9 @@
</div>
<div v-if="withdrawType === 'relayer'" class="withdraw-data-item">
{{ $t('networkFee') }}
<span data-test="label_network_fee">{{ toDecimals(networkFee, 18, 6) }} {{ networkCurrency }}</span>
<span data-test="label_network_fee"
>{{ toDecimals(withdrawalNetworkFee, 18, 6) }} {{ networkCurrency }}</span
>
</div>
<div v-if="withdrawType === 'relayer'" class="withdraw-data-item">
{{ $t('relayerFee') }}
@ -69,13 +71,13 @@ export default {
},
computed: {
...mapState('application', ['selectedStatistic']),
...mapState('fees', ['withdrawalNetworkFee']),
...mapGetters('metamask', ['networkConfig', 'nativeCurrency']),
...mapGetters('metamask', {
networkCurrency: 'currency'
}),
...mapGetters('gasPrices', ['gasPriceInGwei']),
...mapGetters('fees', ['gasPriceInGwei']),
...mapGetters('token', ['toDecimals', 'fromDecimals']),
...mapGetters('application', ['networkFee']),
...mapGetters('price', ['tokenRate']),
relayerFee() {
const { amount } = this.selectedStatistic
@ -91,7 +93,7 @@ export default {
const tornadoServiceFee = this.relayerFee
const { currency } = this.selectedStatistic
const { decimals } = this.networkConfig.tokens[currency]
const ethFee = this.networkFee
const ethFee = this.withdrawalNetworkFee
if (currency === this.nativeCurrency) {
return ethFee.add(tornadoServiceFee)
}

View File

@ -65,7 +65,7 @@ export default {
created() {
this.checkRecoveryKey()
this.newNotify()
this.$store.dispatch('gasPrices/setDefault')
this.$store.dispatch('fees/setDefaultGasPrice')
},
mounted() {
this.$preventMultitabs()
@ -80,7 +80,7 @@ export default {
await this.selectRpc({ netId: 1, action: this.preselectRpc })
}
this.$store.dispatch('gasPrices/fetchGasPrice')
this.$store.dispatch('fees/fetchGasPrice')
this.$store.dispatch('price/fetchTokenPrice', {}, { root: true })
try {
this.$store.dispatch('application/loadAllNotesData')

View File

@ -24,7 +24,7 @@
"@metamask/onboarding": "^1.0.0",
"@nuxtjs/moment": "^1.6.0",
"@tornado/snarkjs": "0.1.20-p2",
"@tornado/tornado-oracles": "^0.3.0",
"@tornado/tornado-oracles": "1.0.0",
"@tornado/websnark": "0.0.4-p1",
"@walletconnect/web3-provider": "1.7.8",
"ajv": "^6.10.2",

View File

@ -163,18 +163,6 @@ const getters = {
return ACTION_GAS[action]
},
networkFee: (state, getters, rootState, rootGetters) => {
const gasPrice = rootGetters['gasPrices/gasPrice']
const networkFee = toBN(gasPrice).mul(toBN(state.relayerWithdrawGasLimit || getters.defaultWithdrawGas))
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
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
@ -185,7 +173,7 @@ const getters = {
const roundDecimal = 10 ** decimalsPoint
const aroundFee = toBN(parseInt(fee * roundDecimal, 10))
const tornadoServiceFee = total.mul(aroundFee).div(toBN(roundDecimal * 100))
const ethFee = getters.networkFee
const ethFee = rootState.fees.withdrawalNetworkFee
switch (currency) {
case nativeCurrency: {
return ethFee.add(tornadoServiceFee)
@ -648,7 +636,7 @@ const actions = {
const tornadoInstance = getters.instanceContract({ currency, amount, netId })
const relayer = rootState.relayer.selectedRelayer.address
const gasPrice = toBN(rootGetters['gasPrices/gasPrice'])
const gasPrice = toBN(rootGetters['fees/gasPrice'])
let gasLimit
try {
@ -993,7 +981,7 @@ const actions = {
},
calculateEthToReceive({ commit, state, rootGetters }, { currency }) {
const gasLimit = rootGetters['metamask/networkConfig'].tokens[currency].gasLimit
const gasPrice = toBN(rootGetters['gasPrices/gasPrice'])
const gasPrice = toBN(rootGetters['fees/gasPrice'])
const ethToReceive = gasPrice
.mul(toBN(gasLimit))

68
store/fees.js Normal file
View File

@ -0,0 +1,68 @@
/* eslint-disable no-console */
import { toWei, fromWei, toBN } from 'web3-utils'
import { TornadoFeeOracleV4, TornadoFeeOracleV5 } from '@tornado/tornado-oracles'
export const state = () => {
return {
gasPriceParams: { gasPrice: toWei(toBN(50), 'gwei') },
withdrawalNetworkFee: toBN(0)
}
}
export const getters = {
oracle: (state, getters, rootState, rootGetters) => {
const netId = Number(rootGetters['metamask/netId'])
const { url: rpcUrl } = rootState.settings[`netId${netId}`].rpc
const { gasPrices } = rootGetters['metamask/networkConfig']
// Return old oracle for backwards compatibility, if chain is ETH Mainnet
return netId === 1
? new TornadoFeeOracleV4(netId, rpcUrl, gasPrices)
: new TornadoFeeOracleV5(netId, rpcUrl, gasPrices)
},
getGasPriceParams: (state) => {
return state.gasPriceParams
},
gasPrice: (state, getters) => {
const { gasPrice, maxFeePerGas } = getters.getGasPriceParams
return maxFeePerGas || gasPrice
},
gasPriceInGwei: (state, getters) => {
return fromWei(getters.gasPrice, 'gwei')
}
}
export const mutations = {
SAVE_GAS_PARAMS(state, payload) {
state.gasPriceParams = payload
},
SAVE_WITHDRAWAL_NETWORK_FEE(state, gasFee) {
state.withdrawalNetworkFee = gasFee
}
}
export const actions = {
async fetchGasPrice({ getters, dispatch, commit, rootGetters }) {
const { pollInterval } = rootGetters['metamask/networkConfig']
try {
const gasPriceParams = await getters.oracle.getGasPriceParams()
console.log(gasPriceParams)
commit('SAVE_GAS_PARAMS', gasPriceParams)
} catch (e) {
console.error('fetchGasPrice', e)
} finally {
setTimeout(() => dispatch('fetchGasPrice'), 2000 * pollInterval)
}
},
setDefaultGasPrice({ commit, rootGetters }) {
const { gasPrices } = rootGetters['metamask/networkConfig']
commit('SAVE_GAS_PARAMS', { gasPrice: toWei(gasPrices?.fast?.toFixed(9) || 0, 'gwei') })
},
async calculateWithdrawalNetworkFee({ getters, commit }, { tx }) {
const withdrawalGas = await getters.oracle.getGas(tx, 'user_withdrawal')
commit('SAVE_WITHDRAWAL_NETWORK_FEE', toBN(withdrawalGas))
}
}

View File

@ -1,142 +0,0 @@
/* eslint-disable no-console */
import Web3 from 'web3'
import { toHex, toWei, fromWei, toBN } from 'web3-utils'
import { GasPriceOracle } from '@tornado/gas-price-oracle'
import { serialize } from '@ethersproject/transactions'
import networkConfig from '@/networkConfig'
import OvmGasPriceOracleABI from '@/abis/OvmGasPriceOracle.abi.json'
import { DUMMY_NONCE, DUMMY_WITHDRAW_DATA } from '@/constants/variables'
export const state = () => {
return {
gasParams: { gasPrice: toWei(toBN(50), 'gwei') },
l1Fee: '0'
}
}
export const getters = {
oracle: (state, getters, rootState, rootGetters) => {
const netId = Number(rootGetters['metamask/netId'])
const { gasPrices } = rootGetters['metamask/networkConfig']
return new GasPriceOracle({
chainId: netId,
defaultRpc: rootGetters['settings/currentRpc'].url,
minPriority: netId === 1 || netId === 5 ? 2 : 0.05,
percentile: 5,
blocksCount: 20,
defaultFallbackGasPrices: gasPrices
})
},
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
},
getGasParams: (state) => {
return state.gasParams
},
gasPrice: (state, getters) => {
const { gasPrice, maxFeePerGas } = getters.getGasParams
return toHex(maxFeePerGas || gasPrice)
},
gasPriceInGwei: (state, getters) => {
return fromWei(getters.gasPrice, 'gwei')
}
}
export const mutations = {
SAVE_GAS_PARAMS(state, payload) {
state.gasParams = payload
},
SAVE_L1_FEE(state, l1Fee) {
state.l1Fee = l1Fee
}
}
export const actions = {
async fetchGasPrice({ getters, dispatch, commit, rootGetters, rootState }) {
const { pollInterval } = rootGetters['metamask/networkConfig']
const netId = Number(rootGetters['metamask/netId'])
const { url: rpcUrl } = rootState.settings[`netId${netId}`].rpc
try {
// Bump more for Polygon (MATIC) and for Goerli, because minPriority for this sidechains don't affect correctly
let bumpPercent
switch (netId) {
case 5:
bumpPercent = 100
break
case 137:
case 43114:
case 100:
bumpPercent = 30
break
default:
bumpPercent = 10
}
let txGasParams = {}
try {
// Use maxFeePerGas if eip1599 gas support by chain, use fast if legacy gas fetched
txGasParams = await getters.oracle.getTxGasParams({ legacySpeed: 'fast', bumpPercent }) // in wei
} catch (e) {
const web3 = new Web3(rpcUrl)
const wei = toBN(await web3.eth.getGasPrice())
const bumped = wei.add(wei.mul(toBN(bumpPercent)).div(toBN(100)))
txGasParams = { gasPrice: toHex(bumped) }
}
commit('SAVE_GAS_PARAMS', txGasParams)
await dispatch('fetchL1Fee')
} catch (e) {
console.error('fetchGasPrice', e)
} finally {
setTimeout(() => dispatch('fetchGasPrice'), 2000 * pollInterval)
}
},
setDefault({ commit, rootGetters }) {
const { gasPrices } = rootGetters['metamask/networkConfig']
commit('SAVE_GAS_PARAMS', { gasPrice: toWei(gasPrices?.fast?.toFixed(9) || 0, 'gwei') })
},
async fetchL1Fee({ commit, getters, 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 tx = serialize({
type: 0,
gasLimit,
chainId: netId,
nonce: DUMMY_NONCE,
data: DUMMY_WITHDRAW_DATA,
gasPrice: getters.gasPrice,
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)
}
}
}
}

View File

@ -153,7 +153,7 @@ const actions = {
) {
try {
const { ethAccount, netId } = state
const gasParams = rootGetters['gasPrices/getGasParams']
const gasParams = rootGetters['fees/getGasPriceParams']
const callParams = {
method,

View File

@ -2477,10 +2477,10 @@
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-config/-/2.0.0/tornado-config-2.0.0.tgz#52bbc179ecb2385f71b4d56e060b68e7dd6fb8b4"
integrity sha512-7EkpWNfEm34VEOrbLnPpvd/aUJYnA1L+6/qx2fZ/AfmuJFkjSZ18Z4jvVGNY7ktKIhTu3/Tbze+9l3eNueCNIA==
"@tornado/tornado-oracles@^0.3.0":
version "0.3.0"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-oracles/-/0.3.0/tornado-oracles-0.3.0.tgz#51dcb0f17662b463ce10c044162b926bcdbb74a8"
integrity sha512-zyQRr45eSu2Hl8567Zr3J5hkNOhCsL7CKlwp6MW/NRi13yupeQalV2qcSL6RB7uVt/X+1+Hc5O2xNLXxG2gyGw==
"@tornado/tornado-oracles@1.0.0":
version "1.0.0"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-oracles/-/1.0.0/tornado-oracles-1.0.0.tgz#d4f1d76c1028aec5ba75fbd5abe0edfcf8e4e412"
integrity sha512-zshMYIX3MgRKqhWJ2UA71Y/Plo+ssFBB7L08XqSNCND5rPgeL0CPjyVFrqgruAb343vVcIpo2eaOUPtd+mzLSA==
dependencies:
"@tornado/gas-price-oracle" "^0.5.3"
"@tornado/tornado-config" "^2.0.0"