diff --git a/src/config.ts b/src/config.ts index 57bf45c..974ed21 100644 --- a/src/config.ts +++ b/src/config.ts @@ -26,11 +26,12 @@ export const tornadoServiceFee = Number(process.env.REGULAR_TORNADO_WITHDRAW_FEE export const rewardAccount = process.env.REWARD_ACCOUNT; export const governanceAddress = '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce'; export const tornadoGoerliProxy = '0x454d870a72e29d5E5697f635128D18077BD04C60'; +export const ovmGasPriceOracleContract = '0x420000000000000000000000000000000000000F'; export const gasLimits = { [RelayerJobType.TORNADO_WITHDRAW]: 390000, - WITHDRAW_WITH_EXTRA: 700000, - [RelayerJobType.MINING_REWARD]: 455000, - [RelayerJobType.MINING_WITHDRAW]: 400000, + [RelayerJobType.WITHDRAW_WITH_EXTRA]: 700000, + [RelayerJobType.OP_TORNADO_WITHDRAW]: 440000, + [RelayerJobType.ARB_TORNADO_WITHDRAW]: 1900000, }; // export const minimumBalance = '1000000000000000000'; // export const minimumTornBalance = '30000000000000000000'; diff --git a/src/services/tx.service.ts b/src/services/tx.service.ts index 242a2ee..f28375f 100644 --- a/src/services/tx.service.ts +++ b/src/services/tx.service.ts @@ -1,17 +1,19 @@ import { TransactionData, TxManager } from 'tx-manager'; import { GasPriceOracle } from 'gas-price-oracle'; import { Provider } from '@ethersproject/providers'; +import { serialize } from '@ethersproject/transactions'; import { formatEther, parseUnits } from 'ethers/lib/utils'; import { BigNumber, BigNumberish, BytesLike } from 'ethers'; import { ProxyLightABI, TornadoProxyABI } from '../contracts'; -import { BASE_FEE_RESERVE_PERCENTAGE, CONFIRMATIONS, gasLimits, MAX_GAS_PRICE, tornadoServiceFee } from '../config'; -import { JobStatus, RelayerJobType } from '../types'; +import { BASE_FEE_RESERVE_PERCENTAGE, CONFIRMATIONS, gasLimits, MAX_GAS_PRICE, netId, tornadoServiceFee } from '../config'; +import { ChainIds, JobStatus, RelayerJobType } from '../types'; import { PriceService } from './price.service'; import { Job } from 'bullmq'; import { RelayerJobData } from '../queue'; import { ConfigService } from './config.service'; import { container, injectable } from 'tsyringe'; import { parseJSON } from '../modules/utils'; +import { getOvmGasPriceOracle } from '../modules/contracts'; export type WithdrawalData = { contract: string; @@ -34,6 +36,7 @@ export class TxService { this._currentJob = value; } + gasLimit: number; txManager: TxManager; tornadoProxy: TornadoProxyABI | ProxyLightABI; oracle: GasPriceOracle; @@ -44,17 +47,33 @@ export class TxService { const { privateKey, rpcUrl, netId } = this.config; this.tornadoProxy = this.config.proxyContract; this.provider = this.tornadoProxy.provider; + const gasPriceOracleConfig = { + defaultRpc: rpcUrl, + chainId: netId, + fallbackGasPrices: this.config?.fallbackGasPrices, + }; this.txManager = new TxManager({ privateKey, rpcUrl, config: { THROW_ON_REVERT: true, CONFIRMATIONS, MAX_GAS_PRICE, BASE_FEE_RESERVE_PERCENTAGE }, + gasPriceOracleConfig, provider: this.provider, }); - this.oracle = new GasPriceOracle({ - defaultRpc: rpcUrl, - chainId: netId, - fallbackGasPrices: this.config?.fallbackGasPrices, - }); + this.oracle = new GasPriceOracle(gasPriceOracleConfig); + switch (netId) { + case ChainIds.ethereum: + case ChainIds.goerli: + this.gasLimit = gasLimits[RelayerJobType.WITHDRAW_WITH_EXTRA]; + break; + case ChainIds.optimism: + this.gasLimit = gasLimits[RelayerJobType.OP_TORNADO_WITHDRAW]; + break; + case ChainIds.arbitrum: + this.gasLimit = gasLimits[RelayerJobType.ARB_TORNADO_WITHDRAW]; + break; + default: + this.gasLimit = gasLimits[RelayerJobType.TORNADO_WITHDRAW]; + } } async updateJobData(data: Partial) { @@ -103,18 +122,42 @@ export class TxService { value: args[5], to: this.tornadoProxy.address, data: calldata, - gasLimit: gasLimits['WITHDRAW_WITH_EXTRA'], + gasLimit: this.gasLimit, }; } - async checkTornadoFee({ args, contract }: WithdrawalData) { + async getL1Fee(data: WithdrawalData, gasPrice: BigNumber) { + const { contract, proof, args } = data; + const ovmOracle = getOvmGasPriceOracle(); + const calldata = this.tornadoProxy.interface.encodeFunctionData('withdraw', [contract, proof, ...args]); + const nonce = await this.config.wallet.getTransactionCount(); + const tx = serialize({ + nonce, + type: 0, + data: calldata, + chainId: netId, + value: data.args[5], + to: this.tornadoProxy.address, + gasLimit: this.gasLimit, + gasPrice: BigNumber.from(gasPrice), + }); + return await ovmOracle.getL1Fee(tx); + } + + async checkTornadoFee(data: WithdrawalData) { + const { contract, args } = data; const instance = this.config.getInstance(contract); if (!instance) throw new Error('Instance not found'); const { currency, amount, decimals } = instance; const [fee, refund] = [args[4], args[5]].map(BigNumber.from); const gasPrice = await this.getGasPrice(); // TODO check refund value - const operationCost = gasPrice.mul(gasLimits[RelayerJobType.TORNADO_WITHDRAW]); + let operationCost = gasPrice.mul(this.gasLimit); + + if (netId === ChainIds.optimism) { + const l1Fee = await this.getL1Fee(data, gasPrice); + operationCost = operationCost.add(l1Fee); + } const serviceFee = parseUnits(amount, decimals) .mul(`${tornadoServiceFee * 1e10}`) diff --git a/src/types.ts b/src/types.ts index 27bcea3..4caf3bb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,8 @@ export enum RelayerJobType { TORNADO_WITHDRAW = 'TORNADO_WITHDRAW', - MINING_REWARD = 'MINING_REWARD', - MINING_WITHDRAW = 'MINING_WITHDRAW', + WITHDRAW_WITH_EXTRA = 'WITHDRAW_WITH_EXTRA', + OP_TORNADO_WITHDRAW = 'OP_TORNADO_WITHDRAW', + ARB_TORNADO_WITHDRAW = 'ARB_TORNADO_WITHDRAW', } export enum JobStatus { @@ -19,6 +20,7 @@ export type Token = { address: string; decimals: number; symbol?: string }; export enum ChainIds { 'kardia' = 0, 'ethereum' = 1, + 'goerli' = 5, 'ubiq' = 8, 'optimism' = 10, 'songbird' = 19,