From c9f43ff29266c48dc030a3b66e818201ff4cfc8d Mon Sep 17 00:00:00 2001 From: tornadocontrib Date: Sat, 23 Nov 2024 18:12:22 +0000 Subject: [PATCH] Remove broken external oracle and fixed EIP-1559 gasPrice calculation * Updated 1inch Oracle link and use multicall3 ( because this is the only contract supported on sepolia ) * Simplify EIP-1559 gasPrice calculation ( EIP-1559 removes necessity of using external oracles, just enough premium of basefee will ensure transaction being mined ) * Apply respective premium for fees ( Only applied on V6 Oracle class ) * Removed @tornado/gas-price-oracle oracle --- abis/Multicall.abi.json | 39 +- package.json | 3 +- src/config.ts | 13 +- src/contracts/MulticallAbi.ts | 395 +++++++++++++++- src/contracts/factories.ts | 13 +- .../factories/MulticallAbi__factory.ts | 422 +++++++++++++++++- src/feeOracle.ts | 60 ++- src/feeOracleV4.ts | 14 +- src/feeOracleV5.ts | 26 +- src/feeOracleV6.ts | 73 +++ src/index.ts | 1 + src/tokenPriceOracle.ts | 18 +- src/types.ts | 14 +- yarn.lock | 35 +- 14 files changed, 961 insertions(+), 165 deletions(-) create mode 100644 src/feeOracleV6.ts diff --git a/abis/Multicall.abi.json b/abis/Multicall.abi.json index 8f30555..75da07c 100644 --- a/abis/Multicall.abi.json +++ b/abis/Multicall.abi.json @@ -1,38 +1 @@ -[ - { - "inputs": [ - { - "components": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "internalType": "struct MultiCall.Call[]", - "name": "calls", - "type": "tuple[]" - } - ], - "name": "multicall", - "outputs": [ - { - "internalType": "bytes[]", - "name": "results", - "type": "bytes[]" - }, - { - "internalType": "bool[]", - "name": "success", - "type": "bool[]" - } - ], - "stateMutability": "view", - "type": "function" - } -] +[{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call[]","name":"calls","type":"tuple[]"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"allowFailure","type":"bool"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call3[]","name":"calls","type":"tuple[]"}],"name":"aggregate3","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct Multicall3.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bool","name":"allowFailure","type":"bool"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call3Value[]","name":"calls","type":"tuple[]"}],"name":"aggregate3Value","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct Multicall3.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call[]","name":"calls","type":"tuple[]"}],"name":"blockAndAggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct Multicall3.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getBasefee","outputs":[{"internalType":"uint256","name":"basefee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBlockNumber","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"chainid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockCoinbase","outputs":[{"internalType":"address","name":"coinbase","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockDifficulty","outputs":[{"internalType":"uint256","name":"difficulty","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockGasLimit","outputs":[{"internalType":"uint256","name":"gaslimit","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentBlockTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"getEthBalance","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastBlockHash","outputs":[{"internalType":"bytes32","name":"blockHash","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"requireSuccess","type":"bool"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call[]","name":"calls","type":"tuple[]"}],"name":"tryAggregate","outputs":[{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct Multicall3.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bool","name":"requireSuccess","type":"bool"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct Multicall3.Call[]","name":"calls","type":"tuple[]"}],"name":"tryBlockAndAggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes32","name":"blockHash","type":"bytes32"},{"components":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"returnData","type":"bytes"}],"internalType":"struct Multicall3.Result[]","name":"returnData","type":"tuple[]"}],"stateMutability":"payable","type":"function"}] \ No newline at end of file diff --git a/package.json b/package.json index 1c5baa1..84255c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tornado/tornado-oracles", - "version": "3.3.0", + "version": "3.4.0", "description": "Oracles for Tornado-specific transactions & actions", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -29,7 +29,6 @@ "author": "Theo", "license": "MIT", "dependencies": { - "@tornado/gas-price-oracle": "^0.5.3", "@tornado/tornado-config": "^2.0.0", "@types/node": "^20.5.1", "bignumber.js": "^9.1.1", diff --git a/src/config.ts b/src/config.ts index 502c9ba..a4256a0 100644 --- a/src/config.ts +++ b/src/config.ts @@ -9,6 +9,7 @@ export enum ChainId { OPTIMISM = 10, ARBITRUM = 42161, AVAX = 43114, + SEPOLIA = 11155111, } export enum InstanceTokenSymbol { @@ -72,6 +73,12 @@ export const defaultGasPrices: GasPricesConfig = { standard: 25, low: 25, }, + [ChainId.SEPOLIA]: { + instant: 80, + fast: 50, + standard: 25, + low: 8, + }, }; type GasLimitConfig = { @@ -87,6 +94,7 @@ export const defaultWithdrawalGasLimit: GasLimitConfig = { [ChainId.BSC]: 390000, [ChainId.POLYGON]: 390000, [ChainId.XDAI]: 390000, + [ChainId.SEPOLIA]: 550000, }; type InstanceTokenGasLimitConfig = { @@ -102,5 +110,6 @@ export const defaultInstanceTokensGasLimit: InstanceTokenGasLimitConfig = { }; export const optimismL1FeeOracleAddress = '0x420000000000000000000000000000000000000F'; -export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb'; -export const multiCallAddress = '0xda3c19c6fe954576707fa24695efb830d9cca1ca'; +export const offchainOracleAddress = '0x00000000000D6FFc74A8feb35aF5827bf57f6786'; +export const sepoliaOffchainOracleAddress = '0x1f89EAF03E5b260Bc6D4Ae3c3334b1B750F3e127'; +export const multiCallAddress = '0xcA11bde05977b3631167028862bE2a173976CA11'; diff --git a/src/contracts/MulticallAbi.ts b/src/contracts/MulticallAbi.ts index e4730b6..5a88929 100644 --- a/src/contracts/MulticallAbi.ts +++ b/src/contracts/MulticallAbi.ts @@ -1,30 +1,137 @@ /* Autogenerated file. Do not edit manually. */ /* tslint:disable */ /* eslint-disable */ -import type { BaseContract, BigNumber, BytesLike, CallOverrides, PopulatedTransaction, Signer, utils } from 'ethers'; +import type { + BaseContract, + BigNumber, + BigNumberish, + BytesLike, + CallOverrides, + ContractTransaction, + PayableOverrides, + PopulatedTransaction, + Signer, + utils, +} from 'ethers'; import type { FunctionFragment, Result } from '@ethersproject/abi'; import type { Listener, Provider } from '@ethersproject/providers'; import type { TypedEventFilter, TypedEvent, TypedListener, OnEvent } from './common'; -export declare namespace MultiCall { - export type CallStruct = { to: string; data: BytesLike }; +export declare namespace Multicall3 { + export type CallStruct = { target: string; callData: BytesLike }; export type CallStructOutput = [string, string] & { - to: string; - data: string; + target: string; + callData: string; + }; + + export type Call3Struct = { + target: string; + allowFailure: boolean; + callData: BytesLike; + }; + + export type Call3StructOutput = [string, boolean, string] & { + target: string; + allowFailure: boolean; + callData: string; + }; + + export type ResultStruct = { success: boolean; returnData: BytesLike }; + + export type ResultStructOutput = [boolean, string] & { + success: boolean; + returnData: string; + }; + + export type Call3ValueStruct = { + target: string; + allowFailure: boolean; + value: BigNumberish; + callData: BytesLike; + }; + + export type Call3ValueStructOutput = [string, boolean, BigNumber, string] & { + target: string; + allowFailure: boolean; + value: BigNumber; + callData: string; }; } export interface MulticallAbiInterface extends utils.Interface { functions: { - 'multicall((address,bytes)[])': FunctionFragment; + 'aggregate((address,bytes)[])': FunctionFragment; + 'aggregate3((address,bool,bytes)[])': FunctionFragment; + 'aggregate3Value((address,bool,uint256,bytes)[])': FunctionFragment; + 'blockAndAggregate((address,bytes)[])': FunctionFragment; + 'getBasefee()': FunctionFragment; + 'getBlockHash(uint256)': FunctionFragment; + 'getBlockNumber()': FunctionFragment; + 'getChainId()': FunctionFragment; + 'getCurrentBlockCoinbase()': FunctionFragment; + 'getCurrentBlockDifficulty()': FunctionFragment; + 'getCurrentBlockGasLimit()': FunctionFragment; + 'getCurrentBlockTimestamp()': FunctionFragment; + 'getEthBalance(address)': FunctionFragment; + 'getLastBlockHash()': FunctionFragment; + 'tryAggregate(bool,(address,bytes)[])': FunctionFragment; + 'tryBlockAndAggregate(bool,(address,bytes)[])': FunctionFragment; }; - getFunction(nameOrSignatureOrTopic: 'multicall'): FunctionFragment; + getFunction( + nameOrSignatureOrTopic: + | 'aggregate' + | 'aggregate3' + | 'aggregate3Value' + | 'blockAndAggregate' + | 'getBasefee' + | 'getBlockHash' + | 'getBlockNumber' + | 'getChainId' + | 'getCurrentBlockCoinbase' + | 'getCurrentBlockDifficulty' + | 'getCurrentBlockGasLimit' + | 'getCurrentBlockTimestamp' + | 'getEthBalance' + | 'getLastBlockHash' + | 'tryAggregate' + | 'tryBlockAndAggregate', + ): FunctionFragment; - encodeFunctionData(functionFragment: 'multicall', values: [MultiCall.CallStruct[]]): string; + encodeFunctionData(functionFragment: 'aggregate', values: [Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: 'aggregate3', values: [Multicall3.Call3Struct[]]): string; + encodeFunctionData(functionFragment: 'aggregate3Value', values: [Multicall3.Call3ValueStruct[]]): string; + encodeFunctionData(functionFragment: 'blockAndAggregate', values: [Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: 'getBasefee', values?: undefined): string; + encodeFunctionData(functionFragment: 'getBlockHash', values: [BigNumberish]): string; + encodeFunctionData(functionFragment: 'getBlockNumber', values?: undefined): string; + encodeFunctionData(functionFragment: 'getChainId', values?: undefined): string; + encodeFunctionData(functionFragment: 'getCurrentBlockCoinbase', values?: undefined): string; + encodeFunctionData(functionFragment: 'getCurrentBlockDifficulty', values?: undefined): string; + encodeFunctionData(functionFragment: 'getCurrentBlockGasLimit', values?: undefined): string; + encodeFunctionData(functionFragment: 'getCurrentBlockTimestamp', values?: undefined): string; + encodeFunctionData(functionFragment: 'getEthBalance', values: [string]): string; + encodeFunctionData(functionFragment: 'getLastBlockHash', values?: undefined): string; + encodeFunctionData(functionFragment: 'tryAggregate', values: [boolean, Multicall3.CallStruct[]]): string; + encodeFunctionData(functionFragment: 'tryBlockAndAggregate', values: [boolean, Multicall3.CallStruct[]]): string; - decodeFunctionResult(functionFragment: 'multicall', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'aggregate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'aggregate3', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'aggregate3Value', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'blockAndAggregate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getBasefee', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getBlockHash', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getBlockNumber', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getChainId', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getCurrentBlockCoinbase', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getCurrentBlockDifficulty', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getCurrentBlockGasLimit', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getCurrentBlockTimestamp', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getEthBalance', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'getLastBlockHash', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'tryAggregate', data: BytesLike): Result; + decodeFunctionResult(functionFragment: 'tryBlockAndAggregate', data: BytesLike): Result; events: {}; } @@ -52,31 +159,275 @@ export interface MulticallAbi extends BaseContract { removeListener: OnEvent; functions: { - multicall( - calls: MultiCall.CallStruct[], - overrides?: CallOverrides, - ): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>; + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise<[BigNumber] & { basefee: BigNumber }>; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<[string] & { blockHash: string }>; + + getBlockNumber(overrides?: CallOverrides): Promise<[BigNumber] & { blockNumber: BigNumber }>; + + getChainId(overrides?: CallOverrides): Promise<[BigNumber] & { chainid: BigNumber }>; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<[string] & { coinbase: string }>; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<[BigNumber] & { difficulty: BigNumber }>; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<[BigNumber] & { gaslimit: BigNumber }>; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<[BigNumber] & { timestamp: BigNumber }>; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise<[BigNumber] & { balance: BigNumber }>; + + getLastBlockHash(overrides?: CallOverrides): Promise<[string] & { blockHash: string }>; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; }; - multicall( - calls: MultiCall.CallStruct[], - overrides?: CallOverrides, - ): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>; + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; callStatic: { - multicall( - calls: MultiCall.CallStruct[], + aggregate( + calls: Multicall3.CallStruct[], overrides?: CallOverrides, - ): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>; + ): Promise<[BigNumber, string[]] & { blockNumber: BigNumber; returnData: string[] }>; + + aggregate3(calls: Multicall3.Call3Struct[], overrides?: CallOverrides): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: CallOverrides, + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: CallOverrides, + ): Promise< + [BigNumber, string, Multicall3.ResultStructOutput[]] & { + blockNumber: BigNumber; + blockHash: string; + returnData: Multicall3.ResultStructOutput[]; + } + >; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: CallOverrides, + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: CallOverrides, + ): Promise< + [BigNumber, string, Multicall3.ResultStructOutput[]] & { + blockNumber: BigNumber; + blockHash: string; + returnData: Multicall3.ResultStructOutput[]; + } + >; }; filters: {}; estimateGas: { - multicall(calls: MultiCall.CallStruct[], overrides?: CallOverrides): Promise; + aggregate(calls: Multicall3.CallStruct[], overrides?: PayableOverrides & { from?: string }): Promise; + + aggregate3(calls: Multicall3.Call3Struct[], overrides?: PayableOverrides & { from?: string }): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; }; populateTransaction: { - multicall(calls: MultiCall.CallStruct[], overrides?: CallOverrides): Promise; + aggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3( + calls: Multicall3.Call3Struct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + aggregate3Value( + calls: Multicall3.Call3ValueStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + blockAndAggregate( + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + getBasefee(overrides?: CallOverrides): Promise; + + getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise; + + getBlockNumber(overrides?: CallOverrides): Promise; + + getChainId(overrides?: CallOverrides): Promise; + + getCurrentBlockCoinbase(overrides?: CallOverrides): Promise; + + getCurrentBlockDifficulty(overrides?: CallOverrides): Promise; + + getCurrentBlockGasLimit(overrides?: CallOverrides): Promise; + + getCurrentBlockTimestamp(overrides?: CallOverrides): Promise; + + getEthBalance(addr: string, overrides?: CallOverrides): Promise; + + getLastBlockHash(overrides?: CallOverrides): Promise; + + tryAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; + + tryBlockAndAggregate( + requireSuccess: boolean, + calls: Multicall3.CallStruct[], + overrides?: PayableOverrides & { from?: string }, + ): Promise; }; } diff --git a/src/contracts/factories.ts b/src/contracts/factories.ts index 7b9efd2..225d933 100644 --- a/src/contracts/factories.ts +++ b/src/contracts/factories.ts @@ -1,12 +1,21 @@ import { OptimismL1FeeOracleAbi__factory, OffchainOracleAbi__factory, MulticallAbi__factory } from './'; -import { optimismL1FeeOracleAddress, offchainOracleAddress, multiCallAddress } from '../config'; +import { + optimismL1FeeOracleAddress, + offchainOracleAddress, + multiCallAddress, + sepoliaOffchainOracleAddress, +} from '../config'; import { Provider } from '@ethersproject/abstract-provider'; +import { ChainId } from '../config'; export const getOptimismL1FeeOracle = (provider: Provider) => { return OptimismL1FeeOracleAbi__factory.connect(optimismL1FeeOracleAddress, provider); }; -export const getOffchainOracleContract = (provider: Provider) => { +export const getOffchainOracleContract = (provider: Provider, chainId?: ChainId) => { + if (chainId === ChainId.SEPOLIA) { + return OffchainOracleAbi__factory.connect(sepoliaOffchainOracleAddress, provider); + } return OffchainOracleAbi__factory.connect(offchainOracleAddress, provider); }; diff --git a/src/contracts/factories/MulticallAbi__factory.ts b/src/contracts/factories/MulticallAbi__factory.ts index a598f0f..7415b12 100644 --- a/src/contracts/factories/MulticallAbi__factory.ts +++ b/src/contracts/factories/MulticallAbi__factory.ts @@ -13,36 +13,438 @@ const _abi = [ components: [ { internalType: 'address', - name: 'to', + name: 'target', type: 'address', }, { internalType: 'bytes', - name: 'data', + name: 'callData', type: 'bytes', }, ], - internalType: 'struct MultiCall.Call[]', + internalType: 'struct Multicall3.Call[]', name: 'calls', type: 'tuple[]', }, ], - name: 'multicall', + name: 'aggregate', outputs: [ { - internalType: 'bytes[]', - name: 'results', - type: 'bytes[]', + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', }, { - internalType: 'bool[]', - name: 'success', - type: 'bool[]', + internalType: 'bytes[]', + name: 'returnData', + type: 'bytes[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bool', + name: 'allowFailure', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Call3[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'aggregate3', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bool', + name: 'allowFailure', + type: 'bool', + }, + { + internalType: 'uint256', + name: 'value', + type: 'uint256', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Call3Value[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'aggregate3Value', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'blockAndAggregate', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [], + name: 'getBasefee', + outputs: [ + { + internalType: 'uint256', + name: 'basefee', + type: 'uint256', }, ], stateMutability: 'view', type: 'function', }, + { + inputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + name: 'getBlockHash', + outputs: [ + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getBlockNumber', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getChainId', + outputs: [ + { + internalType: 'uint256', + name: 'chainid', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockCoinbase', + outputs: [ + { + internalType: 'address', + name: 'coinbase', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockDifficulty', + outputs: [ + { + internalType: 'uint256', + name: 'difficulty', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockGasLimit', + outputs: [ + { + internalType: 'uint256', + name: 'gaslimit', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getCurrentBlockTimestamp', + outputs: [ + { + internalType: 'uint256', + name: 'timestamp', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: 'addr', + type: 'address', + }, + ], + name: 'getEthBalance', + outputs: [ + { + internalType: 'uint256', + name: 'balance', + type: 'uint256', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'getLastBlockHash', + outputs: [ + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bool', + name: 'requireSuccess', + type: 'bool', + }, + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'tryAggregate', + outputs: [ + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bool', + name: 'requireSuccess', + type: 'bool', + }, + { + components: [ + { + internalType: 'address', + name: 'target', + type: 'address', + }, + { + internalType: 'bytes', + name: 'callData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Call[]', + name: 'calls', + type: 'tuple[]', + }, + ], + name: 'tryBlockAndAggregate', + outputs: [ + { + internalType: 'uint256', + name: 'blockNumber', + type: 'uint256', + }, + { + internalType: 'bytes32', + name: 'blockHash', + type: 'bytes32', + }, + { + components: [ + { + internalType: 'bool', + name: 'success', + type: 'bool', + }, + { + internalType: 'bytes', + name: 'returnData', + type: 'bytes', + }, + ], + internalType: 'struct Multicall3.Result[]', + name: 'returnData', + type: 'tuple[]', + }, + ], + stateMutability: 'payable', + type: 'function', + }, ] as const; export class MulticallAbi__factory { diff --git a/src/feeOracle.ts b/src/feeOracle.ts index 9fb44ac..b43d562 100644 --- a/src/feeOracle.ts +++ b/src/feeOracle.ts @@ -1,4 +1,3 @@ -import { GasPriceOracle } from '@tornado/gas-price-oracle'; import { BigNumber, BigNumberish, ethers } from 'ethers'; import BigNumberFloat from 'bignumber.js'; import { parseUnits } from 'ethers/lib/utils'; @@ -24,10 +23,9 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle { protected provider: JsonRpcProvider; public constructor( - public version: 4 | 5, + public version: 4 | 5 | 6, protected chainId: ChainId, rpcUrl: string, - protected oracle: GasPriceOracle, ) { this.provider = new ethers.providers.JsonRpcProvider(rpcUrl); } @@ -122,12 +120,41 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle { * @param {number} [bumpPercent=0] Gas bump percent to prioritize transaction * @returns {Promise} Estimated gas price info in WEI (hexed) - legacy object with gasPrice property or * EIP-1559 object with maxFeePerGas and maxPriorityFeePerGas properties + * NOTICE: It is recommended to bump fees for EIP-1559 transactions, because they can bump 12.5% per block */ async getGasPriceParams(speed?: LegacyGasPriceKey, bumpPercent: number = 0): Promise { // Use instant for BSC, because on this chain "fast" and "instant" differs more than third and "fast" transaction can take hours if (!speed) speed = this.chainId === ChainId.BSC ? 'instant' : 'fast'; try { - return await this.oracle.getTxGasParams({ legacySpeed: speed, bumpPercent }); + const [block, gasPrice, priorityFee] = await Promise.all([ + this.provider.getBlock('latest'), + this.provider.getGasPrice(), + (async () => { + try { + return BigNumber.from( + (await this.provider.send('eth_maxPriorityFeePerGas', [])) || parseUnits('1.5', 'gwei'), + ); + } catch { + return parseUnits('1.5', 'gwei'); + } + })(), + ]); + + if (block?.baseFeePerGas?.gt(0)) { + const maxPriorityFeePerGas = priorityFee.toHexString(); + const maxFeePerGas = bump(block.baseFeePerGas as BigNumber, bumpPercent) + .add(priorityFee) + .toHexString(); + + return { + maxFeePerGas, + maxPriorityFeePerGas, + }; + } + + return { + gasPrice: bump(gasPrice, bumpPercent).toHexString(), + }; } catch (e) { return { gasPrice: bump(fromGweiToWeiHex(defaultGasPrices[this.chainId][speed]), bumpPercent).toHexString() }; } @@ -256,22 +283,33 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle { tokenPriceInEth, predefinedGasLimit, predefinedGasPrice, + bumpGasLimitPercent, + bumpGasPricePercent, }: GetWithdrawalFeeViaRelayerInput): Promise { const relayerFee = this.calculateRelayerFeeInWei(relayerFeePercent, amount, decimals); - const { gasPrice, gasLimit } = await this.getGasParams({ tx, txType, predefinedGasLimit, predefinedGasPrice }); + const { gasPrice, gasLimit } = await this.getGasParams({ + tx, + txType, + predefinedGasLimit, + predefinedGasPrice, + bumpGasLimitPercent, + bumpGasPricePercent, + }); const gasCosts = BigNumber.from(gasPrice).mul(gasLimit); - if ((this.chainId === ChainId.MAINNET || this.chainId === ChainId.GOERLI) && currency.toLowerCase() != 'eth') { - if (!tokenPriceInEth) { - console.error('Token price is required argument, if not native chain token is withdrawed'); - return '0'; - } + const hasTokenPrice = + typeof tokenPriceInEth === 'object' && typeof (tokenPriceInEth as BigNumber)?.gt === 'function' + ? Boolean((tokenPriceInEth as BigNumber).gt(0)) + : Boolean(tokenPriceInEth); + if (hasTokenPrice) { if (txType === 'user_withdrawal' && refundInEth === undefined) refundInEth = this.calculateRefundInETH(gasPrice, currency.toLowerCase() as InstanceTokenSymbol); const feeInEth = BigNumber.from(gasCosts).add(refundInEth || 0); - return convertETHToToken(feeInEth, decimals, tokenPriceInEth).add(relayerFee).toHexString(); + return convertETHToToken(feeInEth, decimals, tokenPriceInEth as BigNumberish) + .add(relayerFee) + .toHexString(); } return BigNumber.from(gasCosts).add(relayerFee).toHexString(); diff --git a/src/feeOracleV4.ts b/src/feeOracleV4.ts index d073362..bc6ee12 100644 --- a/src/feeOracleV4.ts +++ b/src/feeOracleV4.ts @@ -1,22 +1,14 @@ import { defaultWithdrawalGasLimit } from './config'; import { TornadoFeeOracle } from './feeOracle'; -import { ITornadoFeeOracle, TransactionData, TxType, LegacyGasPrices } from './types'; -import { GasPriceOracle } from '@tornado/gas-price-oracle'; +import { ITornadoFeeOracle, TransactionData, TxType } from './types'; import { bump } from './utils'; /** * Oracle for V4 (old-version) transactions - estimates fee with predefined gas limit and without smart bumping */ export class TornadoFeeOracleV4 extends TornadoFeeOracle implements ITornadoFeeOracle { - public constructor(chainId: number, rpcUrl: string, defaultGasPrices?: LegacyGasPrices) { - const oracleConfig = { - chainId, - defaultRpc: rpcUrl, - defaultFallbackGasPrices: defaultGasPrices, - }; - const gasPriceOracle = new GasPriceOracle(oracleConfig); - - super(4, chainId, rpcUrl, gasPriceOracle); + public constructor(chainId: number, rpcUrl: string) { + super(4, chainId, rpcUrl); } async getGasLimit(tx?: TransactionData, type: TxType = 'other', bumpPercent: number = 0): Promise { diff --git a/src/feeOracleV5.ts b/src/feeOracleV5.ts index 7babced..61e5d0c 100644 --- a/src/feeOracleV5.ts +++ b/src/feeOracleV5.ts @@ -1,14 +1,6 @@ import { ChainId } from './config'; import { TornadoFeeOracle } from './feeOracle'; -import { - ITornadoFeeOracle, - TransactionData, - TxType, - LegacyGasPrices, - LegacyGasPriceKey, - GasPriceParams, -} from './types'; -import { GasPriceOracle } from '@tornado/gas-price-oracle'; +import { ITornadoFeeOracle, TransactionData, TxType, LegacyGasPriceKey, GasPriceParams } from './types'; import { bump } from './utils'; import { TornadoFeeOracleV4 } from './feeOracleV4'; @@ -18,20 +10,10 @@ import { TornadoFeeOracleV4 } from './feeOracleV4'; export class TornadoFeeOracleV5 extends TornadoFeeOracle implements ITornadoFeeOracle { private fallbackFeeOracle: TornadoFeeOracleV4; - public constructor(chainId: number, rpcUrl: string, defaultGasPrices?: LegacyGasPrices) { - const oracleConfig = { - chainId, - defaultRpc: rpcUrl, - minPriority: chainId === ChainId.MAINNET || chainId === ChainId.GOERLI ? 2 : chainId === ChainId.BSC ? 3 : 0.05, - percentile: 5, - blocksCount: 20, - defaultFallbackGasPrices: defaultGasPrices, - }; - const gasPriceOracle = new GasPriceOracle(oracleConfig); + public constructor(chainId: number, rpcUrl: string) { + super(5, chainId, rpcUrl); - super(5, chainId, rpcUrl, gasPriceOracle); - - this.fallbackFeeOracle = new TornadoFeeOracleV4(chainId, rpcUrl, defaultGasPrices); + this.fallbackFeeOracle = new TornadoFeeOracleV4(chainId, rpcUrl); } async getGasLimit(tx?: TransactionData, type: TxType = 'other', bumpPercent: number = 20): Promise { diff --git a/src/feeOracleV6.ts b/src/feeOracleV6.ts new file mode 100644 index 0000000..034bffb --- /dev/null +++ b/src/feeOracleV6.ts @@ -0,0 +1,73 @@ +import { ChainId } from './config'; +import { TornadoFeeOracle } from './feeOracle'; +import { + ITornadoFeeOracle, + TransactionData, + TxType, + LegacyGasPriceKey, + GasPriceParams, + GetWithdrawalFeeViaRelayerInput, + HexadecimalStringifiedNumber, +} from './types'; +import { bump } from './utils'; +import { TornadoFeeOracleV5 } from './feeOracleV5'; + +/** + * V6 version that would cover every available networks and relayers + * + * Ported from https://git.tornado.ws/tornadocontrib/tornado-core/src/branch/main/src/fees.ts and has been verified over time + */ +export class TornadoFeeOracleV6 extends TornadoFeeOracle implements ITornadoFeeOracle { + private fallbackFeeOracle: TornadoFeeOracleV5; + // Override value for BSC (Since old relayers use static value of 3.3 gwei) + public overrideGasPrice?: GasPriceParams; + + public constructor(chainId: number, rpcUrl: string, overrideGasPrice?: GasPriceParams) { + super(6, chainId, rpcUrl); + + this.fallbackFeeOracle = new TornadoFeeOracleV5(chainId, rpcUrl); + this.overrideGasPrice = overrideGasPrice; + } + + /** + * Apply static 10% gasLimit premium as it wouldn't change across nodes or relayers + */ + async getGasLimit(tx?: TransactionData, type: TxType = 'other', bumpPercent: number = 10): Promise { + if (!tx || Object.keys(tx).length === 0) return this.fallbackFeeOracle.getGasLimit(tx, type, bumpPercent); + + const fetchedGasLimit = await this.provider.estimateGas(tx); + return bump(fetchedGasLimit, bumpPercent).toNumber(); + } + + /** + * Apply static 50% gasPrice premium for EIP-1559 enabled networks + * + * Because Tornado Transactions are censored from block builders + * it would take some time to be confirmed after when the transaction is broadcasted. + * + * We apply 50% premium to combat basefee spike (ethers.js uses 100% premium by default) + * (Can spike 12.5% per block accoring to the EIP-1559 metrics https://metamask.io/1559/) + */ + async getGasPriceParams(speed?: LegacyGasPriceKey, bumpPercent?: number): Promise { + if (this.overrideGasPrice) { + return this.overrideGasPrice; + } + if (typeof bumpPercent === 'undefined') { + bumpPercent = this.chainId === ChainId.BSC ? undefined : 50; + } + return super.getGasPriceParams(speed, bumpPercent); + } + + /** + * Apply 20% premium from the calculated fee from UI, applies 5% fee from relayer to prevent arbitrage from refund + */ + async calculateWithdrawalFeeViaRelayer( + params: GetWithdrawalFeeViaRelayerInput & { premium?: number }, + ): Promise { + const fees = await super.calculateWithdrawalFeeViaRelayer(params); + + const premium = params.premium || (params.txType === 'user_withdrawal' ? 20 : 5); + + return bump(fees, premium).toHexString(); + } +} diff --git a/src/index.ts b/src/index.ts index bbf0996..127e543 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ export * from './feeOracleV4'; export * from './feeOracleV5'; +export * from './feeOracleV6'; export * from './tokenPriceOracle'; diff --git a/src/tokenPriceOracle.ts b/src/tokenPriceOracle.ts index a2c0ae8..acc9594 100644 --- a/src/tokenPriceOracle.ts +++ b/src/tokenPriceOracle.ts @@ -1,4 +1,4 @@ -import { MultiCall } from './contracts/MulticallAbi'; +import { Multicall3 } from './contracts/MulticallAbi'; import { ITornadoPriceOracle, Token, TokenPrices, TokenSymbol } from './types'; import { MulticallAbi, OffchainOracleAbi } from './contracts'; import { getMultiCallContract, getOffchainOracleContract } from './contracts/factories'; @@ -49,9 +49,10 @@ export class TokenPriceOracle implements ITornadoPriceOracle { rpcUrl: string, private tokens: Token[] = tornadoTokens, private defaultTokenPrices: TokenPrices = defaultTornadoTokenPrices, + chainId?: ChainId, ) { this.provider = new ethers.providers.JsonRpcProvider(rpcUrl); - this.oracle = getOffchainOracleContract(this.provider); + this.oracle = getOffchainOracleContract(this.provider, chainId); this.multiCall = getMultiCallContract(this.provider); } @@ -65,10 +66,11 @@ export class TokenPriceOracle implements ITornadoPriceOracle { * @param {Token[]} [tokens] Tokens array * @returns Valid structure to provide to MultiCall contract */ - private prepareCallData(tokens: Token[] = this.tokens): MultiCall.CallStruct[] { + private prepareCallData(tokens: Token[] = this.tokens): Multicall3.Call3Struct[] { return tokens.map((token) => ({ - to: this.oracle.address, - data: this.oracle.interface.encodeFunctionData('getRateToEth', [token.tokenAddress, true]), + target: this.oracle.address, + allowFailure: true, + callData: this.oracle.interface.encodeFunctionData('getRateToEth', [token.tokenAddress, true]), })); } @@ -82,17 +84,17 @@ export class TokenPriceOracle implements ITornadoPriceOracle { if (!tokens?.length) return {}; const callData = this.prepareCallData(tokens); - const { results, success } = await this.multiCall.multicall(callData); + const results = await this.multiCall.callStatic.aggregate3(callData); const prices: TokenPrices = {}; for (let i = 0; i < results.length; i++) { const tokenSymbol = tokens[i].symbol.toLowerCase() as TokenSymbol; - if (!success[i]) { + if (!results[i].success) { if (this.defaultTokenPrices[tokenSymbol]) prices[tokenSymbol] = this.defaultTokenPrices[tokenSymbol]; continue; } - const decodedRate = defaultAbiCoder.decode(['uint256'], results[i]).toString(); + const decodedRate = defaultAbiCoder.decode(['uint256'], results[i].returnData).toString(); const tokenDecimals = BigNumber.from(10).pow(tokens[i].decimals); const ethDecimals = BigNumber.from(10).pow(18); const price = BigNumber.from(decodedRate).mul(tokenDecimals).div(ethDecimals); diff --git a/src/types.ts b/src/types.ts index b21a705..9ffabe8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,13 +1,19 @@ import { BigNumberish, BytesLike } from 'ethers'; -import { GasPriceKey, GetTxGasParamsRes } from '@tornado/gas-price-oracle/lib/services'; import { AvailableTokenSymbols } from '@tornado/tornado-config'; import { InstanceTokenSymbol } from './config'; // Type for big hexadecimal numbers, like 0x1eff87f47e37a0 export type HexadecimalStringifiedNumber = string; -export type LegacyGasPriceKey = GasPriceKey; -export type GasPriceParams = GetTxGasParamsRes; +export type LegacyGasPriceKey = 'instant' | 'fast' | 'standard' | 'low'; +export type GasPriceParams = + | { + gasPrice: string; + } + | { + maxFeePerGas: string; + maxPriorityFeePerGas: string; + }; export type LegacyGasPrices = { [gasPriceType in LegacyGasPriceKey]: number; }; @@ -111,4 +117,6 @@ export type GetWithdrawalFeeViaRelayerInput = { tokenPriceInEth?: HexadecimalStringifiedNumber | string; // Token (currency) price in ETH wei, if withdrawing non-native currency predefinedGasPrice?: HexadecimalStringifiedNumber; // Predefined gas price for withdrawal tx (wont be calculated again in function) predefinedGasLimit?: number; // Predefined gas limit for withdrawal tx (wont be calculated again in function) + bumpGasLimitPercent?: number; // Gas limit bump percent to prioritize transaction (recenlty used) + bumpGasPricePercent?: number; // Gas price bump percent to prioritize transaction (rarely used) }; diff --git a/yarn.lock b/yarn.lock index cadb3b5..a0a61df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -369,15 +369,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@tornado/gas-price-oracle@^0.5.3": - version "0.5.3" - resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Fgas-price-oracle/-/0.5.3/gas-price-oracle-0.5.3.tgz#fb5423dddee2f52edbc16174c5ddce90bea5413d" - integrity sha512-LpVfPiPIz3FOmJdiqJf/yoeO5n9/Pd5jgtdY+6hB9lNW0AiWhylhpScojICViS+3OL9QC8CoTlgr+kbfGeO9pQ== - dependencies: - axios "^0.21.2" - bignumber.js "^9.0.0" - node-cache "^5.1.2" - "@tornado/tornado-config@^2.0.0": version "2.0.0" resolved "https://git.tornado.ws/api/packages/tornado-packages/npm/%40tornado%2Ftornado-config/-/2.0.0/tornado-config-2.0.0.tgz#52bbc179ecb2385f71b4d56e060b68e7dd6fb8b4" @@ -478,13 +469,6 @@ array-back@^4.0.1, array-back@^4.0.2: resolved "https://registry.yarnpkg.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== -axios@^0.21.2: - version "0.21.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -495,7 +479,7 @@ bech32@1.1.4: resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== -bignumber.js@^9.0.0, bignumber.js@^9.1.1: +bignumber.js@^9.1.1: version "9.1.1" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== @@ -567,11 +551,6 @@ chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" -clone@2.x: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -718,11 +697,6 @@ find-replace@^3.0.0: dependencies: array-back "^3.0.1" -follow-redirects@^1.14.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== - fs-extra@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" @@ -901,13 +875,6 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -node-cache@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" - integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== - dependencies: - clone "2.x" - nodemon@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.0.1.tgz#affe822a2c5f21354466b2fc8ae83277d27dadc7"