Change gas & fees calculations:

- Use @tornado/tornado-oracles lib to calculate withdrawal fee via relayer
	- When calculating fee, save backwards compatibility for Ethereum Mainnet V4 relayers & old UI builds
	- Bump UI version to 1.2.0
	- Display most up-to-date information about relayer withdrawal fees on WithdrawalTotal page
This commit is contained in:
Theo 2023-08-27 12:30:25 -07:00
parent fb0a5131f4
commit 9210330208
7 changed files with 73 additions and 112 deletions

@ -192,7 +192,7 @@ export default {
...mapState('relayer', ['isLoadingRelayers']),
...mapGetters('txHashKeeper', ['txExplorerUrl']),
...mapGetters('application', ['isNotEnoughTokens', 'selectedStatisticCurrency']),
...mapGetters('metamask', ['networkConfig', 'netId', 'isLoggedIn', 'nativeCurrency']),
...mapGetters('metamask', ['networkConfig', 'netId', 'isLoggedIn']),
notEnoughDeposits() {
if (this.depositsPast < 5) {
return true
@ -337,10 +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 })
}
this.$store.dispatch('fees/calculateWithdrawalFeeViaRelayer', {})
this.$store.dispatch('loading/updateProgress', { progress: -1 })
this.depositsPast = Number(depositsPast) <= 0 ? 0 : depositsPast
this.depositTxHash = txHash

@ -71,7 +71,7 @@ export default {
},
computed: {
...mapState('application', ['selectedStatistic']),
...mapState('fees', ['withdrawalNetworkFee']),
...mapState('fees', ['withdrawalNetworkFee', 'withdrawalFeeViaRelayer']),
...mapGetters('metamask', ['networkConfig', 'nativeCurrency']),
...mapGetters('metamask', {
networkCurrency: 'currency'
@ -119,17 +119,12 @@ export default {
return fromWei(this.ethToReceive)
},
total() {
const { amount, currency } = this.selectedStatistic
const { amount } = this.selectedStatistic
let total = toBN(this.fromDecimals(amount.toString()))
if (this.withdrawType === 'relayer') {
const relayerFee = this.totalRelayerFee
if (currency === this.nativeCurrency) {
total = total.sub(relayerFee)
} else {
total = total.sub(relayerFee).sub(this.ethToReceiveInToken)
}
const relayerFee = this.withdrawalFeeViaRelayer
total = total.sub(relayerFee)
}
return this.toDecimals(total, null, 6)

@ -1,6 +1,6 @@
{
"name": "tornadocash-classic-ui",
"version": "1.1.0",
"version": "1.2.0",
"description": "Private ethereum transactions",
"author": "Tornado Cash Team",
"scripts": {
@ -24,7 +24,7 @@
"@metamask/onboarding": "^1.0.0",
"@nuxtjs/moment": "^1.6.0",
"@tornado/snarkjs": "0.1.20-p2",
"@tornado/tornado-oracles": "1.2",
"@tornado/tornado-oracles": "1.3.2",
"@tornado/websnark": "0.0.4-p1",
"@walletconnect/web3-provider": "1.7.8",
"ajv": "^6.10.2",

@ -9,7 +9,6 @@ import MulticallABI from '@/abis/Multicall.json'
import InstanceABI from '@/abis/Instance.abi.json'
import TornadoProxyABI from '@/abis/TornadoProxy.abi.json'
import { ACTION, ACTION_GAS } from '@/constants/variables'
import { graph, treesInterface, EventsFactory } from '@/services'
import {
@ -18,7 +17,6 @@ import {
toFixedHex,
saveAsFile,
isEmptyArray,
decimalPlaces,
parseHexNote,
checkCommitments,
buffPedersenHash
@ -63,8 +61,7 @@ const state = () => {
withdrawType: 'relayer',
ethToReceive: '20000000000000000',
defaultEthToReceive: '20000000000000000',
withdrawNote: '',
relayerWithdrawGasLimit: null
withdrawNote: ''
}
}
@ -105,9 +102,6 @@ const mutations = {
},
SET_WITHDRAW_NOTE(state, withdrawNote) {
state.withdrawNote = withdrawNote
},
SET_RELAYER_WITHDRAW_GAS_LIMIT(state, { relayerWithdrawGasLimit }) {
this._vm.$set(state, 'relayerWithdrawGasLimit', relayerWithdrawGasLimit)
}
}
@ -146,42 +140,24 @@ const getters = {
currentContract: (state, getters) => (params) => {
return getters.tornadoProxyContract(params)
},
defaultWithdrawGas: (state, getters) => {
let action = ACTION.WITHDRAW_WITH_EXTRA
relayerWithdrawalTxData: (state, getters, rootState, rootGetters) => ({
proof,
withdrawCallArgs,
currency,
amount
}) => {
const netId = rootGetters['metamask/netId']
const tornadoProxy = getters.tornadoProxyContract({ netId })
const tornadoInstance = getters.instanceContract({ currency, amount, netId })
if (getters.hasEnabledLightProxy) {
action = ACTION.WITHDRAW
}
const calldata = tornadoProxy.methods
.withdraw(tornadoInstance._address, proof, ...withdrawCallArgs)
.encodeABI()
if (getters.isOptimismConnected) {
action = ACTION.OP_WITHDRAW
}
if (getters.isArbitrumConnected) {
action = ACTION.ARB_WITHDRAW
}
return ACTION_GAS[action]
},
relayerFee: (state, getters, rootState, rootGetters) => {
const { currency, amount } = rootState.application.selectedStatistic
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
const nativeCurrency = rootGetters['metamask/nativeCurrency']
const total = toBN(rootGetters['token/fromDecimals'](amount.toString()))
const fee = rootState.relayer.selectedRelayer.tornadoServiceFee
const decimalsPoint = decimalPlaces(fee)
const roundDecimal = 10 ** decimalsPoint
const aroundFee = toBN(parseInt(fee * roundDecimal, 10))
const tornadoServiceFee = total.mul(aroundFee).div(toBN(roundDecimal * 100))
const ethFee = rootState.fees.withdrawalNetworkFee
switch (currency) {
case nativeCurrency: {
return ethFee.add(tornadoServiceFee)
}
default: {
const tokenFee = ethFee.mul(toBN(10 ** decimals)).div(toBN(rootState.price.prices[currency]))
return tokenFee.add(tornadoServiceFee)
}
return {
to: tornadoProxy._address,
data: calldata,
value: withdrawCallArgs[5] || 0
}
},
ethToReceiveInToken: (state, getters, rootState, rootGetters) => {
@ -196,7 +172,7 @@ const getters = {
let total = toBN(rootGetters['token/fromDecimals'](amount.toString()))
if (state.withdrawType === 'relayer') {
const relayerFee = getters.relayerFee
const relayerFee = rootState.fees.withdrawalFeeViaRelayer
const nativeCurrency = rootGetters['metamask/nativeCurrency']
if (currency === nativeCurrency) {
@ -214,9 +190,8 @@ const getters = {
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
const total = toBN(rootGetters['token/fromDecimals'](amount.toString()))
const price = rootState.price.prices[currency]
const relayerFee = getters.relayerFee
return total
.sub(relayerFee)
.sub(rootState.fees.withdrawalFeeViaRelayer)
.mul(toBN(price))
.div(toBN(10 ** decimals))
},
@ -628,34 +603,6 @@ const actions = {
return false
}
},
async estimateRelayerWithdrawGasLimit(
{ getters, rootState, rootGetters, commit },
{ currency, amount, netId, proof, withdrawCallArgs }
) {
const tornadoProxy = getters.tornadoProxyContract({ netId })
const tornadoInstance = getters.instanceContract({ currency, amount, netId })
const relayer = rootState.relayer.selectedRelayer.address
const gasPrice = toBN(rootGetters['fees/gasPrice'])
let gasLimit
try {
const fetchedGasLimit = await tornadoProxy.methods
.withdraw(tornadoInstance._address, proof, ...withdrawCallArgs)
.estimateGas({
from: relayer,
to: tornadoProxy._address,
value: withdrawCallArgs[5] || 0,
gasPrice,
gasLimit: getters.defaultWithdrawGas
})
gasLimit = Math.floor(fetchedGasLimit * 1.3)
} catch (e) {
gasLimit = getters.defaultWithdrawGas
console.error(`Cannot fetch gas limit for relayer withdrawal, using default: ${gasLimit}`)
}
commit('SET_RELAYER_WITHDRAW_GAS_LIMIT', { relayerWithdrawGasLimit: gasLimit })
},
async checkSpentEventFromNullifier({ getters, dispatch }, parsedNote) {
try {
const isSpent = await dispatch('loadEvent', {
@ -724,7 +671,7 @@ const actions = {
const nativeCurrency = rootGetters['metamask/nativeCurrency']
const withdrawType = state.withdrawType
let relayer = BigInt(recipient)
const relayer = BigInt(rootState.relayer.selectedRelayer.address)
let fee = BigInt(0)
let refund = BigInt(0)
@ -770,24 +717,21 @@ const actions = {
// Don't need to calculate or estimate relayer fee, so, return proof immediately
if (withdrawType !== 'relayer') return calculateSnarkProof()
relayer = BigInt(rootState.relayer.selectedRelayer.address)
const { proof: dummyProof, args: dummyArgs } = await calculateSnarkProof()
const { netId, amount, currency } = note
await dispatch('estimateRelayerWithdrawGasLimit', {
netId,
amount,
currency,
fee = BigInt(rootState.fees.withdrawalFeeViaRelayer)
const naiveProof = await calculateSnarkProof()
if (Number(note.netId) === 1) return naiveProof // Don't need to smart-estimate fee if we use V4 withdrawal
const { proof: dummyProof, args: dummyArgs } = naiveProof
const withdrawalTx = getters.relayerWithdrawalTxData({
proof: dummyProof,
withdrawCallArgs: dummyArgs
withdrawCallArgs: dummyArgs,
amount: note.amount,
currency: note.currency
})
let totalRelayerFee = getters.relayerFee
if (note.currency !== nativeCurrency) refund = BigInt(state.ethToReceive.toString())
if (note.currency !== nativeCurrency) {
refund = BigInt(state.ethToReceive.toString())
totalRelayerFee = totalRelayerFee.add(getters.ethToReceiveInToken)
}
fee = BigInt(totalRelayerFee.toString())
await dispatch('fees/calculateWithdrawalFeeViaRelayer', { tx: withdrawalTx }, { root: true })
fee = BigInt(rootState.fees.withdrawalFeeViaRelayer)
// Recalculate proof with actual fee and refund
return calculateSnarkProof()

@ -5,7 +5,8 @@ import { TornadoFeeOracleV4, TornadoFeeOracleV5 } from '@tornado/tornado-oracles
export const state = () => {
return {
gasPriceParams: { gasPrice: toWei(toBN(50), 'gwei') },
withdrawalNetworkFee: toBN(0)
withdrawalNetworkFee: toBN(0),
withdrawalFeeViaRelayer: toBN(0)
}
}
@ -38,6 +39,9 @@ export const mutations = {
},
SAVE_WITHDRAWAL_NETWORK_FEE(state, gasFee) {
state.withdrawalNetworkFee = gasFee
},
SAVE_WITHDRAWAL_FEE_VIA_RELAYER(state, fee) {
state.withdrawalFeeViaRelayer = fee
}
}
@ -47,8 +51,6 @@ export const actions = {
try {
const gasPriceParams = await getters.oracle.getGasPriceParams()
console.log(gasPriceParams)
commit('SAVE_GAS_PARAMS', gasPriceParams)
} catch (e) {
console.error('fetchGasPrice', e)
@ -64,5 +66,28 @@ export const actions = {
const withdrawalGas = await getters.oracle.getGas(tx, 'user_withdrawal')
commit('SAVE_WITHDRAWAL_NETWORK_FEE', toBN(withdrawalGas))
},
async calculateWithdrawalFeeViaRelayer({ dispatch, getters, commit, rootGetters, rootState }, { tx }) {
const feePercent = rootState.relayer.selectedRelayer.tornadoServiceFee
const { currency, amount } = rootState.application.selectedStatistic
const nativeCurrency = rootGetters['metamask/nativeCurrency']
const { decimals } = rootGetters['metamask/networkConfig'].tokens[currency]
await dispatch('calculateWithdrawalNetworkFee', { tx })
if (currency !== nativeCurrency)
await dispatch('application/setDefaultEthToReceive', { currency }, { root: true })
const withdrawalFee = await getters.oracle.calculateWithdrawalFeeViaRelayer(
'user_withdrawal',
tx,
feePercent,
currency.toLowerCase(),
amount,
decimals,
rootState.application.ethToReceive || 0,
rootState.price.prices[currency.toLowerCase()]
)
commit('SAVE_WITHDRAWAL_FEE_VIA_RELAYER', toBN(withdrawalFee))
}
}

@ -249,7 +249,7 @@ export const actions = {
const isUpdatedMajor = major === requiredMajor
if (prerelease) return false
return isUpdatedMajor && Number(patch) >= 4 // Patch checking - also backwards compatibility
return isUpdatedMajor && (Number(patch) >= 4 || netId !== 1) // Patch checking - also backwards compatibility for Mainnet
}
if (!isRelayerUpdated()) {

@ -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@1.2":
version "1.2.0"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-oracles/-/1.2.0/tornado-oracles-1.2.0.tgz#07121625343ba683f2d82f3e0cdf5ec70378d833"
integrity sha512-AmqudzDi5LS7Enm2uEAzDxjqqByUeUvs4Bg6FfkEufE6MPs3twOwdWxMDKx8xxlFMVlVeVCv2hMs1nGHnabWdw==
"@tornado/tornado-oracles@1.3.2":
version "1.3.2"
resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-oracles/-/1.3.2/tornado-oracles-1.3.2.tgz#83d269619b6e3a9a1abe964a561c3dfd533cca4c"
integrity sha512-z3NI35GKKznxVigF0OghqQ8S3sT/S4oD3AtXqyf+P2bfkriAsdrXnsSMW7Vxej529e5k3cA0dPtOs4eFqFE/7Q==
dependencies:
"@tornado/gas-price-oracle" "^0.5.3"
"@tornado/tornado-config" "^2.0.0"