Fix refund calculation: we need to use different gas limits for each ERC tokens & bump lib version to 1.2.0

This commit is contained in:
Theo 2023-08-22 11:56:38 -07:00
parent 40bf17177b
commit 76a0ccea68
4 changed files with 35 additions and 13 deletions

@ -1,6 +1,6 @@
{ {
"name": "@tornado/tornado-oracles", "name": "@tornado/tornado-oracles",
"version": "1.1.0", "version": "1.2.0",
"description": "Gas oracle for Tornado-specific transactions", "description": "Gas oracle for Tornado-specific transactions",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",

@ -11,6 +11,14 @@ export enum ChainId {
AVAX = 43114, AVAX = 43114,
} }
export enum InstanceTokenSymbol {
DAI = 'dai',
cDAI = 'cdai',
WBTC = 'wbtc',
USDT = 'usdt',
USDC = 'usdc',
}
export type GasPricesConfig = { export type GasPricesConfig = {
[chainId in ChainId]: LegacyGasPrices; [chainId in ChainId]: LegacyGasPrices;
}; };
@ -81,6 +89,18 @@ export const defaultWithdrawalGasLimit: GasLimitConfig = {
[ChainId.XDAI]: 390000, [ChainId.XDAI]: 390000,
}; };
type InstanceTokenGasLimitConfig = {
[tokenSymbol in InstanceTokenSymbol]: number;
};
export const defaultInstanceTokensGasLimit: InstanceTokenGasLimitConfig = {
[InstanceTokenSymbol.DAI]: 55000,
[InstanceTokenSymbol.cDAI]: 425000,
[InstanceTokenSymbol.WBTC]: 85000,
[InstanceTokenSymbol.USDT]: 100000,
[InstanceTokenSymbol.USDC]: 80000,
};
export const optimismL1FeeOracleAddress = '0x420000000000000000000000000000000000000F'; export const optimismL1FeeOracleAddress = '0x420000000000000000000000000000000000000F';
export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb'; export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb';
export const multiCallAddress = '0xda3c19c6fe954576707fa24695efb830d9cca1ca'; export const multiCallAddress = '0xda3c19c6fe954576707fa24695efb830d9cca1ca';

@ -3,7 +3,7 @@ import { BigNumber, BigNumberish, ethers } from 'ethers';
import { parseUnits } from 'ethers/lib/utils'; import { parseUnits } from 'ethers/lib/utils';
import { TransactionData, TxType, ITornadoFeeOracle, LegacyGasPriceKey, GasPriceParams } from './types'; import { TransactionData, TxType, ITornadoFeeOracle, LegacyGasPriceKey, GasPriceParams } from './types';
import { JsonRpcProvider } from '@ethersproject/providers'; import { JsonRpcProvider } from '@ethersproject/providers';
import { ChainId, defaultGasPrices } from './config'; import { ChainId, defaultGasPrices, defaultInstanceTokensGasLimit, InstanceTokenSymbol } from './config';
import { bump, calculateGasPriceInWei, convertETHToToken, fromGweiToWeiHex, serializeTx } from './utils'; import { bump, calculateGasPriceInWei, convertETHToToken, fromGweiToWeiHex, serializeTx } from './utils';
import { getOptimismL1FeeOracle } from './contracts/factories'; import { getOptimismL1FeeOracle } from './contracts/factories';
import { AvailableTokenSymbols } from '@tornado/tornado-config'; import { AvailableTokenSymbols } from '@tornado/tornado-config';
@ -102,28 +102,29 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
* and if the relayer pays a commission and the transfer of tokens fails, this commission will remain to the relayer. * and if the relayer pays a commission and the transfer of tokens fails, this commission will remain to the relayer.
* *
* Refund needed that recipient can use tokens after withdrawal (covers gas fee for send/swap) * Refund needed that recipient can use tokens after withdrawal (covers gas fee for send/swap)
* @param {TransactionData} [tx] Transaction data (object in web3 / ethers format) * @param {InstanceTokenSymbol} tokenSymbol Withdrawal token (currency) symbol - for example, 'dai'
* @returns {Promise<string>} Refund amount in WEI (hexed number) * @returns {Promise<string>} Refund amount in WEI (hexed number)
*/ */
async calculateRefundInETH(tx?: TransactionData): Promise<string> { async calculateRefundInETH(tokenSymbol: InstanceTokenSymbol): Promise<string> {
// In Tornado we need to calculate refund only on user side, relayer get refund value in proof // In Tornado we need to calculate refund only on user side, relayer get refund value in proof
const gas = await this.getGas(tx, 'user_withdrawal'); const gasPrice = await this.getGasPrice();
return BigNumber.from(gas).mul(2).toHexString(); const gasLimit = defaultInstanceTokensGasLimit[tokenSymbol];
return BigNumber.from(gasPrice).mul(gasLimit).mul(2).toHexString();
} }
/** /**
* Get refund amount on ETH or Goerli in non-native token * Get refund amount on ETH or Goerli in non-native token
* @param {BigNumberish} tokenPriceInEth Token price in WEI in native currency * @param {BigNumberish} tokenPriceInEth Token price in WEI in native currency
* @param {string | number} tokenDecimals Token (currency) decimals * @param {string | number} tokenDecimals Token (currency) decimals
* @param {TransactionData} [tx] Transaction data (object in web3 / ethers format) * @param {InstanceTokenSymbol} tokenSymbol Withdrawal token (currency) symbol - for example, 'dai'
* @returns {Promise<string>} Refund amount in WEI in selected token (hexed number) * @returns {Promise<string>} Refund amount in WEI in selected token (hexed number)
*/ */
async calculateRefundInToken( async calculateRefundInToken(
tokenPriceInEth: BigNumberish, tokenPriceInEth: BigNumberish,
tokenDecimals: string | number, tokenDecimals: string | number,
tx?: TransactionData, tokenSymbol: InstanceTokenSymbol,
): Promise<string> { ): Promise<string> {
const refundInEth = await this.calculateRefundInETH(tx); const refundInEth = await this.calculateRefundInETH(tokenSymbol);
return convertETHToToken(refundInEth, tokenDecimals, tokenPriceInEth).toHexString(); return convertETHToToken(refundInEth, tokenDecimals, tokenPriceInEth).toHexString();
} }
@ -148,7 +149,7 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
currency: AvailableTokenSymbols | Uppercase<AvailableTokenSymbols>, currency: AvailableTokenSymbols | Uppercase<AvailableTokenSymbols>,
amount: string | number, amount: string | number,
decimals: string | number, decimals: string | number,
refund: BigNumberish = 0, refundInEth: BigNumberish = 0,
tokenPriceInEth?: BigNumberish, tokenPriceInEth?: BigNumberish,
): Promise<string> { ): Promise<string> {
const gasCosts = BigNumber.from(await this.getGas(tx, type)); const gasCosts = BigNumber.from(await this.getGas(tx, type));
@ -163,7 +164,7 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
return '0'; return '0';
} }
const feeInEth = gasCosts.add(refund); const feeInEth = gasCosts.add(refundInEth);
return convertETHToToken(feeInEth, decimals, tokenPriceInEth).add(relayerFee).toHexString(); return convertETHToToken(feeInEth, decimals, tokenPriceInEth).add(relayerFee).toHexString();
} }

@ -1,6 +1,7 @@
import { BigNumberish, BytesLike } from 'ethers'; import { BigNumberish, BytesLike } from 'ethers';
import { GasPriceKey, GetTxGasParamsRes } from '@tornado/gas-price-oracle/lib/services'; import { GasPriceKey, GetTxGasParamsRes } from '@tornado/gas-price-oracle/lib/services';
import { AvailableTokenSymbols } from '@tornado/tornado-config'; import { AvailableTokenSymbols } from '@tornado/tornado-config';
import { InstanceTokenSymbol } from './config';
export type LegacyGasPriceKey = GasPriceKey; export type LegacyGasPriceKey = GasPriceKey;
export type GasPriceParams = GetTxGasParamsRes; export type GasPriceParams = GetTxGasParamsRes;
@ -36,11 +37,11 @@ export interface ITornadoFeeOracle {
getGasPrice: (type?: TxType, speed?: LegacyGasPriceKey, bumpPercent?: number) => Promise<string>; getGasPrice: (type?: TxType, speed?: LegacyGasPriceKey, bumpPercent?: number) => Promise<string>;
getGasLimit: (tx?: TransactionData, type?: TxType, bumpPercent?: number) => Promise<number>; getGasLimit: (tx?: TransactionData, type?: TxType, bumpPercent?: number) => Promise<number>;
fetchL1OptimismFee: (tx?: TransactionData) => Promise<string>; fetchL1OptimismFee: (tx?: TransactionData) => Promise<string>;
calculateRefundInETH: (tx?: TransactionData) => Promise<string>; calculateRefundInETH: (tokenSymbol: InstanceTokenSymbol) => Promise<string>;
calculateRefundInToken: ( calculateRefundInToken: (
tokenPriceInEth: BigNumberish, tokenPriceInEth: BigNumberish,
tokenDecimals: string | number, tokenDecimals: string | number,
tx?: TransactionData, tokenSymbol: InstanceTokenSymbol,
) => Promise<string>; ) => Promise<string>;
calculateWithdrawalFeeViaRelayer: ( calculateWithdrawalFeeViaRelayer: (
type: TxType, type: TxType,