Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

14 changed files with 163 additions and 959 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "@tornado/tornado-oracles",
"version": "3.4.0",
"version": "3.3.0",
"description": "Oracles for Tornado-specific transactions & actions",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
@ -29,6 +29,7 @@
"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",

View File

@ -9,7 +9,6 @@ export enum ChainId {
OPTIMISM = 10,
ARBITRUM = 42161,
AVAX = 43114,
SEPOLIA = 11155111,
}
export enum InstanceTokenSymbol {
@ -73,12 +72,6 @@ export const defaultGasPrices: GasPricesConfig = {
standard: 25,
low: 25,
},
[ChainId.SEPOLIA]: {
instant: 80,
fast: 50,
standard: 25,
low: 8,
},
};
type GasLimitConfig = {
@ -94,7 +87,6 @@ export const defaultWithdrawalGasLimit: GasLimitConfig = {
[ChainId.BSC]: 390000,
[ChainId.POLYGON]: 390000,
[ChainId.XDAI]: 390000,
[ChainId.SEPOLIA]: 550000,
};
type InstanceTokenGasLimitConfig = {
@ -110,6 +102,5 @@ export const defaultInstanceTokensGasLimit: InstanceTokenGasLimitConfig = {
};
export const optimismL1FeeOracleAddress = '0x420000000000000000000000000000000000000F';
export const offchainOracleAddress = '0x00000000000D6FFc74A8feb35aF5827bf57f6786';
export const sepoliaOffchainOracleAddress = '0x1f89EAF03E5b260Bc6D4Ae3c3334b1B750F3e127';
export const multiCallAddress = '0xcA11bde05977b3631167028862bE2a173976CA11';
export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb';
export const multiCallAddress = '0xda3c19c6fe954576707fa24695efb830d9cca1ca';

View File

@ -1,137 +1,30 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
PayableOverrides,
PopulatedTransaction,
Signer,
utils,
} from 'ethers';
import type { BaseContract, BigNumber, BytesLike, CallOverrides, 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 Multicall3 {
export type CallStruct = { target: string; callData: BytesLike };
export declare namespace MultiCall {
export type CallStruct = { to: string; data: BytesLike };
export type CallStructOutput = [string, 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;
to: string;
data: string;
};
}
export interface MulticallAbiInterface extends utils.Interface {
functions: {
'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;
'multicall((address,bytes)[])': FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| 'aggregate'
| 'aggregate3'
| 'aggregate3Value'
| 'blockAndAggregate'
| 'getBasefee'
| 'getBlockHash'
| 'getBlockNumber'
| 'getChainId'
| 'getCurrentBlockCoinbase'
| 'getCurrentBlockDifficulty'
| 'getCurrentBlockGasLimit'
| 'getCurrentBlockTimestamp'
| 'getEthBalance'
| 'getLastBlockHash'
| 'tryAggregate'
| 'tryBlockAndAggregate',
): FunctionFragment;
getFunction(nameOrSignatureOrTopic: 'multicall'): FunctionFragment;
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;
encodeFunctionData(functionFragment: 'multicall', values: [MultiCall.CallStruct[]]): string;
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;
decodeFunctionResult(functionFragment: 'multicall', data: BytesLike): Result;
events: {};
}
@ -159,275 +52,31 @@ export interface MulticallAbi extends BaseContract {
removeListener: OnEvent<this>;
functions: {
aggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
aggregate3(
calls: Multicall3.Call3Struct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
aggregate3Value(
calls: Multicall3.Call3ValueStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
blockAndAggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
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<ContractTransaction>;
tryBlockAndAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
};
aggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
aggregate3(
calls: Multicall3.Call3Struct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
aggregate3Value(
calls: Multicall3.Call3ValueStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
blockAndAggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
getBasefee(overrides?: CallOverrides): Promise<BigNumber>;
getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<string>;
getBlockNumber(overrides?: CallOverrides): Promise<BigNumber>;
getChainId(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<string>;
getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
getEthBalance(addr: string, overrides?: CallOverrides): Promise<BigNumber>;
getLastBlockHash(overrides?: CallOverrides): Promise<string>;
tryAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
tryBlockAndAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<ContractTransaction>;
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
callStatic: {
aggregate(
calls: Multicall3.CallStruct[],
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[BigNumber, string[]] & { blockNumber: BigNumber; returnData: string[] }>;
aggregate3(calls: Multicall3.Call3Struct[], overrides?: CallOverrides): Promise<Multicall3.ResultStructOutput[]>;
aggregate3Value(
calls: Multicall3.Call3ValueStruct[],
overrides?: CallOverrides,
): Promise<Multicall3.ResultStructOutput[]>;
blockAndAggregate(
calls: Multicall3.CallStruct[],
overrides?: CallOverrides,
): Promise<
[BigNumber, string, Multicall3.ResultStructOutput[]] & {
blockNumber: BigNumber;
blockHash: string;
returnData: Multicall3.ResultStructOutput[];
}
>;
getBasefee(overrides?: CallOverrides): Promise<BigNumber>;
getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<string>;
getBlockNumber(overrides?: CallOverrides): Promise<BigNumber>;
getChainId(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<string>;
getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
getEthBalance(addr: string, overrides?: CallOverrides): Promise<BigNumber>;
getLastBlockHash(overrides?: CallOverrides): Promise<string>;
tryAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: CallOverrides,
): Promise<Multicall3.ResultStructOutput[]>;
tryBlockAndAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: CallOverrides,
): Promise<
[BigNumber, string, Multicall3.ResultStructOutput[]] & {
blockNumber: BigNumber;
blockHash: string;
returnData: Multicall3.ResultStructOutput[];
}
>;
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
};
filters: {};
estimateGas: {
aggregate(calls: Multicall3.CallStruct[], overrides?: PayableOverrides & { from?: string }): Promise<BigNumber>;
aggregate3(calls: Multicall3.Call3Struct[], overrides?: PayableOverrides & { from?: string }): Promise<BigNumber>;
aggregate3Value(
calls: Multicall3.Call3ValueStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<BigNumber>;
blockAndAggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<BigNumber>;
getBasefee(overrides?: CallOverrides): Promise<BigNumber>;
getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<BigNumber>;
getBlockNumber(overrides?: CallOverrides): Promise<BigNumber>;
getChainId(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<BigNumber>;
getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
getEthBalance(addr: string, overrides?: CallOverrides): Promise<BigNumber>;
getLastBlockHash(overrides?: CallOverrides): Promise<BigNumber>;
tryAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<BigNumber>;
tryBlockAndAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<BigNumber>;
multicall(calls: MultiCall.CallStruct[], overrides?: CallOverrides): Promise<BigNumber>;
};
populateTransaction: {
aggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
aggregate3(
calls: Multicall3.Call3Struct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
aggregate3Value(
calls: Multicall3.Call3ValueStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
blockAndAggregate(
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
getBasefee(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getBlockHash(blockNumber: BigNumberish, overrides?: CallOverrides): Promise<PopulatedTransaction>;
getBlockNumber(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getChainId(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getCurrentBlockCoinbase(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getCurrentBlockDifficulty(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getCurrentBlockGasLimit(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getCurrentBlockTimestamp(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getEthBalance(addr: string, overrides?: CallOverrides): Promise<PopulatedTransaction>;
getLastBlockHash(overrides?: CallOverrides): Promise<PopulatedTransaction>;
tryAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
tryBlockAndAggregate(
requireSuccess: boolean,
calls: Multicall3.CallStruct[],
overrides?: PayableOverrides & { from?: string },
): Promise<PopulatedTransaction>;
multicall(calls: MultiCall.CallStruct[], overrides?: CallOverrides): Promise<PopulatedTransaction>;
};
}

View File

@ -1,21 +1,12 @@
import { OptimismL1FeeOracleAbi__factory, OffchainOracleAbi__factory, MulticallAbi__factory } from './';
import {
optimismL1FeeOracleAddress,
offchainOracleAddress,
multiCallAddress,
sepoliaOffchainOracleAddress,
} from '../config';
import { optimismL1FeeOracleAddress, offchainOracleAddress, multiCallAddress } 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, chainId?: ChainId) => {
if (chainId === ChainId.SEPOLIA) {
return OffchainOracleAbi__factory.connect(sepoliaOffchainOracleAddress, provider);
}
export const getOffchainOracleContract = (provider: Provider) => {
return OffchainOracleAbi__factory.connect(offchainOracleAddress, provider);
};

View File

@ -13,438 +13,36 @@ const _abi = [
components: [
{
internalType: 'address',
name: 'target',
name: 'to',
type: 'address',
},
{
internalType: 'bytes',
name: 'callData',
name: 'data',
type: 'bytes',
},
],
internalType: 'struct Multicall3.Call[]',
internalType: 'struct MultiCall.Call[]',
name: 'calls',
type: 'tuple[]',
},
],
name: 'aggregate',
name: 'multicall',
outputs: [
{
internalType: 'uint256',
name: 'blockNumber',
type: 'uint256',
},
{
internalType: 'bytes[]',
name: 'returnData',
name: 'results',
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',
internalType: 'bool[]',
name: 'success',
type: 'bool[]',
},
],
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 {

View File

@ -1,3 +1,4 @@
import { GasPriceOracle } from '@tornado/gas-price-oracle';
import { BigNumber, BigNumberish, ethers } from 'ethers';
import BigNumberFloat from 'bignumber.js';
import { parseUnits } from 'ethers/lib/utils';
@ -23,9 +24,10 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
protected provider: JsonRpcProvider;
public constructor(
public version: 4 | 5 | 6,
public version: 4 | 5,
protected chainId: ChainId,
rpcUrl: string,
protected oracle: GasPriceOracle,
) {
this.provider = new ethers.providers.JsonRpcProvider(rpcUrl);
}
@ -120,41 +122,12 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
* @param {number} [bumpPercent=0] Gas bump percent to prioritize transaction
* @returns {Promise<GasPriceParams>} 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<GasPriceParams> {
// 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 {
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(),
};
return await this.oracle.getTxGasParams({ legacySpeed: speed, bumpPercent });
} catch (e) {
return { gasPrice: bump(fromGweiToWeiHex(defaultGasPrices[this.chainId][speed]), bumpPercent).toHexString() };
}
@ -283,33 +256,22 @@ export abstract class TornadoFeeOracle implements ITornadoFeeOracle {
tokenPriceInEth,
predefinedGasLimit,
predefinedGasPrice,
bumpGasLimitPercent,
bumpGasPricePercent,
}: GetWithdrawalFeeViaRelayerInput): Promise<HexadecimalStringifiedNumber> {
const relayerFee = this.calculateRelayerFeeInWei(relayerFeePercent, amount, decimals);
const { gasPrice, gasLimit } = await this.getGasParams({
tx,
txType,
predefinedGasLimit,
predefinedGasPrice,
bumpGasLimitPercent,
bumpGasPricePercent,
});
const { gasPrice, gasLimit } = await this.getGasParams({ tx, txType, predefinedGasLimit, predefinedGasPrice });
const gasCosts = BigNumber.from(gasPrice).mul(gasLimit);
const hasTokenPrice =
typeof tokenPriceInEth === 'object' && typeof (tokenPriceInEth as BigNumber)?.gt === 'function'
? Boolean((tokenPriceInEth as BigNumber).gt(0))
: Boolean(tokenPriceInEth);
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';
}
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 as BigNumberish)
.add(relayerFee)
.toHexString();
return convertETHToToken(feeInEth, decimals, tokenPriceInEth).add(relayerFee).toHexString();
}
return BigNumber.from(gasCosts).add(relayerFee).toHexString();

View File

@ -1,14 +1,22 @@
import { defaultWithdrawalGasLimit } from './config';
import { TornadoFeeOracle } from './feeOracle';
import { ITornadoFeeOracle, TransactionData, TxType } from './types';
import { ITornadoFeeOracle, TransactionData, TxType, LegacyGasPrices } from './types';
import { GasPriceOracle } from '@tornado/gas-price-oracle';
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) {
super(4, chainId, rpcUrl);
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);
}
async getGasLimit(tx?: TransactionData, type: TxType = 'other', bumpPercent: number = 0): Promise<number> {

View File

@ -1,6 +1,14 @@
import { ChainId } from './config';
import { TornadoFeeOracle } from './feeOracle';
import { ITornadoFeeOracle, TransactionData, TxType, LegacyGasPriceKey, GasPriceParams } from './types';
import {
ITornadoFeeOracle,
TransactionData,
TxType,
LegacyGasPrices,
LegacyGasPriceKey,
GasPriceParams,
} from './types';
import { GasPriceOracle } from '@tornado/gas-price-oracle';
import { bump } from './utils';
import { TornadoFeeOracleV4 } from './feeOracleV4';
@ -10,10 +18,20 @@ import { TornadoFeeOracleV4 } from './feeOracleV4';
export class TornadoFeeOracleV5 extends TornadoFeeOracle implements ITornadoFeeOracle {
private fallbackFeeOracle: TornadoFeeOracleV4;
public constructor(chainId: number, rpcUrl: string) {
super(5, chainId, rpcUrl);
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);
this.fallbackFeeOracle = new TornadoFeeOracleV4(chainId, rpcUrl);
super(5, chainId, rpcUrl, gasPriceOracle);
this.fallbackFeeOracle = new TornadoFeeOracleV4(chainId, rpcUrl, defaultGasPrices);
}
async getGasLimit(tx?: TransactionData, type: TxType = 'other', bumpPercent: number = 20): Promise<number> {

View File

@ -1,73 +0,0 @@
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<number> {
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<GasPriceParams> {
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<HexadecimalStringifiedNumber> {
const fees = await super.calculateWithdrawalFeeViaRelayer(params);
const premium = params.premium || (params.txType === 'user_withdrawal' ? 20 : 5);
return bump(fees, premium).toHexString();
}
}

View File

@ -1,4 +1,3 @@
export * from './feeOracleV4';
export * from './feeOracleV5';
export * from './feeOracleV6';
export * from './tokenPriceOracle';

View File

@ -1,4 +1,4 @@
import { Multicall3 } from './contracts/MulticallAbi';
import { MultiCall } from './contracts/MulticallAbi';
import { ITornadoPriceOracle, Token, TokenPrices, TokenSymbol } from './types';
import { MulticallAbi, OffchainOracleAbi } from './contracts';
import { getMultiCallContract, getOffchainOracleContract } from './contracts/factories';
@ -49,10 +49,9 @@ 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, chainId);
this.oracle = getOffchainOracleContract(this.provider);
this.multiCall = getMultiCallContract(this.provider);
}
@ -66,11 +65,10 @@ export class TokenPriceOracle implements ITornadoPriceOracle {
* @param {Token[]} [tokens] Tokens array
* @returns Valid structure to provide to MultiCall contract
*/
private prepareCallData(tokens: Token[] = this.tokens): Multicall3.Call3Struct[] {
private prepareCallData(tokens: Token[] = this.tokens): MultiCall.CallStruct[] {
return tokens.map((token) => ({
target: this.oracle.address,
allowFailure: true,
callData: this.oracle.interface.encodeFunctionData('getRateToEth', [token.tokenAddress, true]),
to: this.oracle.address,
data: this.oracle.interface.encodeFunctionData('getRateToEth', [token.tokenAddress, true]),
}));
}
@ -84,17 +82,17 @@ export class TokenPriceOracle implements ITornadoPriceOracle {
if (!tokens?.length) return {};
const callData = this.prepareCallData(tokens);
const results = await this.multiCall.callStatic.aggregate3(callData);
const { results, success } = await this.multiCall.multicall(callData);
const prices: TokenPrices = {};
for (let i = 0; i < results.length; i++) {
const tokenSymbol = tokens[i].symbol.toLowerCase() as TokenSymbol;
if (!results[i].success) {
if (!success[i]) {
if (this.defaultTokenPrices[tokenSymbol]) prices[tokenSymbol] = this.defaultTokenPrices[tokenSymbol];
continue;
}
const decodedRate = defaultAbiCoder.decode(['uint256'], results[i].returnData).toString();
const decodedRate = defaultAbiCoder.decode(['uint256'], results[i]).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);

View File

@ -1,19 +1,13 @@
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 = 'instant' | 'fast' | 'standard' | 'low';
export type GasPriceParams =
| {
gasPrice: string;
}
| {
maxFeePerGas: string;
maxPriorityFeePerGas: string;
};
export type LegacyGasPriceKey = GasPriceKey;
export type GasPriceParams = GetTxGasParamsRes;
export type LegacyGasPrices = {
[gasPriceType in LegacyGasPriceKey]: number;
};
@ -117,6 +111,4 @@ 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)
};

View File

@ -369,6 +369,15 @@
"@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"
@ -469,6 +478,13 @@ 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"
@ -479,7 +495,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.1.1:
bignumber.js@^9.0.0, 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==
@ -551,6 +567,11 @@ 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"
@ -697,6 +718,11 @@ 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"
@ -875,6 +901,13 @@ 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"