forked from tornadocash/classic-ui
Estimate gas limit for withdrawal transaction via relayer correctly
This commit is contained in:
parent
6130c46d90
commit
311f6ebc85
@ -63,7 +63,8 @@ const state = () => {
|
|||||||
withdrawType: 'relayer',
|
withdrawType: 'relayer',
|
||||||
ethToReceive: '20000000000000000',
|
ethToReceive: '20000000000000000',
|
||||||
defaultEthToReceive: '20000000000000000',
|
defaultEthToReceive: '20000000000000000',
|
||||||
withdrawNote: ''
|
withdrawNote: '',
|
||||||
|
relayerWithdrawGasLimit: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +105,9 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_WITHDRAW_NOTE(state, withdrawNote) {
|
SET_WITHDRAW_NOTE(state, withdrawNote) {
|
||||||
state.withdrawNote = withdrawNote
|
state.withdrawNote = withdrawNote
|
||||||
|
},
|
||||||
|
SET_RELAYER_WITHDRAW_GAS_LIMIT(state, { relayerWithdrawGasLimit }) {
|
||||||
|
this._vm.$set(state, 'relayerWithdrawGasLimit', relayerWithdrawGasLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +146,7 @@ const getters = {
|
|||||||
currentContract: (state, getters) => (params) => {
|
currentContract: (state, getters) => (params) => {
|
||||||
return getters.tornadoProxyContract(params)
|
return getters.tornadoProxyContract(params)
|
||||||
},
|
},
|
||||||
withdrawGas: (state, getters) => {
|
defaultWithdrawGas: (state, getters) => {
|
||||||
let action = ACTION.WITHDRAW_WITH_EXTRA
|
let action = ACTION.WITHDRAW_WITH_EXTRA
|
||||||
|
|
||||||
if (getters.hasEnabledLightProxy) {
|
if (getters.hasEnabledLightProxy) {
|
||||||
@ -162,7 +166,7 @@ const getters = {
|
|||||||
networkFee: (state, getters, rootState, rootGetters) => {
|
networkFee: (state, getters, rootState, rootGetters) => {
|
||||||
const gasPrice = rootGetters['gasPrices/gasPrice']
|
const gasPrice = rootGetters['gasPrices/gasPrice']
|
||||||
|
|
||||||
const networkFee = toBN(gasPrice).mul(toBN(getters.withdrawGas))
|
const networkFee = toBN(gasPrice).mul(toBN(state.relayerWithdrawGasLimit || getters.defaultWithdrawGas))
|
||||||
|
|
||||||
if (getters.isOptimismConnected) {
|
if (getters.isOptimismConnected) {
|
||||||
const l1Fee = rootGetters['gasPrices/l1Fee']
|
const l1Fee = rootGetters['gasPrices/l1Fee']
|
||||||
@ -636,6 +640,30 @@ const actions = {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async estimateRelayerWithdrawGasLimit(
|
||||||
|
{ getters, rootState, commit },
|
||||||
|
{ currency, amount, netId, proof, withdrawCallArgs }
|
||||||
|
) {
|
||||||
|
const tornadoProxy = getters.tornadoProxyContract({ netId })
|
||||||
|
const tornadoInstance = getters.instanceContract({ currency, amount, netId })
|
||||||
|
const relayer = rootState.relayer.selectedRelayer.address
|
||||||
|
|
||||||
|
let gasLimit
|
||||||
|
try {
|
||||||
|
const fetchedGasLimit = await tornadoProxy.methods
|
||||||
|
.withdraw(tornadoInstance._address, proof, ...withdrawCallArgs)
|
||||||
|
.estimateGas({
|
||||||
|
from: relayer,
|
||||||
|
to: tornadoProxy._address,
|
||||||
|
value: withdrawCallArgs[5] || 0
|
||||||
|
})
|
||||||
|
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) {
|
async checkSpentEventFromNullifier({ getters, dispatch }, parsedNote) {
|
||||||
try {
|
try {
|
||||||
const isSpent = await dispatch('loadEvent', {
|
const isSpent = await dispatch('loadEvent', {
|
||||||
@ -695,7 +723,7 @@ const actions = {
|
|||||||
return { tree, root }
|
return { tree, root }
|
||||||
},
|
},
|
||||||
async createSnarkProof(
|
async createSnarkProof(
|
||||||
{ rootGetters, rootState, state, getters },
|
{ rootGetters, rootState, state, getters, dispatch },
|
||||||
{ root, note, tree, recipient, leafIndex }
|
{ root, note, tree, recipient, leafIndex }
|
||||||
) {
|
) {
|
||||||
const { pathElements, pathIndices } = tree.path(leafIndex)
|
const { pathElements, pathIndices } = tree.path(leafIndex)
|
||||||
@ -708,55 +736,71 @@ const actions = {
|
|||||||
let fee = BigInt(0)
|
let fee = BigInt(0)
|
||||||
let refund = BigInt(0)
|
let refund = BigInt(0)
|
||||||
|
|
||||||
if (withdrawType === 'relayer') {
|
async function calculateSnarkProof() {
|
||||||
let totalRelayerFee = getters.relayerFee
|
const input = {
|
||||||
relayer = BigInt(rootState.relayer.selectedRelayer.address)
|
// public
|
||||||
|
fee,
|
||||||
if (note.currency !== nativeCurrency) {
|
root,
|
||||||
refund = BigInt(state.ethToReceive.toString())
|
refund,
|
||||||
totalRelayerFee = totalRelayerFee.add(getters.ethToReceiveInToken)
|
relayer,
|
||||||
|
recipient: BigInt(recipient),
|
||||||
|
nullifierHash: note.nullifierHash,
|
||||||
|
// private
|
||||||
|
pathIndices,
|
||||||
|
pathElements,
|
||||||
|
secret: note.secret,
|
||||||
|
nullifier: note.nullifier
|
||||||
}
|
}
|
||||||
|
|
||||||
fee = BigInt(totalRelayerFee.toString())
|
const { circuit, provingKey } = await getTornadoKeys()
|
||||||
|
|
||||||
|
if (!groth16) {
|
||||||
|
groth16 = await buildGroth16()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Start generating SNARK proof', input)
|
||||||
|
console.time('SNARK proof time')
|
||||||
|
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, provingKey)
|
||||||
|
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
||||||
|
|
||||||
|
const args = [
|
||||||
|
toFixedHex(input.root),
|
||||||
|
toFixedHex(input.nullifierHash),
|
||||||
|
toFixedHex(input.recipient, 20),
|
||||||
|
toFixedHex(input.relayer, 20),
|
||||||
|
toFixedHex(input.fee),
|
||||||
|
toFixedHex(input.refund)
|
||||||
|
]
|
||||||
|
console.timeEnd('SNARK proof time')
|
||||||
|
return { args, proof }
|
||||||
}
|
}
|
||||||
|
|
||||||
const input = {
|
// Don't need to calculate or estimate relayer fee, so, return proof immediately
|
||||||
// public
|
if (withdrawType !== 'relayer') return calculateSnarkProof()
|
||||||
fee,
|
|
||||||
root,
|
relayer = BigInt(rootState.relayer.selectedRelayer.address)
|
||||||
refund,
|
const { proof: dummyProof, args: dummyArgs } = await calculateSnarkProof()
|
||||||
relayer,
|
const { netId, amount, currency } = note
|
||||||
recipient: BigInt(recipient),
|
await dispatch('estimateRelayerWithdrawGasLimit', {
|
||||||
nullifierHash: note.nullifierHash,
|
netId,
|
||||||
// private
|
amount,
|
||||||
pathIndices,
|
currency,
|
||||||
pathElements,
|
proof: dummyProof,
|
||||||
secret: note.secret,
|
withdrawCallArgs: dummyArgs
|
||||||
nullifier: note.nullifier
|
})
|
||||||
|
let totalRelayerFee = getters.relayerFee
|
||||||
|
|
||||||
|
if (note.currency !== nativeCurrency) {
|
||||||
|
refund = BigInt(state.ethToReceive.toString())
|
||||||
|
totalRelayerFee = totalRelayerFee.add(getters.ethToReceiveInToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { circuit, provingKey } = await getTornadoKeys()
|
fee = BigInt(totalRelayerFee.toString())
|
||||||
|
|
||||||
if (!groth16) {
|
// Recalculate proof with actual fee and refund
|
||||||
groth16 = await buildGroth16()
|
return calculateSnarkProof()
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Start generating SNARK proof', input)
|
|
||||||
console.time('SNARK proof time')
|
|
||||||
const proofData = await websnarkUtils.genWitnessAndProve(groth16, input, circuit, provingKey)
|
|
||||||
const { proof } = websnarkUtils.toSolidityInput(proofData)
|
|
||||||
|
|
||||||
const args = [
|
|
||||||
toFixedHex(input.root),
|
|
||||||
toFixedHex(input.nullifierHash),
|
|
||||||
toFixedHex(input.recipient, 20),
|
|
||||||
toFixedHex(input.relayer, 20),
|
|
||||||
toFixedHex(input.fee),
|
|
||||||
toFixedHex(input.refund)
|
|
||||||
]
|
|
||||||
return { args, proof }
|
|
||||||
},
|
},
|
||||||
async prepareWithdraw({ dispatch, getters, commit }, { note, recipient }) {
|
async prepareWithdraw({ dispatch, commit }, { note, recipient }) {
|
||||||
commit('REMOVE_PROOF', { note })
|
commit('REMOVE_PROOF', { note })
|
||||||
try {
|
try {
|
||||||
const parsedNote = parseNote(note)
|
const parsedNote = parseNote(note)
|
||||||
@ -776,7 +820,6 @@ const actions = {
|
|||||||
note: parsedNote,
|
note: parsedNote,
|
||||||
leafIndex: tree.indexOf(parsedNote.commitmentHex)
|
leafIndex: tree.indexOf(parsedNote.commitmentHex)
|
||||||
})
|
})
|
||||||
console.timeEnd('SNARK proof time')
|
|
||||||
commit('SAVE_PROOF', { proof, args, note })
|
commit('SAVE_PROOF', { proof, args, note })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('prepareWithdraw', e)
|
console.error('prepareWithdraw', e)
|
||||||
|
Loading…
Reference in New Issue
Block a user