This commit is contained in:
smart_ex 2022-05-10 18:52:07 +10:00
parent 3c5eaa2c4b
commit 4595085d61
58 changed files with 17604 additions and 1070 deletions

View File

@ -1,45 +1,35 @@
{
"env": {
"node": true,
"browser": true,
"es6": true,
"mocha": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
"commonjs": true,
"es2020": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018
"ecmaVersion": 11
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": [
"linebreak-style": [
"error",
2,
{
"SwitchCase": 1
}
"unix"
],
"linebreak-style": ["error", "unix"],
"quotes": [
"error",
"single",
{
"avoidEscape": true
}
"single"
],
"semi": ["error", "never"],
"object-curly-spacing": ["error", "always"],
"require-await": "error",
"comma-dangle": ["error", "only-multiline"],
"space-before-function-paren": [
"semi": [
"error",
{
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}
]
"always"
],
"no-useless-catch": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}

View File

@ -1 +0,0 @@
keys/TreeUpdate.json

View File

@ -1,7 +0,0 @@
{
"semi": false,
"arrowParens": "avoid",
"singleQuote": true,
"printWidth": 110,
"trailingComma": "all"
}

View File

@ -2,107 +2,198 @@
{
"inputs": [
{
"internalType": "bytes32[]",
"name": "domains",
"type": "bytes32[]"
}
],
"name": "bulkResolve",
"outputs": [
"internalType": "contract MultiWrapper",
"name": "_multiWrapper",
"type": "address"
},
{
"internalType": "address[]",
"name": "result",
"internalType": "contract IOracle[]",
"name": "existingOracles",
"type": "address[]"
},
{
"internalType": "enum OffchainOracle.OracleType[]",
"name": "oracleTypes",
"type": "uint8[]"
},
{
"internalType": "contract IERC20[]",
"name": "existingConnectors",
"type": "address[]"
},
{
"internalType": "contract IERC20",
"name": "wBase",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract IERC20",
"name": "connector",
"type": "address"
}
],
"name": "ConnectorAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract IERC20",
"name": "connector",
"type": "address"
}
],
"name": "ConnectorRemoved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract MultiWrapper",
"name": "multiWrapper",
"type": "address"
}
],
"name": "MultiWrapperUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract IOracle",
"name": "oracle",
"type": "address"
},
{
"indexed": false,
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleType",
"type": "uint8"
}
],
"name": "OracleAdded",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "contract IOracle",
"name": "oracle",
"type": "address"
},
{
"indexed": false,
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleType",
"type": "uint8"
}
],
"name": "OracleRemoved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [
{
"internalType": "contract IERC20",
"name": "connector",
"type": "address"
}
],
"name": "addConnector",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
}
],
"name": "getAllProposals",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "uint256",
"name": "startTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "endTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "forVotes",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "againstVotes",
"type": "uint256"
},
{
"internalType": "bool",
"name": "executed",
"type": "bool"
},
{
"internalType": "bool",
"name": "extended",
"type": "bool"
},
{
"internalType": "enum Governance.ProposalState",
"name": "state",
"type": "uint8"
}
],
"internalType": "struct GovernanceAggregator.Proposal[]",
"name": "proposals",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"internalType": "contract IOracle",
"name": "oracle",
"type": "address"
},
{
"internalType": "address[]",
"name": "accs",
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleKind",
"type": "uint8"
}
],
"name": "addOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "connectors",
"outputs": [
{
"internalType": "contract IERC20[]",
"name": "allConnectors",
"type": "address[]"
}
],
"name": "getGovernanceBalances",
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract IERC20",
"name": "srcToken",
"type": "address"
},
{
"internalType": "contract IERC20",
"name": "dstToken",
"type": "address"
},
{
"internalType": "bool",
"name": "useWrappers",
"type": "bool"
}
],
"name": "getRate",
"outputs": [
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
"internalType": "uint256",
"name": "weightedRate",
"type": "uint256"
}
],
"stateMutability": "view",
@ -111,104 +202,61 @@
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"internalType": "contract IERC20",
"name": "srcToken",
"type": "address"
},
{
"internalType": "bool",
"name": "useSrcWrappers",
"type": "bool"
}
],
"name": "getRateToEth",
"outputs": [
{
"internalType": "uint256",
"name": "weightedRate",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "multiWrapper",
"outputs": [
{
"internalType": "contract MultiWrapper",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "oracles",
"outputs": [
{
"internalType": "contract IOracle[]",
"name": "allOracles",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
}
],
"name": "getPricesInETH",
"outputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
"internalType": "enum OffchainOracle.OracleType[]",
"name": "oracleTypes",
"type": "uint8[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Governance",
"name": "governance",
"type": "address"
},
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "getUserData",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalId",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "latestProposalIdState",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "timelock",
"type": "uint256"
},
{
"internalType": "address",
"name": "delegatee",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
}
],
"name": "minerRates",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes32",
"name": "node",
"type": "bytes32"
}
],
"name": "resolve",
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
@ -222,98 +270,65 @@
{
"inputs": [
{
"internalType": "contract RewardSwap",
"name": "swap",
"internalType": "contract IERC20",
"name": "connector",
"type": "address"
}
],
"name": "swapState",
"outputs": [
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"name": "removeConnector",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract Miner",
"name": "miner",
"internalType": "contract IOracle",
"name": "oracle",
"type": "address"
},
{
"internalType": "address[]",
"name": "instances",
"type": "address[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"type": "address"
"internalType": "enum OffchainOracle.OracleType",
"name": "oracleKind",
"type": "uint8"
}
],
"name": "miningData",
"outputs": [
{
"internalType": "uint256[]",
"name": "_rates",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "poolWeight",
"type": "uint256"
}
],
"stateMutability": "view",
"name": "removeOracle",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "fromTokens",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "oneUnitAmounts",
"type": "uint256[]"
},
{
"internalType": "contract RewardSwap",
"name": "swap",
"internalType": "contract MultiWrapper",
"name": "_multiWrapper",
"type": "address"
}
],
"name": "marketData",
"outputs": [
"name": "setMultiWrapper",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256[]",
"name": "prices",
"type": "uint256[]"
},
{
"internalType": "uint256",
"name": "balance",
"type": "uint256"
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"stateMutability": "view",
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

38
abis/Multicall.abi.json Normal file
View File

@ -0,0 +1,38 @@
[
{
"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"
}
]

1
app.js
View File

@ -1 +0,0 @@
module.exports = require('./src/index')

521
contracts/AggregatorAbi.ts Normal file
View File

@ -0,0 +1,521 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
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 GovernanceAggregator {
export type ProposalStruct = {
proposer: string;
target: string;
startTime: BigNumberish;
endTime: BigNumberish;
forVotes: BigNumberish;
againstVotes: BigNumberish;
executed: boolean;
extended: boolean;
state: BigNumberish;
};
export type ProposalStructOutput = [
string,
string,
BigNumber,
BigNumber,
BigNumber,
BigNumber,
boolean,
boolean,
number
] & {
proposer: string;
target: string;
startTime: BigNumber;
endTime: BigNumber;
forVotes: BigNumber;
againstVotes: BigNumber;
executed: boolean;
extended: boolean;
state: number;
};
}
export interface AggregatorAbiInterface extends utils.Interface {
functions: {
"bulkResolve(bytes32[])": FunctionFragment;
"getAllProposals(address)": FunctionFragment;
"getGovernanceBalances(address,address[])": FunctionFragment;
"getPricesInETH(address[],uint256[])": FunctionFragment;
"getUserData(address,address)": FunctionFragment;
"minerRates(address,address[])": FunctionFragment;
"resolve(bytes32)": FunctionFragment;
"swapState(address)": FunctionFragment;
"miningData(address,address[],address)": FunctionFragment;
"marketData(address[],uint256[],address)": FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| "bulkResolve"
| "getAllProposals"
| "getGovernanceBalances"
| "getPricesInETH"
| "getUserData"
| "minerRates"
| "resolve"
| "swapState"
| "miningData"
| "marketData"
): FunctionFragment;
encodeFunctionData(
functionFragment: "bulkResolve",
values: [BytesLike[]]
): string;
encodeFunctionData(
functionFragment: "getAllProposals",
values: [string]
): string;
encodeFunctionData(
functionFragment: "getGovernanceBalances",
values: [string, string[]]
): string;
encodeFunctionData(
functionFragment: "getPricesInETH",
values: [string[], BigNumberish[]]
): string;
encodeFunctionData(
functionFragment: "getUserData",
values: [string, string]
): string;
encodeFunctionData(
functionFragment: "minerRates",
values: [string, string[]]
): string;
encodeFunctionData(functionFragment: "resolve", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "swapState", values: [string]): string;
encodeFunctionData(
functionFragment: "miningData",
values: [string, string[], string]
): string;
encodeFunctionData(
functionFragment: "marketData",
values: [string[], BigNumberish[], string]
): string;
decodeFunctionResult(
functionFragment: "bulkResolve",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getAllProposals",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getGovernanceBalances",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getPricesInETH",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "getUserData",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "minerRates", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "resolve", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "swapState", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "miningData", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "marketData", data: BytesLike): Result;
events: {};
}
export interface AggregatorAbi extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: AggregatorAbiInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
bulkResolve(
domains: BytesLike[],
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getAllProposals(
governance: string,
overrides?: CallOverrides
): Promise<
[GovernanceAggregator.ProposalStructOutput[]] & {
proposals: GovernanceAggregator.ProposalStructOutput[];
}
>;
getGovernanceBalances(
governance: string,
accs: string[],
overrides?: CallOverrides
): Promise<[BigNumber[]] & { amounts: BigNumber[] }>;
getPricesInETH(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
overrides?: CallOverrides
): Promise<[BigNumber[]] & { prices: BigNumber[] }>;
getUserData(
governance: string,
account: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber, BigNumber, BigNumber, string] & {
balance: BigNumber;
latestProposalId: BigNumber;
latestProposalIdState: BigNumber;
timelock: BigNumber;
delegatee: string;
}
>;
minerRates(
miner: string,
instances: string[],
overrides?: CallOverrides
): Promise<[BigNumber[]] & { _rates: BigNumber[] }>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<[string]>;
swapState(
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber] & { balance: BigNumber; poolWeight: BigNumber }
>;
miningData(
miner: string,
instances: string[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber, BigNumber] & {
_rates: BigNumber[];
balance: BigNumber;
poolWeight: BigNumber;
}
>;
marketData(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber] & { prices: BigNumber[]; balance: BigNumber }
>;
};
bulkResolve(
domains: BytesLike[],
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getAllProposals(
governance: string,
overrides?: CallOverrides
): Promise<GovernanceAggregator.ProposalStructOutput[]>;
getGovernanceBalances(
governance: string,
accs: string[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
getPricesInETH(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
getUserData(
governance: string,
account: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber, BigNumber, BigNumber, string] & {
balance: BigNumber;
latestProposalId: BigNumber;
latestProposalIdState: BigNumber;
timelock: BigNumber;
delegatee: string;
}
>;
minerRates(
miner: string,
instances: string[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
swapState(
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber] & { balance: BigNumber; poolWeight: BigNumber }
>;
miningData(
miner: string,
instances: string[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber, BigNumber] & {
_rates: BigNumber[];
balance: BigNumber;
poolWeight: BigNumber;
}
>;
marketData(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber] & { prices: BigNumber[]; balance: BigNumber }
>;
callStatic: {
bulkResolve(
domains: BytesLike[],
overrides?: CallOverrides
): Promise<string[]>;
getAllProposals(
governance: string,
overrides?: CallOverrides
): Promise<GovernanceAggregator.ProposalStructOutput[]>;
getGovernanceBalances(
governance: string,
accs: string[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
getPricesInETH(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
getUserData(
governance: string,
account: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber, BigNumber, BigNumber, string] & {
balance: BigNumber;
latestProposalId: BigNumber;
latestProposalIdState: BigNumber;
timelock: BigNumber;
delegatee: string;
}
>;
minerRates(
miner: string,
instances: string[],
overrides?: CallOverrides
): Promise<BigNumber[]>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
swapState(
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber, BigNumber] & { balance: BigNumber; poolWeight: BigNumber }
>;
miningData(
miner: string,
instances: string[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber, BigNumber] & {
_rates: BigNumber[];
balance: BigNumber;
poolWeight: BigNumber;
}
>;
marketData(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
swap: string,
overrides?: CallOverrides
): Promise<
[BigNumber[], BigNumber] & { prices: BigNumber[]; balance: BigNumber }
>;
};
filters: {};
estimateGas: {
bulkResolve(
domains: BytesLike[],
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
getAllProposals(
governance: string,
overrides?: CallOverrides
): Promise<BigNumber>;
getGovernanceBalances(
governance: string,
accs: string[],
overrides?: CallOverrides
): Promise<BigNumber>;
getPricesInETH(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
overrides?: CallOverrides
): Promise<BigNumber>;
getUserData(
governance: string,
account: string,
overrides?: CallOverrides
): Promise<BigNumber>;
minerRates(
miner: string,
instances: string[],
overrides?: CallOverrides
): Promise<BigNumber>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<BigNumber>;
swapState(swap: string, overrides?: CallOverrides): Promise<BigNumber>;
miningData(
miner: string,
instances: string[],
swap: string,
overrides?: CallOverrides
): Promise<BigNumber>;
marketData(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
swap: string,
overrides?: CallOverrides
): Promise<BigNumber>;
};
populateTransaction: {
bulkResolve(
domains: BytesLike[],
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
getAllProposals(
governance: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
getGovernanceBalances(
governance: string,
accs: string[],
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
getPricesInETH(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
getUserData(
governance: string,
account: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
minerRates(
miner: string,
instances: string[],
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
resolve(
node: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
swapState(
swap: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
miningData(
miner: string,
instances: string[],
swap: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
marketData(
fromTokens: string[],
oneUnitAmounts: BigNumberish[],
swap: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
};
}

1207
contracts/MiningAbi.ts Normal file

File diff suppressed because it is too large Load Diff

114
contracts/MulticallAbi.ts Normal file
View File

@ -0,0 +1,114 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
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 MultiCall {
export type CallStruct = { to: string; data: BytesLike };
export type CallStructOutput = [string, string] & {
to: string;
data: string;
};
}
export interface MulticallAbiInterface extends utils.Interface {
functions: {
'multicall((address,bytes)[])': FunctionFragment;
};
getFunction(nameOrSignatureOrTopic: 'multicall'): FunctionFragment;
encodeFunctionData(
functionFragment: 'multicall',
values: [MultiCall.CallStruct[]],
): string;
decodeFunctionResult(functionFragment: 'multicall', data: BytesLike): Result;
events: {};
}
export interface MulticallAbi extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: MulticallAbiInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined,
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>,
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>,
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
};
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
callStatic: {
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<[string[], boolean[]] & { results: string[]; success: boolean[] }>;
};
filters: {};
estimateGas: {
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<BigNumber>;
};
populateTransaction: {
multicall(
calls: MultiCall.CallStruct[],
overrides?: CallOverrides,
): Promise<PopulatedTransaction>;
};
}

View File

@ -0,0 +1,615 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
PopulatedTransaction,
Signer,
utils,
} from "ethers";
import type {
FunctionFragment,
Result,
EventFragment,
} from "@ethersproject/abi";
import type { Listener, Provider } from "@ethersproject/providers";
import type {
TypedEventFilter,
TypedEvent,
TypedListener,
OnEvent,
} from "./common";
export interface OffchainOracleAbiInterface extends utils.Interface {
functions: {
"addConnector(address)": FunctionFragment;
"addOracle(address,uint8)": FunctionFragment;
"connectors()": FunctionFragment;
"getRate(address,address,bool)": FunctionFragment;
"getRateToEth(address,bool)": FunctionFragment;
"multiWrapper()": FunctionFragment;
"oracles()": FunctionFragment;
"owner()": FunctionFragment;
"removeConnector(address)": FunctionFragment;
"removeOracle(address,uint8)": FunctionFragment;
"renounceOwnership()": FunctionFragment;
"setMultiWrapper(address)": FunctionFragment;
"transferOwnership(address)": FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| "addConnector"
| "addOracle"
| "connectors"
| "getRate"
| "getRateToEth"
| "multiWrapper"
| "oracles"
| "owner"
| "removeConnector"
| "removeOracle"
| "renounceOwnership"
| "setMultiWrapper"
| "transferOwnership"
): FunctionFragment;
encodeFunctionData(
functionFragment: "addConnector",
values: [string]
): string;
encodeFunctionData(
functionFragment: "addOracle",
values: [string, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "connectors",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "getRate",
values: [string, string, boolean]
): string;
encodeFunctionData(
functionFragment: "getRateToEth",
values: [string, boolean]
): string;
encodeFunctionData(
functionFragment: "multiWrapper",
values?: undefined
): string;
encodeFunctionData(functionFragment: "oracles", values?: undefined): string;
encodeFunctionData(functionFragment: "owner", values?: undefined): string;
encodeFunctionData(
functionFragment: "removeConnector",
values: [string]
): string;
encodeFunctionData(
functionFragment: "removeOracle",
values: [string, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "renounceOwnership",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "setMultiWrapper",
values: [string]
): string;
encodeFunctionData(
functionFragment: "transferOwnership",
values: [string]
): string;
decodeFunctionResult(
functionFragment: "addConnector",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "addOracle", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "connectors", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "getRate", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "getRateToEth",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "multiWrapper",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "oracles", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "owner", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "removeConnector",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "removeOracle",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "renounceOwnership",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "setMultiWrapper",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "transferOwnership",
data: BytesLike
): Result;
events: {
"ConnectorAdded(address)": EventFragment;
"ConnectorRemoved(address)": EventFragment;
"MultiWrapperUpdated(address)": EventFragment;
"OracleAdded(address,uint8)": EventFragment;
"OracleRemoved(address,uint8)": EventFragment;
"OwnershipTransferred(address,address)": EventFragment;
};
getEvent(nameOrSignatureOrTopic: "ConnectorAdded"): EventFragment;
getEvent(nameOrSignatureOrTopic: "ConnectorRemoved"): EventFragment;
getEvent(nameOrSignatureOrTopic: "MultiWrapperUpdated"): EventFragment;
getEvent(nameOrSignatureOrTopic: "OracleAdded"): EventFragment;
getEvent(nameOrSignatureOrTopic: "OracleRemoved"): EventFragment;
getEvent(nameOrSignatureOrTopic: "OwnershipTransferred"): EventFragment;
}
export interface ConnectorAddedEventObject {
connector: string;
}
export type ConnectorAddedEvent = TypedEvent<[string],
ConnectorAddedEventObject>;
export type ConnectorAddedEventFilter = TypedEventFilter<ConnectorAddedEvent>;
export interface ConnectorRemovedEventObject {
connector: string;
}
export type ConnectorRemovedEvent = TypedEvent<[string],
ConnectorRemovedEventObject>;
export type ConnectorRemovedEventFilter =
TypedEventFilter<ConnectorRemovedEvent>;
export interface MultiWrapperUpdatedEventObject {
multiWrapper: string;
}
export type MultiWrapperUpdatedEvent = TypedEvent<[string],
MultiWrapperUpdatedEventObject>;
export type MultiWrapperUpdatedEventFilter =
TypedEventFilter<MultiWrapperUpdatedEvent>;
export interface OracleAddedEventObject {
oracle: string;
oracleType: number;
}
export type OracleAddedEvent = TypedEvent<[string, number],
OracleAddedEventObject>;
export type OracleAddedEventFilter = TypedEventFilter<OracleAddedEvent>;
export interface OracleRemovedEventObject {
oracle: string;
oracleType: number;
}
export type OracleRemovedEvent = TypedEvent<[string, number],
OracleRemovedEventObject>;
export type OracleRemovedEventFilter = TypedEventFilter<OracleRemovedEvent>;
export interface OwnershipTransferredEventObject {
previousOwner: string;
newOwner: string;
}
export type OwnershipTransferredEvent = TypedEvent<[string, string],
OwnershipTransferredEventObject>;
export type OwnershipTransferredEventFilter =
TypedEventFilter<OwnershipTransferredEvent>;
export interface OffchainOracleAbi extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: OffchainOracleAbiInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
addConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
addOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
connectors(
overrides?: CallOverrides
): Promise<[string[]] & { allConnectors: string[] }>;
getRate(
srcToken: string,
dstToken: string,
useWrappers: boolean,
overrides?: CallOverrides
): Promise<[BigNumber] & { weightedRate: BigNumber }>;
getRateToEth(
srcToken: string,
useSrcWrappers: boolean,
overrides?: CallOverrides
): Promise<[BigNumber] & { weightedRate: BigNumber }>;
multiWrapper(overrides?: CallOverrides): Promise<[string]>;
oracles(
overrides?: CallOverrides
): Promise<[string[], number[]] & { allOracles: string[]; oracleTypes: number[] }>;
owner(overrides?: CallOverrides): Promise<[string]>;
removeConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
removeOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
renounceOwnership(
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
setMultiWrapper(
_multiWrapper: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
transferOwnership(
newOwner: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
};
addConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
addOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
connectors(overrides?: CallOverrides): Promise<string[]>;
getRate(
srcToken: string,
dstToken: string,
useWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
getRateToEth(
srcToken: string,
useSrcWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
multiWrapper(overrides?: CallOverrides): Promise<string>;
oracles(
overrides?: CallOverrides
): Promise<[string[], number[]] & { allOracles: string[]; oracleTypes: number[] }>;
owner(overrides?: CallOverrides): Promise<string>;
removeConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
removeOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
renounceOwnership(
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
setMultiWrapper(
_multiWrapper: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
transferOwnership(
newOwner: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
callStatic: {
addConnector(connector: string, overrides?: CallOverrides): Promise<void>;
addOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
connectors(overrides?: CallOverrides): Promise<string[]>;
getRate(
srcToken: string,
dstToken: string,
useWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
getRateToEth(
srcToken: string,
useSrcWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
multiWrapper(overrides?: CallOverrides): Promise<string>;
oracles(
overrides?: CallOverrides
): Promise<[string[], number[]] & { allOracles: string[]; oracleTypes: number[] }>;
owner(overrides?: CallOverrides): Promise<string>;
removeConnector(
connector: string,
overrides?: CallOverrides
): Promise<void>;
removeOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
renounceOwnership(overrides?: CallOverrides): Promise<void>;
setMultiWrapper(
_multiWrapper: string,
overrides?: CallOverrides
): Promise<void>;
transferOwnership(
newOwner: string,
overrides?: CallOverrides
): Promise<void>;
};
filters: {
"ConnectorAdded(address)"(connector?: null): ConnectorAddedEventFilter;
ConnectorAdded(connector?: null): ConnectorAddedEventFilter;
"ConnectorRemoved(address)"(connector?: null): ConnectorRemovedEventFilter;
ConnectorRemoved(connector?: null): ConnectorRemovedEventFilter;
"MultiWrapperUpdated(address)"(
multiWrapper?: null
): MultiWrapperUpdatedEventFilter;
MultiWrapperUpdated(multiWrapper?: null): MultiWrapperUpdatedEventFilter;
"OracleAdded(address,uint8)"(
oracle?: null,
oracleType?: null
): OracleAddedEventFilter;
OracleAdded(oracle?: null, oracleType?: null): OracleAddedEventFilter;
"OracleRemoved(address,uint8)"(
oracle?: null,
oracleType?: null
): OracleRemovedEventFilter;
OracleRemoved(oracle?: null, oracleType?: null): OracleRemovedEventFilter;
"OwnershipTransferred(address,address)"(
previousOwner?: string | null,
newOwner?: string | null
): OwnershipTransferredEventFilter;
OwnershipTransferred(
previousOwner?: string | null,
newOwner?: string | null
): OwnershipTransferredEventFilter;
};
estimateGas: {
addConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
addOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
connectors(overrides?: CallOverrides): Promise<BigNumber>;
getRate(
srcToken: string,
dstToken: string,
useWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
getRateToEth(
srcToken: string,
useSrcWrappers: boolean,
overrides?: CallOverrides
): Promise<BigNumber>;
multiWrapper(overrides?: CallOverrides): Promise<BigNumber>;
oracles(overrides?: CallOverrides): Promise<BigNumber>;
owner(overrides?: CallOverrides): Promise<BigNumber>;
removeConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
removeOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
renounceOwnership(
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
setMultiWrapper(
_multiWrapper: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
transferOwnership(
newOwner: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
};
populateTransaction: {
addConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
addOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
connectors(overrides?: CallOverrides): Promise<PopulatedTransaction>;
getRate(
srcToken: string,
dstToken: string,
useWrappers: boolean,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
getRateToEth(
srcToken: string,
useSrcWrappers: boolean,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
multiWrapper(overrides?: CallOverrides): Promise<PopulatedTransaction>;
oracles(overrides?: CallOverrides): Promise<PopulatedTransaction>;
owner(overrides?: CallOverrides): Promise<PopulatedTransaction>;
removeConnector(
connector: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
removeOracle(
oracle: string,
oracleKind: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
renounceOwnership(
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
setMultiWrapper(
_multiWrapper: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
transferOwnership(
newOwner: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
};
}

394
contracts/SwapAbi.ts Normal file
View File

@ -0,0 +1,394 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
PopulatedTransaction,
Signer,
utils,
} from "ethers";
import type {
FunctionFragment,
Result,
EventFragment,
} from "@ethersproject/abi";
import type { Listener, Provider } from "@ethersproject/providers";
import type {
TypedEventFilter,
TypedEvent,
TypedListener,
OnEvent,
} from "./common";
export interface SwapAbiInterface extends utils.Interface {
functions: {
"DURATION()": FunctionFragment;
"initialLiquidity()": FunctionFragment;
"liquidity()": FunctionFragment;
"miner()": FunctionFragment;
"poolWeight()": FunctionFragment;
"resolve(bytes32)": FunctionFragment;
"startTimestamp()": FunctionFragment;
"tokensSold()": FunctionFragment;
"torn()": FunctionFragment;
"swap(address,uint256)": FunctionFragment;
"getExpectedReturn(uint256)": FunctionFragment;
"tornVirtualBalance()": FunctionFragment;
"setPoolWeight(uint256)": FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| "DURATION"
| "initialLiquidity"
| "liquidity"
| "miner"
| "poolWeight"
| "resolve"
| "startTimestamp"
| "tokensSold"
| "torn"
| "swap"
| "getExpectedReturn"
| "tornVirtualBalance"
| "setPoolWeight"
): FunctionFragment;
encodeFunctionData(functionFragment: "DURATION", values?: undefined): string;
encodeFunctionData(
functionFragment: "initialLiquidity",
values?: undefined
): string;
encodeFunctionData(functionFragment: "liquidity", values?: undefined): string;
encodeFunctionData(functionFragment: "miner", values?: undefined): string;
encodeFunctionData(
functionFragment: "poolWeight",
values?: undefined
): string;
encodeFunctionData(functionFragment: "resolve", values: [BytesLike]): string;
encodeFunctionData(
functionFragment: "startTimestamp",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "tokensSold",
values?: undefined
): string;
encodeFunctionData(functionFragment: "torn", values?: undefined): string;
encodeFunctionData(
functionFragment: "swap",
values: [string, BigNumberish]
): string;
encodeFunctionData(
functionFragment: "getExpectedReturn",
values: [BigNumberish]
): string;
encodeFunctionData(
functionFragment: "tornVirtualBalance",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "setPoolWeight",
values: [BigNumberish]
): string;
decodeFunctionResult(functionFragment: "DURATION", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "initialLiquidity",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "liquidity", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "miner", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "poolWeight", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "resolve", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "startTimestamp",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "tokensSold", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "torn", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "swap", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "getExpectedReturn",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "tornVirtualBalance",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "setPoolWeight",
data: BytesLike
): Result;
events: {
"PoolWeightUpdated(uint256)": EventFragment;
"Swap(address,uint256,uint256)": EventFragment;
};
getEvent(nameOrSignatureOrTopic: "PoolWeightUpdated"): EventFragment;
getEvent(nameOrSignatureOrTopic: "Swap"): EventFragment;
}
export interface PoolWeightUpdatedEventObject {
newWeight: BigNumber;
}
export type PoolWeightUpdatedEvent = TypedEvent<
[BigNumber],
PoolWeightUpdatedEventObject
>;
export type PoolWeightUpdatedEventFilter =
TypedEventFilter<PoolWeightUpdatedEvent>;
export interface SwapEventObject {
recipient: string;
pTORN: BigNumber;
TORN: BigNumber;
}
export type SwapEvent = TypedEvent<
[string, BigNumber, BigNumber],
SwapEventObject
>;
export type SwapEventFilter = TypedEventFilter<SwapEvent>;
export interface SwapAbi extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: SwapAbiInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
DURATION(overrides?: CallOverrides): Promise<[BigNumber]>;
initialLiquidity(overrides?: CallOverrides): Promise<[BigNumber]>;
liquidity(overrides?: CallOverrides): Promise<[BigNumber]>;
miner(overrides?: CallOverrides): Promise<[string]>;
poolWeight(overrides?: CallOverrides): Promise<[BigNumber]>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<[string]>;
startTimestamp(overrides?: CallOverrides): Promise<[BigNumber]>;
tokensSold(overrides?: CallOverrides): Promise<[BigNumber]>;
torn(overrides?: CallOverrides): Promise<[string]>;
swap(
recipient: string,
amount: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getExpectedReturn(
amount: BigNumberish,
overrides?: CallOverrides
): Promise<[BigNumber]>;
tornVirtualBalance(overrides?: CallOverrides): Promise<[BigNumber]>;
setPoolWeight(
newWeight: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
};
DURATION(overrides?: CallOverrides): Promise<BigNumber>;
initialLiquidity(overrides?: CallOverrides): Promise<BigNumber>;
liquidity(overrides?: CallOverrides): Promise<BigNumber>;
miner(overrides?: CallOverrides): Promise<string>;
poolWeight(overrides?: CallOverrides): Promise<BigNumber>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
startTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
tokensSold(overrides?: CallOverrides): Promise<BigNumber>;
torn(overrides?: CallOverrides): Promise<string>;
swap(
recipient: string,
amount: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getExpectedReturn(
amount: BigNumberish,
overrides?: CallOverrides
): Promise<BigNumber>;
tornVirtualBalance(overrides?: CallOverrides): Promise<BigNumber>;
setPoolWeight(
newWeight: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
callStatic: {
DURATION(overrides?: CallOverrides): Promise<BigNumber>;
initialLiquidity(overrides?: CallOverrides): Promise<BigNumber>;
liquidity(overrides?: CallOverrides): Promise<BigNumber>;
miner(overrides?: CallOverrides): Promise<string>;
poolWeight(overrides?: CallOverrides): Promise<BigNumber>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
startTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
tokensSold(overrides?: CallOverrides): Promise<BigNumber>;
torn(overrides?: CallOverrides): Promise<string>;
swap(
recipient: string,
amount: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
getExpectedReturn(
amount: BigNumberish,
overrides?: CallOverrides
): Promise<BigNumber>;
tornVirtualBalance(overrides?: CallOverrides): Promise<BigNumber>;
setPoolWeight(
newWeight: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
};
filters: {
"PoolWeightUpdated(uint256)"(
newWeight?: null
): PoolWeightUpdatedEventFilter;
PoolWeightUpdated(newWeight?: null): PoolWeightUpdatedEventFilter;
"Swap(address,uint256,uint256)"(
recipient?: string | null,
pTORN?: null,
TORN?: null
): SwapEventFilter;
Swap(recipient?: string | null, pTORN?: null, TORN?: null): SwapEventFilter;
};
estimateGas: {
DURATION(overrides?: CallOverrides): Promise<BigNumber>;
initialLiquidity(overrides?: CallOverrides): Promise<BigNumber>;
liquidity(overrides?: CallOverrides): Promise<BigNumber>;
miner(overrides?: CallOverrides): Promise<BigNumber>;
poolWeight(overrides?: CallOverrides): Promise<BigNumber>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<BigNumber>;
startTimestamp(overrides?: CallOverrides): Promise<BigNumber>;
tokensSold(overrides?: CallOverrides): Promise<BigNumber>;
torn(overrides?: CallOverrides): Promise<BigNumber>;
swap(
recipient: string,
amount: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
getExpectedReturn(
amount: BigNumberish,
overrides?: CallOverrides
): Promise<BigNumber>;
tornVirtualBalance(overrides?: CallOverrides): Promise<BigNumber>;
setPoolWeight(
newWeight: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
};
populateTransaction: {
DURATION(overrides?: CallOverrides): Promise<PopulatedTransaction>;
initialLiquidity(overrides?: CallOverrides): Promise<PopulatedTransaction>;
liquidity(overrides?: CallOverrides): Promise<PopulatedTransaction>;
miner(overrides?: CallOverrides): Promise<PopulatedTransaction>;
poolWeight(overrides?: CallOverrides): Promise<PopulatedTransaction>;
resolve(
node: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
startTimestamp(overrides?: CallOverrides): Promise<PopulatedTransaction>;
tokensSold(overrides?: CallOverrides): Promise<PopulatedTransaction>;
torn(overrides?: CallOverrides): Promise<PopulatedTransaction>;
swap(
recipient: string,
amount: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
getExpectedReturn(
amount: BigNumberish,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
tornVirtualBalance(
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
setPoolWeight(
newWeight: BigNumberish,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
};
}

691
contracts/TornadoABI.ts Normal file
View File

@ -0,0 +1,691 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
PayableOverrides,
PopulatedTransaction,
Signer,
utils,
} from "ethers";
import type {
FunctionFragment,
Result,
EventFragment,
} from "@ethersproject/abi";
import type { Listener, Provider } from "@ethersproject/providers";
import type {
TypedEventFilter,
TypedEvent,
TypedListener,
OnEvent,
} from "./common";
export interface TornadoABIInterface extends utils.Interface {
functions: {
"changeOperator(address)": FunctionFragment;
"nullifierHashes(bytes32)": FunctionFragment;
"withdraw(bytes,bytes32,bytes32,address,address,uint256,uint256)": FunctionFragment;
"verifier()": FunctionFragment;
"hashLeftRight(bytes32,bytes32)": FunctionFragment;
"FIELD_SIZE()": FunctionFragment;
"levels()": FunctionFragment;
"operator()": FunctionFragment;
"isKnownRoot(bytes32)": FunctionFragment;
"commitments(bytes32)": FunctionFragment;
"denomination()": FunctionFragment;
"currentRootIndex()": FunctionFragment;
"updateVerifier(address)": FunctionFragment;
"deposit(bytes32)": FunctionFragment;
"getLastRoot()": FunctionFragment;
"roots(uint256)": FunctionFragment;
"ROOT_HISTORY_SIZE()": FunctionFragment;
"isSpent(bytes32)": FunctionFragment;
"zeros(uint256)": FunctionFragment;
"ZERO_VALUE()": FunctionFragment;
"filledSubtrees(uint256)": FunctionFragment;
"nextIndex()": FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| "changeOperator"
| "nullifierHashes"
| "withdraw"
| "verifier"
| "hashLeftRight"
| "FIELD_SIZE"
| "levels"
| "operator"
| "isKnownRoot"
| "commitments"
| "denomination"
| "currentRootIndex"
| "updateVerifier"
| "deposit"
| "getLastRoot"
| "roots"
| "ROOT_HISTORY_SIZE"
| "isSpent"
| "zeros"
| "ZERO_VALUE"
| "filledSubtrees"
| "nextIndex"
): FunctionFragment;
encodeFunctionData(
functionFragment: "changeOperator",
values: [string]
): string;
encodeFunctionData(
functionFragment: "nullifierHashes",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "withdraw",
values: [
BytesLike,
BytesLike,
BytesLike,
string,
string,
BigNumberish,
BigNumberish
]
): string;
encodeFunctionData(functionFragment: "verifier", values?: undefined): string;
encodeFunctionData(
functionFragment: "hashLeftRight",
values: [BytesLike, BytesLike]
): string;
encodeFunctionData(
functionFragment: "FIELD_SIZE",
values?: undefined
): string;
encodeFunctionData(functionFragment: "levels", values?: undefined): string;
encodeFunctionData(functionFragment: "operator", values?: undefined): string;
encodeFunctionData(
functionFragment: "isKnownRoot",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "commitments",
values: [BytesLike]
): string;
encodeFunctionData(
functionFragment: "denomination",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "currentRootIndex",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "updateVerifier",
values: [string]
): string;
encodeFunctionData(functionFragment: "deposit", values: [BytesLike]): string;
encodeFunctionData(
functionFragment: "getLastRoot",
values?: undefined
): string;
encodeFunctionData(functionFragment: "roots", values: [BigNumberish]): string;
encodeFunctionData(
functionFragment: "ROOT_HISTORY_SIZE",
values?: undefined
): string;
encodeFunctionData(functionFragment: "isSpent", values: [BytesLike]): string;
encodeFunctionData(functionFragment: "zeros", values: [BigNumberish]): string;
encodeFunctionData(
functionFragment: "ZERO_VALUE",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "filledSubtrees",
values: [BigNumberish]
): string;
encodeFunctionData(functionFragment: "nextIndex", values?: undefined): string;
decodeFunctionResult(
functionFragment: "changeOperator",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "nullifierHashes",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "withdraw", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "verifier", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "hashLeftRight",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "FIELD_SIZE", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "levels", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "operator", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "isKnownRoot",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "commitments",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "denomination",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "currentRootIndex",
data: BytesLike
): Result;
decodeFunctionResult(
functionFragment: "updateVerifier",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "deposit", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "getLastRoot",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "roots", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "ROOT_HISTORY_SIZE",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "isSpent", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "zeros", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "ZERO_VALUE", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "filledSubtrees",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "nextIndex", data: BytesLike): Result;
events: {
"Deposit(bytes32,uint32,uint256)": EventFragment;
"Withdrawal(address,bytes32,address,uint256)": EventFragment;
};
getEvent(nameOrSignatureOrTopic: "Deposit"): EventFragment;
getEvent(nameOrSignatureOrTopic: "Withdrawal"): EventFragment;
}
export interface DepositEventObject {
commitment: string;
leafIndex: number;
timestamp: BigNumber;
}
export type DepositEvent = TypedEvent<
[string, number, BigNumber],
DepositEventObject
>;
export type DepositEventFilter = TypedEventFilter<DepositEvent>;
export interface WithdrawalEventObject {
to: string;
nullifierHash: string;
relayer: string;
fee: BigNumber;
}
export type WithdrawalEvent = TypedEvent<
[string, string, string, BigNumber],
WithdrawalEventObject
>;
export type WithdrawalEventFilter = TypedEventFilter<WithdrawalEvent>;
export interface TornadoABI extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: TornadoABIInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
changeOperator(
_newOperator: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
nullifierHashes(
arg0: BytesLike,
overrides?: CallOverrides
): Promise<[boolean]>;
withdraw(
_proof: BytesLike,
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: string,
_relayer: string,
_fee: BigNumberish,
_refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
verifier(overrides?: CallOverrides): Promise<[string]>;
hashLeftRight(
_left: BytesLike,
_right: BytesLike,
overrides?: CallOverrides
): Promise<[string]>;
FIELD_SIZE(overrides?: CallOverrides): Promise<[BigNumber]>;
levels(overrides?: CallOverrides): Promise<[number]>;
operator(overrides?: CallOverrides): Promise<[string]>;
isKnownRoot(
_root: BytesLike,
overrides?: CallOverrides
): Promise<[boolean]>;
commitments(arg0: BytesLike, overrides?: CallOverrides): Promise<[boolean]>;
denomination(overrides?: CallOverrides): Promise<[BigNumber]>;
currentRootIndex(overrides?: CallOverrides): Promise<[number]>;
updateVerifier(
_newVerifier: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
deposit(
_commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getLastRoot(overrides?: CallOverrides): Promise<[string]>;
roots(arg0: BigNumberish, overrides?: CallOverrides): Promise<[string]>;
ROOT_HISTORY_SIZE(overrides?: CallOverrides): Promise<[number]>;
isSpent(
_nullifierHash: BytesLike,
overrides?: CallOverrides
): Promise<[boolean]>;
zeros(arg0: BigNumberish, overrides?: CallOverrides): Promise<[string]>;
ZERO_VALUE(overrides?: CallOverrides): Promise<[BigNumber]>;
filledSubtrees(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<[string]>;
nextIndex(overrides?: CallOverrides): Promise<[number]>;
};
changeOperator(
_newOperator: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
nullifierHashes(arg0: BytesLike, overrides?: CallOverrides): Promise<boolean>;
withdraw(
_proof: BytesLike,
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: string,
_relayer: string,
_fee: BigNumberish,
_refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
verifier(overrides?: CallOverrides): Promise<string>;
hashLeftRight(
_left: BytesLike,
_right: BytesLike,
overrides?: CallOverrides
): Promise<string>;
FIELD_SIZE(overrides?: CallOverrides): Promise<BigNumber>;
levels(overrides?: CallOverrides): Promise<number>;
operator(overrides?: CallOverrides): Promise<string>;
isKnownRoot(_root: BytesLike, overrides?: CallOverrides): Promise<boolean>;
commitments(arg0: BytesLike, overrides?: CallOverrides): Promise<boolean>;
denomination(overrides?: CallOverrides): Promise<BigNumber>;
currentRootIndex(overrides?: CallOverrides): Promise<number>;
updateVerifier(
_newVerifier: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
deposit(
_commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
getLastRoot(overrides?: CallOverrides): Promise<string>;
roots(arg0: BigNumberish, overrides?: CallOverrides): Promise<string>;
ROOT_HISTORY_SIZE(overrides?: CallOverrides): Promise<number>;
isSpent(
_nullifierHash: BytesLike,
overrides?: CallOverrides
): Promise<boolean>;
zeros(arg0: BigNumberish, overrides?: CallOverrides): Promise<string>;
ZERO_VALUE(overrides?: CallOverrides): Promise<BigNumber>;
filledSubtrees(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<string>;
nextIndex(overrides?: CallOverrides): Promise<number>;
callStatic: {
changeOperator(
_newOperator: string,
overrides?: CallOverrides
): Promise<void>;
nullifierHashes(
arg0: BytesLike,
overrides?: CallOverrides
): Promise<boolean>;
withdraw(
_proof: BytesLike,
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: string,
_relayer: string,
_fee: BigNumberish,
_refund: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
verifier(overrides?: CallOverrides): Promise<string>;
hashLeftRight(
_left: BytesLike,
_right: BytesLike,
overrides?: CallOverrides
): Promise<string>;
FIELD_SIZE(overrides?: CallOverrides): Promise<BigNumber>;
levels(overrides?: CallOverrides): Promise<number>;
operator(overrides?: CallOverrides): Promise<string>;
isKnownRoot(_root: BytesLike, overrides?: CallOverrides): Promise<boolean>;
commitments(arg0: BytesLike, overrides?: CallOverrides): Promise<boolean>;
denomination(overrides?: CallOverrides): Promise<BigNumber>;
currentRootIndex(overrides?: CallOverrides): Promise<number>;
updateVerifier(
_newVerifier: string,
overrides?: CallOverrides
): Promise<void>;
deposit(_commitment: BytesLike, overrides?: CallOverrides): Promise<void>;
getLastRoot(overrides?: CallOverrides): Promise<string>;
roots(arg0: BigNumberish, overrides?: CallOverrides): Promise<string>;
ROOT_HISTORY_SIZE(overrides?: CallOverrides): Promise<number>;
isSpent(
_nullifierHash: BytesLike,
overrides?: CallOverrides
): Promise<boolean>;
zeros(arg0: BigNumberish, overrides?: CallOverrides): Promise<string>;
ZERO_VALUE(overrides?: CallOverrides): Promise<BigNumber>;
filledSubtrees(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<string>;
nextIndex(overrides?: CallOverrides): Promise<number>;
};
filters: {
"Deposit(bytes32,uint32,uint256)"(
commitment?: BytesLike | null,
leafIndex?: null,
timestamp?: null
): DepositEventFilter;
Deposit(
commitment?: BytesLike | null,
leafIndex?: null,
timestamp?: null
): DepositEventFilter;
"Withdrawal(address,bytes32,address,uint256)"(
to?: null,
nullifierHash?: null,
relayer?: string | null,
fee?: null
): WithdrawalEventFilter;
Withdrawal(
to?: null,
nullifierHash?: null,
relayer?: string | null,
fee?: null
): WithdrawalEventFilter;
};
estimateGas: {
changeOperator(
_newOperator: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
nullifierHashes(
arg0: BytesLike,
overrides?: CallOverrides
): Promise<BigNumber>;
withdraw(
_proof: BytesLike,
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: string,
_relayer: string,
_fee: BigNumberish,
_refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
verifier(overrides?: CallOverrides): Promise<BigNumber>;
hashLeftRight(
_left: BytesLike,
_right: BytesLike,
overrides?: CallOverrides
): Promise<BigNumber>;
FIELD_SIZE(overrides?: CallOverrides): Promise<BigNumber>;
levels(overrides?: CallOverrides): Promise<BigNumber>;
operator(overrides?: CallOverrides): Promise<BigNumber>;
isKnownRoot(
_root: BytesLike,
overrides?: CallOverrides
): Promise<BigNumber>;
commitments(arg0: BytesLike, overrides?: CallOverrides): Promise<BigNumber>;
denomination(overrides?: CallOverrides): Promise<BigNumber>;
currentRootIndex(overrides?: CallOverrides): Promise<BigNumber>;
updateVerifier(
_newVerifier: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
deposit(
_commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
getLastRoot(overrides?: CallOverrides): Promise<BigNumber>;
roots(arg0: BigNumberish, overrides?: CallOverrides): Promise<BigNumber>;
ROOT_HISTORY_SIZE(overrides?: CallOverrides): Promise<BigNumber>;
isSpent(
_nullifierHash: BytesLike,
overrides?: CallOverrides
): Promise<BigNumber>;
zeros(arg0: BigNumberish, overrides?: CallOverrides): Promise<BigNumber>;
ZERO_VALUE(overrides?: CallOverrides): Promise<BigNumber>;
filledSubtrees(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<BigNumber>;
nextIndex(overrides?: CallOverrides): Promise<BigNumber>;
};
populateTransaction: {
changeOperator(
_newOperator: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
nullifierHashes(
arg0: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
withdraw(
_proof: BytesLike,
_root: BytesLike,
_nullifierHash: BytesLike,
_recipient: string,
_relayer: string,
_fee: BigNumberish,
_refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
verifier(overrides?: CallOverrides): Promise<PopulatedTransaction>;
hashLeftRight(
_left: BytesLike,
_right: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
FIELD_SIZE(overrides?: CallOverrides): Promise<PopulatedTransaction>;
levels(overrides?: CallOverrides): Promise<PopulatedTransaction>;
operator(overrides?: CallOverrides): Promise<PopulatedTransaction>;
isKnownRoot(
_root: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
commitments(
arg0: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
denomination(overrides?: CallOverrides): Promise<PopulatedTransaction>;
currentRootIndex(overrides?: CallOverrides): Promise<PopulatedTransaction>;
updateVerifier(
_newVerifier: string,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
deposit(
_commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
getLastRoot(overrides?: CallOverrides): Promise<PopulatedTransaction>;
roots(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
ROOT_HISTORY_SIZE(overrides?: CallOverrides): Promise<PopulatedTransaction>;
isSpent(
_nullifierHash: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
zeros(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
ZERO_VALUE(overrides?: CallOverrides): Promise<PopulatedTransaction>;
filledSubtrees(
arg0: BigNumberish,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
nextIndex(overrides?: CallOverrides): Promise<PopulatedTransaction>;
};
}

View File

@ -0,0 +1,298 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type {
BaseContract,
BigNumber,
BigNumberish,
BytesLike,
CallOverrides,
ContractTransaction,
Overrides,
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 interface TornadoProxyABIInterface extends utils.Interface {
functions: {
"governance()": FunctionFragment;
"instances(address)": FunctionFragment;
"resolve(bytes32)": FunctionFragment;
"tornadoTrees()": FunctionFragment;
"deposit(address,bytes32)": FunctionFragment;
"updateInstances(address,bool)": FunctionFragment;
"withdraw(address,bytes,bytes32,bytes32,address,address,uint256,uint256)": FunctionFragment;
};
getFunction(
nameOrSignatureOrTopic:
| "governance"
| "instances"
| "resolve"
| "tornadoTrees"
| "deposit"
| "updateInstances"
| "withdraw"
): FunctionFragment;
encodeFunctionData(
functionFragment: "governance",
values?: undefined
): string;
encodeFunctionData(functionFragment: "instances", values: [string]): string;
encodeFunctionData(functionFragment: "resolve", values: [BytesLike]): string;
encodeFunctionData(
functionFragment: "tornadoTrees",
values?: undefined
): string;
encodeFunctionData(
functionFragment: "deposit",
values: [string, BytesLike]
): string;
encodeFunctionData(
functionFragment: "updateInstances",
values: [string, boolean]
): string;
encodeFunctionData(
functionFragment: "withdraw",
values: [
string,
BytesLike,
BytesLike,
BytesLike,
string,
string,
BigNumberish,
BigNumberish
]
): string;
decodeFunctionResult(functionFragment: "governance", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "instances", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "resolve", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "tornadoTrees",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "deposit", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "updateInstances",
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "withdraw", data: BytesLike): Result;
events: {};
}
export interface TornadoProxyABI extends BaseContract {
connect(signerOrProvider: Signer | Provider | string): this;
attach(addressOrName: string): this;
deployed(): Promise<this>;
interface: TornadoProxyABIInterface;
queryFilter<TEvent extends TypedEvent>(
event: TypedEventFilter<TEvent>,
fromBlockOrBlockhash?: string | number | undefined,
toBlock?: string | number | undefined
): Promise<Array<TEvent>>;
listeners<TEvent extends TypedEvent>(
eventFilter?: TypedEventFilter<TEvent>
): Array<TypedListener<TEvent>>;
listeners(eventName?: string): Array<Listener>;
removeAllListeners<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>
): this;
removeAllListeners(eventName?: string): this;
off: OnEvent<this>;
on: OnEvent<this>;
once: OnEvent<this>;
removeListener: OnEvent<this>;
functions: {
governance(overrides?: CallOverrides): Promise<[string]>;
instances(arg0: string, overrides?: CallOverrides): Promise<[boolean]>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<[string]>;
tornadoTrees(overrides?: CallOverrides): Promise<[string]>;
deposit(
tornado: string,
commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
updateInstances(
instance: string,
update: boolean,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
withdraw(
tornado: string,
proof: BytesLike,
root: BytesLike,
nullifierHash: BytesLike,
recipient: string,
relayer: string,
fee: BigNumberish,
refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
};
governance(overrides?: CallOverrides): Promise<string>;
instances(arg0: string, overrides?: CallOverrides): Promise<boolean>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
tornadoTrees(overrides?: CallOverrides): Promise<string>;
deposit(
tornado: string,
commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
updateInstances(
instance: string,
update: boolean,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
withdraw(
tornado: string,
proof: BytesLike,
root: BytesLike,
nullifierHash: BytesLike,
recipient: string,
relayer: string,
fee: BigNumberish,
refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<ContractTransaction>;
callStatic: {
governance(overrides?: CallOverrides): Promise<string>;
instances(arg0: string, overrides?: CallOverrides): Promise<boolean>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<string>;
tornadoTrees(overrides?: CallOverrides): Promise<string>;
deposit(
tornado: string,
commitment: BytesLike,
overrides?: CallOverrides
): Promise<void>;
updateInstances(
instance: string,
update: boolean,
overrides?: CallOverrides
): Promise<void>;
withdraw(
tornado: string,
proof: BytesLike,
root: BytesLike,
nullifierHash: BytesLike,
recipient: string,
relayer: string,
fee: BigNumberish,
refund: BigNumberish,
overrides?: CallOverrides
): Promise<void>;
};
filters: {};
estimateGas: {
governance(overrides?: CallOverrides): Promise<BigNumber>;
instances(arg0: string, overrides?: CallOverrides): Promise<BigNumber>;
resolve(node: BytesLike, overrides?: CallOverrides): Promise<BigNumber>;
tornadoTrees(overrides?: CallOverrides): Promise<BigNumber>;
deposit(
tornado: string,
commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
updateInstances(
instance: string,
update: boolean,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
withdraw(
tornado: string,
proof: BytesLike,
root: BytesLike,
nullifierHash: BytesLike,
recipient: string,
relayer: string,
fee: BigNumberish,
refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<BigNumber>;
};
populateTransaction: {
governance(overrides?: CallOverrides): Promise<PopulatedTransaction>;
instances(
arg0: string,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
resolve(
node: BytesLike,
overrides?: CallOverrides
): Promise<PopulatedTransaction>;
tornadoTrees(overrides?: CallOverrides): Promise<PopulatedTransaction>;
deposit(
tornado: string,
commitment: BytesLike,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
updateInstances(
instance: string,
update: boolean,
overrides?: Overrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
withdraw(
tornado: string,
proof: BytesLike,
root: BytesLike,
nullifierHash: BytesLike,
recipient: string,
relayer: string,
fee: BigNumberish,
refund: BigNumberish,
overrides?: PayableOverrides & { from?: string | Promise<string> }
): Promise<PopulatedTransaction>;
};
}

44
contracts/common.ts Normal file
View File

@ -0,0 +1,44 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import type { Listener } from "@ethersproject/providers";
import type { Event, EventFilter } from "ethers";
export interface TypedEvent<
TArgsArray extends Array<any> = any,
TArgsObject = any
> extends Event {
args: TArgsArray & TArgsObject;
}
export interface TypedEventFilter<_TEvent extends TypedEvent>
extends EventFilter {}
export interface TypedListener<TEvent extends TypedEvent> {
(...listenerArg: [...__TypechainArgsArray<TEvent>, TEvent]): void;
}
type __TypechainArgsArray<T> = T extends TypedEvent<infer U> ? U : never;
export interface OnEvent<TRes> {
<TEvent extends TypedEvent>(
eventFilter: TypedEventFilter<TEvent>,
listener: TypedListener<TEvent>
): TRes;
(eventName: string, listener: Listener): TRes;
}
export type MinEthersFactory<C, ARGS> = {
deploy(...a: ARGS[]): Promise<C>;
};
export type GetContractTypeFromFactory<F> = F extends MinEthersFactory<
infer C,
any
>
? C
: never;
export type GetARGsTypeFromFactory<F> = F extends MinEthersFactory<any, any>
? Parameters<F["deploy"]>
: never;

View File

@ -0,0 +1,340 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from "ethers";
import type { Provider } from "@ethersproject/providers";
import type { AggregatorAbi, AggregatorAbiInterface } from "../AggregatorAbi";
const _abi = [
{
inputs: [
{
internalType: "bytes32[]",
name: "domains",
type: "bytes32[]",
},
],
name: "bulkResolve",
outputs: [
{
internalType: "address[]",
name: "result",
type: "address[]",
},
],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "contract Governance",
name: "governance",
type: "address",
},
],
name: "getAllProposals",
outputs: [
{
components: [
{
internalType: "address",
name: "proposer",
type: "address",
},
{
internalType: "address",
name: "target",
type: "address",
},
{
internalType: "uint256",
name: "startTime",
type: "uint256",
},
{
internalType: "uint256",
name: "endTime",
type: "uint256",
},
{
internalType: "uint256",
name: "forVotes",
type: "uint256",
},
{
internalType: "uint256",
name: "againstVotes",
type: "uint256",
},
{
internalType: "bool",
name: "executed",
type: "bool",
},
{
internalType: "bool",
name: "extended",
type: "bool",
},
{
internalType: "enum Governance.ProposalState",
name: "state",
type: "uint8",
},
],
internalType: "struct GovernanceAggregator.Proposal[]",
name: "proposals",
type: "tuple[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract Governance",
name: "governance",
type: "address",
},
{
internalType: "address[]",
name: "accs",
type: "address[]",
},
],
name: "getGovernanceBalances",
outputs: [
{
internalType: "uint256[]",
name: "amounts",
type: "uint256[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address[]",
name: "fromTokens",
type: "address[]",
},
{
internalType: "uint256[]",
name: "oneUnitAmounts",
type: "uint256[]",
},
],
name: "getPricesInETH",
outputs: [
{
internalType: "uint256[]",
name: "prices",
type: "uint256[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract Governance",
name: "governance",
type: "address",
},
{
internalType: "address",
name: "account",
type: "address",
},
],
name: "getUserData",
outputs: [
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "latestProposalId",
type: "uint256",
},
{
internalType: "uint256",
name: "latestProposalIdState",
type: "uint256",
},
{
internalType: "uint256",
name: "timelock",
type: "uint256",
},
{
internalType: "address",
name: "delegatee",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract Miner",
name: "miner",
type: "address",
},
{
internalType: "address[]",
name: "instances",
type: "address[]",
},
],
name: "minerRates",
outputs: [
{
internalType: "uint256[]",
name: "_rates",
type: "uint256[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "node",
type: "bytes32",
},
],
name: "resolve",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract RewardSwap",
name: "swap",
type: "address",
},
],
name: "swapState",
outputs: [
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "poolWeight",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract Miner",
name: "miner",
type: "address",
},
{
internalType: "address[]",
name: "instances",
type: "address[]",
},
{
internalType: "contract RewardSwap",
name: "swap",
type: "address",
},
],
name: "miningData",
outputs: [
{
internalType: "uint256[]",
name: "_rates",
type: "uint256[]",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
{
internalType: "uint256",
name: "poolWeight",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address[]",
name: "fromTokens",
type: "address[]",
},
{
internalType: "uint256[]",
name: "oneUnitAmounts",
type: "uint256[]",
},
{
internalType: "contract RewardSwap",
name: "swap",
type: "address",
},
],
name: "marketData",
outputs: [
{
internalType: "uint256[]",
name: "prices",
type: "uint256[]",
},
{
internalType: "uint256",
name: "balance",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
];
export class AggregatorAbi__factory {
static readonly abi = _abi;
static createInterface(): AggregatorAbiInterface {
return new utils.Interface(_abi) as AggregatorAbiInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): AggregatorAbi {
return new Contract(address, _abi, signerOrProvider) as AggregatorAbi;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from 'ethers';
import type { Provider } from '@ethersproject/providers';
import type { MulticallAbi, MulticallAbiInterface } from '../MulticallAbi';
const _abi = [
{
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',
},
];
export class MulticallAbi__factory {
static readonly abi = _abi;
static createInterface(): MulticallAbiInterface {
return new utils.Interface(_abi) as MulticallAbiInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider,
): MulticallAbi {
return new Contract(address, _abi, signerOrProvider) as MulticallAbi;
}
}

View File

@ -0,0 +1,358 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from "ethers";
import type { Provider } from "@ethersproject/providers";
import type {
OffchainOracleAbi,
OffchainOracleAbiInterface,
} from "../OffchainOracleAbi";
const _abi = [
{
inputs: [
{
internalType: "contract MultiWrapper",
name: "_multiWrapper",
type: "address",
},
{
internalType: "contract IOracle[]",
name: "existingOracles",
type: "address[]",
},
{
internalType: "enum OffchainOracle.OracleType[]",
name: "oracleTypes",
type: "uint8[]",
},
{
internalType: "contract IERC20[]",
name: "existingConnectors",
type: "address[]",
},
{
internalType: "contract IERC20",
name: "wBase",
type: "address",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "contract IERC20",
name: "connector",
type: "address",
},
],
name: "ConnectorAdded",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "contract IERC20",
name: "connector",
type: "address",
},
],
name: "ConnectorRemoved",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "contract MultiWrapper",
name: "multiWrapper",
type: "address",
},
],
name: "MultiWrapperUpdated",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "contract IOracle",
name: "oracle",
type: "address",
},
{
indexed: false,
internalType: "enum OffchainOracle.OracleType",
name: "oracleType",
type: "uint8",
},
],
name: "OracleAdded",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "contract IOracle",
name: "oracle",
type: "address",
},
{
indexed: false,
internalType: "enum OffchainOracle.OracleType",
name: "oracleType",
type: "uint8",
},
],
name: "OracleRemoved",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "previousOwner",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "OwnershipTransferred",
type: "event",
},
{
inputs: [
{
internalType: "contract IERC20",
name: "connector",
type: "address",
},
],
name: "addConnector",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "contract IOracle",
name: "oracle",
type: "address",
},
{
internalType: "enum OffchainOracle.OracleType",
name: "oracleKind",
type: "uint8",
},
],
name: "addOracle",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "connectors",
outputs: [
{
internalType: "contract IERC20[]",
name: "allConnectors",
type: "address[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract IERC20",
name: "srcToken",
type: "address",
},
{
internalType: "contract IERC20",
name: "dstToken",
type: "address",
},
{
internalType: "bool",
name: "useWrappers",
type: "bool",
},
],
name: "getRate",
outputs: [
{
internalType: "uint256",
name: "weightedRate",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract IERC20",
name: "srcToken",
type: "address",
},
{
internalType: "bool",
name: "useSrcWrappers",
type: "bool",
},
],
name: "getRateToEth",
outputs: [
{
internalType: "uint256",
name: "weightedRate",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "multiWrapper",
outputs: [
{
internalType: "contract MultiWrapper",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "oracles",
outputs: [
{
internalType: "contract IOracle[]",
name: "allOracles",
type: "address[]",
},
{
internalType: "enum OffchainOracle.OracleType[]",
name: "oracleTypes",
type: "uint8[]",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "owner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract IERC20",
name: "connector",
type: "address",
},
],
name: "removeConnector",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "contract IOracle",
name: "oracle",
type: "address",
},
{
internalType: "enum OffchainOracle.OracleType",
name: "oracleKind",
type: "uint8",
},
],
name: "removeOracle",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [],
name: "renounceOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "contract MultiWrapper",
name: "_multiWrapper",
type: "address",
},
],
name: "setMultiWrapper",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "newOwner",
type: "address",
},
],
name: "transferOwnership",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
];
export class OffchainOracleAbi__factory {
static readonly abi = _abi;
static createInterface(): OffchainOracleAbiInterface {
return new utils.Interface(_abi) as OffchainOracleAbiInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): OffchainOracleAbi {
return new Contract(address, _abi, signerOrProvider) as OffchainOracleAbi;
}
}

View File

@ -0,0 +1,273 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from "ethers";
import type { Provider } from "@ethersproject/providers";
import type { SwapAbi, SwapAbiInterface } from "../SwapAbi";
const _abi = [
{
inputs: [
{
internalType: "bytes32",
name: "_torn",
type: "bytes32",
},
{
internalType: "bytes32",
name: "_miner",
type: "bytes32",
},
{
internalType: "uint256",
name: "_miningCap",
type: "uint256",
},
{
internalType: "uint256",
name: "_initialLiquidity",
type: "uint256",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "uint256",
name: "newWeight",
type: "uint256",
},
],
name: "PoolWeightUpdated",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "recipient",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "pTORN",
type: "uint256",
},
{
indexed: false,
internalType: "uint256",
name: "TORN",
type: "uint256",
},
],
name: "Swap",
type: "event",
},
{
inputs: [],
name: "DURATION",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "initialLiquidity",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "liquidity",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "miner",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "poolWeight",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "node",
type: "bytes32",
},
],
name: "resolve",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "startTimestamp",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "tokensSold",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "torn",
outputs: [
{
internalType: "contract IERC20",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "address",
name: "recipient",
type: "address",
},
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "swap",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "amount",
type: "uint256",
},
],
name: "getExpectedReturn",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "tornVirtualBalance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "uint256",
name: "newWeight",
type: "uint256",
},
],
name: "setPoolWeight",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
];
export class SwapAbi__factory {
static readonly abi = _abi;
static createInterface(): SwapAbiInterface {
return new utils.Interface(_abi) as SwapAbiInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): SwapAbi {
return new Contract(address, _abi, signerOrProvider) as SwapAbi;
}
}

View File

@ -0,0 +1,519 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from "ethers";
import type { Provider } from "@ethersproject/providers";
import type { TornadoABI, TornadoABIInterface } from "../TornadoABI";
const _abi = [
{
constant: false,
inputs: [
{
internalType: "address",
name: "_newOperator",
type: "address",
},
],
name: "changeOperator",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
name: "nullifierHashes",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: false,
inputs: [
{
internalType: "bytes",
name: "_proof",
type: "bytes",
},
{
internalType: "bytes32",
name: "_root",
type: "bytes32",
},
{
internalType: "bytes32",
name: "_nullifierHash",
type: "bytes32",
},
{
internalType: "address payable",
name: "_recipient",
type: "address",
},
{
internalType: "address payable",
name: "_relayer",
type: "address",
},
{
internalType: "uint256",
name: "_fee",
type: "uint256",
},
{
internalType: "uint256",
name: "_refund",
type: "uint256",
},
],
name: "withdraw",
outputs: [],
payable: true,
stateMutability: "payable",
type: "function",
},
{
constant: true,
inputs: [],
name: "verifier",
outputs: [
{
internalType: "contract IVerifier",
name: "",
type: "address",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "bytes32",
name: "_left",
type: "bytes32",
},
{
internalType: "bytes32",
name: "_right",
type: "bytes32",
},
],
name: "hashLeftRight",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "pure",
type: "function",
},
{
constant: true,
inputs: [],
name: "FIELD_SIZE",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "levels",
outputs: [
{
internalType: "uint32",
name: "",
type: "uint32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "operator",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "bytes32",
name: "_root",
type: "bytes32",
},
],
name: "isKnownRoot",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
name: "commitments",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "denomination",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "currentRootIndex",
outputs: [
{
internalType: "uint32",
name: "",
type: "uint32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: false,
inputs: [
{
internalType: "address",
name: "_newVerifier",
type: "address",
},
],
name: "updateVerifier",
outputs: [],
payable: false,
stateMutability: "nonpayable",
type: "function",
},
{
constant: false,
inputs: [
{
internalType: "bytes32",
name: "_commitment",
type: "bytes32",
},
],
name: "deposit",
outputs: [],
payable: true,
stateMutability: "payable",
type: "function",
},
{
constant: true,
inputs: [],
name: "getLastRoot",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
name: "roots",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "ROOT_HISTORY_SIZE",
outputs: [
{
internalType: "uint32",
name: "",
type: "uint32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "bytes32",
name: "_nullifierHash",
type: "bytes32",
},
],
name: "isSpent",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
name: "zeros",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "ZERO_VALUE",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [
{
internalType: "uint256",
name: "",
type: "uint256",
},
],
name: "filledSubtrees",
outputs: [
{
internalType: "bytes32",
name: "",
type: "bytes32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
constant: true,
inputs: [],
name: "nextIndex",
outputs: [
{
internalType: "uint32",
name: "",
type: "uint32",
},
],
payable: false,
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract IVerifier",
name: "_verifier",
type: "address",
},
{
internalType: "uint256",
name: "_denomination",
type: "uint256",
},
{
internalType: "uint32",
name: "_merkleTreeHeight",
type: "uint32",
},
{
internalType: "address",
name: "_operator",
type: "address",
},
],
payable: false,
stateMutability: "nonpayable",
type: "constructor",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "bytes32",
name: "commitment",
type: "bytes32",
},
{
indexed: false,
internalType: "uint32",
name: "leafIndex",
type: "uint32",
},
{
indexed: false,
internalType: "uint256",
name: "timestamp",
type: "uint256",
},
],
name: "Deposit",
type: "event",
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: "address",
name: "to",
type: "address",
},
{
indexed: false,
internalType: "bytes32",
name: "nullifierHash",
type: "bytes32",
},
{
indexed: true,
internalType: "address",
name: "relayer",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "fee",
type: "uint256",
},
],
name: "Withdrawal",
type: "event",
},
];
export class TornadoABI__factory {
static readonly abi = _abi;
static createInterface(): TornadoABIInterface {
return new utils.Interface(_abi) as TornadoABIInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): TornadoABI {
return new Contract(address, _abi, signerOrProvider) as TornadoABI;
}
}

View File

@ -0,0 +1,195 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
import { Contract, Signer, utils } from "ethers";
import type { Provider } from "@ethersproject/providers";
import type {
TornadoProxyABI,
TornadoProxyABIInterface,
} from "../TornadoProxyABI";
const _abi = [
{
inputs: [
{
internalType: "bytes32",
name: "_tornadoTrees",
type: "bytes32",
},
{
internalType: "bytes32",
name: "_governance",
type: "bytes32",
},
{
internalType: "contract ITornado[]",
name: "_instances",
type: "address[]",
},
],
stateMutability: "nonpayable",
type: "constructor",
},
{
inputs: [],
name: "governance",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract ITornado",
name: "",
type: "address",
},
],
name: "instances",
outputs: [
{
internalType: "bool",
name: "",
type: "bool",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "node",
type: "bytes32",
},
],
name: "resolve",
outputs: [
{
internalType: "address",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [],
name: "tornadoTrees",
outputs: [
{
internalType: "contract ITornadoTrees",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "contract ITornado",
name: "tornado",
type: "address",
},
{
internalType: "bytes32",
name: "commitment",
type: "bytes32",
},
],
name: "deposit",
outputs: [],
stateMutability: "payable",
type: "function",
},
{
inputs: [
{
internalType: "contract ITornado",
name: "instance",
type: "address",
},
{
internalType: "bool",
name: "update",
type: "bool",
},
],
name: "updateInstances",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
internalType: "contract ITornado",
name: "tornado",
type: "address",
},
{
internalType: "bytes",
name: "proof",
type: "bytes",
},
{
internalType: "bytes32",
name: "root",
type: "bytes32",
},
{
internalType: "bytes32",
name: "nullifierHash",
type: "bytes32",
},
{
internalType: "address payable",
name: "recipient",
type: "address",
},
{
internalType: "address payable",
name: "relayer",
type: "address",
},
{
internalType: "uint256",
name: "fee",
type: "uint256",
},
{
internalType: "uint256",
name: "refund",
type: "uint256",
},
],
name: "withdraw",
outputs: [],
stateMutability: "payable",
type: "function",
},
];
export class TornadoProxyABI__factory {
static readonly abi = _abi;
static createInterface(): TornadoProxyABIInterface {
return new utils.Interface(_abi) as TornadoProxyABIInterface;
}
static connect(
address: string,
signerOrProvider: Signer | Provider
): TornadoProxyABI {
return new Contract(address, _abi, signerOrProvider) as TornadoProxyABI;
}
}

View File

@ -0,0 +1,10 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export { AggregatorAbi__factory } from './AggregatorAbi__factory';
export { MulticallAbi__factory } from './MulticallAbi__factory';
export { OffchainOracleAbi__factory } from './OffchainOracleAbi__factory';
export { MiningAbi__factory } from './MiningAbi__factory';
export { SwapAbi__factory } from './SwapAbi__factory';
export { TornadoABI__factory } from './TornadoABI__factory';
export { TornadoProxyABI__factory } from './TornadoProxyABI__factory';

18
contracts/index.ts Normal file
View File

@ -0,0 +1,18 @@
/* Autogenerated file. Do not edit manually. */
/* tslint:disable */
/* eslint-disable */
export type { AggregatorAbi } from './AggregatorAbi';
export type { MulticallAbi } from './MulticallAbi';
export type { OffchainOracleAbi } from './OffchainOracleAbi';
export type { MiningAbi } from './MiningAbi';
export type { SwapAbi } from './SwapAbi';
export type { TornadoABI } from './TornadoABI';
export type { TornadoProxyABI } from './TornadoProxyABI';
export * as factories from './factories';
export { AggregatorAbi__factory } from './factories/AggregatorAbi__factory';
export { MiningAbi__factory } from './factories/MiningAbi__factory';
export { MulticallAbi__factory } from './factories/MulticallAbi__factory';
export { OffchainOracleAbi__factory } from './factories/OffchainOracleAbi__factory';
export { SwapAbi__factory } from './factories/SwapAbi__factory';
export { TornadoABI__factory } from './factories/TornadoABI__factory';
export { TornadoProxyABI__factory } from './factories/TornadoProxyABI__factory';

View File

@ -3,7 +3,8 @@
"version": "4.1.3",
"description": "Relayer for Tornado.cash privacy solution. https://tornado.cash",
"scripts": {
"server": "node src/server.js",
"dev:app": "nodemon --watch './src/**/*.ts' --exec ts-node src/api/index.ts",
"server": "node src/api/server.ts",
"worker": "node src/worker",
"treeWatcher": "node src/treeWatcher",
"priceWatcher": "node src/priceWatcher",
@ -18,18 +19,19 @@
"author": "tornado.cash",
"license": "MIT",
"dependencies": {
"ajv": "^6.12.5",
"async-mutex": "^0.2.4",
"bull": "^3.12.1",
"bullmq": "^1.80.6",
"circomlib": "git+https://github.com/tornadocash/circomlib.git#3b492f9801573eebcfe1b6c584afe8a3beecf2b4",
"dotenv": "^8.2.0",
"eth-ens-namehash": "^2.0.8",
"express": "^4.17.1",
"fixed-merkle-tree": "^0.4.0",
"ethers": "^5.6.4",
"fastify": "^3.28.0",
"fastify-cors": "^6.0.3",
"fixed-merkle-tree": "^0.7.3",
"gas-price-oracle": "^0.3.5",
"ioredis": "^4.14.1",
"json-schema-to-ts": "^2.2.0",
"node-fetch": "^2.6.7",
"torn-token": "1.0.6",
"torn-token": "link:../torn-token",
"tornado-anonymity-mining": "^2.1.2",
"tx-manager": "^0.4.1",
"uuid": "^8.3.0",
@ -38,11 +40,18 @@
"web3-utils": "^1.2.2"
},
"devDependencies": {
"@typechain/ethers-v5": "^10.0.0",
"@types/ioredis": "^4.28.10",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"chai": "^4.2.0",
"eslint": "^6.6.0",
"eslint": "^8.14.0",
"eslint-config-prettier": "^6.12.0",
"eslint-plugin-prettier": "^3.1.4",
"mocha": "^8.1.3",
"prettier": "^2.1.2"
"nodemon": "^2.0.15",
"ts-node": "^10.7.0",
"typechain": "^8.0.0",
"typescript": "^4.6.3"
}
}

15
src/api/index.ts Normal file
View File

@ -0,0 +1,15 @@
import createServer from './server';
import { utils } from 'ethers';
import { port, rewardAccount } from '../config';
import { version } from '../../package.json';
if (!utils.isAddress(rewardAccount)) {
throw new Error('No REWARD_ACCOUNT specified');
}
const server = createServer();
server.listen(port, '0.0.0.0', (err, address) => {
if (err) throw err;
console.log(`Relayer ${version} started on port ${address}`);
});

View File

@ -0,0 +1,47 @@
import Ajv from 'ajv';
import fp from 'fastify-plugin';
import { rewardAccount } from '../../config';
import { getAddress, isAddress } from 'ethers/lib/utils';
export default fp(async server => {
const ajv = new Ajv();
ajv.addKeyword('isAddress', {
validate: (schema, data) => {
try {
return isAddress(data);
} catch (e) {
return false;
}
},
errors: true,
});
// ajv.addKeyword('isKnownContract', {
// validate: (schema, data) => {
// try {
// return !!getInstance(data);
// } catch (e) {
// return false;
// }
// },
// errors: true,
// });
ajv.addKeyword('isFeeRecipient', {
validate: (schema, data) => {
try {
return getAddress(rewardAccount) === getAddress(data);
} catch (e) {
return false;
}
},
errors: true,
});
server.setValidatorCompiler(({ schema, method, url, httpPart }) => {
return ajv.compile(schema);
});
console.log('validator plugin registered');
return Promise.resolve();
});

34
src/api/routes.ts Normal file
View File

@ -0,0 +1,34 @@
import { FastifyInstance } from 'fastify';
import { statusSchema, withdrawBodySchema, withdrawSchema } from './schema';
import { FromSchema } from 'json-schema-to-ts';
export function relayerHandler(server: FastifyInstance, options, next) {
/*
write some code here, please
*/
server.get('/',
async (req, res) => {
res.send({});
});
server.get('/status',
{ schema: statusSchema },
async (req, res) => {
res.send({ status: 'status' });
});
server.post<{ Body: FromSchema<typeof withdrawBodySchema> }>('/relay',
{ schema: withdrawSchema },
async (req, res) => {
res.send({});
},
);
server.get('/jobs/:id',
async (req, res) => {
res.send({});
});
server.post('/tornadoWithdraw',
async (req, res) => {
res.send({});
});
next();
}

149
src/api/schema.ts Normal file
View File

@ -0,0 +1,149 @@
const addressType = { type: 'string', pattern: '^0x[a-fA-F0-9]{40}$', isAddress: true } as const;
const proofType = { type: 'string', pattern: '^0x[a-fA-F0-9]{512}$' } as const;
const encryptedAccountType = { type: 'string', pattern: '^0x[a-fA-F0-9]{392}$' } as const;
const bytes32Type = { type: 'string', pattern: '^0x[a-fA-F0-9]{64}$' } as const;
const instanceType = { ...addressType, isKnownContract: true } as const;
const relayerType = { ...addressType, isFeeRecipient: true } as const;
export const withdrawBodySchema = {
type: 'object',
properties: {
proof: proofType,
contract: instanceType,
args: {
type: 'array',
maxItems: 6,
minItems: 6,
items: [bytes32Type, bytes32Type, addressType, relayerType, bytes32Type, bytes32Type],
},
},
additionalProperties: false,
required: ['proof', 'contract', 'args'],
} as const;
export const withdrawSchema = {
body: withdrawBodySchema,
response: {
200: {
type: 'boolean',
},
},
};
const statusResponseSchema = {
type: 'object',
properties: {
status: { type: 'string' },
},
} as const;
export const statusSchema = {
response: {
200: statusResponseSchema,
},
};
const miningRewardSchema = {
type: 'object',
properties: {
proof: proofType,
args: {
type: 'object',
properties: {
rate: bytes32Type,
fee: bytes32Type,
instance: instanceType,
rewardNullifier: bytes32Type,
extDataHash: bytes32Type,
depositRoot: bytes32Type,
withdrawalRoot: bytes32Type,
extData: {
type: 'object',
properties: {
relayer: relayerType,
encryptedAccount: encryptedAccountType,
},
additionalProperties: false,
required: ['relayer', 'encryptedAccount'],
},
account: {
type: 'object',
properties: {
inputRoot: bytes32Type,
inputNullifierHash: bytes32Type,
outputRoot: bytes32Type,
outputPathIndices: bytes32Type,
outputCommitment: bytes32Type,
},
additionalProperties: false,
required: [
'inputRoot',
'inputNullifierHash',
'outputRoot',
'outputPathIndices',
'outputCommitment',
],
},
},
additionalProperties: false,
required: [
'rate',
'fee',
'instance',
'rewardNullifier',
'extDataHash',
'depositRoot',
'withdrawalRoot',
'extData',
'account',
],
},
},
additionalProperties: false,
required: ['proof', 'args'],
} as const;
const miningWithdrawSchema = {
type: 'object',
properties: {
proof: proofType,
args: {
type: 'object',
properties: {
amount: bytes32Type,
extDataHash: bytes32Type,
extData: {
type: 'object',
properties: {
fee: bytes32Type,
recipient: addressType,
relayer: relayerType,
encryptedAccount: encryptedAccountType,
},
additionalProperties: false,
required: ['fee', 'relayer', 'encryptedAccount', 'recipient'],
},
account: {
type: 'object',
properties: {
inputRoot: bytes32Type,
inputNullifierHash: bytes32Type,
outputRoot: bytes32Type,
outputPathIndices: bytes32Type,
outputCommitment: bytes32Type,
},
additionalProperties: false,
required: [
'inputRoot',
'inputNullifierHash',
'outputRoot',
'outputPathIndices',
'outputCommitment',
],
},
},
additionalProperties: false,
required: ['amount', 'extDataHash', 'extData', 'account'],
},
},
additionalProperties: false,
required: ['proof', 'args'],
};

25
src/api/server.ts Normal file
View File

@ -0,0 +1,25 @@
import fastify from 'fastify';
import cors from 'fastify-cors';
import validator from './plugins/validator';
import { relayerHandler } from './routes';
function createServer() {
const server = fastify({
logger: true,
pluginTimeout: 5000,
bodyLimit: 1048576, // 1 mb
});
server.register(cors);
server.register(validator);
server.register(relayerHandler);
server.setErrorHandler((error, req, res) => {
req.log.error(error.toString());
res.code(500).send({ error });
});
return server;
}
export default createServer;

View File

@ -1,31 +0,0 @@
require('dotenv').config()
const { jobType } = require('./constants')
const tornConfig = require('torn-token')
module.exports = {
netId: Number(process.env.NET_ID) || 1,
redisUrl: process.env.REDIS_URL || 'redis://127.0.0.1:6379',
httpRpcUrl: process.env.HTTP_RPC_URL,
wsRpcUrl: process.env.WS_RPC_URL,
oracleRpcUrl: process.env.ORACLE_RPC_URL || 'https://mainnet.infura.io/',
offchainOracleAddress: '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb',
aggregatorAddress: process.env.AGGREGATOR,
minerMerkleTreeHeight: 20,
privateKey: process.env.PRIVATE_KEY,
instances: tornConfig.instances,
torn: tornConfig,
port: process.env.APP_PORT || 8000,
tornadoServiceFee: Number(process.env.REGULAR_TORNADO_WITHDRAW_FEE),
miningServiceFee: Number(process.env.MINING_SERVICE_FEE),
rewardAccount: process.env.REWARD_ACCOUNT,
governanceAddress: '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce',
tornadoGoerliProxy: '0x454d870a72e29d5E5697f635128D18077BD04C60',
gasLimits: {
[jobType.TORNADO_WITHDRAW]: 390000,
WITHDRAW_WITH_EXTRA: 700000,
[jobType.MINING_REWARD]: 455000,
[jobType.MINING_WITHDRAW]: 400000,
},
minimumBalance: '1000000000000000000',
baseFeeReserve: Number(process.env.BASE_FEE_RESERVE_PERCENTAGE),
}

51
src/config.ts Normal file
View File

@ -0,0 +1,51 @@
import { jobType } from './types';
import tornConfig from 'torn-token';
import { EnsResolver } from './modules';
import { getProvider } from './modules/contracts';
require('dotenv').config();
export const netId = Number(process.env.NET_ID) || 1;
export const redisUrl = process.env.REDIS_URL || 'redis://127.0.0.1:6379';
export const httpRpcUrl = process.env.HTTP_RPC_URL;
export const wsRpcUrl = process.env.WS_RPC_URL;
export const oracleRpcUrl = process.env.ORACLE_RPC_URL || 'https://mainnet.infura.io/';
export const offchainOracleAddress = '0x07D91f5fb9Bf7798734C3f606dB065549F6893bb';
export const multiCallAddress = '0xda3c19c6fe954576707fa24695efb830d9cca1ca';
export const aggregatorAddress = process.env.AGGREGATOR;
export const minerMerkleTreeHeight = 20;
export const privateKey = process.env.PRIVATE_KEY;
export const instances = tornConfig.instances;
export const torn = tornConfig;
export const port = process.env.APP_PORT || 8000;
export const tornadoServiceFee = Number(process.env.REGULAR_TORNADO_WITHDRAW_FEE);
export const miningServiceFee = Number(process.env.MINING_SERVICE_FEE);
export const rewardAccount = process.env.REWARD_ACCOUNT;
export const governanceAddress = '0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce';
export const tornadoGoerliProxy = '0x454d870a72e29d5E5697f635128D18077BD04C60';
export const gasLimits = {
[jobType.TORNADO_WITHDRAW]: 390000,
WITHDRAW_WITH_EXTRA: 700000,
[jobType.MINING_REWARD]: 455000,
[jobType.MINING_WITHDRAW]: 400000,
};
export const minimumBalance = '1000000000000000000';
export const baseFeeReserve = Number(process.env.BASE_FEE_RESERVE_PERCENTAGE);
let tornadoProxyAddress: string;
let tornadoMiningAddress: string;
export const initConfig = async () => {
const provider = getProvider();
const resolver = new EnsResolver(provider);
if (netId === 5) {
tornadoProxyAddress = tornadoGoerliProxy;
} else {
tornadoProxyAddress = await resolver.resolve(torn.tornadoRouter.address);
}
tornadoMiningAddress = await resolver.resolve(torn.miningV2.address);
};
export { tornadoProxyAddress, tornadoMiningAddress };

View File

@ -1,20 +0,0 @@
const jobType = Object.freeze({
TORNADO_WITHDRAW: 'TORNADO_WITHDRAW',
MINING_REWARD: 'MINING_REWARD',
MINING_WITHDRAW: 'MINING_WITHDRAW',
})
const status = Object.freeze({
QUEUED: 'QUEUED',
ACCEPTED: 'ACCEPTED',
SENT: 'SENT',
MINED: 'MINED',
RESUBMITTED: 'RESUBMITTED',
CONFIRMED: 'CONFIRMED',
FAILED: 'FAILED',
})
module.exports = {
jobType,
status,
}

View File

@ -1,55 +1,57 @@
import { postJob } from './queue';
import { jobType } from './types';
const {
getTornadoWithdrawInputError,
getMiningRewardInputError,
getMiningWithdrawInputError,
} = require('./validator')
const { postJob } = require('./queue')
const { jobType } = require('./constants')
} = require('./validator');
async function tornadoWithdraw(req, res) {
const inputError = getTornadoWithdrawInputError(req.body)
const inputError = getTornadoWithdrawInputError(req.body);
if (inputError) {
console.log('Invalid input:', inputError)
return res.status(400).json({ error: inputError })
console.log('Invalid input:', inputError);
return res.status(400).json({ error: inputError });
}
const id = await postJob({
type: jobType.TORNADO_WITHDRAW,
request: req.body,
})
return res.json({ id })
});
return res.json({ id });
}
async function miningReward(req, res) {
const inputError = getMiningRewardInputError(req.body)
const inputError = getMiningRewardInputError(req.body);
if (inputError) {
console.log('Invalid input:', inputError)
return res.status(400).json({ error: inputError })
console.log('Invalid input:', inputError);
return res.status(400).json({ error: inputError });
}
const id = await postJob({
type: jobType.MINING_REWARD,
request: req.body,
})
return res.json({ id })
});
return res.json({ id });
}
async function miningWithdraw(req, res) {
const inputError = getMiningWithdrawInputError(req.body)
const inputError = getMiningWithdrawInputError(req.body);
if (inputError) {
console.log('Invalid input:', inputError)
return res.status(400).json({ error: inputError })
console.log('Invalid input:', inputError);
return res.status(400).json({ error: inputError });
}
const id = await postJob({
type: jobType.MINING_WITHDRAW,
request: req.body,
})
return res.json({ id })
});
return res.json({ id });
}
module.exports = {
tornadoWithdraw,
miningReward,
miningWithdraw,
}
};

View File

@ -1,27 +1,27 @@
const Web3 = require('web3')
const Redis = require('ioredis')
const { toBN, fromWei } = require('web3-utils')
const Web3 = require('web3');
const Redis = require('ioredis');
const { toBN, fromWei } = require('web3-utils');
const { setSafeInterval } = require('./utils')
const { redisUrl, httpRpcUrl, privateKey, minimumBalance } = require('./config')
const { setSafeInterval } = require('./utils');
const { redisUrl, httpRpcUrl, privateKey, minimumBalance } = require('./config');
const web3 = new Web3(httpRpcUrl)
const redis = new Redis(redisUrl)
const web3 = new Web3(httpRpcUrl);
const redis = new Redis(redisUrl);
async function main() {
try {
const { address } = web3.eth.accounts.privateKeyToAccount(privateKey)
const balance = await web3.eth.getBalance(address)
const { address } = web3.eth.accounts.privateKeyToAccount(privateKey);
const balance = await web3.eth.getBalance(address);
if (toBN(balance).lt(toBN(minimumBalance))) {
throw new Error(`Not enough balance, less than ${fromWei(minimumBalance)} ETH`)
throw new Error(`Not enough balance, less than ${fromWei(minimumBalance)} ETH`);
}
await redis.hset('health', { status: true, error: '' })
await redis.hset('health', { status: true, error: '' });
} catch (e) {
console.error('healthWatcher', e.message)
await redis.hset('health', { status: false, error: e.message })
console.error('healthWatcher', e.message);
await redis.hset('health', { status: false, error: e.message });
}
}
setSafeInterval(main, 30 * 1000)
setSafeInterval(main, 30 * 1000);

View File

@ -0,0 +1,25 @@
import { Provider } from '@ethersproject/providers';
export default class EnsResolver {
addresses: Map<string, string>;
provider: Provider;
constructor(provider: Provider) {
this.addresses = new Map<string, string>();
this.provider = provider;
}
async resolve(domain: string) {
try {
if (!this.addresses.has(domain)) {
const resolved = await this.provider.resolveName(domain);
this.addresses.set(domain, resolved);
}
return this.addresses.get(domain);
} catch (e) {
console.log(e);
return null;
}
}
}

40
src/modules/contracts.ts Normal file
View File

@ -0,0 +1,40 @@
import {
AggregatorAbi__factory,
MiningAbi__factory,
MulticallAbi__factory,
OffchainOracleAbi__factory,
TornadoProxyABI__factory,
} from '../../contracts';
import { providers } from 'ethers';
import {
aggregatorAddress,
httpRpcUrl,
multiCallAddress,
netId,
offchainOracleAddress,
tornadoMiningAddress,
tornadoProxyAddress,
} from '../config';
export function getProvider() {
return new providers.StaticJsonRpcProvider(httpRpcUrl, netId);
}
export const getTornadoProxyContract = () => {
return TornadoProxyABI__factory.connect(tornadoProxyAddress, getProvider());
};
export const getAggregatorContract = () => {
return AggregatorAbi__factory.connect(aggregatorAddress, getProvider());
};
export const getOffchainOracleContract = () => {
return OffchainOracleAbi__factory.connect(offchainOracleAddress, getProvider());
};
export const getMultiCallContract = () => {
return MulticallAbi__factory.connect(multiCallAddress, getProvider());
};
export const getTornadoMiningContract = () => {
return MiningAbi__factory.connect(tornadoMiningAddress, getProvider());
};

3
src/modules/index.ts Normal file
View File

@ -0,0 +1,3 @@
export { default as redis } from './redis';
export { default as EnsResolver } from './EnsResolver';
export { default as readJSON } from './readJSON';

12
src/modules/readJSON.ts Normal file
View File

@ -0,0 +1,12 @@
import fs from 'fs/promises';
import path from 'path';
export default async (pathToFile: string) => {
try {
const file = await fs.readFile(path.resolve(__dirname, pathToFile), { encoding: 'utf8' });
return JSON.parse(file);
} catch (e) {
console.log(e);
return null;
}
};

10
src/modules/redis.ts Normal file
View File

@ -0,0 +1,10 @@
import Redis from 'ioredis';
import { redisUrl } from '../config';
const redisClient = new Redis(redisUrl);
const redisSubscriber = new Redis(redisUrl);
export const getClient = () => redisClient;
export const getSubscriber = () => redisSubscriber;
export default { getClient, getSubscriber };

View File

@ -1,47 +1,46 @@
const Redis = require('ioredis')
const { redisUrl, offchainOracleAddress, oracleRpcUrl } = require('./config')
const { getArgsForOracle, setSafeInterval } = require('./utils')
const { toChecksumAddress } = require('web3-utils')
const redis = new Redis(redisUrl)
const Web3 = require('web3')
const Redis = require('ioredis');
const { redisUrl, offchainOracleAddress, oracleRpcUrl } = require('./config');
const { getArgsForOracle, setSafeInterval } = require('./utils');
const { toChecksumAddress } = require('web3-utils');
const redis = new Redis(redisUrl);
const Web3 = require('web3');
const web3 = new Web3(
new Web3.providers.HttpProvider(oracleRpcUrl, {
timeout: 200000, // ms
}),
)
);
const offchainOracleABI = require('../abis/OffchainOracle.abi.json')
const offchainOracleABI = require('../abis/OffchainOracle.abi.json');
const offchainOracle = new web3.eth.Contract(offchainOracleABI, offchainOracleAddress)
const { tokenAddresses, oneUintAmount, currencyLookup } = getArgsForOracle()
const offchainOracle = new web3.eth.Contract(offchainOracleABI, offchainOracleAddress);
const { tokenAddresses, oneUintAmount, currencyLookup } = getArgsForOracle();
const { toBN } = require('web3-utils')
const { toBN } = require('web3-utils');
async function main() {
try {
const ethPrices = {}
const ethPrices = {};
for (let i = 0; i < tokenAddresses.length; i++) {
try {
const isWrap =
toChecksumAddress(tokenAddresses[i]) ===
toChecksumAddress('0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643')
toChecksumAddress('0x5d3a536E4D6DbD6114cc1Ead35777bAB948E3643');
const price = await offchainOracle.methods.getRateToEth(tokenAddresses[i], isWrap).call();
const numerator = toBN(oneUintAmount[i]);
const denominator = toBN(10).pow(toBN(18)); // eth decimals
const priceFormatted = toBN(price).mul(numerator).div(denominator);
const price = await offchainOracle.methods.getRateToEth(tokenAddresses[i], isWrap).call()
const numerator = toBN(oneUintAmount[i])
const denominator = toBN(10).pow(toBN(18)) // eth decimals
const priceFormatted = toBN(price).mul(numerator).div(denominator)
ethPrices[currencyLookup[tokenAddresses[i]]] = priceFormatted.toString()
ethPrices[currencyLookup[tokenAddresses[i]]] = priceFormatted.toString();
} catch (e) {
console.error('cant get price of ', tokenAddresses[i])
console.error('cant get price of ', tokenAddresses[i]);
}
}
await redis.hmset('prices', ethPrices)
console.log('Wrote following prices to redis', ethPrices)
await redis.hmset('prices', ethPrices);
console.log('Wrote following prices to redis', ethPrices);
} catch (e) {
console.error('priceWatcher error', e)
console.error('priceWatcher error', e);
}
}
setSafeInterval(main, 30 * 1000)
setSafeInterval(main, 30 * 1000);

View File

@ -1,9 +1,9 @@
const { v4: uuid } = require('uuid')
const Queue = require('bull')
const Redis = require('ioredis')
const { redisUrl } = require('./config')
const { status } = require('./constants')
const redis = new Redis(redisUrl)
const { v4: uuid } = require('uuid');
const Queue = require('bull');
const Redis = require('ioredis');
const { redisUrl } = require('./config');
const { status } = require('./types');
const redis = new Redis(redisUrl);
const queue = new Queue('proofs', redisUrl, {
lockDuration: 300000, // Key expiration time for job locks.
@ -13,10 +13,10 @@ const queue = new Queue('proofs', redisUrl, {
guardInterval: 5000, // Poll interval for delayed jobs and added jobs.
retryProcessDelay: 5000, // delay before processing next job in case of internal error.
drainDelay: 5, // A timeout for when the queue is in drained state (empty waiting for jobs).
})
});
async function postJob({ type, request }) {
const id = uuid()
const id = uuid();
const job = await queue.add(
{
@ -28,25 +28,25 @@ async function postJob({ type, request }) {
{
//removeOnComplete: true
},
)
await redis.set(`job:${id}`, job.id)
return id
);
await redis.set(`job:${id}`, job.id);
return id;
}
async function getJob(uuid) {
const id = await redis.get(`job:${uuid}`)
return queue.getJobFromId(id)
const id = await redis.get(`job:${uuid}`);
return queue.getJobFromId(id);
}
async function getJobStatus(uuid) {
const job = await getJob(uuid)
const job = await getJob(uuid);
if (!job) {
return null
return null;
}
return {
...job.data,
failedReason: job.failedReason,
}
};
}
module.exports = {
@ -54,4 +54,4 @@ module.exports = {
getJob,
getJobStatus,
queue,
}
};

View File

@ -0,0 +1,8 @@
import priceService from '../services/PriceService';
import { Job } from 'bullmq';
export const priceProcessor = async (job: Job) => {
const { tokens } = job.data;
const prices = await priceService.getPrices(tokens);
console.log(prices);
};

View File

8
src/queue/worker.ts Normal file
View File

@ -0,0 +1,8 @@
import { redis } from '../modules';
import { Worker } from 'bullmq';
const connection = redis.getClient();
const worker = new Worker('proof', async (job) => {
// do some processing
}, { connection });

View File

@ -1,30 +1,30 @@
const { httpRpcUrl, aggregatorAddress } = require('./config')
const Web3 = require('web3')
const web3 = new Web3(httpRpcUrl)
const aggregator = new web3.eth.Contract(require('../abis/Aggregator.abi.json'), aggregatorAddress)
const ens = require('eth-ens-namehash')
const { httpRpcUrl, aggregatorAddress } = require('./config');
const Web3 = require('web3');
const web3 = new Web3(httpRpcUrl);
const aggregator = new web3.eth.Contract(require('../abis/Aggregator.abi.json'), aggregatorAddress);
const ens = require('eth-ens-namehash');
class ENSResolver {
constructor() {
this.addresses = {}
this.addresses = {};
}
async resolve(domains) {
if (!Array.isArray(domains)) {
domains = [domains]
domains = [domains];
}
const unresolved = domains.filter(d => !this.addresses[d])
const unresolved = domains.filter(d => !this.addresses[d]);
if (unresolved.length) {
const resolved = await aggregator.methods.bulkResolve(unresolved.map(ens.hash)).call()
const resolved = await aggregator.methods.bulkResolve(unresolved.map(ens.hash)).call();
for (let i = 0; i < resolved.length; i++) {
this.addresses[domains[i]] = resolved[i]
this.addresses[domains[i]] = resolved[i];
}
}
const addresses = domains.map(domain => this.addresses[domain])
return addresses.length === 1 ? addresses[0] : addresses
const addresses = domains.map(domain => this.addresses[domain]);
return addresses.length === 1 ? addresses[0] : addresses;
}
}
module.exports = ENSResolver
module.exports = ENSResolver;

View File

@ -1,41 +0,0 @@
const express = require('express')
const status = require('./status')
const controller = require('./controller')
const { port, rewardAccount } = require('./config')
const { version } = require('../package.json')
const { isAddress } = require('web3-utils')
const app = express()
app.use(express.json())
// Add CORS headers
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept')
next()
})
// Log error to console but don't send it to the client to avoid leaking data
app.use((err, req, res, next) => {
if (err) {
console.error(err)
return res.sendStatus(500)
}
next()
})
app.get('/', status.index)
app.get('/v1/status', status.status)
app.get('/v1/jobs/:id', status.getJob)
app.post('/v1/tornadoWithdraw', controller.tornadoWithdraw)
app.get('/status', status.status)
app.post('/relay', controller.tornadoWithdraw)
app.post('/v1/miningReward', controller.miningReward)
app.post('/v1/miningWithdraw', controller.miningWithdraw)
if (!isAddress(rewardAccount)) {
throw new Error('No REWARD_ACCOUNT specified')
}
app.listen(port)
console.log(`Relayer ${version} started on port ${port}`)

View File

@ -0,0 +1,42 @@
import { netId, torn, tornadoGoerliProxy } from '../config';
import { Token } from '../types';
import { getProvider } from '../modules/contracts';
import { EnsResolver } from '../modules';
const tornToken = {
tokenAddress: '0x77777FeDdddFfC19Ff86DB637967013e6C6A116C',
symbol: 'TORN',
decimals: 18,
};
export class ConfigService {
get proxyAddress(): string {
if (!this._proxyAddress) {
this.init().then(() =>
this._proxyAddress);
}
return this._proxyAddress;
}
tokens: Token[];
private _proxyAddress: string;
constructor() {
this.tokens = [tornToken, ...Object.values(torn.instances.netId1)].map<Token>(el => ({
address: el.tokenAddress,
...el,
})).filter(e => e.address);
}
async init() {
const provider = getProvider();
const resolver = new EnsResolver(provider);
if (netId === 5) {
this._proxyAddress = tornadoGoerliProxy;
} else {
this._proxyAddress = await resolver.resolve(torn.tornadoRouter.address);
}
}
}
export default new ConfigService();

View File

@ -0,0 +1,48 @@
import { getMultiCallContract, getOffchainOracleContract } from '../modules/contracts';
import { MulticallAbi, OffchainOracleAbi } from '../../contracts';
import { MultiCall } from '../../contracts/MulticallAbi';
import { BigNumber } from 'ethers';
import { defaultAbiCoder } from 'ethers/lib/utils';
import { Token } from '../types';
export class PriceService {
oracle: OffchainOracleAbi;
multiCall: MulticallAbi;
constructor() {
this.oracle = getOffchainOracleContract();
this.multiCall = getMultiCallContract();
}
prepareCallData(tokens: Token[]): MultiCall.CallStruct[] {
return tokens.map((token) => ({
to: this.oracle.address,
data: this.oracle.interface.encodeFunctionData('getRateToEth',
[token.address, true],
),
}));
}
async getPrices(tokens: Token[]) {
const names = tokens.reduce((p, c) => {
p[c.address] = c.symbol;
return p;
}, {});
const callData = this.prepareCallData(tokens);
const { results, success } = await this.multiCall.multicall(callData);
const prices: { [p: string]: string } = {};
for (let i = 0; i < results.length; i++) {
if (!success[i]) {
continue;
}
const decodedRate = defaultAbiCoder.decode(['uint256'], results[i]).toString();
const numerator = BigNumber.from(10).pow(tokens[i].decimals);
const denominator = BigNumber.from(10).pow(18); // eth decimals
const price = BigNumber.from(decodedRate).mul(numerator).div(denominator);
prices[names[tokens[i].address]] = price.toString();
}
return prices;
}
}
export default new PriceService();

View File

@ -0,0 +1,66 @@
import { getTornadoMiningContract, getTornadoProxyContract } from '../modules/contracts';
import { MiningAbi, TornadoProxyABI } from '../../contracts';
import { NewAccountEvent } from '../../contracts/MiningAbi';
import MerkleTree from 'fixed-merkle-tree';
import { minerMerkleTreeHeight, netId } from '../config';
import { poseidon } from 'circomlib';
import { BigNumber } from 'ethers';
import { readJSON } from '../modules';
const poseidonHash = (items) => BigNumber.from(poseidon(items)).toString();
const poseidonHash2 = (a, b) => poseidonHash([a, b]);
export class TreeService {
proxy: TornadoProxyABI;
miner: MiningAbi;
tree: MerkleTree;
constructor() {
this.proxy = getTornadoProxyContract();
this.miner = getTornadoMiningContract();
}
async initTree() {
const cachedEvents = await readJSON(`../../cache/accounts_farmer_${netId}.json`);
console.log('loaded cached events', cachedEvents.length);
const cachedCommitments = cachedEvents.map(e => BigNumber.from(e.commitment).toString());
const [{ blockNumber: fromBlock }] = cachedEvents.slice(-1);
console.log('fetching new events');
const newEvents = await this.fetchEvents(fromBlock);
console.log('fetched', newEvents.length);
const newCommitments = newEvents
.sort((a, b) => a.args.index.sub(b.args.index).toNumber())
.map(e => BigNumber.from(e.args.commitment).toString())
.filter((item, index, arr) => !index || item !== arr[index - 1]);
const commitments = cachedCommitments.concat(newCommitments);
console.log(newEvents.slice(-1), commitments.slice(-1));
console.log('create tree');
this.tree = new MerkleTree(minerMerkleTreeHeight, commitments, { hashFunction: poseidonHash2 });
const rootOnContract = await this.miner.callStatic.getLastAccountRoot();
console.log(this.tree.root, BigNumber.from(rootOnContract).toString());
}
async fetchEvents(fromBlock: number, toBlock?: number): Promise<NewAccountEvent[]> {
toBlock = toBlock ?? await this.proxy.provider.getBlockNumber();
if (fromBlock <= toBlock) {
try {
const newAccountEvent = this.miner.filters.NewAccount();
return await this.miner.queryFilter(newAccountEvent, fromBlock, toBlock);
} catch (error) {
const midBlock = (fromBlock + toBlock) >> 1;
if (midBlock - fromBlock < 2) {
throw new Error(`error fetching events: ${error.message}`);
}
const result = await Promise.all([this.fetchEvents(fromBlock, midBlock), this.fetchEvents(midBlock + 1, toBlock)]);
return result.flat();
}
}
return [];
}
}

2
src/services/index.ts Normal file
View File

@ -0,0 +1,2 @@
export { default as priceService } from './PriceService';
export { default as configService } from './ConfigService';

View File

@ -1,12 +1,12 @@
const MerkleTree = require('fixed-merkle-tree')
const { redisUrl, wsRpcUrl, minerMerkleTreeHeight, torn, netId } = require('./config')
const { poseidonHash2 } = require('./utils')
const { toBN } = require('web3-utils')
const Redis = require('ioredis')
const redis = new Redis(redisUrl)
const ENSResolver = require('./resolver')
const resolver = new ENSResolver()
const Web3 = require('web3')
const MerkleTree = require('fixed-merkle-tree');
const { redisUrl, wsRpcUrl, minerMerkleTreeHeight, torn, netId } = require('./config');
const { poseidonHash2 } = require('./utils');
const { toBN } = require('web3-utils');
const Redis = require('ioredis');
const redis = new Redis(redisUrl);
const ENSResolver = require('./resolver');
const resolver = new ENSResolver();
const Web3 = require('web3');
const web3 = new Web3(
new Web3.providers.WebsocketProvider(wsRpcUrl, {
clientConfig: {
@ -14,12 +14,12 @@ const web3 = new Web3(
maxReceivedMessageSize: 100000000,
},
}),
)
const MinerABI = require('../abis/mining.abi.json')
let contract
);
const MinerABI = require('../abis/mining.abi.json');
let contract;
// eslint-disable-next-line no-unused-vars
let tree, eventSubscription, blockSubscription
let tree, eventSubscription, blockSubscription;
async function fetchEvents(fromBlock, toBlock) {
if (fromBlock <= toBlock) {
@ -27,25 +27,25 @@ async function fetchEvents(fromBlock, toBlock) {
return await contract.getPastEvents('NewAccount', {
fromBlock,
toBlock,
})
});
} catch (error) {
const midBlock = (fromBlock + toBlock) >> 1
const midBlock = (fromBlock + toBlock) >> 1;
if (midBlock - fromBlock < 2) {
throw new Error(`error fetching events: ${error.message}`)
throw new Error(`error fetching events: ${error.message}`);
}
const arr1 = await fetchEvents(fromBlock, midBlock)
const arr2 = await fetchEvents(midBlock + 1, toBlock)
return [...arr1, ...arr2]
const arr1 = await fetchEvents(fromBlock, midBlock);
const arr2 = await fetchEvents(midBlock + 1, toBlock);
return [...arr1, ...arr2];
}
}
return []
return [];
}
async function processNewEvent(err, event) {
if (err) {
throw new Error(`Event handler error: ${err}`)
throw new Error(`Event handler error: ${err}`);
// console.error(err)
// return
}
@ -56,52 +56,52 @@ async function processNewEvent(err, event) {
Commitment: ${event.returnValues.commitment}
Nullifier: ${event.returnValues.nullifier}
EncAcc: ${event.returnValues.encryptedAccount}`,
)
const { commitment, index } = event.returnValues
);
const { commitment, index } = event.returnValues;
if (tree.elements().length === Number(index)) {
tree.insert(toBN(commitment))
await updateRedis()
tree.insert(toBN(commitment));
await updateRedis();
} else if (tree.elements().length === Number(index) + 1) {
console.log('Replacing element', index)
tree.update(index, toBN(commitment))
await updateRedis()
console.log('Replacing element', index);
tree.update(index, toBN(commitment));
await updateRedis();
} else {
console.log(`Invalid element index ${index}, rebuilding tree`)
rebuild()
console.log(`Invalid element index ${index}, rebuilding tree`);
rebuild();
}
}
async function processNewBlock(err) {
if (err) {
throw new Error(`Event handler error: ${err}`)
throw new Error(`Event handler error: ${err}`);
// console.error(err)
// return
}
// what if updateRedis takes more than 15 sec?
await updateRedis()
await updateRedis();
}
async function updateRedis() {
const rootOnContract = await contract.methods.getLastAccountRoot().call()
const rootOnContract = await contract.methods.getLastAccountRoot().call();
if (!tree.root().eq(toBN(rootOnContract))) {
console.log(`Invalid tree root: ${tree.root()} != ${toBN(rootOnContract)}, rebuilding tree`)
rebuild()
return
console.log(`Invalid tree root: ${tree.root()} != ${toBN(rootOnContract)}, rebuilding tree`);
rebuild();
return;
}
const rootInRedis = await redis.get('tree:root')
const rootInRedis = await redis.get('tree:root');
if (!rootInRedis || !tree.root().eq(toBN(rootInRedis))) {
const serializedTree = JSON.stringify(tree.serialize())
await redis.set('tree:elements', serializedTree)
await redis.set('tree:root', tree.root().toString())
await redis.publish('treeUpdate', tree.root().toString())
console.log('Updated tree in redis, new root:', tree.root().toString())
const serializedTree = JSON.stringify(tree.serialize());
await redis.set('tree:elements', serializedTree);
await redis.set('tree:root', tree.root().toString());
await redis.publish('treeUpdate', tree.root().toString());
console.log('Updated tree in redis, new root:', tree.root().toString());
} else {
console.log('Tree in redis is up to date, skipping update')
console.log('Tree in redis is up to date, skipping update');
}
}
function rebuild() {
process.exit(1)
process.exit(1);
// await eventSubscription.unsubscribe()
// await blockSubscription.unsubscribe()
// setTimeout(init, 3000)
@ -109,38 +109,38 @@ function rebuild() {
async function init() {
try {
console.log('Initializing')
const miner = await resolver.resolve(torn.miningV2.address)
contract = new web3.eth.Contract(MinerABI, miner)
console.log('Initializing');
const miner = await resolver.resolve(torn.miningV2.address);
contract = new web3.eth.Contract(MinerABI, miner);
const cachedEvents = require(`../cache/accounts_farmer_${netId}.json`)
const cachedCommitments = cachedEvents.map(e => toBN(e.commitment))
const cachedEvents = require(`../cache/accounts_farmer_${netId}.json`);
const cachedCommitments = cachedEvents.map(e => toBN(e.commitment));
const toBlock = await web3.eth.getBlockNumber()
const [{ blockNumber: fromBlock }] = cachedEvents.slice(-1)
const toBlock = await web3.eth.getBlockNumber();
const [{ blockNumber: fromBlock }] = cachedEvents.slice(-1);
const newEvents = await fetchEvents(fromBlock + 1, toBlock)
const newEvents = await fetchEvents(fromBlock + 1, toBlock);
const newCommitments = newEvents
.sort((a, b) => a.returnValues.index - b.returnValues.index)
.map(e => toBN(e.returnValues.commitment))
.filter((item, index, arr) => !index || item != arr[index - 1])
.filter((item, index, arr) => !index || item !== arr[index - 1]);
const commitments = cachedCommitments.concat(newCommitments)
const commitments = cachedCommitments.concat(newCommitments);
tree = new MerkleTree(minerMerkleTreeHeight, commitments, { hashFunction: poseidonHash2 })
await updateRedis()
console.log(`Rebuilt tree with ${commitments.length} elements, root: ${tree.root()}`)
tree = new MerkleTree(minerMerkleTreeHeight, commitments, { hashFunction: poseidonHash2 });
await updateRedis();
console.log(`Rebuilt tree with ${commitments.length} elements, root: ${tree.root()}`);
eventSubscription = contract.events.NewAccount({ fromBlock: toBlock + 1 }, processNewEvent)
blockSubscription = web3.eth.subscribe('newBlockHeaders', processNewBlock)
eventSubscription = contract.events.NewAccount({ fromBlock: toBlock + 1 }, processNewEvent);
blockSubscription = web3.eth.subscribe('newBlockHeaders', processNewBlock);
} catch (e) {
console.error('error on init treeWatcher', e.message)
console.error('error on init treeWatcher', e.message);
}
}
init()
init();
process.on('unhandledRejection', error => {
console.error('Unhandled promise rejection', error)
process.exit(1)
})
console.error('Unhandled promise rejection', error);
process.exit(1);
});

17
src/types.ts Normal file
View File

@ -0,0 +1,17 @@
export enum jobType {
TORNADO_WITHDRAW = 'TORNADO_WITHDRAW',
MINING_REWARD = 'MINING_REWARD',
MINING_WITHDRAW = 'MINING_WITHDRAW',
}
export enum jobStatus {
QUEUED = 'QUEUED',
ACCEPTED = 'ACCEPTED',
SENT = 'SENT',
MINED = 'MINED',
RESUBMITTED = 'RESUBMITTED',
CONFIRMED = 'CONFIRMED',
FAILED = 'FAILED',
}
export type Token = { address: string, decimals: number, symbol?: string }

View File

@ -1,6 +1,6 @@
const { instances, netId } = require('./config')
const { poseidon } = require('circomlib')
const { toBN, toChecksumAddress, BN } = require('web3-utils')
const { instances, netId } = require('./config');
const { poseidon } = require('circomlib');
const { toBN, toChecksumAddress, BN } = require('web3-utils');
const TOKENS = {
torn: {
@ -8,32 +8,42 @@ const TOKENS = {
symbol: 'TORN',
decimals: 18,
},
};
const addressMap = new Map();
const instance = instances[`netId${netId}`];
for (const [currency, { instanceAddress, symbol, decimals }] of Object.entries(instance)) {
Object.entries(instanceAddress).forEach(([amount, address]) =>
addressMap.set(`${netId}_${address}`, {
currency,
amount,
symbol,
decimals,
}),
);
}
const sleep = ms => new Promise(res => setTimeout(res, ms))
const sleep = ms => new Promise(res => setTimeout(res, ms));
function getInstance(address) {
address = toChecksumAddress(address)
const inst = instances[`netId${netId}`]
for (const currency of Object.keys(inst)) {
for (const amount of Object.keys(inst[currency].instanceAddress)) {
if (inst[currency].instanceAddress[amount] === address) {
return { currency, amount }
}
}
export function getInstance(address) {
const key = `${netId}_${toChecksumAddress(address)}`;
if (addressMap.has(key)) {
return addressMap.get(key);
} else {
throw new Error('Unknown contact address');
}
return null
}
const poseidonHash = items => toBN(poseidon(items).toString())
const poseidonHash2 = (a, b) => poseidonHash([a, b])
const poseidonHash = items => toBN(poseidon(items).toString());
const poseidonHash2 = (a, b) => poseidonHash([a, b]);
function setSafeInterval(func, interval) {
func()
.catch(console.error)
.finally(() => {
setTimeout(() => setSafeInterval(func, interval), interval)
})
setTimeout(() => setSafeInterval(func, interval), interval);
});
}
/**
@ -43,79 +53,79 @@ function when(source, event) {
return new Promise((resolve, reject) => {
source
.once(event, payload => {
resolve(payload)
resolve(payload);
})
.on('error', error => {
reject(error)
})
})
reject(error);
});
});
}
function getArgsForOracle() {
const tokens = {
...instances.netId1,
...TOKENS,
}
const tokenAddresses = []
const oneUintAmount = []
const currencyLookup = {}
};
const tokenAddresses = [];
const oneUintAmount = [];
const currencyLookup = {};
Object.entries(tokens).map(([currency, data]) => {
if (currency !== 'eth') {
tokenAddresses.push(data.tokenAddress)
oneUintAmount.push(toBN('10').pow(toBN(data.decimals.toString())).toString())
currencyLookup[data.tokenAddress] = currency
tokenAddresses.push(data.tokenAddress);
oneUintAmount.push(toBN('10').pow(toBN(data.decimals.toString())).toString());
currencyLookup[data.tokenAddress] = currency;
}
})
return { tokenAddresses, oneUintAmount, currencyLookup }
});
return { tokenAddresses, oneUintAmount, currencyLookup };
}
function fromDecimals(value, decimals) {
value = value.toString()
let ether = value.toString()
const base = new BN('10').pow(new BN(decimals))
const baseLength = base.toString(10).length - 1 || 1
value = value.toString();
let ether = value.toString();
const base = new BN('10').pow(new BN(decimals));
const baseLength = base.toString(10).length - 1 || 1;
const negative = ether.substring(0, 1) === '-'
const negative = ether.substring(0, 1) === '-';
if (negative) {
ether = ether.substring(1)
ether = ether.substring(1);
}
if (ether === '.') {
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, invalid value')
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, invalid value');
}
// Split it into a whole and fractional part
const comps = ether.split('.')
const comps = ether.split('.');
if (comps.length > 2) {
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, too many decimal points')
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, too many decimal points');
}
let whole = comps[0]
let fraction = comps[1]
let whole = comps[0];
let fraction = comps[1];
if (!whole) {
whole = '0'
whole = '0';
}
if (!fraction) {
fraction = '0'
fraction = '0';
}
if (fraction.length > baseLength) {
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, too many decimal places')
throw new Error('[ethjs-unit] while converting number ' + value + ' to wei, too many decimal places');
}
while (fraction.length < baseLength) {
fraction += '0'
fraction += '0';
}
whole = new BN(whole)
fraction = new BN(fraction)
let wei = whole.mul(base).add(fraction)
whole = new BN(whole);
fraction = new BN(fraction);
let wei = whole.mul(base).add(fraction);
if (negative) {
wei = wei.mul(negative)
wei = wei.mul(negative);
}
return new BN(wei.toString(10), 10)
return new BN(wei.toString(10), 10);
}
module.exports = {
@ -126,4 +136,4 @@ module.exports = {
when,
getArgsForOracle,
fromDecimals,
}
};

View File

@ -1,49 +1,15 @@
const { isAddress, toChecksumAddress } = require('web3-utils')
const { getInstance } = require('./utils')
const { rewardAccount } = require('./config')
const { isAddress, toChecksumAddress } = require('web3-utils');
const { getInstance } = require('./utils');
const { rewardAccount } = require('./config');
const Ajv = require('ajv')
const ajv = new Ajv({ format: 'fast' })
const Ajv = require('ajv');
ajv.addKeyword('isAddress', {
validate: (schema, data) => {
try {
return isAddress(data)
} catch (e) {
return false
}
},
errors: true,
})
ajv.addKeyword('isKnownContract', {
validate: (schema, data) => {
try {
return getInstance(data) !== null
} catch (e) {
return false
}
},
errors: true,
})
ajv.addKeyword('isFeeRecipient', {
validate: (schema, data) => {
try {
return toChecksumAddress(rewardAccount) === toChecksumAddress(data)
} catch (e) {
return false
}
},
errors: true,
})
const addressType = { type: 'string', pattern: '^0x[a-fA-F0-9]{40}$', isAddress: true }
const proofType = { type: 'string', pattern: '^0x[a-fA-F0-9]{512}$' }
const encryptedAccountType = { type: 'string', pattern: '^0x[a-fA-F0-9]{392}$' }
const bytes32Type = { type: 'string', pattern: '^0x[a-fA-F0-9]{64}$' }
const instanceType = { ...addressType, isKnownContract: true }
const relayerType = { ...addressType, isFeeRecipient: true }
const addressType = { type: 'string', pattern: '^0x[a-fA-F0-9]{40}$', isAddress: true };
const proofType = { type: 'string', pattern: '^0x[a-fA-F0-9]{512}$' };
const encryptedAccountType = { type: 'string', pattern: '^0x[a-fA-F0-9]{392}$' };
const bytes32Type = { type: 'string', pattern: '^0x[a-fA-F0-9]{64}$' };
const instanceType = { ...addressType, isKnownContract: true };
const relayerType = { ...addressType, isFeeRecipient: true };
const tornadoWithdrawSchema = {
type: 'object',
@ -59,7 +25,7 @@ const tornadoWithdrawSchema = {
},
additionalProperties: false,
required: ['proof', 'contract', 'args'],
}
};
const miningRewardSchema = {
type: 'object',
@ -119,7 +85,7 @@ const miningRewardSchema = {
},
additionalProperties: false,
required: ['proof', 'args'],
}
};
const miningWithdrawSchema = {
type: 'object',
@ -166,35 +132,35 @@ const miningWithdrawSchema = {
},
additionalProperties: false,
required: ['proof', 'args'],
}
};
const validateTornadoWithdraw = ajv.compile(tornadoWithdrawSchema)
const validateMiningReward = ajv.compile(miningRewardSchema)
const validateMiningWithdraw = ajv.compile(miningWithdrawSchema)
const validateTornadoWithdraw = ajv.compile(tornadoWithdrawSchema);
const validateMiningReward = ajv.compile(miningRewardSchema);
const validateMiningWithdraw = ajv.compile(miningWithdrawSchema);
function getInputError(validator, data) {
validator(data)
validator(data);
if (validator.errors) {
const error = validator.errors[0]
return `${error.dataPath} ${error.message}`
const error = validator.errors[0];
return `${error.dataPath} ${error.message}`;
}
return null
return null;
}
function getTornadoWithdrawInputError(data) {
return getInputError(validateTornadoWithdraw, data)
return getInputError(validateTornadoWithdraw, data);
}
function getMiningRewardInputError(data) {
return getInputError(validateMiningReward, data)
return getInputError(validateMiningReward, data);
}
function getMiningWithdrawInputError(data) {
return getInputError(validateMiningWithdraw, data)
return getInputError(validateMiningWithdraw, data);
}
module.exports = {
getTornadoWithdrawInputError,
getMiningRewardInputError,
getMiningWithdrawInputError,
}
};

View File

@ -1,19 +1,19 @@
const fs = require('fs')
const Web3 = require('web3')
const { toBN, toWei, fromWei, toChecksumAddress } = require('web3-utils')
const MerkleTree = require('fixed-merkle-tree')
const Redis = require('ioredis')
const { GasPriceOracle } = require('gas-price-oracle')
const { Utils, Controller } = require('tornado-anonymity-mining')
const fs = require('fs');
const Web3 = require('web3');
const { toBN, toWei, fromWei, toChecksumAddress } = require('web3-utils');
const MerkleTree = require('fixed-merkle-tree');
const Redis = require('ioredis');
const { GasPriceOracle } = require('gas-price-oracle');
const { Utils, Controller } = require('tornado-anonymity-mining');
const swapABI = require('../abis/swap.abi.json')
const miningABI = require('../abis/mining.abi.json')
const tornadoABI = require('../abis/tornadoABI.json')
const tornadoProxyABI = require('../abis/tornadoProxyABI.json')
const aggregatorAbi = require('../abis/Aggregator.abi.json')
const { queue } = require('./queue')
const { poseidonHash2, getInstance, fromDecimals, sleep } = require('./utils')
const { jobType, status } = require('./constants')
// const swapABI = require('../abis/swap.abi.json');
const miningABI = require('../abis/mining.abi.json');
const tornadoABI = require('../abis/tornadoABI.json');
const tornadoProxyABI = require('../abis/tornadoProxyABI.json');
const aggregatorAbi = require('../abis/Aggregator.abi.json');
const { queue } = require('./queue');
const { poseidonHash2, getInstance, fromDecimals, sleep } = require('./utils');
const { jobType, status } = require('./constants');
const {
torn,
netId,
@ -29,57 +29,57 @@ const {
tornadoGoerliProxy,
governanceAddress,
aggregatorAddress,
} = require('./config')
const ENSResolver = require('./resolver')
const resolver = new ENSResolver()
const { TxManager } = require('tx-manager')
} = require('./config');
const ENSResolver = require('./resolver');
const resolver = new ENSResolver();
const { TxManager } = require('tx-manager');
let web3
let currentTx
let currentJob
let tree
let txManager
let controller
let swap
let minerContract
const redis = new Redis(redisUrl)
const redisSubscribe = new Redis(redisUrl)
const gasPriceOracle = new GasPriceOracle({ defaultRpc: oracleRpcUrl })
let web3;
let currentTx;
let currentJob;
let tree;
let txManager;
let controller;
let swap;
let minerContract;
const redis = new Redis(redisUrl);
const redisSubscribe = new Redis(redisUrl);
const gasPriceOracle = new GasPriceOracle({ defaultRpc: oracleRpcUrl });
async function fetchTree() {
const elements = await redis.get('tree:elements')
const convert = (_, val) => (typeof val === 'string' ? toBN(val) : val)
tree = MerkleTree.deserialize(JSON.parse(elements, convert), poseidonHash2)
const elements = await redis.get('tree:elements');
const convert = (_, val) => (typeof val === 'string' ? toBN(val) : val);
tree = MerkleTree.deserialize(JSON.parse(elements, convert), poseidonHash2);
if (currentTx && currentJob && ['MINING_REWARD', 'MINING_WITHDRAW'].includes(currentJob.data.type)) {
const { proof, args } = currentJob.data
const { proof, args } = currentJob.data;
if (toBN(args.account.inputRoot).eq(toBN(tree.root()))) {
console.log('Account root is up to date. Skipping Root Update operation...')
return
console.log('Account root is up to date. Skipping Root Update operation...');
return;
} else {
console.log('Account root is outdated. Starting Root Update operation...')
console.log('Account root is outdated. Starting Root Update operation...');
}
const update = await controller.treeUpdate(args.account.outputCommitment, tree)
const update = await controller.treeUpdate(args.account.outputCommitment, tree);
const minerAddress = await resolver.resolve(torn.miningV2.address)
const instance = new web3.eth.Contract(miningABI, minerAddress)
const minerAddress = await resolver.resolve(torn.miningV2.address);
const instance = new web3.eth.Contract(miningABI, minerAddress);
const data =
currentJob.data.type === 'MINING_REWARD'
? instance.methods.reward(proof, args, update.proof, update.args).encodeABI()
: instance.methods.withdraw(proof, args, update.proof, update.args).encodeABI()
: instance.methods.withdraw(proof, args, update.proof, update.args).encodeABI();
await currentTx.replace({
to: minerAddress,
data,
})
console.log('replaced pending tx')
});
console.log('replaced pending tx');
}
}
async function start() {
try {
web3 = new Web3(httpRpcUrl)
const { CONFIRMATIONS, MAX_GAS_PRICE } = process.env
web3 = new Web3(httpRpcUrl);
const { CONFIRMATIONS, MAX_GAS_PRICE } = process.env;
txManager = new TxManager({
privateKey,
rpcUrl: httpRpcUrl,
@ -89,161 +89,163 @@ async function start() {
THROW_ON_REVERT: false,
BASE_FEE_RESERVE_PERCENTAGE: baseFeeReserve,
},
})
swap = new web3.eth.Contract(swapABI, await resolver.resolve(torn.rewardSwap.address))
minerContract = new web3.eth.Contract(miningABI, await resolver.resolve(torn.miningV2.address))
redisSubscribe.subscribe('treeUpdate', fetchTree)
await fetchTree()
});
swap = new web3.eth.Contract(swapABI, await resolver.resolve(torn.rewardSwap.address));
minerContract = new web3.eth.Contract(miningABI, await resolver.resolve(torn.miningV2.address));
redisSubscribe.subscribe('treeUpdate', fetchTree);
await fetchTree();
const provingKeys = {
treeUpdateCircuit: require('../keys/TreeUpdate.json'),
treeUpdateProvingKey: fs.readFileSync('./keys/TreeUpdate_proving_key.bin').buffer,
}
controller = new Controller({ provingKeys })
await controller.init()
queue.process(processJob)
console.log('Worker started')
};
controller = new Controller({ provingKeys });
await controller.init();
queue.process(processJob);
console.log('Worker started');
} catch (e) {
console.error('error on start worker', e.message)
console.error('error on start worker', e.message);
}
}
function checkFee({ data }) {
if (data.type === jobType.TORNADO_WITHDRAW) {
return checkTornadoFee(data)
return checkTornadoFee(data);
}
return checkMiningFee(data)
// return checkMiningFee(data);
}
async function getGasPrice() {
const block = await web3.eth.getBlock('latest')
const block = await web3.eth.getBlock('latest');
if (block && block.baseFeePerGas) {
const baseFeePerGas = toBN(block.baseFeePerGas)
return baseFeePerGas
const baseFeePerGas = toBN(block.baseFeePerGas);
return baseFeePerGas;
}
const { fast } = await gasPriceOracle.gasPrices()
const gasPrice = toBN(toWei(fast.toString(), 'gwei'))
return gasPrice
const { fast } = await gasPriceOracle.gasPrices();
const gasPrice = toBN(toWei(fast.toString(), 'gwei'));
return gasPrice;
}
async function checkTornadoFee({ args, contract }) {
const { currency, amount } = getInstance(contract)
const { decimals } = instances[`netId${netId}`][currency]
const [fee, refund] = [args[4], args[5]].map(toBN)
const gasPrice = await getGasPrice()
const { currency, amount } = getInstance(contract);
const { decimals } = instances[`netId${netId}`][currency];
const [fee, refund] = [args[4], args[5]].map(toBN);
const gasPrice = await getGasPrice();
const ethPrice = await redis.hget('prices', currency)
const expense = gasPrice.mul(toBN(gasLimits[jobType.TORNADO_WITHDRAW]))
const ethPrice = await redis.hget('prices', currency);
const expense = gasPrice.mul(toBN(gasLimits[jobType.TORNADO_WITHDRAW]));
const feePercent = toBN(fromDecimals(amount, decimals))
.mul(toBN(parseInt(tornadoServiceFee * 1e10)))
.div(toBN(1e10 * 100))
.div(toBN(1e10 * 100));
let desiredFee
let desiredFee;
switch (currency) {
case 'eth': {
desiredFee = expense.add(feePercent)
break
}
default: {
desiredFee = expense
.add(refund)
.mul(toBN(10 ** decimals))
.div(toBN(ethPrice))
desiredFee = desiredFee.add(feePercent)
break
}
case 'eth': {
desiredFee = expense.add(feePercent);
break;
}
default: {
desiredFee = expense
.add(refund)
.mul(toBN(10 ** decimals))
.div(toBN(ethPrice));
desiredFee = desiredFee.add(feePercent);
break;
}
}
console.log(
'sent fee, desired fee, feePercent',
fromWei(fee.toString()),
fromWei(desiredFee.toString()),
fromWei(feePercent.toString()),
)
);
if (fee.lt(desiredFee)) {
throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.')
throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.');
}
}
async function checkMiningFee({ args }) {
const gasPrice = await getGasPrice()
const ethPrice = await redis.hget('prices', 'torn')
const isMiningReward = currentJob.data.type === jobType.MINING_REWARD
const providedFee = isMiningReward ? toBN(args.fee) : toBN(args.extData.fee)
const expense = gasPrice.mul(toBN(gasLimits[currentJob.data.type]))
const expenseInTorn = expense.mul(toBN(1e18)).div(toBN(ethPrice))
// todo make aggregator for ethPrices and rewardSwap data
const balance = await swap.methods.tornVirtualBalance().call()
const poolWeight = await swap.methods.poolWeight().call()
const expenseInPoints = Utils.reverseTornadoFormula({ balance, tokens: expenseInTorn, poolWeight })
/* eslint-disable */
const serviceFeePercent = isMiningReward
? toBN(0)
: toBN(args.amount)
.sub(providedFee) // args.amount includes fee
.mul(toBN(parseInt(miningServiceFee * 1e10)))
.div(toBN(1e10 * 100))
/* eslint-enable */
const desiredFee = expenseInPoints.add(serviceFeePercent) // in points
console.log(
'user provided fee, desired fee, serviceFeePercent',
providedFee.toString(),
desiredFee.toString(),
serviceFeePercent.toString(),
)
if (toBN(providedFee).lt(desiredFee)) {
throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.')
}
}
// async function checkMiningFee({ args }) {
// const gasPrice = await getGasPrice();
// const ethPrice = await redis.hget('prices', 'torn');
// const isMiningReward = currentJob.data.type === jobType.MINING_REWARD;
// const providedFee = isMiningReward ? toBN(args.fee) : toBN(args.extData.fee);
//
// const expense = gasPrice.mul(toBN(gasLimits[currentJob.data.type]));
// const expenseInTorn = expense.mul(toBN(1e18)).div(toBN(ethPrice));
// // todo make aggregator for ethPrices and rewardSwap data
// const balance = await swap.methods.tornVirtualBalance().call();
// const poolWeight = await swap.methods.poolWeight().call();
// const expenseInPoints = Utils.reverseTornadoFormula({ balance, tokens: expenseInTorn, poolWeight });
// /* eslint-disable */
// const serviceFeePercent = isMiningReward
// ? toBN(0)
// : toBN(args.amount)
// .sub(providedFee) // args.amount includes fee
// .mul(toBN(parseInt(miningServiceFee * 1e10)))
// .div(toBN(1e10 * 100))
// /* eslint-enable */
// const desiredFee = expenseInPoints.add(serviceFeePercent); // in points
// console.log(
// 'user provided fee, desired fee, serviceFeePercent',
// providedFee.toString(),
// desiredFee.toString(),
// serviceFeePercent.toString(),
// );
// if (toBN(providedFee).lt(desiredFee)) {
// throw new Error('Provided fee is not enough. Probably it is a Gas Price spike, try to resubmit.');
// }
// }
async function isLatestProposalExecuted() {
const PROPOSAL_EXECUTED_STATUS = 5
const expectedProposalId = 10
const PROPOSAL_EXECUTED_STATUS = 5;
const expectedProposalId = 10;
try {
const aggregator = new web3.eth.Contract(aggregatorAbi, aggregatorAddress)
const proposals = await aggregator.methods.getAllProposals(governanceAddress).call()
const expectedProposal = proposals[expectedProposalId - 1]
return expectedProposal && Number(expectedProposal['state']) === PROPOSAL_EXECUTED_STATUS
const aggregator = new web3.eth.Contract(aggregatorAbi, aggregatorAddress);
const proposals = await aggregator.methods.getAllProposals(governanceAddress).call();
const expectedProposal = proposals[expectedProposalId - 1];
return expectedProposal && Number(expectedProposal['state']) === PROPOSAL_EXECUTED_STATUS;
} catch (e) {
console.error(e.message)
return false
console.error(e.message);
return false;
}
}
async function getProxyContract() {
let proxyAddress
let proxyAddress;
if (netId === 5) {
proxyAddress = tornadoGoerliProxy
proxyAddress = tornadoGoerliProxy;
} else {
const latestProposalExecuted = await isLatestProposalExecuted()
const latestProposalExecuted = await isLatestProposalExecuted();
proxyAddress = latestProposalExecuted
? await resolver.resolve(torn.tornadoRouter.address)
: await resolver.resolve(torn.tornadoProxy.address)
: await resolver.resolve(torn.tornadoProxy.address);
}
const contract = new web3.eth.Contract(tornadoProxyABI, proxyAddress)
const contract = new web3.eth.Contract(tornadoProxyABI, proxyAddress);
return {
contract,
isOldProxy: checkOldProxy(proxyAddress),
}
};
}
function checkOldProxy(address) {
const OLD_PROXY = '0x905b63Fff465B9fFBF41DeA908CEb12478ec7601'
return toChecksumAddress(address) === toChecksumAddress(OLD_PROXY)
const OLD_PROXY = '0x905b63Fff465B9fFBF41DeA908CEb12478ec7601';
return toChecksumAddress(address) === toChecksumAddress(OLD_PROXY);
}
async function getTxObject({ data }) {
if (data.type === jobType.TORNADO_WITHDRAW) {
let { contract, isOldProxy } = await getProxyContract()
let { contract, isOldProxy } = await getProxyContract();
let calldata = contract.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI()
let calldata = contract.methods.withdraw(data.contract, data.proof, ...data.args).encodeABI();
if (isOldProxy && getInstance(data.contract).currency !== 'eth') {
contract = new web3.eth.Contract(tornadoABI, data.contract)
calldata = contract.methods.withdraw(data.proof, ...data.args).encodeABI()
contract = new web3.eth.Contract(tornadoABI, data.contract);
calldata = contract.methods.withdraw(data.proof, ...data.args).encodeABI();
}
return {
@ -251,81 +253,81 @@ async function getTxObject({ data }) {
to: contract._address,
data: calldata,
gasLimit: gasLimits['WITHDRAW_WITH_EXTRA'],
}
};
} else {
const method = data.type === jobType.MINING_REWARD ? 'reward' : 'withdraw'
const calldata = minerContract.methods[method](data.proof, data.args).encodeABI()
const method = data.type === jobType.MINING_REWARD ? 'reward' : 'withdraw';
const calldata = minerContract.methods[method](data.proof, data.args).encodeABI();
return {
to: minerContract._address,
data: calldata,
gasLimit: gasLimits[data.type],
}
};
}
}
async function isOutdatedTreeRevert(receipt, currentTx) {
try {
await web3.eth.call(currentTx.tx, receipt.blockNumber)
console.log('Simulated call successful')
return false
await web3.eth.call(currentTx.tx, receipt.blockNumber);
console.log('Simulated call successful');
return false;
} catch (e) {
console.log('Decoded revert reason:', e.message)
console.log('Decoded revert reason:', e.message);
return (
e.message.indexOf('Outdated account merkle root') !== -1 ||
e.message.indexOf('Outdated tree update merkle root') !== -1
)
);
}
}
async function processJob(job) {
try {
if (!jobType[job.data.type]) {
throw new Error(`Unknown job type: ${job.data.type}`)
throw new Error(`Unknown job type: ${job.data.type}`);
}
currentJob = job
await updateStatus(status.ACCEPTED)
console.log(`Start processing a new ${job.data.type} job #${job.id}`)
await submitTx(job)
currentJob = job;
await updateStatus(status.ACCEPTED);
console.log(`Start processing a new ${job.data.type} job #${job.id}`);
await submitTx(job);
} catch (e) {
console.error('processJob', e.message)
await updateStatus(status.FAILED)
throw e
console.error('processJob', e.message);
await updateStatus(status.FAILED);
throw e;
}
}
async function submitTx(job, retry = 0) {
await checkFee(job)
currentTx = await txManager.createTx(await getTxObject(job))
await checkFee(job);
currentTx = await txManager.createTx(await getTxObject(job));
if (job.data.type !== jobType.TORNADO_WITHDRAW) {
await fetchTree()
await fetchTree();
}
try {
const receipt = await currentTx
.send()
.on('transactionHash', txHash => {
updateTxHash(txHash)
updateStatus(status.SENT)
updateTxHash(txHash);
updateStatus(status.SENT);
})
.on('mined', receipt => {
console.log('Mined in block', receipt.blockNumber)
updateStatus(status.MINED)
console.log('Mined in block', receipt.blockNumber);
updateStatus(status.MINED);
})
.on('confirmations', updateConfirmations)
.on('confirmations', updateConfirmations);
if (receipt.status === 1) {
await updateStatus(status.CONFIRMED)
await updateStatus(status.CONFIRMED);
} else {
if (job.data.type !== jobType.TORNADO_WITHDRAW && (await isOutdatedTreeRevert(receipt, currentTx))) {
if (retry < 3) {
await updateStatus(status.RESUBMITTED)
await submitTx(job, retry + 1)
await updateStatus(status.RESUBMITTED);
await submitTx(job, retry + 1);
} else {
throw new Error('Tree update retry limit exceeded')
throw new Error('Tree update retry limit exceeded');
}
} else {
throw new Error('Submitted transaction failed')
throw new Error('Submitted transaction failed');
}
}
} catch (e) {
@ -337,34 +339,34 @@ async function submitTx(job, retry = 0) {
e.message.indexOf('Outdated tree update merkle root') !== -1)
) {
if (retry < 5) {
await sleep(3000)
console.log('Tree is still not up to date, resubmitting')
await submitTx(job, retry + 1)
await sleep(3000);
console.log('Tree is still not up to date, resubmitting');
await submitTx(job, retry + 1);
} else {
throw new Error('Tree update retry limit exceeded')
throw new Error('Tree update retry limit exceeded');
}
} else {
throw new Error(`Revert by smart contract ${e.message}`)
throw new Error(`Revert by smart contract ${e.message}`);
}
}
}
async function updateTxHash(txHash) {
console.log(`A new successfully sent tx ${txHash}`)
currentJob.data.txHash = txHash
await currentJob.update(currentJob.data)
console.log(`A new successfully sent tx ${txHash}`);
currentJob.data.txHash = txHash;
await currentJob.update(currentJob.data);
}
async function updateConfirmations(confirmations) {
console.log(`Confirmations count ${confirmations}`)
currentJob.data.confirmations = confirmations
await currentJob.update(currentJob.data)
console.log(`Confirmations count ${confirmations}`);
currentJob.data.confirmations = confirmations;
await currentJob.update(currentJob.data);
}
async function updateStatus(status) {
console.log(`Job status updated ${status}`)
currentJob.data.status = status
await currentJob.update(currentJob.data)
console.log(`Job status updated ${status}`);
currentJob.data.status = status;
await currentJob.update(currentJob.data);
}
start()
start();

25
tsconfig.json Normal file
View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"lib": [
"es6",
"es2020"
],
"target": "es2017",
"module": "commonjs",
"moduleResolution": "node",
"outDir": "./build",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"resolveJsonModule": true
},
"include": [
"src"
],
"exclude": [
"node_modules",
"test"
]
}

7544
yarn-error.log Normal file

File diff suppressed because it is too large Load Diff

2171
yarn.lock

File diff suppressed because it is too large Load Diff